Patch "ovl: lookup whiteouts outside iterate_dir()" has been added to the 4.1-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
ovl: lookup whiteouts outside iterate_dir()
to the 4.1-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
ovl-lookup-whiteouts-outside-iterate_dir.patch
and it can be found in the queue-4.1 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
cdb672795876d7bc1870aed9a2d7cb59f43d1d96Mon Sep 17 00:00:00 2001
From: Miklos Szeredi <[email protected]>
Date: Mon, 22 Jun 2015 13:53:48 +0200
Subject: ovl: lookup whiteouts outside iterate_dir()
From: Miklos Szeredi <[email protected]>
commit cdb672795876d7bc1870aed9a2d7cb59f43d1d96 upstream.
If jffs2 can deadlock on overlayfs readdir because it takes the same lock on ->iterate() as in ->lookup().
Fix by moving whiteout checking outside iterate_dir(). Optimized by collecting potential whiteouts (DT_CHR) in a temporary list and if non-empty iterating throug these and checking for a 0/0 chardev.
--- fs/overlayfs/readdir.c | 77 +++++++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 28 deletions(-)
fs/overlayfs/readdir.c +49 -28
@@ -23,6 +23,7 @@ struct ovl_cache_entry {u64 ino;struct list_head l_node;struct rb_node node; +struct ovl_cache_entry *next_maybe_whiteout;bool is_whiteout;char name[]; };
@@ -39,7 +40,7 @@ struct ovl_readdir_data {struct rb_root root;struct list_head *list;struct list_head middle; -struct dentry *dir; +struct ovl_cache_entry *first_maybe_whiteout;int count;int err; };
@@ -79,7 +80,7 @@ static struct ovl_cache_entry *ovl_cachereturn NULL ; } -static struct ovl_cache_entry *ovl_cache_entry_new (struct dentry *dir, +static struct ovl_cache_entry *ovl_cache_entry_new (struct ovl_readdir_data *rdd,const char *name,int len,u64 ino,unsigned int d_type) {
@@ -98,29 +99,8 @@ static struct ovl_cache_entry *ovl_cache p->is_whiteout = false;if (d_type ==DT_CHR ) { -struct dentry *dentry; -const struct cred *old_cred; -struct cred *override_cred; - - override_cred =prepare_creds (); -if (!override_cred) { -kfree (p); -return NULL ; - } - -/* -* CAP_DAC_OVERRIDE for lookup -*/ -cap_raise (override_cred->cap_effective,CAP_DAC_OVERRIDE ); - old_cred =override_creds (override_cred); - - dentry =lookup_one_len (name, dir, len); -if (!IS_ERR (dentry)) { - p->is_whiteout =ovl_is_whiteout (dentry); -dput (dentry); - } -revert_creds (old_cred); -put_cred (override_cred); + p->next_maybe_whiteout = rdd->first_maybe_whiteout; + rdd->first_maybe_whiteout = p; }return p; }
@@ -148,7 +128,7 @@ static int ovl_cache_entry_add_rb(structreturn 0 ; } - p =ovl_cache_entry_new (rdd->dir, name, len, ino, d_type); + p =ovl_cache_entry_new (rdd, name, len, ino, d_type);if (p ==NULL )return -ENOMEM ;
@@ -169,7 +149,7 @@ static int ovl_fill_lower(struct ovl_reaif (p) {list_move_tail (&p->l_node, &rdd->middle); }else { - p =ovl_cache_entry_new (rdd->dir, name, namelen, ino, d_type); + p =ovl_cache_entry_new (rdd, name, namelen, ino, d_type);if (p ==NULL ) rdd->err = -ENOMEM ;else
@@ -219,6 +199,43 @@ static int ovl_fill_merge(struct dir_conreturn ovl_fill_lower (rdd, name, namelen, offset, ino, d_type); } +static int ovl_check_whiteouts (struct dentry *dir,struct ovl_readdir_data *rdd) +{ +int err; +struct ovl_cache_entry *p; +struct dentry *dentry; +const struct cred *old_cred; +struct cred *override_cred; + + override_cred =prepare_creds (); +if (!override_cred) +return -ENOMEM ; + +/* +* CAP_DAC_OVERRIDE for lookup +*/ +cap_raise (override_cred->cap_effective,CAP_DAC_OVERRIDE ); + old_cred =override_creds (override_cred); + + err =mutex_lock_killable (&dir->d_inode->i_mutex); +if (!err) { +while (rdd->first_maybe_whiteout) { + p = rdd->first_maybe_whiteout; + rdd->first_maybe_whiteout = p->next_maybe_whiteout; + dentry =lookup_one_len (p->name, dir, p->len); +if (!IS_ERR (dentry)) { + p->is_whiteout =ovl_is_whiteout (dentry); +dput (dentry); + } + } +mutex_unlock (&dir->d_inode->i_mutex); + } +revert_creds (old_cred); +put_cred (override_cred); + +return err; +} +static inline int ovl_dir_read (struct path *realpath,struct ovl_readdir_data *rdd) {
@@ -229,7 +246,7 @@ static inline int ovl_dir_read(struct paif (IS_ERR (realfile))return PTR_ERR (realfile); - rdd->dir = realpath->dentry; + rdd->first_maybe_whiteout =NULL ; rdd->ctx.pos =0 ; do { rdd->count = 0;
@@ -238,6 +255,10 @@ static inline int ovl_dir_read(struct paif (err >=0 ) err = rdd->err; }while (!err && rdd->count); + +if (!err && rdd->first_maybe_whiteout) + err =ovl_check_whiteouts (realpath->dentry, rdd); +fput (realfile);return err;
Patches currently in stable-queue which might be from [email protected] are
queue-4.1/ovl-lookup-whiteouts-outside-iterate_dir.patch queue-4.1/fuse-initialize-fc-release-before-calling-it.patch