From 02b0038a47410d38fc6590a7279be7f4be9ef394 Mon Sep 17 00:00:00 2001 From: liuzerun Date: Tue, 25 Jun 2024 14:26:26 +0000 Subject: [PATCH] sharefs upper and lower Signed-off-by: liuzerun --- fs/sharefs/dentry.c | 95 +++++++++++++++++++++++++++++++++++++++++- fs/sharefs/file.c | 16 ++++++-- fs/sharefs/inode.c | 98 +++++++++++++++++++++++++++++++++++--------- fs/sharefs/lookup.c | 31 ++++++++------ fs/sharefs/main.c | 1 + fs/sharefs/sharefs.h | 21 ++++++---- fs/sharefs/super.c | 8 ++-- 7 files changed, 221 insertions(+), 49 deletions(-) diff --git a/fs/sharefs/dentry.c b/fs/sharefs/dentry.c index dee29cace6b7..99bebb4df2b1 100644 --- a/fs/sharefs/dentry.c +++ b/fs/sharefs/dentry.c @@ -29,7 +29,7 @@ static void sharefs_d_release(struct dentry *dentry) */ if (SHAREFS_D(dentry)) { /* release and reset the lower paths */ - sharefs_put_reset_lower_path(dentry); + sharefs_reset_lower_path(dentry); free_dentry_private_data(dentry); } return; @@ -39,3 +39,96 @@ const struct dentry_operations sharefs_dops = { .d_revalidate = sharefs_d_revalidate, .d_release = sharefs_d_release, }; + +static int try_to_create_lower_path(struct dentry *d, struct path *lower_path) +{ + int err; + struct path lower_dir_path; + struct qstr this; + struct dentry *parent; + struct dentry *lower_dentry; + struct inode *lower_dir_inode; + + parent = dget_parent(d); + err = sharefs_get_lower_path(parent, &lower_dir_path, 0); + dput(parent); + if (err) + return err; + /* instantiate a new negative dentry */ + this.name = d->d_name.name; + this.len = strlen(d->d_name.name); + this.hash = full_name_hash(lower_dir_path.dentry, this.name, this.len); + lower_dentry = d_alloc(lower_dir_path.dentry, &this); + if (!lower_dentry) { + err = -ENOMEM; + goto out; + } + lower_dir_inode = d_inode(lower_dir_path.dentry); + if (lower_dir_inode->i_op && lower_dir_inode->i_op->lookup) + lower_dir_inode->i_op->lookup(lower_dir_inode, lower_dentry, 0); + + spin_lock(&SHAREFS_D(d)->lock); + lower_path->dentry = lower_dentry; + lower_path->mnt = lower_dir_path.mnt; + spin_unlock(&SHAREFS_D(d)->lock); + +out: + sharefs_put_lower_path(parent, &lower_dir_path); + return err; +} + +/* Returns struct path. Caller must path_put it. */ +int sharefs_get_lower_path(struct dentry *d, struct path *lower_path, + bool try_to_create) +{ + int err = -ENOMEM; + char *path_buf = kmalloc(PATH_MAX, GFP_KERNEL); + char *path_name = NULL; + struct path lower_root_path; + + if (unlikely(!path_buf)) + goto out; + if (unlikely(!d)) + goto out_free; + path_name = dentry_path_raw(d, path_buf, PATH_MAX); + if (IS_ERR(path_name)) { + err = PTR_ERR(path_name); + goto out_free; + } + sharefs_get_lower_root_path(d, &lower_root_path); + spin_lock(&SHAREFS_D(d)->lock); + err = vfs_path_lookup(lower_root_path.dentry, lower_root_path.mnt, + path_name, LOOKUP_CREATE, lower_path); + spin_unlock(&SHAREFS_D(d)->lock); + sharefs_put_lower_path(d, &lower_root_path); + + if (err != -ENOENT || !try_to_create) + goto out_free; + err = try_to_create_lower_path(d, lower_path); + +out_free: + kfree(path_buf); +out: + return err; +} + +int sharefs_get_lower_inode(struct dentry *d, struct inode **lower_inode) +{ + int err = 0; + struct path lower_path; + + err = sharefs_get_lower_path(d, &lower_path, 0); + if (err) + goto out; + + *lower_inode = d_inode(lower_path.dentry); + if ((*lower_inode)->i_flags & S_DEAD) { + err = -ENOENT; + } else if (!igrab(*lower_inode)) { + err = -ESTALE; + } + + sharefs_put_lower_path(d, &lower_path); +out: + return err; +} \ No newline at end of file diff --git a/fs/sharefs/file.c b/fs/sharefs/file.c index f04963d57a4a..1aa44baf67e5 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)) { @@ -46,7 +47,9 @@ static int sharefs_open(struct inode *inode, struct file *file) } /* open lower object and link sharefs's file struct to lower's */ - sharefs_get_lower_path(file->f_path.dentry, &lower_path); + err = sharefs_get_lower_path(file->f_path.dentry, &lower_path, 0); + if (err) + goto out_free; lower_file = dentry_open(&lower_path, file->f_flags, current_cred()); path_put(&lower_path); if (IS_ERR(lower_file)) { @@ -60,16 +63,21 @@ static int sharefs_open(struct inode *inode, struct file *file) sharefs_set_lower_file(file, lower_file); } +out_free: if (err) { kfree(SHAREFS_F(file)); } else { 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)); + err = sharefs_get_lower_inode(file->f_path.dentry, &lower_inode); + if (err) + goto out_err; + fsstack_copy_attr_all(inode, lower_inode); inode->i_uid = uid; inode->i_gid = gid; inode->i_mode = mode; + iput(lower_inode); } out_err: return err; @@ -116,7 +124,9 @@ static int sharefs_fsync(struct file *file, loff_t start, loff_t end, if (err) goto out; lower_file = sharefs_lower_file(file); - sharefs_get_lower_path(dentry, &lower_path); + err = sharefs_get_lower_path(dentry, &lower_path, 0); + if (err) + goto out; err = vfs_fsync_range(lower_file, start, end, datasync); sharefs_put_lower_path(dentry, &lower_path); out: diff --git a/fs/sharefs/inode.c b/fs/sharefs/inode.c index d0964f744338..7313e34b8441 100644 --- a/fs/sharefs/inode.c +++ b/fs/sharefs/inode.c @@ -18,6 +18,7 @@ static const char *sharefs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { DEFINE_DELAYED_CALL(lower_done); + int err; struct dentry *lower_dentry; struct path lower_path; char *buf; @@ -26,7 +27,9 @@ static const char *sharefs_get_link(struct dentry *dentry, struct inode *inode, if (!dentry) return ERR_PTR(-ECHILD); - sharefs_get_lower_path(dentry, &lower_path); + err = sharefs_get_lower_path(dentry, &lower_path, 0); + if (err) + return ERR_PTR(err); lower_dentry = lower_path.dentry; /* @@ -64,7 +67,9 @@ static int sharefs_getattr(const struct path *path, struct kstat *stat, struct path lower_path; int ret; - sharefs_get_lower_path(path->dentry, &lower_path); + ret = sharefs_get_lower_path(path->dentry, &lower_path, 0); + if (ret) + return ret; ret = vfs_getattr(&lower_path, stat, request_mask, flags); stat->ino = d_inode(path->dentry)->i_ino; stat->uid = d_inode(path->dentry)->i_uid; @@ -83,8 +88,14 @@ static ssize_t sharefs_listxattr(struct dentry *dentry, char *buffer, size_t buf struct dentry *lower_dentry; struct path lower_path; - sharefs_get_lower_path(dentry, &lower_path); + err = sharefs_get_lower_path(dentry, &lower_path, 0); + if (err) + return err; 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 +140,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); @@ -137,9 +149,15 @@ static int sharefs_create(struct inode *dir, struct dentry *dentry, return err; } - sharefs_get_lower_path(dentry, &lower_path); + err = sharefs_get_lower_path(dentry, &lower_path, 1); + if (err) + goto out_revert; lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); + if (unlikely(!lower_parent_dentry)) { + err = -ENOENT; + goto out; + } err = vfs_create(d_inode(lower_parent_dentry), lower_dentry, mode, want_excl); if (err) @@ -147,12 +165,17 @@ 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)); + err = sharefs_get_lower_inode(dentry, &lower_inode); + if (err) + 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); sharefs_put_lower_path(dentry, &lower_path); +out_revert: sharefs_revert_fsids(saved_cred); return err; } @@ -164,6 +187,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); @@ -172,9 +196,15 @@ static int sharefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) return err; } - sharefs_get_lower_path(dentry, &lower_path); + err = sharefs_get_lower_path(dentry, &lower_path, 1); + if (err) + goto out_revert; lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); + if (unlikely(!lower_parent_dentry)) { + err = -ENOENT; + goto out; + } err = vfs_mkdir(d_inode(lower_parent_dentry), lower_dentry, mode); if (err) goto out; @@ -183,14 +213,19 @@ static int sharefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) if (err) goto out; - fsstack_copy_attr_times(dir, sharefs_lower_inode(dir)); + err = sharefs_get_lower_inode(dentry, &lower_inode); + if (err) + 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); sharefs_put_lower_path(dentry, &lower_path); +out_revert: sharefs_revert_fsids(saved_cred); return err; } @@ -199,11 +234,20 @@ 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; - sharefs_get_lower_path(dentry, &lower_path); + err = sharefs_get_lower_inode(dentry->d_parent, &lower_dir_inode); + if (err) + return err; + err = sharefs_get_lower_inode(dentry, &lower_inode); + if (err) + goto put; + err = sharefs_get_lower_path(dentry, &lower_path, 0); + if (err) + goto put_dir; lower_dentry = lower_path.dentry; dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); @@ -212,8 +256,7 @@ static int sharefs_unlink(struct inode *dir, struct dentry *dentry) goto out; 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); @@ -221,6 +264,10 @@ static int sharefs_unlink(struct inode *dir, struct dentry *dentry) unlock_dir(lower_dir_dentry); dput(lower_dentry); sharefs_put_lower_path(dentry, &lower_path); +put_dir: + iput(lower_inode); +put: + iput(lower_dir_inode); return err; } @@ -231,7 +278,9 @@ static int sharefs_rmdir(struct inode *dir, struct dentry *dentry) struct dentry *lower_dir_dentry; struct path lower_path; - sharefs_get_lower_path(dentry, &lower_path); + err = sharefs_get_lower_path(dentry, &lower_path, 0); + if (err) + return err; lower_dentry = lower_path.dentry; lower_dir_dentry = lock_parent(lower_dentry); err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); @@ -266,8 +315,14 @@ static int sharefs_rename(struct inode *old_dir, struct dentry *old_dentry, if (flags) return -EINVAL; - sharefs_get_lower_path(old_dentry, &lower_old_path); - sharefs_get_lower_path(new_dentry, &lower_new_path); + err = sharefs_get_lower_path(old_dentry, &lower_old_path, 0); + if (err) + return err; + err = sharefs_get_lower_path(new_dentry, &lower_new_path, 1); + if (err) { + sharefs_put_lower_path(old_dentry, &lower_old_path); + return err; + } lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); @@ -326,11 +381,15 @@ static int sharefs_setattr(struct dentry *dentry, struct iattr *ia) err = setattr_prepare(dentry, ia); if (err) - goto out_err; + return err; - sharefs_get_lower_path(dentry, &lower_path); + err = sharefs_get_lower_path(dentry, &lower_path, 0); + if (err) + return err; lower_dentry = lower_path.dentry; - lower_inode = sharefs_lower_inode(inode); + err = sharefs_get_lower_inode(dentry, &lower_inode); + if (err) + goto out_err; /* prepare our own lower struct iattr (with the lower file) */ memcpy(&lower_ia, ia, sizeof(lower_ia)); @@ -383,8 +442,9 @@ static int sharefs_setattr(struct dentry *dentry, struct iattr *ia) */ out: - sharefs_put_lower_path(dentry, &lower_path); + iput(lower_inode); out_err: + sharefs_put_lower_path(dentry, &lower_path); return err; } #endif diff --git a/fs/sharefs/lookup.c b/fs/sharefs/lookup.c index 0b0c30ef46f1..a7e019d74c0d 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; } @@ -199,14 +200,14 @@ int sharefs_interpose(struct dentry *dentry, struct super_block *sb, */ static struct dentry *__sharefs_lookup(struct dentry *dentry, unsigned int flags, - struct path *lower_parent_path) + struct path *lower_parent_path, + struct path *lower_path) { int err = 0; struct vfsmount *lower_dir_mnt; struct dentry *lower_dir_dentry = NULL; struct dentry *lower_dentry; const char *name; - struct path lower_path; struct qstr this; struct dentry *ret_dentry = NULL; @@ -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; @@ -224,12 +225,12 @@ static struct dentry *__sharefs_lookup(struct dentry *dentry, /* Use vfs_path_lookup to check if the dentry exists or not */ err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0, - &lower_path); + lower_path); /* no error: handle positive dentries */ if (!err) { - sharefs_set_lower_path(dentry, &lower_path); + sharefs_set_lower_path(dentry, lower_path); ret_dentry = - __sharefs_interpose(dentry, dentry->d_sb, &lower_path); + __sharefs_interpose(dentry, dentry->d_sb, lower_path); if (IS_ERR(ret_dentry)) { err = PTR_ERR(ret_dentry); /* path_put underlying path on error */ @@ -267,9 +268,9 @@ static struct dentry *__sharefs_lookup(struct dentry *dentry, lower_dentry, flags); setup_lower: - lower_path.dentry = lower_dentry; - lower_path.mnt = mntget(lower_dir_mnt); - sharefs_set_lower_path(dentry, &lower_path); + lower_path->dentry = lower_dentry; + lower_path->mnt = mntget(lower_dir_mnt); + sharefs_set_lower_path(dentry, lower_path); /* * If the intent is to create a file, then don't return an error, so @@ -290,14 +291,18 @@ struct dentry *sharefs_lookup(struct inode *dir, struct dentry *dentry, { int err; struct dentry *ret, *parent; + struct path lower_path; struct path lower_parent_path; #ifdef CONFIG_SHAREFS_SUPPORT_OVERRIDE const struct cred *saved_cred = NULL; __u16 permission; #endif - parent = dget_parent(dentry); - sharefs_get_lower_path(parent, &lower_parent_path); + err = sharefs_get_lower_path(parent, &lower_parent_path, 0); + if (err) { + dput(parent); + return ERR_PTR(err); + } #ifdef CONFIG_SHAREFS_SUPPORT_OVERRIDE saved_cred = sharefs_override_file_fsids(dir, &permission); if (!saved_cred) { @@ -305,14 +310,13 @@ struct dentry *sharefs_lookup(struct inode *dir, struct dentry *dentry, goto out_err; } #endif - /* allocate dentry private data. We free it in ->d_release */ err = new_dentry_private_data(dentry); if (err) { ret = ERR_PTR(err); goto out; } - ret = __sharefs_lookup(dentry, flags, &lower_parent_path); + ret = __sharefs_lookup(dentry, flags, &lower_parent_path, &lower_path); if (IS_ERR(ret)) { sharefs_err("sharefs_lookup error!"); goto out; @@ -327,6 +331,7 @@ struct dentry *sharefs_lookup(struct inode *dir, struct dentry *dentry, fsstack_copy_attr_atime(d_inode(parent), sharefs_lower_inode(d_inode(parent))); fixup_perm_from_level(d_inode(parent), dentry); + sharefs_put_lower_path(dentry, &lower_path); out: #ifdef CONFIG_SHAREFS_SUPPORT_OVERRIDE sharefs_revert_fsids(saved_cred); diff --git a/fs/sharefs/main.c b/fs/sharefs/main.c index 2ce5bb71bcac..10cc7d626307 100644 --- a/fs/sharefs/main.c +++ b/fs/sharefs/main.c @@ -181,6 +181,7 @@ static void __exit exit_sharefs_fs(void) sharefs_destroy_inode_cache(); sharefs_destroy_dentry_cache(); unregister_filesystem(&sharefs_fs_type); + sharefs_exit_configfs(); pr_info("Completed sharefs module unload\n"); } diff --git a/fs/sharefs/sharefs.h b/fs/sharefs/sharefs.h index 143f047b235f..7b5540b09d33 100644 --- a/fs/sharefs/sharefs.h +++ b/fs/sharefs/sharefs.h @@ -91,6 +91,9 @@ 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 int sharefs_get_lower_inode(struct dentry *d, struct inode **lower_path); +extern int sharefs_get_lower_path(struct dentry *d, struct path *lower_path, + bool try_to_create); /* * inode to private data @@ -154,16 +157,18 @@ static inline void pathcpy(struct path *dst, const struct path *src) dst->dentry = src->dentry; dst->mnt = src->mnt; } -/* Returns struct path. Caller must path_put it. */ -static inline void sharefs_get_lower_path(const struct dentry *dent, - struct path *lower_path) + +static inline void sharefs_get_lower_root_path(const struct dentry *dent, + struct path *lower_root_path) { - spin_lock(&SHAREFS_D(dent)->lock); - pathcpy(lower_path, &SHAREFS_D(dent)->lower_path); - path_get(lower_path); - spin_unlock(&SHAREFS_D(dent)->lock); - return; + struct super_block *sb = dent->d_sb; + + spin_lock(&SHAREFS_D(sb->s_root)->lock); + pathcpy(lower_root_path, &SHAREFS_D(sb->s_root)->lower_path); + path_get(lower_root_path); + spin_unlock(&SHAREFS_D(sb->s_root)->lock); } + static inline void sharefs_put_lower_path(const struct dentry *dent, struct path *lower_path) { diff --git a/fs/sharefs/super.c b/fs/sharefs/super.c index bbe65944647f..b7cd611adcfd 100644 --- a/fs/sharefs/super.c +++ b/fs/sharefs/super.c @@ -99,7 +99,9 @@ static int sharefs_statfs(struct dentry *dentry, struct kstatfs *buf) int err; struct path lower_path; - sharefs_get_lower_path(dentry, &lower_path); + err = sharefs_get_lower_path(dentry, &lower_path, 0); + if (err) + return err; err = vfs_statfs(&lower_path, buf); sharefs_put_lower_path(dentry, &lower_path); @@ -117,17 +119,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, -- Gitee