[PATCH] fuse: Expose read from directory to userspace

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH] fuse: Expose read from directory to userspace

Emily Maier
The VFS permits filesystems to implement read(2) on directories, but
FUSE unconditionally returns -EISDIR for it. Expose this to userspace as
FUSE_DIR_READ and continue returning the old behavior if the filesystem
doesn't implement it.

Signed-off-by: Emily Maier <[hidden email]>
---
 fs/fuse/dir.c             | 51 ++++++++++++++++++++++++++++++++++++++++++++++-
 fs/fuse/fuse_i.h          |  6 ++++++
 include/uapi/linux/fuse.h | 18 ++++++++++++++++-
 3 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 4b855b6..dbae010 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1870,6 +1870,55 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
  return err;
 }
 
+static ssize_t fuse_dir_read(struct file *file, char __user *buf, size_t size,
+ loff_t *ppos)
+{
+ struct inode *inode = file_inode(file);
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_dir_read_in inarg;
+ ssize_t ret;
+ struct fuse_file *ff = file->private_data;
+ char *kbuf;
+ FUSE_ARGS(args);
+
+ if (fc->no_dir_read || fc->minor < 25)
+ return -EISDIR;
+
+ if (size > FUSE_DIR_READ_MAX)
+ size = FUSE_DIR_READ_MAX;
+ kbuf = kmalloc(size, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ memset(&inarg, 0, sizeof(inarg));
+ inarg.size = size;
+ inarg.off = *ppos;
+ inarg.fh = ff->fh;
+ args.in.h.opcode = FUSE_DIR_READ;
+ args.in.h.nodeid = get_node_id(inode);
+ args.in.numargs = 1;
+ args.in.args[0].size = sizeof(inarg);
+ args.in.args[0].value = &inarg;
+ args.out.numargs = 1;
+ args.out.argvar = 1;
+ args.out.args[0].size = size;
+ args.out.args[0].value = kbuf;
+ ret = fuse_simple_request(fc, &args);
+ if (ret == -ENOSYS) {
+ fc->no_dir_read = 1;
+ ret = -EISDIR;
+ }
+ if (ret > 0) {
+ if (copy_to_user(buf, kbuf, ret))
+ ret = -EFAULT;
+ else
+ *ppos += ret;
+ }
+ fuse_invalidate_atime(inode);
+ kfree(kbuf);
+ return ret;
+}
+
 static const struct inode_operations fuse_dir_inode_operations = {
  .lookup = fuse_lookup,
  .mkdir = fuse_mkdir,
@@ -1892,7 +1941,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
 
 static const struct file_operations fuse_dir_operations = {
  .llseek = generic_file_llseek,
- .read = generic_read_dir,
+ .read = fuse_dir_read,
  .iterate = fuse_readdir,
  .open = fuse_dir_open,
  .release = fuse_dir_release,
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index eddbe02..a953910 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -48,6 +48,9 @@
 /** Number of page pointers embedded in fuse_req */
 #define FUSE_REQ_INLINE_PAGES 1
 
+/** Maximum length of a read from a directory */
+#define FUSE_DIR_READ_MAX 4096
+
 /** List of active connections */
 extern struct list_head fuse_conn_list;
 
@@ -658,6 +661,9 @@ struct fuse_conn {
 
  /** List of device instances belonging to this connection */
  struct list_head devices;
+
+ /** Is dir_read not implemented by fs? */
+ unsigned no_dir_read:1;
 };
 
 static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 5974fae..50f5fa5 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -105,6 +105,9 @@
  *
  *  7.24
  *  - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
+ *
+ *  7.25
+ *  - add FUSE_DIR_READ
  */
 
 #ifndef _LINUX_FUSE_H
@@ -140,7 +143,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 24
+#define FUSE_KERNEL_MINOR_VERSION 25
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -362,6 +365,7 @@ enum fuse_opcode {
  FUSE_READDIRPLUS   = 44,
  FUSE_RENAME2       = 45,
  FUSE_LSEEK         = 46,
+ FUSE_DIR_READ      = 47,
 
  /* CUSE specific operations */
  CUSE_INIT          = 4096,
@@ -773,4 +777,16 @@ struct fuse_lseek_out {
  uint64_t offset;
 };
 
+struct fuse_dir_read_in {
+ uint32_t size;
+ uint32_t padding;
+ int64_t off;
+ uint64_t fh;
+};
+
+struct fuse_dir_read_out {
+ uint32_t size;
+ uint32_t padding;
+};
+
 #endif /* _LINUX_FUSE_H */
--
2.5.5


------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] fuse: Expose read from directory to userspace

Nikolaus Rath
On Apr 16 2016, Emily Maier <[hidden email]> wrote:
> The VFS permits filesystems to implement read(2) on directories, but
> FUSE unconditionally returns -EISDIR for it. Expose this to userspace as
> FUSE_DIR_READ and continue returning the old behavior if the filesystem
> doesn't implement it.

Why a new operation, instead of calling FUSE_READ?


Btw, to get this into the kernel you need to send your patch to some
kernel maintainer. At the moment, the typical recipients for such
patches are linux-kernel, linux-fsdevel and Miklos Szeredi.


Best,
-Nikolaus

--
GPG encrypted emails preferred. Key id: 0xD113FCAC3C4E599F
Fingerprint: ED31 791B 2C5C 1613 AF38 8B8A D113 FCAC 3C4E 599F

             »Time flies like an arrow, fruit flies like a Banana.«

------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] fuse: Expose read from directory to userspace

Emily Maier
On Mon, Apr 18, 2016 at 09:42:03AM -0700, Nikolaus Rath wrote:

> On Apr 16 2016, Emily Maier <[hidden email]> wrote:
> > The VFS permits filesystems to implement read(2) on directories, but
> > FUSE unconditionally returns -EISDIR for it. Expose this to userspace as
> > FUSE_DIR_READ and continue returning the old behavior if the filesystem
> > doesn't implement it.
>
> Why a new operation, instead of calling FUSE_READ?
>
>
> Btw, to get this into the kernel you need to send your patch to some
> kernel maintainer. At the moment, the typical recipients for such
> patches are linux-kernel, linux-fsdevel and Miklos Szeredi.
>
>
> Best,
> -Nikolaus
>
> --
> GPG encrypted emails preferred. Key id: 0xD113FCAC3C4E599F
> Fingerprint: ED31 791B 2C5C 1613 AF38 8B8A D113 FCAC 3C4E 599F
>
>              »Time flies like an arrow, fruit flies like a Banana.«
>
> ------------------------------------------------------------------------------
> Find and fix application performance issues faster with Applications Manager
> Applications Manager provides deep performance insights into multiple tiers of
> your business applications. It resolves application problems quickly and
> reduces your MTTR. Get your free trial!
> https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
> --
> fuse-devel mailing list
> To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel

There are a couple reasons. One is that right now read-on-directory
doesn't get sent to FUSE_READ, so after the change any FS that doesn't
do its own isdir check might break. libfuse could do its own check and
separate them again, but I don't see the value in that when the VFS
already separates file and directory reads for us.

The other is that conceptually I don't see it as a standard read call.  
The only in-tree filesystem that permits a read-on-directory (Ceph) uses
it to print metadata about the directory, and so does the FS I'm messing
with that inspired this patch.

Emily Maier

------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel