diff --git a/fs/sharefs/dentry.c b/fs/sharefs/dentry.c index dee29cace6b751a5cd29b648bb5024bc53e96714..29d0f2e685db87eb91ec82c3a49dbf3002f25912 100644 --- a/fs/sharefs/dentry.c +++ b/fs/sharefs/dentry.c @@ -29,7 +29,6 @@ static void sharefs_d_release(struct dentry *dentry) */ if (SHAREFS_D(dentry)) { /* release and reset the lower paths */ - sharefs_put_reset_lower_path(dentry); free_dentry_private_data(dentry); } return; diff --git a/fs/sharefs/file.c b/fs/sharefs/file.c index f04963d57a4a6b8896393ade9d80d59cae885ff9..21f240303e3beb1bc51734fe4cd6c1cc38bfd55c 100644 --- a/fs/sharefs/file.c +++ b/fs/sharefs/file.c @@ -31,6 +31,7 @@ static int sharefs_open(struct inode *inode, struct file *file) int err = 0; struct file *lower_file = NULL; struct path lower_path; + struct inode *lower_inode = NULL; /* don't open unhashed/deleted files */ if (d_unhashed(file->f_path.dentry)) { @@ -66,7 +67,13 @@ static int sharefs_open(struct inode *inode, struct file *file) kuid_t uid = inode->i_uid; kgid_t gid = inode->i_gid; mode_t mode = inode->i_mode; - fsstack_copy_attr_all(inode, sharefs_lower_inode(inode)); + lower_inode = sharefs_get_lower_inode(file->f_path.dentry); + if (IS_ERR(lower_inode)) { + err = PTR_ERR(lower_inode); + goto out_err; + } + fsstack_copy_attr_all(inode, lower_inode); + iput(lower_inode); inode->i_uid = uid; inode->i_gid = gid; inode->i_mode = mode; diff --git a/fs/sharefs/inode.c b/fs/sharefs/inode.c index d0964f74433839e937128f7349951111633faa73..e56a90f847b23d807eb0795f7c8fb50d617709c2 100644 --- a/fs/sharefs/inode.c +++ b/fs/sharefs/inode.c @@ -14,6 +14,39 @@ #include "authentication.h" #endif +struct inode *sharefs_get_lower_inode(struct dentry *d) +{ + int err = 0; + struct path lower_path; + struct path lower_parent_dentry; + struct inode *lower_inode; + struct dentry *parent; + + parent = dget_parent(d); + sharefs_get_lower_path(parent, &lower_parent_dentry); + err = vfs_path_lookup(lower_parent_dentry.dentry, lower_parent_dentry.mnt, + d->d_name.name, 0, &lower_path); + if (err) + goto out; + + lower_inode = d_inode(lower_path.dentry); + if (!lower_inode) { + err = -ENOENT; + } else if (lower_inode->i_flags & S_DEAD) { + err = -ENOENT; + } else if (!igrab(lower_inode)) { + err = -ESTALE; + } + + sharefs_put_lower_path(d, &lower_path); +out: + sharefs_put_lower_path(parent, &lower_parent_dentry); + dput(parent); + if (err) + return ERR_PTR(err); + return lower_inode; +} + static const char *sharefs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { @@ -85,6 +118,10 @@ static ssize_t sharefs_listxattr(struct dentry *dentry, char *buffer, size_t buf sharefs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; + if (d_inode(lower_dentry)->i_flags & S_DEAD) { + err = -ENOENT; + goto out; + } if (!(d_inode(lower_dentry)->i_opflags & IOP_XATTR)) { err = -EOPNOTSUPP; goto out; @@ -129,6 +166,7 @@ static int sharefs_create(struct inode *dir, struct dentry *dentry, struct dentry *lower_parent_dentry = NULL; struct path lower_path; const struct cred *saved_cred = NULL; + struct inode *lower_inode = NULL; __u16 child_perm; saved_cred = sharefs_override_file_fsids(dir, &child_perm); @@ -147,8 +185,14 @@ static int sharefs_create(struct inode *dir, struct dentry *dentry, err = sharefs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; - fsstack_copy_attr_times(dir, sharefs_lower_inode(dir)); + lower_inode = sharefs_get_lower_inode(dentry); + if (IS_ERR(lower_inode)) { + err = PTR_ERR(lower_inode); + goto out; + } + fsstack_copy_attr_times(dir, lower_inode); fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry)); + iput(lower_inode); out: unlock_dir(lower_parent_dentry); @@ -164,6 +208,7 @@ static int sharefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) struct dentry *lower_parent_dentry = NULL; struct path lower_path; const struct cred *saved_cred = NULL; + struct inode *lower_inode = NULL; __u16 child_perm; saved_cred = sharefs_override_file_fsids(dir, &child_perm); @@ -182,11 +227,16 @@ static int sharefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) err = sharefs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; - - fsstack_copy_attr_times(dir, sharefs_lower_inode(dir)); + lower_inode = sharefs_get_lower_inode(dentry); + if (IS_ERR(lower_inode)) { + err = PTR_ERR(lower_inode); + goto out; + } + fsstack_copy_attr_times(dir, lower_inode); fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry)); /* update number of links on parent directory */ - set_nlink(dir, sharefs_lower_inode(dir)->i_nlink); + set_nlink(dir, lower_inode->i_nlink); + iput(lower_inode); out: unlock_dir(lower_parent_dentry); @@ -199,24 +249,38 @@ static int sharefs_unlink(struct inode *dir, struct dentry *dentry) { int err; struct dentry *lower_dentry = NULL; - struct inode *lower_dir_inode = sharefs_lower_inode(dir); + struct inode *lower_dir_inode = NULL; + struct inode *lower_inode = NULL; struct dentry *lower_dir_dentry = NULL; struct path lower_path; + lower_dir_inode = sharefs_get_lower_inode(dentry->d_parent); + if (IS_ERR(lower_dir_inode)) { + err = PTR_ERR(lower_dir_inode); + goto out; + } + lower_inode = sharefs_get_lower_inode(dentry); + if (IS_ERR(lower_inode)) { + err = PTR_ERR(lower_inode); + goto put_dir; + } sharefs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); err = vfs_unlink(lower_dir_inode, lower_dentry, NULL); if (err) - goto out; + goto put; fsstack_copy_attr_times(dir, lower_dir_inode); fsstack_copy_inode_size(dir, lower_dir_inode); - set_nlink(dentry->d_inode, - sharefs_lower_inode(dentry->d_inode)->i_nlink); + set_nlink(dentry->d_inode, lower_inode->i_nlink); dentry->d_inode->i_ctime = dir->i_ctime; d_drop(dentry); +put: + iput(lower_dir_inode); +put_dir: + iput(lower_inode); out: unlock_dir(lower_dir_dentry); dput(lower_dentry); @@ -313,7 +377,7 @@ static int sharefs_setattr(struct dentry *dentry, struct iattr *ia) int err; struct dentry *lower_dentry; struct inode *inode; - struct inode *lower_inode; + struct inode *lower_inode = NULL; struct path lower_path; struct iattr lower_ia; @@ -330,7 +394,11 @@ static int sharefs_setattr(struct dentry *dentry, struct iattr *ia) sharefs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; - lower_inode = sharefs_lower_inode(inode); + lower_dentry = sharefs_get_lower_inode(dentry); + if (IS_ERR(lower_dentry)) { + err = PTR_ERR(lower_dentry); + goto out_err; + } /* prepare our own lower struct iattr (with the lower file) */ memcpy(&lower_ia, ia, sizeof(lower_ia)); @@ -383,6 +451,7 @@ static int sharefs_setattr(struct dentry *dentry, struct iattr *ia) */ out: + iput(lower_inode); sharefs_put_lower_path(dentry, &lower_path); out_err: return err; diff --git a/fs/sharefs/lookup.c b/fs/sharefs/lookup.c index 0b0c30ef46f12aa9e22c49ebe7cee8ca5efd9875..72e2c9768fc5d7f0555f906a21c37376a373029e 100644 --- a/fs/sharefs/lookup.c +++ b/fs/sharefs/lookup.c @@ -141,6 +141,7 @@ struct inode *sharefs_iget(struct super_block *sb, struct inode *lower_inode) fsstack_copy_inode_size(inode, lower_inode); unlock_new_inode(inode); + iput(lower_inode); return inode; } @@ -214,7 +215,7 @@ static struct dentry *__sharefs_lookup(struct dentry *dentry, d_set_d_op(dentry, &sharefs_dops); if (IS_ROOT(dentry)) - goto out; + return NULL; name = dentry->d_name.name; @@ -282,6 +283,7 @@ static struct dentry *__sharefs_lookup(struct dentry *dentry, out: if (err) return ERR_PTR(err); + sharefs_put_lower_path(dentry, &lower_path); return ret_dentry; } diff --git a/fs/sharefs/sharefs.h b/fs/sharefs/sharefs.h index 143f047b235f340d0d8122e34ec3b15b9d5ddf6f..114c40cdb875dff28f7cf652df2dcd23d3f4985d 100644 --- a/fs/sharefs/sharefs.h +++ b/fs/sharefs/sharefs.h @@ -91,6 +91,7 @@ extern int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, struct path *path); extern int sharefs_parse_options(struct sharefs_sb_info *sbi, const char *data); +extern struct inode *sharefs_get_lower_inode(struct dentry *d); /* * inode to private data diff --git a/fs/sharefs/super.c b/fs/sharefs/super.c index bbe65944647fd611c2aea433b7228f03eeab8e89..ef6437c9e455b9726b2a29375897a2ea79f6aa5c 100644 --- a/fs/sharefs/super.c +++ b/fs/sharefs/super.c @@ -117,17 +117,13 @@ static int sharefs_statfs(struct dentry *dentry, struct kstatfs *buf) */ static void sharefs_evict_inode(struct inode *inode) { - struct inode *lower_inode; - truncate_inode_pages(&inode->i_data, 0); clear_inode(inode); /* * Decrement a reference to a lower_inode, which was incremented * by our read_inode when it was created initially. */ - lower_inode = sharefs_lower_inode(inode); sharefs_set_lower_inode(inode, NULL); - iput(lower_inode); } void __sharefs_log(const char *level, const bool ratelimited,