[PATCH driver-core-linus] kernfs: protect lazy kernfs_iattrs allocation with mutex

From: Tejun Heo
Date: Wed Apr 02 2014 - 16:41:09 EST

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@xxxxxxxxxx>
Link: http://lkml.kernel.org/g/533ABA32.9080602@xxxxxxxxxx
Reported-by: Sasha Levin <sasha.levin@xxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx # 3.14
fs/kernfs/inode.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index e55126f..553946c 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -48,14 +48,18 @@ void __init kernfs_inode_init(void)

static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
+ static DEFINE_MUTEX(iattr_mutex);
+ struct kernfs_iattrs *ret;
struct iattr *iattrs;

+ mutex_lock(&iattr_mutex);
if (kn->iattr)
- return kn->iattr;
+ goto out_unlock;

kn->iattr = kzalloc(sizeof(struct kernfs_iattrs), GFP_KERNEL);
if (!kn->iattr)
- return NULL;
+ goto out_unlock;
iattrs = &kn->iattr->ia_iattr;

/* 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;

- return kn->iattr;
+ ret = kn->iattr;
+ mutex_unlock(&iattr_mutex);
+ return ret;

static int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/