diff mbox series

[v2,4/6] kernfs: implement readdir FMODE_NOWAIT

Message ID 20230422-uring-getdents-v2-4-2db1e37dc55e@codewreck.org (mailing list archive)
State New
Headers show
Series io_uring: add getdents support, take 2 | expand

Commit Message

Dominique Martinet May 10, 2023, 10:52 a.m. UTC
Since down_read can block, use the _trylock variant if NOWAIT variant
has been requested.
(can probably do a little bit better style-wise)

Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
---
 fs/kernfs/dir.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

Comments

Dan Carpenter May 11, 2023, 10:55 a.m. UTC | #1
Hi Dominique,

kernel test robot noticed the following build warnings:

url:    https://github.com/intel-lab-lkp/linux/commits/Dominique-Martinet/fs-split-off-vfs_getdents-function-of-getdents64-syscall/20230510-185542
base:   58390c8ce1bddb6c623f62e7ed36383e7fa5c02f
patch link:    https://lore.kernel.org/r/20230422-uring-getdents-v2-4-2db1e37dc55e%40codewreck.org
patch subject: [PATCH v2 4/6] kernfs: implement readdir FMODE_NOWAIT
config: i386-randconfig-m021 (https://download.01.org/0day-ci/archive/20230511/202305110647.eSnSEulg-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-12) 11.3.0

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <error27@gmail.com>
| Link: https://lore.kernel.org/r/202305110647.eSnSEulg-lkp@intel.com/

smatch warnings:
fs/kernfs/dir.c:1863 kernfs_fop_readdir() warn: inconsistent returns '&root->kernfs_rwsem'.

vim +1863 fs/kernfs/dir.c

c637b8acbe079e Tejun Heo          2013-12-11  1815  static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1816  {
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1817  	struct dentry *dentry = file->f_path.dentry;
319ba91d352a74 Shaohua Li         2017-07-12  1818  	struct kernfs_node *parent = kernfs_dentry_node(dentry);
324a56e16e44ba Tejun Heo          2013-12-11  1819  	struct kernfs_node *pos = file->private_data;
393c3714081a53 Minchan Kim        2021-11-18  1820  	struct kernfs_root *root;
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1821  	const void *ns = NULL;
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1822  
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1823  	if (!dir_emit_dots(file, ctx))
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1824  		return 0;
393c3714081a53 Minchan Kim        2021-11-18  1825  
393c3714081a53 Minchan Kim        2021-11-18  1826  	root = kernfs_root(parent);
a551138c4b3b9f Dominique Martinet 2023-05-10  1827  	if (ctx->flags & DIR_CONTEXT_F_NOWAIT) {
a551138c4b3b9f Dominique Martinet 2023-05-10  1828  		if (!down_read_trylock(&root->kernfs_rwsem))
a551138c4b3b9f Dominique Martinet 2023-05-10  1829  			return -EAGAIN;
a551138c4b3b9f Dominique Martinet 2023-05-10  1830  	} else {
393c3714081a53 Minchan Kim        2021-11-18  1831  		down_read(&root->kernfs_rwsem);
a551138c4b3b9f Dominique Martinet 2023-05-10  1832  	}
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1833  
324a56e16e44ba Tejun Heo          2013-12-11  1834  	if (kernfs_ns_enabled(parent))
c525aaddc366df Tejun Heo          2013-12-11  1835  		ns = kernfs_info(dentry->d_sb)->ns;
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1836  
c637b8acbe079e Tejun Heo          2013-12-11  1837  	for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos);
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1838  	     pos;
c637b8acbe079e Tejun Heo          2013-12-11  1839  	     pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) {
adc5e8b58f4886 Tejun Heo          2013-12-11  1840  		const char *name = pos->name;
364595a6851bf6 Jeff Layton        2023-03-30  1841  		unsigned int type = fs_umode_to_dtype(pos->mode);
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1842  		int len = strlen(name);
67c0496e87d193 Tejun Heo          2019-11-04  1843  		ino_t ino = kernfs_ino(pos);
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1844  
adc5e8b58f4886 Tejun Heo          2013-12-11  1845  		ctx->pos = pos->hash;
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1846  		file->private_data = pos;
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1847  		kernfs_get(pos);
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1848  
393c3714081a53 Minchan Kim        2021-11-18  1849  		up_read(&root->kernfs_rwsem);
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1850  		if (!dir_emit(ctx, name, len, ino, type))
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1851  			return 0;
393c3714081a53 Minchan Kim        2021-11-18  1852  		down_read(&root->kernfs_rwsem);
                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Needs to be deleted.

a551138c4b3b9f Dominique Martinet 2023-05-10  1853  		if (ctx->flags & DIR_CONTEXT_F_NOWAIT) {
a551138c4b3b9f Dominique Martinet 2023-05-10  1854  			if (!down_read_trylock(&root->kernfs_rwsem))
a551138c4b3b9f Dominique Martinet 2023-05-10  1855  				return 0;

It's a bit strange the this doesn't return -EAGAIN;

a551138c4b3b9f Dominique Martinet 2023-05-10  1856  		} else {
a551138c4b3b9f Dominique Martinet 2023-05-10  1857  			down_read(&root->kernfs_rwsem);
a551138c4b3b9f Dominique Martinet 2023-05-10  1858  		}
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1859  	}
393c3714081a53 Minchan Kim        2021-11-18  1860  	up_read(&root->kernfs_rwsem);
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1861  	file->private_data = NULL;
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1862  	ctx->pos = INT_MAX;
fd7b9f7b9776b1 Tejun Heo          2013-11-28 @1863  	return 0;
fd7b9f7b9776b1 Tejun Heo          2013-11-28  1864  }
Dominique Martinet May 11, 2023, 11:03 a.m. UTC | #2
Dan Carpenter wrote on Thu, May 11, 2023 at 01:55:57PM +0300:
> fd7b9f7b9776b1 Tejun Heo          2013-11-28  1850  		if (!dir_emit(ctx, name, len, ino, type))
> fd7b9f7b9776b1 Tejun Heo          2013-11-28  1851  			return 0;
> 393c3714081a53 Minchan Kim        2021-11-18  1852  		down_read(&root->kernfs_rwsem);
>                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Needs to be deleted.

Uh, yes, sorry; I'm not sure how I let that slip, I guess I didn't hit
any dead lock because nothing ever tried to take a write lock after
getdents...
Thanks!

I expect there'll be other comments (this might not make it at all), so
I'll keep the v3 of this patch with this fix locally and resend after
other comments.

> a551138c4b3b9f Dominique Martinet 2023-05-10  1853  		if (ctx->flags & DIR_CONTEXT_F_NOWAIT) {
> a551138c4b3b9f Dominique Martinet 2023-05-10  1854  			if (!down_read_trylock(&root->kernfs_rwsem))
> a551138c4b3b9f Dominique Martinet 2023-05-10  1855  				return 0;
> 
> It's a bit strange the this doesn't return -EAGAIN;

That is on purpose: the getdents did work (dir_emit returned success at
least once), so the caller can process whatever was filled in the buffer
before calling iterate_shared() again.

If we were to return -EAGAIN here, we'd actually be throwing out the
entries we just filled in, and that's not what we want.
diff mbox series

Patch

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 45b6919903e6..5a5b3e7881bf 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -1824,7 +1824,12 @@  static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
 		return 0;
 
 	root = kernfs_root(parent);
-	down_read(&root->kernfs_rwsem);
+	if (ctx->flags & DIR_CONTEXT_F_NOWAIT) {
+		if (!down_read_trylock(&root->kernfs_rwsem))
+			return -EAGAIN;
+	} else {
+		down_read(&root->kernfs_rwsem);
+	}
 
 	if (kernfs_ns_enabled(parent))
 		ns = kernfs_info(dentry->d_sb)->ns;
@@ -1845,6 +1850,12 @@  static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
 		if (!dir_emit(ctx, name, len, ino, type))
 			return 0;
 		down_read(&root->kernfs_rwsem);
+		if (ctx->flags & DIR_CONTEXT_F_NOWAIT) {
+			if (!down_read_trylock(&root->kernfs_rwsem))
+				return 0;
+		} else {
+			down_read(&root->kernfs_rwsem);
+		}
 	}
 	up_read(&root->kernfs_rwsem);
 	file->private_data = NULL;
@@ -1852,7 +1863,14 @@  static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
 	return 0;
 }
 
+static int kernfs_fop_dir_open(struct inode *inode, struct file *file)
+{
+	file->f_mode |= FMODE_NOWAIT;
+	return 0;
+}
+
 const struct file_operations kernfs_dir_fops = {
+	.open		= kernfs_fop_dir_open,
 	.read		= generic_read_dir,
 	.iterate_shared	= kernfs_fop_readdir,
 	.release	= kernfs_dir_fop_release,