Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 18 Jul 2011 16:03:15 +0000 (09:03 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 18 Jul 2011 16:03:15 +0000 (09:03 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
  hppfs_lookup(): don't open-code lookup_one_len()
  hppfs: fix dentry leak
  cramfs: get_cramfs_inode() returns ERR_PTR() on failure
  ufs should use d_splice_alias()
  fix exofs ->get_parent()
  ceph analog of cifs build_path_from_dentry() race fix
  cifs: build_path_from_dentry() race fix

fs/ceph/mds_client.c
fs/cifs/dir.c
fs/cramfs/inode.c
fs/exofs/super.c
fs/hppfs/hppfs.c
fs/ufs/namei.c

index 79743d1..0c1d917 100644 (file)
@@ -1438,12 +1438,15 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
        struct dentry *temp;
        char *path;
        int len, pos;
+       unsigned seq;
 
        if (dentry == NULL)
                return ERR_PTR(-EINVAL);
 
 retry:
        len = 0;
+       seq = read_seqbegin(&rename_lock);
+       rcu_read_lock();
        for (temp = dentry; !IS_ROOT(temp);) {
                struct inode *inode = temp->d_inode;
                if (inode && ceph_snap(inode) == CEPH_SNAPDIR)
@@ -1455,10 +1458,12 @@ retry:
                        len += 1 + temp->d_name.len;
                temp = temp->d_parent;
                if (temp == NULL) {
+                       rcu_read_unlock();
                        pr_err("build_path corrupt dentry %p\n", dentry);
                        return ERR_PTR(-EINVAL);
                }
        }
+       rcu_read_unlock();
        if (len)
                len--;  /* no leading '/' */
 
@@ -1467,9 +1472,12 @@ retry:
                return ERR_PTR(-ENOMEM);
        pos = len;
        path[pos] = 0;  /* trailing null */
+       rcu_read_lock();
        for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) {
-               struct inode *inode = temp->d_inode;
+               struct inode *inode;
 
+               spin_lock(&temp->d_lock);
+               inode = temp->d_inode;
                if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
                        dout("build_path path+%d: %p SNAPDIR\n",
                             pos, temp);
@@ -1478,21 +1486,26 @@ retry:
                        break;
                } else {
                        pos -= temp->d_name.len;
-                       if (pos < 0)
+                       if (pos < 0) {
+                               spin_unlock(&temp->d_lock);
                                break;
+                       }
                        strncpy(path + pos, temp->d_name.name,
                                temp->d_name.len);
                }
+               spin_unlock(&temp->d_lock);
                if (pos)
                        path[--pos] = '/';
                temp = temp->d_parent;
                if (temp == NULL) {
+                       rcu_read_unlock();
                        pr_err("build_path corrupt dentry\n");
                        kfree(path);
                        return ERR_PTR(-EINVAL);
                }
        }
-       if (pos != 0) {
+       rcu_read_unlock();
+       if (pos != 0 || read_seqretry(&rename_lock, seq)) {
                pr_err("build_path did not end path lookup where "
                       "expected, namelen is %d, pos is %d\n", len, pos);
                /* presumably this is only possible if racing with a
index 81914df..fa8c21d 100644 (file)
@@ -55,6 +55,7 @@ build_path_from_dentry(struct dentry *direntry)
        char dirsep;
        struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
        struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+       unsigned seq;
 
        if (direntry == NULL)
                return NULL;  /* not much we can do if dentry is freed and
@@ -68,22 +69,29 @@ build_path_from_dentry(struct dentry *direntry)
                dfsplen = 0;
 cifs_bp_rename_retry:
        namelen = dfsplen;
+       seq = read_seqbegin(&rename_lock);
+       rcu_read_lock();
        for (temp = direntry; !IS_ROOT(temp);) {
                namelen += (1 + temp->d_name.len);
                temp = temp->d_parent;
                if (temp == NULL) {
                        cERROR(1, "corrupt dentry");
+                       rcu_read_unlock();
                        return NULL;
                }
        }
+       rcu_read_unlock();
 
        full_path = kmalloc(namelen+1, GFP_KERNEL);
        if (full_path == NULL)
                return full_path;
        full_path[namelen] = 0; /* trailing null */
+       rcu_read_lock();
        for (temp = direntry; !IS_ROOT(temp);) {
+               spin_lock(&temp->d_lock);
                namelen -= 1 + temp->d_name.len;
                if (namelen < 0) {
+                       spin_unlock(&temp->d_lock);
                        break;
                } else {
                        full_path[namelen] = dirsep;
@@ -91,14 +99,17 @@ cifs_bp_rename_retry:
                                temp->d_name.len);
                        cFYI(0, "name: %s", full_path + namelen);
                }
+               spin_unlock(&temp->d_lock);
                temp = temp->d_parent;
                if (temp == NULL) {
                        cERROR(1, "corrupt dentry");
+                       rcu_read_unlock();
                        kfree(full_path);
                        return NULL;
                }
        }
-       if (namelen != dfsplen) {
+       rcu_read_unlock();
+       if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
                cERROR(1, "did not end path lookup where expected namelen is %d",
                        namelen);
                /* presumably this is only possible if racing with a rename
index e141939..739fb59 100644 (file)
@@ -37,7 +37,7 @@ static DEFINE_MUTEX(read_mutex);
 /* These macros may change in future, to provide better st_ino semantics. */
 #define OFFSET(x)      ((x)->i_ino)
 
-static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset)
+static unsigned long cramino(const struct cramfs_inode *cino, unsigned int offset)
 {
        if (!cino->offset)
                return offset + 1;
@@ -61,7 +61,7 @@ static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset)
 }
 
 static struct inode *get_cramfs_inode(struct super_block *sb,
-       struct cramfs_inode *cramfs_inode, unsigned int offset)
+       const struct cramfs_inode *cramfs_inode, unsigned int offset)
 {
        struct inode *inode;
        static struct timespec zerotime;
@@ -317,7 +317,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
        /* Set it all up.. */
        sb->s_op = &cramfs_ops;
        root = get_cramfs_inode(sb, &super.root, 0);
-       if (!root)
+       if (IS_ERR(root))
                goto out;
        sb->s_root = d_alloc_root(root);
        if (!sb->s_root) {
@@ -423,6 +423,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
        unsigned int offset = 0;
+       struct inode *inode = NULL;
        int sorted;
 
        mutex_lock(&read_mutex);
@@ -449,8 +450,8 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
 
                for (;;) {
                        if (!namelen) {
-                               mutex_unlock(&read_mutex);
-                               return ERR_PTR(-EIO);
+                               inode = ERR_PTR(-EIO);
+                               goto out;
                        }
                        if (name[namelen-1])
                                break;
@@ -462,17 +463,18 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
                if (retval > 0)
                        continue;
                if (!retval) {
-                       struct cramfs_inode entry = *de;
-                       mutex_unlock(&read_mutex);
-                       d_add(dentry, get_cramfs_inode(dir->i_sb, &entry, dir_off));
-                       return NULL;
+                       inode = get_cramfs_inode(dir->i_sb, de, dir_off);
+                       break;
                }
                /* else (retval < 0) */
                if (sorted)
                        break;
        }
+out:
        mutex_unlock(&read_mutex);
-       d_add(dentry, NULL);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+       d_add(dentry, inode);
        return NULL;
 }
 
index 06065bd..c57bedd 100644 (file)
@@ -913,7 +913,7 @@ struct dentry *exofs_get_parent(struct dentry *child)
        unsigned long ino = exofs_parent_ino(child);
 
        if (!ino)
-               return NULL;
+               return ERR_PTR(-ESTALE);
 
        return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino));
 }
index 87ed48e..85c098a 100644 (file)
@@ -139,7 +139,8 @@ static int file_removed(struct dentry *dentry, const char *file)
 static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
                                   struct nameidata *nd)
 {
-       struct dentry *proc_dentry, *new, *parent;
+       struct dentry *proc_dentry, *parent;
+       struct qstr *name = &dentry->d_name;
        struct inode *inode;
        int err, deleted;
 
@@ -149,23 +150,9 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
        else if (deleted)
                return ERR_PTR(-ENOENT);
 
-       err = -ENOMEM;
        parent = HPPFS_I(ino)->proc_dentry;
        mutex_lock(&parent->d_inode->i_mutex);
-       proc_dentry = d_lookup(parent, &dentry->d_name);
-       if (proc_dentry == NULL) {
-               proc_dentry = d_alloc(parent, &dentry->d_name);
-               if (proc_dentry == NULL) {
-                       mutex_unlock(&parent->d_inode->i_mutex);
-                       goto out;
-               }
-               new = (*parent->d_inode->i_op->lookup)(parent->d_inode,
-                                                      proc_dentry, NULL);
-               if (new) {
-                       dput(proc_dentry);
-                       proc_dentry = new;
-               }
-       }
+       proc_dentry = lookup_one_len(name->name, parent, name->len);
        mutex_unlock(&parent->d_inode->i_mutex);
 
        if (IS_ERR(proc_dentry))
@@ -174,13 +161,11 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
        err = -ENOMEM;
        inode = get_inode(ino->i_sb, proc_dentry);
        if (!inode)
-               goto out_dput;
+               goto out;
 
        d_add(dentry, inode);
        return NULL;
 
- out_dput:
-       dput(proc_dentry);
  out:
        return ERR_PTR(err);
 }
@@ -690,8 +675,10 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
        struct inode *proc_ino = dentry->d_inode;
        struct inode *inode = new_inode(sb);
 
-       if (!inode)
+       if (!inode) {
+               dput(dentry);
                return ERR_PTR(-ENOMEM);
+       }
 
        if (S_ISDIR(dentry->d_inode->i_mode)) {
                inode->i_op = &hppfs_dir_iops;
@@ -704,7 +691,7 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
                inode->i_fop = &hppfs_file_fops;
        }
 
-       HPPFS_I(inode)->proc_dentry = dget(dentry);
+       HPPFS_I(inode)->proc_dentry = dentry;
 
        inode->i_uid = proc_ino->i_uid;
        inode->i_gid = proc_ino->i_gid;
@@ -737,7 +724,7 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
        sb->s_fs_info = proc_mnt;
 
        err = -ENOMEM;
-       root_inode = get_inode(sb, proc_mnt->mnt_sb->s_root);
+       root_inode = get_inode(sb, dget(proc_mnt->mnt_sb->s_root));
        if (!root_inode)
                goto out_mntput;
 
index 29309e2..b57aab9 100644 (file)
@@ -56,16 +56,12 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru
 
        lock_ufs(dir->i_sb);
        ino = ufs_inode_by_name(dir, &dentry->d_name);
-       if (ino) {
+       if (ino)
                inode = ufs_iget(dir->i_sb, ino);
-               if (IS_ERR(inode)) {
-                       unlock_ufs(dir->i_sb);
-                       return ERR_CAST(inode);
-               }
-       }
        unlock_ufs(dir->i_sb);
-       d_add(dentry, inode);
-       return NULL;
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+       return d_splice_alias(inode, dentry);
 }
 
 /*