mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	ovl: enable RCU'd ->get_acl()
Overlayfs does not cache ACL's (to avoid double caching). Instead it just calls the underlying filesystem's i_op->get_acl(), which will return the cached value, if possible. In rcu path walk, however, get_cached_acl_rcu() is employed to get the value from the cache, which will fail on overlayfs resulting in dropping out of rcu walk mode. This can result in a big performance hit in certain situations. Fix by calling ->get_acl() with rcu=true in case of ACL_DONT_CACHE (which indicates pass-through) Reported-by: garyhuang <zjh.20052005@163.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
		
							parent
							
								
									0cad624662
								
							
						
					
					
						commit
						332f606b32
					
				
					 4 changed files with 23 additions and 5 deletions
				
			
		|  | @ -13,6 +13,7 @@ | |||
| #include <linux/fiemap.h> | ||||
| #include <linux/fileattr.h> | ||||
| #include <linux/security.h> | ||||
| #include <linux/namei.h> | ||||
| #include "overlayfs.h" | ||||
| 
 | ||||
| 
 | ||||
|  | @ -452,12 +453,12 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu) | |||
| 	const struct cred *old_cred; | ||||
| 	struct posix_acl *acl; | ||||
| 
 | ||||
| 	if (rcu) | ||||
| 		return ERR_PTR(-ECHILD); | ||||
| 
 | ||||
| 	if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !IS_POSIXACL(realinode)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (rcu) | ||||
| 		return get_cached_acl_rcu(realinode, type); | ||||
| 
 | ||||
| 	old_cred = ovl_override_creds(inode->i_sb); | ||||
| 	acl = get_acl(realinode, type); | ||||
| 	revert_creds(old_cred); | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ | |||
| #include <linux/xattr.h> | ||||
| #include <linux/export.h> | ||||
| #include <linux/user_namespace.h> | ||||
| #include <linux/namei.h> | ||||
| 
 | ||||
| static struct posix_acl **acl_by_type(struct inode *inode, int type) | ||||
| { | ||||
|  | @ -56,7 +57,17 @@ EXPORT_SYMBOL(get_cached_acl); | |||
| 
 | ||||
| struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type) | ||||
| { | ||||
| 	return rcu_dereference(*acl_by_type(inode, type)); | ||||
| 	struct posix_acl *acl = rcu_dereference(*acl_by_type(inode, type)); | ||||
| 
 | ||||
| 	if (acl == ACL_DONT_CACHE) { | ||||
| 		struct posix_acl *ret; | ||||
| 
 | ||||
| 		ret = inode->i_op->get_acl(inode, type, LOOKUP_RCU); | ||||
| 		if (!IS_ERR(ret)) | ||||
| 			acl = ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return acl; | ||||
| } | ||||
| EXPORT_SYMBOL(get_cached_acl_rcu); | ||||
| 
 | ||||
|  |  | |||
|  | @ -581,6 +581,11 @@ static inline void mapping_allow_writable(struct address_space *mapping) | |||
| 
 | ||||
| struct posix_acl; | ||||
| #define ACL_NOT_CACHED ((void *)(-1)) | ||||
| /*
 | ||||
|  * ACL_DONT_CACHE is for stacked filesystems, that rely on underlying fs to | ||||
|  * cache the ACL.  This also means that ->get_acl() can be called in RCU mode | ||||
|  * with the LOOKUP_RCU flag. | ||||
|  */ | ||||
| #define ACL_DONT_CACHE ((void *)(-3)) | ||||
| 
 | ||||
| static inline struct posix_acl * | ||||
|  |  | |||
|  | @ -72,6 +72,8 @@ extern struct posix_acl *get_posix_acl(struct inode *, int); | |||
| extern int set_posix_acl(struct user_namespace *, struct inode *, int, | ||||
| 			 struct posix_acl *); | ||||
| 
 | ||||
| struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type); | ||||
| 
 | ||||
| #ifdef CONFIG_FS_POSIX_ACL | ||||
| int posix_acl_chmod(struct user_namespace *, struct inode *, umode_t); | ||||
| extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **, | ||||
|  | @ -84,7 +86,6 @@ extern int simple_set_acl(struct user_namespace *, struct inode *, | |||
| extern int simple_acl_create(struct inode *, struct inode *); | ||||
| 
 | ||||
| struct posix_acl *get_cached_acl(struct inode *inode, int type); | ||||
| struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type); | ||||
| void set_cached_acl(struct inode *inode, int type, struct posix_acl *acl); | ||||
| void forget_cached_acl(struct inode *inode, int type); | ||||
| void forget_all_cached_acls(struct inode *inode); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Miklos Szeredi
						Miklos Szeredi