From e2da9b7973ae3dc2dde1094091add50b77c79c12 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 2 Mar 2017 15:11:27 -0800 Subject: 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 Bug: 35643557 Change-Id: I22cf30856d75b5616cbb0c223724f5ab866b5114 --- fs/sdcardfs/derived_perm.c | 32 +++++++++++++++++++------------- 1 file 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) { -- cgit v1.2.3