Merge branch 'overlayfs-af_unix-fix' into overlayfs-linus
authorMiklos Szeredi <mszeredi@redhat.com>
Sun, 12 Jun 2016 10:05:21 +0000 (12:05 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Sun, 12 Jun 2016 10:05:21 +0000 (12:05 +0200)
1  2 
include/linux/dcache.h
net/unix/af_unix.c

diff --combined include/linux/dcache.h
@@@ -10,7 -10,6 +10,7 @@@
  #include <linux/cache.h>
  #include <linux/rcupdate.h>
  #include <linux/lockref.h>
 +#include <linux/stringhash.h>
  
  struct path;
  struct vfsmount;
@@@ -53,6 -52,9 +53,6 @@@ struct qstr 
  };
  
  #define QSTR_INIT(n,l) { { { .len = l } }, .name = n }
 -#define hashlen_hash(hashlen) ((u32) (hashlen))
 -#define hashlen_len(hashlen)  ((u32)((hashlen) >> 32))
 -#define hashlen_create(hash,len) (((u64)(len)<<32)|(u32)(hash))
  
  struct dentry_stat_t {
        long nr_dentry;
  };
  extern struct dentry_stat_t dentry_stat;
  
 -/* Name hashing routines. Initial hash value */
 -/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
 -#define init_name_hash()              0
 -
 -/* partial hash update function. Assume roughly 4 bits per character */
 -static inline unsigned long
 -partial_name_hash(unsigned long c, unsigned long prevhash)
 -{
 -      return (prevhash + (c << 4) + (c >> 4)) * 11;
 -}
 -
 -/*
 - * Finally: cut down the number of bits to a int value (and try to avoid
 - * losing bits)
 - */
 -static inline unsigned long end_name_hash(unsigned long hash)
 -{
 -      return (unsigned int) hash;
 -}
 -
 -/* Compute the hash for a name string. */
 -extern unsigned int full_name_hash(const unsigned char *, unsigned int);
 -
  /*
   * Try to keep struct dentry aligned on 64 byte cachelines (this will
   * give reasonable cacheline footprint with larger lines without the
@@@ -98,10 -123,7 +98,10 @@@ struct dentry 
        unsigned long d_time;           /* used by d_revalidate */
        void *d_fsdata;                 /* fs-specific data */
  
 -      struct list_head d_lru;         /* LRU list */
 +      union {
 +              struct list_head d_lru;         /* LRU list */
 +              wait_queue_head_t *d_wait;      /* in-lookup ones only */
 +      };
        struct list_head d_child;       /* child of parent list */
        struct list_head d_subdirs;     /* our children */
        /*
         */
        union {
                struct hlist_node d_alias;      /* inode alias list */
 +              struct hlist_bl_node d_in_lookup_hash;  /* only for in-lookup ones */
                struct rcu_head d_rcu;
        } d_u;
  };
@@@ -211,8 -232,6 +211,8 @@@ struct dentry_operations 
  #define DCACHE_ENCRYPTED_WITH_KEY     0x04000000 /* dir is encrypted with a valid key */
  #define DCACHE_OP_REAL                        0x08000000
  
 +#define DCACHE_PAR_LOOKUP             0x10000000 /* being looked up (with parent locked shared) */
 +
  extern seqlock_t rename_lock;
  
  /*
@@@ -229,8 -248,6 +229,8 @@@ extern void d_set_d_op(struct dentry *d
  /* allocate/de-allocate */
  extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
  extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *);
 +extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *,
 +                                      wait_queue_head_t *);
  extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
  extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
  extern struct dentry * d_exact_alias(struct dentry *, struct inode *);
@@@ -350,22 -367,6 +350,22 @@@ static inline void dont_mount(struct de
        spin_unlock(&dentry->d_lock);
  }
  
 +extern void __d_lookup_done(struct dentry *);
 +
 +static inline int d_in_lookup(struct dentry *dentry)
 +{
 +      return dentry->d_flags & DCACHE_PAR_LOOKUP;
 +}
 +
 +static inline void d_lookup_done(struct dentry *dentry)
 +{
 +      if (unlikely(d_in_lookup(dentry))) {
 +              spin_lock(&dentry->d_lock);
 +              __d_lookup_done(dentry);
 +              spin_unlock(&dentry->d_lock);
 +      }
 +}
 +
  extern void dput(struct dentry *);
  
  static inline bool d_managed(const struct dentry *dentry)
@@@ -575,5 -576,17 +575,17 @@@ static inline struct inode *vfs_select_
        return inode;
  }
  
+ /**
+  * d_real_inode - Return the real inode
+  * @dentry: The dentry to query
+  *
+  * If dentry is on an union/overlay, then return the underlying, real inode.
+  * Otherwise return d_inode().
+  */
+ static inline struct inode *d_real_inode(struct dentry *dentry)
+ {
+       return d_backing_inode(d_real(dentry));
+ }
  
  #endif        /* __LINUX_DCACHE_H */
diff --combined net/unix/af_unix.c
@@@ -315,7 -315,7 +315,7 @@@ static struct sock *unix_find_socket_by
                    &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
                struct dentry *dentry = unix_sk(s)->path.dentry;
  
-               if (dentry && d_backing_inode(dentry) == i) {
+               if (dentry && d_real_inode(dentry) == i) {
                        sock_hold(s);
                        goto found;
                }
@@@ -911,7 -911,7 +911,7 @@@ static struct sock *unix_find_other(str
                err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path);
                if (err)
                        goto fail;
-               inode = d_backing_inode(path.dentry);
+               inode = d_real_inode(path.dentry);
                err = inode_permission(inode, MAY_WRITE);
                if (err)
                        goto put_fail;
@@@ -953,7 -953,7 +953,7 @@@ fail
        return NULL;
  }
  
 -static int unix_mknod(struct dentry *dentry, struct path *path, umode_t mode,
 +static int unix_mknod(struct dentry *dentry, const struct path *path, umode_t mode,
                      struct path *res)
  {
        int err;
@@@ -1048,7 -1048,7 +1048,7 @@@ static int unix_bind(struct socket *soc
                        goto out_up;
                }
                addr->hash = UNIX_HASH_SIZE;
-               hash = d_backing_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1);
+               hash = d_real_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1);
                spin_lock(&unix_table_lock);
                u->path = u_path;
                list = &unix_socket_table[hash];