Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kernfs: protect lazy kernfs_iattrs allocation with mutex

kernfs_iattrs is allocated lazily when operations which require it
take place; unfortunately, the lazy allocation and returning weren't
properly synchronized and when there are multiple concurrent
operations, it might end up returning kernfs_iattrs which hasn't
finished initialization yet or different copies to different callers.

Fix it by synchronizing with a mutex. This can be smarter with memory
barriers but let's go there if it actually turns out to be necessary.

Signed-off-by: Tejun Heo <tj@kernel.org>
Link: http://lkml.kernel.org/g/533ABA32.9080602@oracle.com
Reported-by: Sasha Levin <sasha.levin@oracle.com>
Cc: stable@vger.kernel.org # 3.14
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Tejun Heo and committed by
Greg Kroah-Hartman
4afddd60 a2a4dc49

+10 -4
+10 -4
fs/kernfs/inode.c
··· 48 48 49 49 static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn) 50 50 { 51 + static DEFINE_MUTEX(iattr_mutex); 52 + struct kernfs_iattrs *ret; 51 53 struct iattr *iattrs; 52 54 55 + mutex_lock(&iattr_mutex); 56 + 53 57 if (kn->iattr) 54 - return kn->iattr; 58 + goto out_unlock; 55 59 56 60 kn->iattr = kzalloc(sizeof(struct kernfs_iattrs), GFP_KERNEL); 57 61 if (!kn->iattr) 58 - return NULL; 62 + goto out_unlock; 59 63 iattrs = &kn->iattr->ia_iattr; 60 64 61 65 /* assign default attributes */ ··· 69 65 iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; 70 66 71 67 simple_xattrs_init(&kn->iattr->xattrs); 72 - 73 - return kn->iattr; 68 + out_unlock: 69 + ret = kn->iattr; 70 + mutex_unlock(&iattr_mutex); 71 + return ret; 74 72 } 75 73 76 74 static int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)