ANDROID: sdcardfs: Added top to sdcardfs_inode_info
Adding packages to the package list and moving files
takes a large amount of locks, and is currently a
heavy operation. This adds a 'top' field to the
inode_info, which points to the inode for the top
most directory whose owner you would like to match.
On permission checks and get_attr, we look up the
owner based on the information at top. When we change
a package mapping, we need only modify the information
in the corresponding top inode_info's. When renaming,
we must ensure top is set correctly in all children.
This happens when an app specific folder gets moved
outside of the folder for that app.
Change-Id: Ib749c60b568e9a45a46f8ceed985c1338246ec6c
Signed-off-by: Daniel Rosenberg <drosen@google.com>
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
index 2a75ad8..89daf69 100644
--- a/fs/sdcardfs/derived_perm.c
+++ b/fs/sdcardfs/derived_perm.c
@@ -30,11 +30,12 @@
ci->userid = pi->userid;
ci->d_uid = pi->d_uid;
ci->under_android = pi->under_android;
+ set_top(ci, pi->top);
}
/* helper function for derived state */
-void setup_derived_state(struct inode *inode, perm_t perm,
- userid_t userid, uid_t uid, bool under_android)
+void setup_derived_state(struct inode *inode, perm_t perm, userid_t userid,
+ uid_t uid, bool under_android, struct inode *top)
{
struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
@@ -42,6 +43,7 @@
info->userid = userid;
info->d_uid = uid;
info->under_android = under_android;
+ set_top(info, top);
}
/* While renaming, there is a point where we want the path from dentry, but the name from newdentry */
@@ -70,6 +72,7 @@
/* Legacy internal layout places users at top level */
info->perm = PERM_ROOT;
info->userid = simple_strtoul(newdentry->d_name.name, NULL, 10);
+ set_top(info, &info->vfs_inode);
break;
case PERM_ROOT:
/* Assume masked off by default. */
@@ -77,19 +80,23 @@
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID;
info->under_android = true;
+ set_top(info, &info->vfs_inode);
}
break;
case PERM_ANDROID:
if (!strcasecmp(newdentry->d_name.name, "data")) {
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID_DATA;
+ set_top(info, &info->vfs_inode);
} else if (!strcasecmp(newdentry->d_name.name, "obb")) {
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID_OBB;
+ set_top(info, &info->vfs_inode);
/* Single OBB directory is always shared */
} else if (!strcasecmp(newdentry->d_name.name, "media")) {
/* App-specific directories inside; let anyone traverse */
info->perm = PERM_ANDROID_MEDIA;
+ set_top(info, &info->vfs_inode);
}
break;
case PERM_ANDROID_DATA:
@@ -99,6 +106,7 @@
if (appid != 0) {
info->d_uid = multiuser_get_uid(parent_info->userid, appid);
}
+ set_top(info, &info->vfs_inode);
break;
}
}
@@ -108,14 +116,65 @@
get_derived_permission_new(parent, dentry, dentry);
}
-void get_derive_permissions_recursive(struct dentry *parent) {
+static int descendant_may_need_fixup(perm_t perm) {
+ if (perm == PERM_PRE_ROOT || perm == PERM_ROOT || perm == PERM_ANDROID)
+ return 1;
+ return 0;
+}
+
+static int needs_fixup(perm_t perm) {
+ if (perm == PERM_ANDROID_DATA || perm == PERM_ANDROID_OBB
+ || perm == PERM_ANDROID_MEDIA)
+ return 1;
+ return 0;
+}
+
+void fixup_perms_recursive(struct dentry *dentry, const char* name, size_t len) {
+ struct dentry *child;
+ struct sdcardfs_inode_info *info;
+ if (!dget(dentry))
+ return;
+ if (!dentry->d_inode) {
+ dput(dentry);
+ return;
+ }
+ info = SDCARDFS_I(d_inode(dentry));
+
+ if (needs_fixup(info->perm)) {
+ mutex_lock(&d_inode(dentry)->i_mutex);
+ child = lookup_one_len(name, dentry, len);
+ mutex_unlock(&d_inode(dentry)->i_mutex);
+ if (!IS_ERR(child)) {
+ if (child->d_inode) {
+ get_derived_permission(dentry, child);
+ fix_derived_permission(d_inode(child));
+ }
+ dput(child);
+ }
+ } else if (descendant_may_need_fixup(info->perm)) {
+ mutex_lock(&d_inode(dentry)->i_mutex);
+ list_for_each_entry(child, &dentry->d_subdirs, d_child) {
+ fixup_perms_recursive(child, name, len);
+ }
+ mutex_unlock(&d_inode(dentry)->i_mutex);
+ }
+ dput(dentry);
+}
+
+void fixup_top_recursive(struct dentry *parent) {
struct dentry *dentry;
+ struct sdcardfs_inode_info *info;
+ if (!d_inode(parent))
+ return;
+ info = SDCARDFS_I(d_inode(parent));
spin_lock(&parent->d_lock);
list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
- if (dentry->d_inode) {
- get_derived_permission(parent, dentry);
- fix_derived_permission(dentry->d_inode);
- get_derive_permissions_recursive(dentry);
+ if (d_inode(dentry)) {
+ if (SDCARDFS_I(d_inode(parent))->top != SDCARDFS_I(d_inode(dentry))->top) {
+ get_derived_permission(parent, dentry);
+ fix_derived_permission(d_inode(dentry));
+ fixup_top_recursive(dentry);
+ }
}
}
spin_unlock(&parent->d_lock);