From 7637a328c442a33ea1d4c111b8fd9b77cb189f35 Mon Sep 17 00:00:00 2001 From: Anan Jaser Date: Fri, 27 Oct 2023 21:04:27 +0400 Subject: [PATCH] fs: sdcardfs: port form exynos8895 4.4 kernel --- fs/sdcardfs/p/dentry.c | 2 +- fs/sdcardfs/p/derived_perm.c | 74 +++++++++++++++-------------- fs/sdcardfs/p/file.c | 28 ++++++----- fs/sdcardfs/p/inode.c | 91 +++++++++++++++++++----------------- fs/sdcardfs/p/lookup.c | 31 ++++++------ fs/sdcardfs/p/main.c | 37 +++++++++++---- fs/sdcardfs/p/sdcardfs.h | 51 +++++++++++--------- fs/sdcardfs/p/super.c | 7 ++- 8 files changed, 181 insertions(+), 140 deletions(-) diff --git a/fs/sdcardfs/p/dentry.c b/fs/sdcardfs/p/dentry.c index 7045d051442a..98235d399aa9 100644 --- a/fs/sdcardfs/p/dentry.c +++ b/fs/sdcardfs/p/dentry.c @@ -104,7 +104,7 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) goto out; /* If our top's inode is gone, we may be out of date */ - inode = igrab(dentry->d_inode); + inode = igrab(d_inode(dentry)); if (inode) { data = top_data_get(SDCARDFS_I(inode)); if (!data || data->abandoned) { diff --git a/fs/sdcardfs/p/derived_perm.c b/fs/sdcardfs/p/derived_perm.c index f708ac746486..1b371cfa430e 100644 --- a/fs/sdcardfs/p/derived_perm.c +++ b/fs/sdcardfs/p/derived_perm.c @@ -32,26 +32,21 @@ static void inherit_derived_state(struct inode *parent, struct inode *child) ci->data->under_android = pi->data->under_android; ci->data->under_cache = pi->data->under_cache; ci->data->under_obb = pi->data->under_obb; - set_top(ci, pi->top_data); - ci->data->under_knox = pi->data->under_knox; } /* helper function for derived state */ void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, - uid_t uid, bool under_android, - struct sdcardfs_inode_data *top) + uid_t uid) { struct sdcardfs_inode_info *info = SDCARDFS_I(inode); info->data->perm = perm; info->data->userid = userid; info->data->d_uid = uid; - info->data->under_android = under_android; + info->data->under_android = false; info->data->under_cache = false; info->data->under_obb = false; - set_top(info, top); - info->data->under_knox = false; } @@ -61,14 +56,15 @@ void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid, void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name) { - struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode); - struct sdcardfs_inode_data *parent_data = - SDCARDFS_I(parent->d_inode)->data; + struct sdcardfs_inode_info *info = SDCARDFS_I(d_inode(dentry)); + struct sdcardfs_inode_info *parent_info = SDCARDFS_I(d_inode(parent)); + struct sdcardfs_inode_data *parent_data = parent_info->data; appid_t appid; unsigned long user_num; int err; struct qstr q_Android = QSTR_LITERAL("Android"); struct qstr q_data = QSTR_LITERAL("data"); + struct qstr q_sandbox = QSTR_LITERAL("sandbox"); struct qstr q_obb = QSTR_LITERAL("obb"); struct qstr q_media = QSTR_LITERAL("media"); struct qstr q_cache = QSTR_LITERAL("cache"); @@ -84,16 +80,18 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, * of using the inode permissions. */ - inherit_derived_state(parent->d_inode, dentry->d_inode); + inherit_derived_state(d_inode(parent), d_inode(dentry)); /* Files don't get special labels */ - if (!S_ISDIR(dentry->d_inode->i_mode)) + if (!S_ISDIR(d_inode(dentry)->i_mode)) { + set_top(info, parent_info); return; + } /* Derive custom permissions based on parent and current node */ switch (parent_data->perm) { case PERM_INHERIT: case PERM_ANDROID_PACKAGE_CACHE: - /* Already inherited above */ + set_top(info, parent_info); break; case PERM_PRE_ROOT: /* Legacy internal layout places users at top level */ @@ -103,7 +101,6 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, info->data->userid = 0; else info->data->userid = user_num; - set_top(info, info->data); break; case PERM_ROOT: /* Assume masked off by default. */ @@ -111,28 +108,30 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, /* App-specific directories inside; let anyone traverse */ info->data->perm = PERM_ANDROID; info->data->under_android = true; - set_top(info, info->data); } else if (qstr_case_eq(name, &q_knox)) { info->data->perm = PERM_KNOX_PRE_ROOT; info->data->under_knox = true; - set_top(info, info->data); + } else { + set_top(info, parent_info); } break; case PERM_ANDROID: if (qstr_case_eq(name, &q_data)) { /* App-specific directories inside; let anyone traverse */ info->data->perm = PERM_ANDROID_DATA; - set_top(info, info->data); + } else if (qstr_case_eq(name, &q_sandbox)) { + /* App-specific directories inside; let anyone traverse */ + info->data->perm = PERM_ANDROID_DATA; } else if (qstr_case_eq(name, &q_obb)) { /* App-specific directories inside; let anyone traverse */ info->data->perm = PERM_ANDROID_OBB; info->data->under_obb = true; - set_top(info, info->data); /* Single OBB directory is always shared */ } else if (qstr_case_eq(name, &q_media)) { /* App-specific directories inside; let anyone traverse */ info->data->perm = PERM_ANDROID_MEDIA; - set_top(info, info->data); + } else { + set_top(info, parent_info); } break; case PERM_ANDROID_OBB: @@ -143,13 +142,13 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, if (appid != 0 && !is_excluded(name->name, parent_data->userid)) info->data->d_uid = multiuser_get_uid(parent_data->userid, appid); - set_top(info, info->data); break; case PERM_ANDROID_PACKAGE: if (qstr_case_eq(name, &q_cache)) { info->data->perm = PERM_ANDROID_PACKAGE_CACHE; info->data->under_cache = true; } + set_top(info, parent_info); break; /* KNOX */ @@ -160,20 +159,22 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, info->data->userid = 10; /* default container no. */ else info->data->userid = user_num; - set_top(info, info->data); break; case PERM_KNOX_ROOT: if (qstr_case_eq(name, &q_Android)) info->data->perm = PERM_KNOX_ANDROID; + set_top(info, parent_info); break; case PERM_KNOX_ANDROID: if (qstr_case_eq(name, &q_data)) { info->data->perm = PERM_KNOX_ANDROID_DATA; + set_top(info, parent_info); } else if (qstr_case_eq(name, &q_shared)) { info->data->perm = PERM_KNOX_ANDROID_SHARED; info->data->d_uid = multiuser_get_uid(parent_data->userid, 0); - set_top(info, info->data); + } else { + set_top(info, parent_info); } break; case PERM_KNOX_ANDROID_DATA: @@ -182,10 +183,10 @@ void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, if (appid != 0 && !is_excluded(name->name, parent_data->userid)) info->data->d_uid = multiuser_get_uid(parent_data->userid, appid); - set_top(info, info->data); break; case PERM_KNOX_ANDROID_SHARED: case PERM_KNOX_ANDROID_PACKAGE: + set_top(info, parent_info); break; } } @@ -226,7 +227,7 @@ void fixup_lower_ownership(struct dentry *dentry, const char *name) if (!sbi->options.gid_derivation) return; - info = SDCARDFS_I(dentry->d_inode); + info = SDCARDFS_I(d_inode(dentry)); info_d = info->data; perm = info_d->perm; if (info_d->under_obb) { @@ -260,7 +261,7 @@ void fixup_lower_ownership(struct dentry *dentry, const char *name) case PERM_ANDROID: case PERM_ANDROID_DATA: case PERM_ANDROID_MEDIA: - if (S_ISDIR(dentry->d_inode->i_mode)) + if (S_ISDIR(d_inode(dentry)->i_mode)) gid = multiuser_get_uid(info_d->userid, AID_MEDIA_RW); else gid = multiuser_get_uid(info_d->userid, get_type(name)); @@ -286,8 +287,8 @@ void fixup_lower_ownership(struct dentry *dentry, const char *name) } sdcardfs_get_lower_path(dentry, &path); - inode = path.dentry->d_inode; - if (path.dentry->d_inode->i_gid.val != gid || path.dentry->d_inode->i_uid.val != uid) { + inode = d_inode(path.dentry); + if (d_inode(path.dentry)->i_gid.val != gid || d_inode(path.dentry)->i_uid.val != uid) { retry_deleg: newattrs.ia_valid = ATTR_GID | ATTR_UID | ATTR_FORCE; newattrs.ia_uid = make_kuid(current_user_ns(), uid); @@ -342,19 +343,19 @@ static void __fixup_perms_recursive(struct dentry *dentry, struct limit_search * */ WARN(depth > 3, "%s: Max expected depth exceeded!\n", __func__); spin_lock_nested(&dentry->d_lock, depth); - if (!dentry->d_inode) { + if (!d_inode(dentry)) { spin_unlock(&dentry->d_lock); return; } - info = SDCARDFS_I(dentry->d_inode); + info = SDCARDFS_I(d_inode(dentry)); if (needs_fixup(info->data->perm)) { list_for_each_entry(child, &dentry->d_subdirs, d_child) { spin_lock_nested(&child->d_lock, depth + 1); if (!(limit->flags & BY_NAME) || qstr_case_eq(&child->d_name, &limit->name)) { - if (child->d_inode) { + if (d_inode(child)) { get_derived_permission(dentry, child); - fixup_tmp_permissions(child->d_inode); + fixup_tmp_permissions(d_inode(child)); spin_unlock(&child->d_lock); break; } @@ -379,7 +380,7 @@ inline void update_derived_permission_lock(struct dentry *dentry) { struct dentry *parent; - if (!dentry || !dentry->d_inode) { + if (!dentry || !d_inode(dentry)) { pr_err("sdcardfs: %s: invalid dentry\n", __func__); return; } @@ -394,18 +395,19 @@ inline void update_derived_permission_lock(struct dentry *dentry) dput(parent); } } - fixup_tmp_permissions(dentry->d_inode); + fixup_tmp_permissions(d_inode(dentry)); } int need_graft_path(struct dentry *dentry) { int ret = 0; struct dentry *parent = dget_parent(dentry); - struct sdcardfs_inode_info *parent_info = SDCARDFS_I(parent->d_inode); + struct sdcardfs_inode_info *parent_info = SDCARDFS_I(d_inode(parent)); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct qstr obb = QSTR_LITERAL("obb"); - if (parent_info->data->perm == PERM_ANDROID && + if (!sbi->options.unshared_obb && + parent_info->data->perm == PERM_ANDROID && qstr_case_eq(&dentry->d_name, &obb)) { /* /Android/obb is the base obbpath of DERIVED_UNIFIED */ @@ -465,7 +467,7 @@ int is_base_obbpath(struct dentry *dentry) { int ret = 0; struct dentry *parent = dget_parent(dentry); - struct sdcardfs_inode_info *parent_info = SDCARDFS_I(parent->d_inode); + struct sdcardfs_inode_info *parent_info = SDCARDFS_I(d_inode(parent)); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct qstr q_obb = QSTR_LITERAL("obb"); diff --git a/fs/sdcardfs/p/file.c b/fs/sdcardfs/p/file.c index 28f6f09559e3..271c4c4cb760 100644 --- a/fs/sdcardfs/p/file.c +++ b/fs/sdcardfs/p/file.c @@ -50,7 +50,7 @@ static ssize_t sdcardfs_read(struct file *file, char __user *buf, err = vfs_read(lower_file, buf, count, ppos); /* update our inode atime upon a successful lower read */ if (err >= 0) - fsstack_copy_attr_atime(dentry->d_inode, + fsstack_copy_attr_atime(d_inode(dentry), file_inode(lower_file)); return err; @@ -62,6 +62,7 @@ static ssize_t sdcardfs_write(struct file *file, const char __user *buf, int err; struct file *lower_file; struct dentry *dentry = file->f_path.dentry; + struct inode *inode = d_inode(dentry); /* check disk space */ if (!check_min_free_space(dentry, count, 0)) { @@ -73,10 +74,12 @@ static ssize_t sdcardfs_write(struct file *file, const char __user *buf, err = vfs_write(lower_file, buf, count, ppos); /* update our inode times+sizes upon a successful lower write */ if (err >= 0) { - fsstack_copy_inode_size(dentry->d_inode, - file_inode(lower_file)); - fsstack_copy_attr_times(dentry->d_inode, - file_inode(lower_file)); + if (sizeof(loff_t) > sizeof(long)) + inode_lock(inode); + fsstack_copy_inode_size(inode, file_inode(lower_file)); + fsstack_copy_attr_times(inode, file_inode(lower_file)); + if (sizeof(loff_t) > sizeof(long)) + inode_unlock(inode); } return err; @@ -94,7 +97,7 @@ static int sdcardfs_readdir(struct file *file, struct dir_context *ctx) err = iterate_dir(lower_file, ctx); file->f_pos = lower_file->f_pos; if (err >= 0) /* copy the atime */ - fsstack_copy_attr_atime(dentry->d_inode, + fsstack_copy_attr_atime(d_inode(dentry), file_inode(lower_file)); return err; } @@ -240,7 +243,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) goto out_err; } - if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { + if (!check_caller_access_to_name(d_inode(parent), &dentry->d_name)) { err = -EACCES; goto out_err; } @@ -403,6 +406,7 @@ ssize_t sdcardfs_write_iter(struct kiocb *iocb, struct iov_iter *iter) { int err; struct file *file = iocb->ki_filp, *lower_file; + struct inode *inode = file->f_path.dentry->d_inode; lower_file = sdcardfs_lower_file(file); if (!lower_file->f_op->write_iter) { @@ -417,10 +421,12 @@ ssize_t sdcardfs_write_iter(struct kiocb *iocb, struct iov_iter *iter) fput(lower_file); /* update upper inode times/sizes as needed */ if (err >= 0 || err == -EIOCBQUEUED) { - fsstack_copy_inode_size(file->f_path.dentry->d_inode, - file_inode(lower_file)); - fsstack_copy_attr_times(file->f_path.dentry->d_inode, - file_inode(lower_file)); + if (sizeof(loff_t) > sizeof(long)) + inode_lock(inode); + fsstack_copy_inode_size(inode, file_inode(lower_file)); + fsstack_copy_attr_times(inode, file_inode(lower_file)); + if (sizeof(loff_t) > sizeof(long)) + inode_unlock(inode); } out: return err; diff --git a/fs/sdcardfs/p/inode.c b/fs/sdcardfs/p/inode.c index 6b115a2b49f6..adf3fdb618d0 100644 --- a/fs/sdcardfs/p/inode.c +++ b/fs/sdcardfs/p/inode.c @@ -20,6 +20,7 @@ #include "sdcardfs.h" #include +#include const struct cred *override_fsids(struct sdcardfs_sb_info *sbi, struct sdcardfs_inode_data *data) @@ -100,7 +101,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, current->fs = copied_fs; task_unlock(current); - err = vfs_create2(lower_dentry_mnt, lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); + err = vfs_create2(lower_dentry_mnt, d_inode(lower_parent_dentry), lower_dentry, mode, want_excl); if (err) goto out; @@ -109,7 +110,7 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, if (err) goto out; fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); - fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry)); fixup_lower_ownership(dentry, dentry->d_name.name); out: @@ -167,9 +168,9 @@ static int sdcardfs_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, - sdcardfs_lower_inode(dentry->d_inode)->i_nlink); - dentry->d_inode->i_ctime = dir->i_ctime; + set_nlink(d_inode(dentry), + sdcardfs_lower_inode(d_inode(dentry))->i_nlink); + d_inode(dentry)->i_ctime = dir->i_ctime; d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */ out: unlock_dir(lower_dir_dentry); @@ -204,6 +205,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct dentry *lower_dentry; struct vfsmount *lower_mnt; struct dentry *lower_parent_dentry = NULL; + struct dentry *parent_dentry = NULL; struct path lower_path; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; @@ -226,11 +228,14 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode return -ENOMEM; /* check disk space */ - if (!check_min_free_space(dentry, 0, 1)) { + parent_dentry = dget_parent(dentry); + if (!check_min_free_space(parent_dentry, 0, 1)) { pr_err("sdcardfs: No minimum free space.\n"); err = -ENOSPC; + dput(parent_dentry); goto out_revert; } + dput(parent_dentry); /* the lower_dentry is negative here */ sdcardfs_get_lower_path(dentry, &lower_path); @@ -254,7 +259,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode current->fs = copied_fs; task_unlock(current); - err = vfs_mkdir2(lower_mnt, lower_parent_dentry->d_inode, lower_dentry, mode); + err = vfs_mkdir2(lower_mnt, d_inode(lower_parent_dentry), lower_dentry, mode); if (err) { unlock_dir(lower_parent_dentry); @@ -289,7 +294,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode } fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); - fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); + fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry)); /* update number of links on parent directory */ set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink); fixup_lower_ownership(dentry, dentry->d_name.name); @@ -304,7 +309,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode && (qstr_case_eq(&dentry->d_name, &q_data)))) { revert_fsids(saved_cred); saved_cred = override_fsids(sbi, - SDCARDFS_I(dentry->d_inode)->data); + SDCARDFS_I(d_inode(dentry))->data); if (!saved_cred) { pr_err("sdcardfs: failed to set up .nomedia in %s: %d\n", lower_path.dentry->d_name.name, @@ -363,16 +368,16 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) lower_mnt = lower_path.mnt; lower_dir_dentry = lock_parent(lower_dentry); - err = vfs_rmdir2(lower_mnt, lower_dir_dentry->d_inode, lower_dentry); + err = vfs_rmdir2(lower_mnt, d_inode(lower_dir_dentry), lower_dentry); if (err) goto out; d_drop(dentry); /* drop our dentry on success (why not VFS's job?) */ - if (dentry->d_inode) - clear_nlink(dentry->d_inode); - fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); - fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); - set_nlink(dir, lower_dir_dentry->d_inode->i_nlink); + if (d_inode(dentry)) + clear_nlink(d_inode(dentry)); + fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry)); + fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry)); + set_nlink(dir, d_inode(lower_dir_dentry)->i_nlink); out: unlock_dir(lower_dir_dentry); @@ -432,22 +437,22 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, } err = vfs_rename2(lower_mnt, - lower_old_dir_dentry->d_inode, lower_old_dentry, - lower_new_dir_dentry->d_inode, lower_new_dentry, + d_inode(lower_old_dir_dentry), lower_old_dentry, + d_inode(lower_new_dir_dentry), lower_new_dentry, NULL, 0); if (err) goto out; /* Copy attrs from lower dir, but i_uid/i_gid */ - sdcardfs_copy_and_fix_attrs(new_dir, lower_new_dir_dentry->d_inode); - fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); + sdcardfs_copy_and_fix_attrs(new_dir, d_inode(lower_new_dir_dentry)); + fsstack_copy_inode_size(new_dir, d_inode(lower_new_dir_dentry)); if (new_dir != old_dir) { - sdcardfs_copy_and_fix_attrs(old_dir, lower_old_dir_dentry->d_inode); - fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); + sdcardfs_copy_and_fix_attrs(old_dir, d_inode(lower_old_dir_dentry)); + fsstack_copy_inode_size(old_dir, d_inode(lower_old_dir_dentry)); } get_derived_permission_new(new_dentry->d_parent, old_dentry, &new_dentry->d_name); - fixup_tmp_permissions(old_dentry->d_inode); + fixup_tmp_permissions(d_inode(old_dentry)); fixup_lower_ownership(old_dentry, new_dentry->d_name.name); d_invalidate(old_dentry); /* Can't fixup ownership recursively :( */ out: @@ -471,17 +476,17 @@ static int sdcardfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; - if (!lower_dentry->d_inode->i_op || - !lower_dentry->d_inode->i_op->readlink) { + if (!d_inode(lower_dentry)->i_op || + !d_inode(lower_dentry)->i_op->readlink) { err = -EINVAL; goto out; } - err = lower_dentry->d_inode->i_op->readlink(lower_dentry, + err = d_inode(lower_dentry)->i_op->readlink(lower_dentry, buf, bufsiz); if (err < 0) goto out; - fsstack_copy_attr_atime(dentry->d_inode, lower_dentry->d_inode); + fsstack_copy_attr_atime(d_inode(dentry), d_inode(lower_dentry)); out: sdcardfs_put_lower_path(dentry, &lower_path); @@ -490,7 +495,7 @@ static int sdcardfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz #endif #if 0 -static void *sdcardfs_follow_link(struct dentry *dentry, struct nameidata *nd) +static const char *sdcardfs_follow_link(struct dentry *dentry, void **cookie) { char *buf; int len = PAGE_SIZE, err; @@ -500,7 +505,7 @@ static void *sdcardfs_follow_link(struct dentry *dentry, struct nameidata *nd) buf = kmalloc(len, GFP_KERNEL); if (!buf) { buf = ERR_PTR(-ENOMEM); - goto out; + return buf; } /* read the symlink, and then we will follow it */ @@ -514,9 +519,7 @@ static void *sdcardfs_follow_link(struct dentry *dentry, struct nameidata *nd) } else { buf[err] = '\0'; } -out: - nd_set_link(nd, buf); - return NULL; + return *cookie = buf; } #endif @@ -554,10 +557,10 @@ static int sdcardfs_permission(struct vfsmount *mnt, struct inode *inode, int ma if (!top) return -EINVAL; - if (IS_ERR(mnt)) { - data_put(top); - return PTR_ERR(mnt); - } + if (IS_ERR(mnt)) { + data_put(top); + return PTR_ERR(mnt); + } /* * Permission check on sdcardfs inode. @@ -603,7 +606,7 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct struct sdcardfs_inode_data *top; const struct cred *saved_cred = NULL; - inode = dentry->d_inode; + inode = d_inode(dentry); top = top_data_get(SDCARDFS_I(inode)); if (!top) @@ -646,7 +649,7 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct if (!err) { /* check the Android group ID */ parent = dget_parent(dentry); - if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) + if (!check_caller_access_to_name(d_inode(parent), &dentry->d_name)) err = -EACCES; dput(parent); } @@ -695,14 +698,14 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct /* notify the (possibly copied-up) lower inode */ /* - * Note: we use lower_dentry->d_inode, because lower_inode may be + * Note: we use d_inode(lower_dentry), because lower_inode may be * unlinked (no inode->i_sb and i_ino==0. This happens if someone * tries to open(), unlink(), then ftruncate() a file. */ - mutex_lock(&lower_dentry->d_inode->i_mutex); + mutex_lock(&d_inode(lower_dentry)->i_mutex); err = notify_change2(lower_mnt, lower_dentry, &lower_ia, /* note: lower_ia */ NULL); - mutex_unlock(&lower_dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(lower_dentry)->i_mutex); if (err) goto out; @@ -758,7 +761,7 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, int err; parent = dget_parent(dentry); - if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { + if (!check_caller_access_to_name(d_inode(parent), &dentry->d_name)) { dput(parent); return -EACCES; } @@ -768,9 +771,9 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, err = vfs_getattr(&lower_path, &lower_stat); if (err) goto out; - sdcardfs_copy_and_fix_attrs(dentry->d_inode, - lower_path.dentry->d_inode); - err = sdcardfs_fillattr(mnt, dentry->d_inode, &lower_stat, stat); + sdcardfs_copy_and_fix_attrs(d_inode(dentry), + d_inode(lower_path.dentry)); + err = sdcardfs_fillattr(mnt, d_inode(dentry), &lower_stat, stat); out: sdcardfs_put_lower_path(dentry, &lower_path); return err; diff --git a/fs/sdcardfs/p/lookup.c b/fs/sdcardfs/p/lookup.c index 884f7bc9d953..aeb24ad03cb9 100644 --- a/fs/sdcardfs/p/lookup.c +++ b/fs/sdcardfs/p/lookup.c @@ -20,7 +20,6 @@ #include "sdcardfs.h" #include "linux/delay.h" -#include "internal.h" /* The dentry cache is just so we have properly sized dentries */ static struct kmem_cache *sdcardfs_dentry_cachep; @@ -175,7 +174,7 @@ static struct dentry *__sdcardfs_interpose(struct dentry *dentry, struct super_block *lower_sb; struct dentry *ret_dentry; - lower_inode = lower_path->dentry->d_inode; + lower_inode = d_inode(lower_path->dentry); lower_sb = sdcardfs_lower_super(sb); /* check that the lower file system didn't cross a mount point */ @@ -196,7 +195,7 @@ static struct dentry *__sdcardfs_interpose(struct dentry *dentry, goto out; } - ret_dentry = d_materialise_unique(dentry, inode); + ret_dentry = d_splice_alias(inode, dentry); dentry = ret_dentry ?: dentry; if (!IS_ERR(dentry)) update_derived_permission_lock(dentry); @@ -228,13 +227,13 @@ struct sdcardfs_name_data { bool found; }; -static int sdcardfs_name_match(void *__buf, const char *name, int namelen, - loff_t offset, u64 ino, unsigned int d_type) +static int sdcardfs_name_match(struct dir_context *ctx, const char *name, + int namelen, loff_t offset, u64 ino, unsigned int d_type) { - struct sdcardfs_name_data *buf = (struct sdcardfs_name_data *) __buf; + struct sdcardfs_name_data *buf = container_of(ctx, struct sdcardfs_name_data, ctx); struct qstr candidate = QSTR_INIT(name, namelen); - if (qstr_n_case_eq(buf->to_find, &candidate)) { + if (qstr_case_eq(buf->to_find, &candidate)) { memcpy(buf->name, name, namelen); buf->name[namelen] = 0; buf->found = true; @@ -363,8 +362,8 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, goto out; mutex_lock(&lower_dir_dentry->d_inode->i_mutex); - lower_dentry = lookup_one_len(dentry->d_name.name, lower_dir_dentry, - dentry->d_name.len); + lower_dentry = lookup_one_len(dentry->d_name.name, lower_dir_dentry, + dentry->d_name.len); mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); if (unlikely(IS_ERR(lower_dentry))) { err = PTR_ERR(lower_dentry); @@ -410,7 +409,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, parent = dget_parent(dentry); - if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) { + if (!check_caller_access_to_name(d_inode(parent), &dentry->d_name)) { ret = ERR_PTR(-EACCES); goto out_err; } @@ -438,17 +437,17 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, goto out; if (ret) dentry = ret; - if (dentry->d_inode) { - fsstack_copy_attr_times(dentry->d_inode, - sdcardfs_lower_inode(dentry->d_inode)); + if (d_inode(dentry)) { + fsstack_copy_attr_times(d_inode(dentry), + sdcardfs_lower_inode(d_inode(dentry))); /* get derived permission */ get_derived_permission(parent, dentry); - fixup_tmp_permissions(dentry->d_inode); + fixup_tmp_permissions(d_inode(dentry)); fixup_lower_ownership(dentry, dentry->d_name.name); } /* update parent directory's atime */ - fsstack_copy_attr_atime(parent->d_inode, - sdcardfs_lower_inode(parent->d_inode)); + fsstack_copy_attr_atime(d_inode(parent), + sdcardfs_lower_inode(d_inode(parent))); out: sdcardfs_put_lower_path(parent, &lower_parent_path); diff --git a/fs/sdcardfs/p/main.c b/fs/sdcardfs/p/main.c index 00f59817176c..ed4512745dd3 100644 --- a/fs/sdcardfs/p/main.c +++ b/fs/sdcardfs/p/main.c @@ -34,6 +34,8 @@ enum { Opt_reserved_mb, Opt_gid_derivation, Opt_default_normal, + Opt_nocache, + Opt_unshared_obb, Opt_err, }; @@ -47,7 +49,9 @@ static const match_table_t sdcardfs_tokens = { {Opt_multiuser, "multiuser"}, {Opt_gid_derivation, "derive_gid"}, {Opt_default_normal, "default_normal"}, + {Opt_unshared_obb, "unshared_obb"}, {Opt_reserved_mb, "reserved_mb=%u"}, + {Opt_nocache, "nocache"}, {Opt_err, NULL} }; @@ -71,6 +75,7 @@ static int parse_options(struct super_block *sb, char *options, int silent, /* by default, gid derivation is off */ opts->gid_derivation = false; opts->default_normal = false; + opts->nocache = false; *debug = 0; @@ -128,6 +133,12 @@ static int parse_options(struct super_block *sb, char *options, int silent, case Opt_default_normal: opts->default_normal = true; break; + case Opt_nocache: + opts->nocache = true; + break; + case Opt_unshared_obb: + opts->unshared_obb = true; + break; /* unknown option */ default: if (!silent) @@ -181,13 +192,16 @@ int parse_options_remount(struct super_block *sb, char *options, int silent, return 0; vfsopts->mask = option; break; + case Opt_unshared_obb: case Opt_default_normal: case Opt_multiuser: case Opt_userid: case Opt_fsuid: case Opt_fsgid: case Opt_reserved_mb: - pr_warn("Option \"%s\" can't be changed during remount\n", p); + case Opt_gid_derivation: + if (!silent) + pr_warn("Option \"%s\" can't be changed during remount\n", p); break; /* unknown option */ default: @@ -294,6 +308,13 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, atomic_inc(&lower_sb->s_active); sdcardfs_set_lower_super(sb, lower_sb); + sb->s_stack_depth = lower_sb->s_stack_depth + 1; + if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + pr_err("sdcardfs: maximum fs stacking depth exceeded\n"); + err = -EINVAL; + goto out_sput; + } + /* inherit maxbytes from lower file system */ sb->s_maxbytes = lower_sb->s_maxbytes; @@ -307,7 +328,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, sb->s_op = &sdcardfs_sops; /* get a new inode and allocate our root dentry */ - inode = sdcardfs_iget(sb, lower_path.dentry->d_inode, 0); + inode = sdcardfs_iget(sb, d_inode(lower_path.dentry), 0); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_sput; @@ -339,17 +360,15 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); mutex_lock(&sdcardfs_super_list_lock); if (sb_info->options.multiuser) { - setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, - sb_info->options.fs_user_id, AID_ROOT, - false, SDCARDFS_I(sb->s_root->d_inode)->data); + setup_derived_state(d_inode(sb->s_root), PERM_PRE_ROOT, + sb_info->options.fs_user_id, AID_ROOT); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name); } else { - setup_derived_state(sb->s_root->d_inode, PERM_ROOT, - sb_info->options.fs_user_id, AID_ROOT, - false, SDCARDFS_I(sb->s_root->d_inode)->data); + setup_derived_state(d_inode(sb->s_root), PERM_ROOT, + sb_info->options.fs_user_id, AID_ROOT); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } - fixup_tmp_permissions(sb->s_root->d_inode); + fixup_tmp_permissions(d_inode(sb->s_root)); sb_info->sb = sb; list_add(&sb_info->list, &sdcardfs_super_list); mutex_unlock(&sdcardfs_super_list_lock); diff --git a/fs/sdcardfs/p/sdcardfs.h b/fs/sdcardfs/p/sdcardfs.h index 035b247c5e51..7f5afa1bc96f 100644 --- a/fs/sdcardfs/p/sdcardfs.h +++ b/fs/sdcardfs/p/sdcardfs.h @@ -139,6 +139,7 @@ typedef enum { PERM_KNOX_ANDROID_SHARED, /* This node is /knox/[userid]/Android/[data|shared]/[package] */ PERM_KNOX_ANDROID_PACKAGE, + } perm_t; struct sdcardfs_sb_info; @@ -203,6 +204,7 @@ struct sdcardfs_inode_info { struct sdcardfs_inode_data *data; /* top folder for ownership */ + spinlock_t top_lock; struct sdcardfs_inode_data *top_data; struct inode vfs_inode; @@ -223,7 +225,9 @@ struct sdcardfs_mount_options { bool multiuser; bool gid_derivation; bool default_normal; + bool unshared_obb; unsigned int reserved_mb; + bool nocache; }; struct sdcardfs_vfsmount_options { @@ -382,7 +386,12 @@ static inline struct sdcardfs_inode_data *data_get( static inline struct sdcardfs_inode_data *top_data_get( struct sdcardfs_inode_info *info) { - return data_get(info->top_data); + struct sdcardfs_inode_data *top_data; + + spin_lock(&info->top_lock); + top_data = data_get(info->top_data); + spin_unlock(&info->top_lock); + return top_data; } extern void data_release(struct kref *ref); @@ -404,15 +413,20 @@ static inline void release_own_data(struct sdcardfs_inode_info *info) } static inline void set_top(struct sdcardfs_inode_info *info, - struct sdcardfs_inode_data *top) + struct sdcardfs_inode_info *top_owner) { - struct sdcardfs_inode_data *old_top = info->top_data; + struct sdcardfs_inode_data *old_top; + struct sdcardfs_inode_data *new_top = NULL; + + if (top_owner) + new_top = top_data_get(top_owner); - if (top) - data_get(top); - info->top_data = top; + spin_lock(&info->top_lock); + old_top = info->top_data; + info->top_data = new_top; if (old_top) data_put(old_top); + spin_unlock(&info->top_lock); } static inline int get_gid(struct vfsmount *mnt, @@ -536,8 +550,7 @@ struct limit_search { }; extern void setup_derived_state(struct inode *inode, perm_t perm, - userid_t userid, uid_t uid, bool under_android, - struct sdcardfs_inode_data *top); + userid_t userid, uid_t uid); extern void get_derived_permission(struct dentry *parent, struct dentry *dentry); extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, const struct qstr *name); extern void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit); @@ -554,13 +567,13 @@ static inline struct dentry *lock_parent(struct dentry *dentry) { struct dentry *dir = dget_parent(dentry); - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_PARENT); return dir; } static inline void unlock_dir(struct dentry *dir) { - mutex_unlock(&dir->d_inode->i_mutex); + mutex_unlock(&d_inode(dir)->i_mutex); dput(dir); } @@ -579,7 +592,7 @@ static inline int prepare_dir(const char *path_s, uid_t uid, gid_t gid, mode_t m goto out_unlock; } - err = vfs_mkdir2(parent.mnt, parent.dentry->d_inode, dent, mode); + err = vfs_mkdir2(parent.mnt, d_inode(parent.dentry), dent, mode); if (err) { if (err == -EEXIST) err = 0; @@ -589,16 +602,16 @@ static inline int prepare_dir(const char *path_s, uid_t uid, gid_t gid, mode_t m attrs.ia_uid = make_kuid(&init_user_ns, uid); attrs.ia_gid = make_kgid(&init_user_ns, gid); attrs.ia_valid = ATTR_UID | ATTR_GID; - mutex_lock(&dent->d_inode->i_mutex); + mutex_lock(&d_inode(dent)->i_mutex); notify_change2(parent.mnt, dent, &attrs, NULL); - mutex_unlock(&dent->d_inode->i_mutex); + mutex_unlock(&d_inode(dent)->i_mutex); out_dput: dput(dent); out_unlock: /* parent dentry locked by lookup_create */ - mutex_unlock(&parent.dentry->d_inode->i_mutex); + mutex_unlock(&d_inode(parent.dentry)->i_mutex); path_put(&parent); return err; } @@ -617,7 +630,7 @@ static inline int check_min_free_space(struct dentry *dentry, size_t size, int d if (uid_eq(GLOBAL_ROOT_UID, current_fsuid()) || capable(CAP_SYS_RESOURCE) || - in_group_p(AID_RESERVED_DISK)) + in_group_p(AID_USE_ROOT_RESERVED)) return 1; if (sbi->options.reserved_mb) { @@ -703,15 +716,9 @@ static inline bool str_n_case_eq(const char *s1, const char *s2, size_t len) static inline bool qstr_case_eq(const struct qstr *q1, const struct qstr *q2) { - return q1->len == q2->len && str_case_eq(q1->name, q2->name); -} - -static inline bool qstr_n_case_eq(const struct qstr *q1, const struct qstr *q2) -{ - return q1->len == q2->len && str_n_case_eq(q1->name, q2->name, q1->len); + return q1->len == q2->len && str_n_case_eq(q1->name, q2->name, q2->len); } -/* */ #define QSTR_LITERAL(string) QSTR_INIT(string, sizeof(string)-1) #endif /* not _SDCARDFS_H_ */ diff --git a/fs/sdcardfs/p/super.c b/fs/sdcardfs/p/super.c index 8d70642831c6..852a69162411 100644 --- a/fs/sdcardfs/p/super.c +++ b/fs/sdcardfs/p/super.c @@ -80,7 +80,7 @@ static int sdcardfs_statfs(struct dentry *dentry, struct kstatfs *buf) if (uid_eq(GLOBAL_ROOT_UID, current_fsuid()) || capable(CAP_SYS_RESOURCE) || - in_group_p(AID_RESERVED_DISK)) + in_group_p(AID_USE_ROOT_RESERVED)) goto out; if (sbi->options.reserved_mb) { @@ -220,6 +220,9 @@ static struct inode *sdcardfs_alloc_inode(struct super_block *sb) i->data = d; kref_init(&d->refcount); + i->top_data = d; + spin_lock_init(&i->top_lock); + kref_get(&d->refcount); i->vfs_inode.i_version = 1; return &i->vfs_inode; @@ -313,6 +316,8 @@ static int sdcardfs_show_options(struct vfsmount *mnt, struct seq_file *m, seq_puts(m, ",default_normal"); if (opts->reserved_mb != 0) seq_printf(m, ",reserved=%uMB", opts->reserved_mb); + if (opts->nocache) + seq_printf(m, ",nocache"); return 0; };