aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Rosenberg <drosen@google.com>2017-03-02 15:11:27 -0800
committerMister Oyster <oysterized@gmail.com>2017-04-13 12:35:18 +0200
commite2da9b7973ae3dc2dde1094091add50b77c79c12 (patch)
tree923945ae01234f49f8d5ca0cd40253d69262ac27
parent5f4b8762512cc370114c0f69baa9f521884aed66 (diff)
ANDROID: sdcardfs: Replace get/put with d_lock
dput cannot be called with a spin_lock. Instead, we protect our accesses by holding the d_lock. Signed-off-by: Daniel Rosenberg <drosen@google.com> Bug: 35643557 Change-Id: I22cf30856d75b5616cbb0c223724f5ab866b5114
-rwxr-xr-xfs/sdcardfs/derived_perm.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
index d31c19f31..ce2f9d34a 100755
--- a/fs/sdcardfs/derived_perm.c
+++ b/fs/sdcardfs/derived_perm.c
@@ -254,40 +254,46 @@ static int needs_fixup(perm_t perm) {
return 0;
}
-void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) {
+static void __fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit, int depth) {
struct dentry *child;
struct sdcardfs_inode_info *info;
- if (!dget(dentry))
- return;
+
+ /*
+ * All paths will terminate their recursion on hitting PERM_ANDROID_OBB,
+ * PERM_ANDROID_MEDIA, or PERM_ANDROID_DATA. This happens at a depth of
+ * at most 3.
+ */
+ WARN(depth > 3, "%s: Max expected depth exceeded!\n", __func__);
+ spin_lock_nested(&dentry->d_lock, depth);
if (!dentry->d_inode) {
- dput(dentry);
+ spin_unlock(&dentry->d_lock);
return;
}
info = SDCARDFS_I(dentry->d_inode);
if (needs_fixup(info->perm)) {
- spin_lock(&dentry->d_lock);
list_for_each_entry(child, &dentry->d_subdirs, d_child) {
- dget(child);
+ spin_lock_nested(&child->d_lock, depth + 1);
if (!(limit->flags & BY_NAME) || !strncasecmp(child->d_name.name, limit->name, limit->length)) {
if (child->d_inode) {
get_derived_permission(dentry, child);
fixup_tmp_permissions(child->d_inode);
- dput(child);
+ spin_unlock(&child->d_lock);
break;
}
}
- dput(child);
+ spin_unlock(&child->d_lock);
}
- spin_unlock(&dentry->d_lock);
} else if (descendant_may_need_fixup(info, limit)) {
- spin_lock(&dentry->d_lock);
list_for_each_entry(child, &dentry->d_subdirs, d_child) {
- fixup_perms_recursive(child, limit);
+ __fixup_perms_recursive(child, limit, depth + 1);
}
- spin_unlock(&dentry->d_lock);
}
- dput(dentry);
+ spin_unlock(&dentry->d_lock);
+}
+
+void fixup_perms_recursive(struct dentry *dentry, struct limit_search *limit) {
+ __fixup_perms_recursive(dentry, limit, 0);
}
void drop_recursive(struct dentry *parent) {