From: Erez Zadok Date: Thu, 28 Nov 2013 01:00:53 +0000 (-0500) Subject: Unionfs: port to 3.13-rc1 X-Git-Url: https://git.fsl.cs.sunysb.edu/?a=commitdiff_plain;h=4ab11b6d2634518d3a3d290cdc52d8215290b6da;p=unionfs-3.13.y.git Unionfs: port to 3.13-rc1 Use file_inode helper. Add NULL extra arg to vfs_* methods and notify_change where it takes a delegated inode. Check DCACHE_OP_REVALIDATE flag in ->d_revalidate. ->setattr implemented, but not used yet. Force our root dentry to be of type DIR. Signed-off-by: Erez Zadok --- diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c index 9dc89e16c95..5e7da8f8223 100644 --- a/fs/unionfs/commonfops.c +++ b/fs/unionfs/commonfops.c @@ -120,7 +120,7 @@ retry: dput(tmp_dentry); err = copyup_named_file(parent->d_inode, file, name, bstart, bindex, - i_size_read(file->f_path.dentry->d_inode)); + i_size_read(file_inode(file))); if (err) { if (unlikely(err == -EEXIST)) goto retry; @@ -135,7 +135,7 @@ retry: lower_dentry->d_inode); } lower_dir_dentry = lock_parent(lower_dentry); - err = vfs_unlink(lower_dir_dentry->d_inode, lower_dentry); + err = vfs_unlink(lower_dir_dentry->d_inode, lower_dentry, NULL); unlock_dir(lower_dir_dentry); out: @@ -745,7 +745,7 @@ int unionfs_file_release(struct inode *inode, struct file *file) if (!err) unionfs_check_file(file); fileinfo = UNIONFS_F(file); - BUG_ON(file->f_path.dentry->d_inode != inode); + BUG_ON(file_inode(file) != inode); inodeinfo = UNIONFS_I(inode); /* fput all the lower files */ diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c index 6b24957e845..7ccecde9387 100644 --- a/fs/unionfs/copyup.c +++ b/fs/unionfs/copyup.c @@ -145,14 +145,14 @@ static int copyup_permissions(struct super_block *sb, ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_FORCE | ATTR_GID | ATTR_UID; mutex_lock(&new_lower_dentry->d_inode->i_mutex); - err = notify_change(new_lower_dentry, &newattrs); + err = notify_change(new_lower_dentry, &newattrs, NULL); if (err) goto out; /* now try to change the mode and ignore EOPNOTSUPP on symlinks */ newattrs.ia_mode = i->i_mode; newattrs.ia_valid = ATTR_MODE | ATTR_FORCE; - err = notify_change(new_lower_dentry, &newattrs); + err = notify_change(new_lower_dentry, &newattrs, NULL); if (err == -EOPNOTSUPP && S_ISLNK(new_lower_dentry->d_inode->i_mode)) { printk(KERN_WARNING @@ -498,7 +498,7 @@ out_unlink: * quota, or something else happened so let's unlink; we don't * really care about the return value of vfs_unlink */ - vfs_unlink(new_lower_parent_dentry->d_inode, new_lower_dentry); + vfs_unlink(new_lower_parent_dentry->d_inode, new_lower_dentry, NULL); if (copyup_file) { /* need to close the file */ diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c index 2183e5c3e73..c7aeaebc73a 100644 --- a/fs/unionfs/dentry.c +++ b/fs/unionfs/dentry.c @@ -302,6 +302,7 @@ static int unionfs_d_revalidate(struct dentry *dentry, unsigned int flags) bool valid = true; int err = 1; /* 1 means valid for the VFS */ struct dentry *parent; + struct dentry *lower_dentry; if (flags & LOOKUP_RCU) return -ECHILD; @@ -310,6 +311,10 @@ static int unionfs_d_revalidate(struct dentry *dentry, unsigned int flags) parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT); unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD); + lower_dentry = unionfs_lower_dentry(dentry); + if (!(lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) + goto out; + valid = __unionfs_d_revalidate(dentry, parent, false, flags); if (valid) { unionfs_postcopyup_setmnt(dentry); @@ -318,6 +323,8 @@ static int unionfs_d_revalidate(struct dentry *dentry, unsigned int flags) d_drop(dentry); err = valid; } + +out: unionfs_unlock_dentry(dentry); unionfs_unlock_parent(dentry, parent); unionfs_read_unlock(dentry->d_sb); diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c index 7b2f3cfd8af..5797763ad4b 100644 --- a/fs/unionfs/dirfops.c +++ b/fs/unionfs/dirfops.c @@ -169,8 +169,7 @@ static int unionfs_readdir(struct file *file, struct dir_context *ctx) uds->dirpos = offset; /* Copy the atime. */ - fsstack_copy_attr_atime(inode, - lower_file->f_path.dentry->d_inode); + fsstack_copy_attr_atime(inode, file_inode(lower_file)); if (err < 0) goto out; diff --git a/fs/unionfs/file.c b/fs/unionfs/file.c index f67db0ab6e6..f9cfc24bcd8 100644 --- a/fs/unionfs/file.c +++ b/fs/unionfs/file.c @@ -39,7 +39,7 @@ static ssize_t unionfs_read(struct file *file, char __user *buf, /* update our inode atime upon a successful lower read */ if (err >= 0) { fsstack_copy_attr_atime(dentry->d_inode, - lower_file->f_path.dentry->d_inode); + file_inode(lower_file)); unionfs_check_file(file); } @@ -71,9 +71,9 @@ static ssize_t unionfs_write(struct file *file, const char __user *buf, /* update our inode times+sizes upon a successful lower write */ if (err >= 0) { fsstack_copy_inode_size(dentry->d_inode, - lower_file->f_path.dentry->d_inode); + file_inode(lower_file)); fsstack_copy_attr_times(dentry->d_inode, - lower_file->f_path.dentry->d_inode); + file_inode(lower_file)); UNIONFS_F(file)->wrote_to_file = true; /* for delayed copyup */ unionfs_check_file(file); } @@ -320,7 +320,7 @@ static ssize_t unionfs_splice_read(struct file *file, loff_t *ppos, /* update our inode atime upon a successful lower splice-read */ if (err >= 0) { fsstack_copy_attr_atime(dentry->d_inode, - lower_file->f_path.dentry->d_inode); + file_inode(lower_file)); unionfs_check_file(file); } @@ -353,9 +353,9 @@ static ssize_t unionfs_splice_write(struct pipe_inode_info *pipe, /* update our inode times+sizes upon a successful lower write */ if (err >= 0) { fsstack_copy_inode_size(dentry->d_inode, - lower_file->f_path.dentry->d_inode); + file_inode(lower_file)); fsstack_copy_attr_times(dentry->d_inode, - lower_file->f_path.dentry->d_inode); + file_inode(lower_file)); unionfs_check_file(file); } diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c index 42a24fb8880..d22935ec3c9 100644 --- a/fs/unionfs/inode.c +++ b/fs/unionfs/inode.c @@ -275,7 +275,7 @@ static int unionfs_link(struct dentry *old_dentry, struct inode *dir, /* see Documentation/filesystems/unionfs/issues.txt */ lockdep_off(); err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, - lower_new_dentry); + lower_new_dentry, NULL); lockdep_on(); } unlock_dir(lower_dir_dentry); @@ -304,7 +304,7 @@ docopyup: /* do vfs_link */ err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, - lower_new_dentry); + lower_new_dentry, NULL); lockdep_on(); unlock_dir(lower_dir_dentry); goto check_link; @@ -999,7 +999,7 @@ static int unionfs_setattr(struct dentry *dentry, struct iattr *ia) } mutex_lock(&lower_dentry->d_inode->i_mutex); - err = notify_change(lower_dentry, &lower_ia); + err = notify_change(lower_dentry, &lower_ia, NULL); mutex_unlock(&lower_dentry->d_inode->i_mutex); if (err) goto out; @@ -1031,6 +1031,45 @@ out_err: return err; } +#if 0 +// XXX: may need this code in future +static int unionfs_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + int err; + struct dentry *parent; + struct kstat lower_stat; + struct path lower_path; + + unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD); + parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT); + unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD); + + if (unlikely(!__unionfs_d_revalidate(dentry, parent, false, 0))) { + err = -ESTALE; + goto out; + } + + lower_path.dentry = unionfs_lower_dentry(dentry); + lower_path.mnt = unionfs_lower_mnt(dentry); + err = vfs_getattr(&lower_path, &lower_stat); + if (err) + goto out; + fsstack_copy_attr_all(dentry->d_inode, + lower_path.dentry->d_inode); + generic_fillattr(dentry->d_inode, stat); + stat->blocks = lower_stat.blocks; + +out: + unionfs_check_dentry(dentry); + unionfs_unlock_dentry(dentry); + unionfs_unlock_parent(dentry, parent); + unionfs_read_unlock(dentry->d_sb); + + return err; +} +#endif + struct inode_operations unionfs_symlink_iops = { .readlink = unionfs_readlink, .permission = unionfs_permission, diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c index 78f8c1a0917..270f55de17e 100644 --- a/fs/unionfs/main.c +++ b/fs/unionfs/main.c @@ -599,7 +599,18 @@ static int unionfs_read_super(struct super_block *sb, void *raw_data, err = PTR_ERR(inode); goto out_dput; } + /* + * Have to set DIR mode temporarily on inode and dentry, before + * calling make_root, because make_root sets the + * DCACHE_DIRECTORY_TYPE dentry flag only if the inode is of type + * dir. Now, later below, we'll be copying the lower inode + * attributes anyway, which'll set our inode's mode to type==DIR, + * but it's too late for the dentry to have the + * DCACHE_DIRECTORY_TYPE flag set. + */ + inode->i_mode = S_IFDIR | 0755; sb->s_root = d_make_root(inode); + d_set_type(sb->s_root, DCACHE_DIRECTORY_TYPE); if (unlikely(!sb->s_root)) { err = -ENOMEM; goto out_iput; diff --git a/fs/unionfs/rdstate.c b/fs/unionfs/rdstate.c index 59b7333b88a..fe0081c2184 100644 --- a/fs/unionfs/rdstate.c +++ b/fs/unionfs/rdstate.c @@ -92,7 +92,7 @@ int init_rdstate(struct file *file) (sizeof(unsigned int) + sizeof(unsigned int))); BUG_ON(UNIONFS_F(file)->rdstate != NULL); - UNIONFS_F(file)->rdstate = alloc_rdstate(file->f_path.dentry->d_inode, + UNIONFS_F(file)->rdstate = alloc_rdstate(file_inode(file), fbstart(file)); return (UNIONFS_F(file)->rdstate ? 0 : -ENOMEM); diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c index 912c1e9e33d..25377a33833 100644 --- a/fs/unionfs/rename.c +++ b/fs/unionfs/rename.c @@ -120,7 +120,8 @@ static int __unionfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out_err_unlock; } err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, - lower_new_dir_dentry->d_inode, lower_new_dentry); + lower_new_dir_dentry->d_inode, lower_new_dentry, + NULL); out_err_unlock: if (!err) { /* update parent dir times */ @@ -202,7 +203,7 @@ static int do_unionfs_rename(struct inode *old_dir, err = is_robranch_super(old_dir->i_sb, bindex); if (!err) err = vfs_unlink(unlink_dir_dentry->d_inode, - unlink_dentry); + unlink_dentry, NULL); fsstack_copy_attr_times(new_parent->d_inode, unlink_dir_dentry->d_inode); diff --git a/fs/unionfs/sioq.c b/fs/unionfs/sioq.c index 3c8eb770379..bdb71f845a7 100644 --- a/fs/unionfs/sioq.c +++ b/fs/unionfs/sioq.c @@ -96,6 +96,6 @@ void __unionfs_unlink(struct work_struct *work) struct sioq_args *args = container_of(work, struct sioq_args, work); struct unlink_args *u = &args->unlink; - args->err = vfs_unlink(u->parent, u->dentry); + args->err = vfs_unlink(u->parent, u->dentry, NULL); complete(&args->comp); } diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c index 50cbd546a7a..37508eb6cdc 100644 --- a/fs/unionfs/unlink.c +++ b/fs/unionfs/unlink.c @@ -72,10 +72,10 @@ static int unionfs_unlink_whiteout(struct inode *dir, struct dentry *dentry, lockdep_off(); if (!S_ISDIR(lower_dentry->d_inode->i_mode)) err = vfs_unlink(lower_dir_dentry->d_inode, - lower_dentry); + lower_dentry, NULL); else err = vfs_rmdir(lower_dir_dentry->d_inode, - lower_dentry); + lower_dentry); lockdep_on(); } diff --git a/fs/unionfs/whiteout.c b/fs/unionfs/whiteout.c index 41c9b09f7df..94a9c24f582 100644 --- a/fs/unionfs/whiteout.c +++ b/fs/unionfs/whiteout.c @@ -171,7 +171,7 @@ int unlink_whiteout(struct dentry *wh_dentry) /* see Documentation/filesystems/unionfs/issues.txt */ lockdep_off(); - err = vfs_unlink(lower_dir_dentry->d_inode, wh_dentry); + err = vfs_unlink(lower_dir_dentry->d_inode, wh_dentry, NULL); lockdep_on(); unlock_dir(lower_dir_dentry); @@ -397,7 +397,8 @@ static int do_delete_whiteouts(struct dentry *dentry, int bindex, break; } if (lower_dentry->d_inode) - err = vfs_unlink(lower_dir, lower_dentry); + err = vfs_unlink(lower_dir, lower_dentry, + NULL); dput(lower_dentry); if (err) break;