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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
a2a4dc494a
commit
4afddd60a7
@ -48,14 +48,18 @@ void __init kernfs_inode_init(void)
|
|||||||
|
|
||||||
static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
|
static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
|
||||||
{
|
{
|
||||||
|
static DEFINE_MUTEX(iattr_mutex);
|
||||||
|
struct kernfs_iattrs *ret;
|
||||||
struct iattr *iattrs;
|
struct iattr *iattrs;
|
||||||
|
|
||||||
|
mutex_lock(&iattr_mutex);
|
||||||
|
|
||||||
if (kn->iattr)
|
if (kn->iattr)
|
||||||
return kn->iattr;
|
goto out_unlock;
|
||||||
|
|
||||||
kn->iattr = kzalloc(sizeof(struct kernfs_iattrs), GFP_KERNEL);
|
kn->iattr = kzalloc(sizeof(struct kernfs_iattrs), GFP_KERNEL);
|
||||||
if (!kn->iattr)
|
if (!kn->iattr)
|
||||||
return NULL;
|
goto out_unlock;
|
||||||
iattrs = &kn->iattr->ia_iattr;
|
iattrs = &kn->iattr->ia_iattr;
|
||||||
|
|
||||||
/* assign default attributes */
|
/* assign default attributes */
|
||||||
@ -65,8 +69,10 @@ static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
|
|||||||
iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME;
|
iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME;
|
||||||
|
|
||||||
simple_xattrs_init(&kn->iattr->xattrs);
|
simple_xattrs_init(&kn->iattr->xattrs);
|
||||||
|
out_unlock:
|
||||||
return kn->iattr;
|
ret = kn->iattr;
|
||||||
|
mutex_unlock(&iattr_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
|
static int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
|
||||||
|
Reference in New Issue
Block a user