bugfix: ensure dentry/inode/mnt validity after a successful ioctl
authorErez_Zadok <ezk@cs.sunysb.edu>
Thu, 31 May 2007 00:14:07 +0000 (20:14 -0400)
committerErez Zadok <ezk@cs.sunysb.edu>
Fri, 20 Jun 2014 00:40:04 +0000 (20:40 -0400)
We call unionfs_partial_lookup in our queryfile ioctl method, so we can find
all instances of a lower object to report back to a suer.  This can violate
the fanout invariants (e.g., a regular file should have only one lower
object active at a time).  So we have to re-establish the invariants on the
lower dentries, inodes, and mnts.

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
fs/unionfs/commonfops.c

index b730934146d58337b94b289d474d2ac41f1caf24..427f70b89230b15641dc1aec950278918291d593 100644 (file)
@@ -686,10 +686,14 @@ static int unionfs_ioctl_queryfile(struct file *file, unsigned int cmd,
        int err = 0;
        fd_set branchlist;
        int bstart = 0, bend = 0, bindex = 0;
+       int orig_bstart, orig_bend;
        struct dentry *dentry, *hidden_dentry;
+       struct vfsmount *mnt;
 
        dentry = file->f_dentry;
        unionfs_lock_dentry(dentry);
+       orig_bstart = dbstart(dentry);
+       orig_bend = dbend(dentry);
        if ((err = unionfs_partial_lookup(dentry)))
                goto out;
        bstart = dbstart(dentry);
@@ -703,7 +707,24 @@ static int unionfs_ioctl_queryfile(struct file *file, unsigned int cmd,
                        continue;
                if (hidden_dentry->d_inode)
                        FD_SET(bindex, &branchlist);
+               /* purge any lower objects after partial_lookup */
+               if (bindex < orig_bstart || bindex > orig_bend) {
+                       dput(hidden_dentry);
+                       unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
+                       iput(unionfs_lower_inode_idx(dentry->d_inode, bindex));
+                       unionfs_set_lower_inode_idx(dentry->d_inode, bindex,
+                                                   NULL);
+                       mnt = unionfs_lower_mnt_idx(dentry, bindex);
+                       if (!mnt)
+                               continue;
+                       unionfs_mntput(dentry, bindex);
+                       unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
+               }
        }
+       /* restore original dentry's offsets */
+       set_dbstart(dentry, orig_bstart);
+       set_dbend(dentry, orig_bend);
+       ibstart(dentry->d_inode) = ibend(dentry->d_inode) = orig_bend;
 
        err = copy_to_user((void __user *)arg, &branchlist, sizeof(fd_set));
        if (err)