fuse: Increase FUSE_NAME_MAX to PATH_MAX
authorBernd Schubert <bschubert@ddn.com>
Mon, 16 Dec 2024 21:14:07 +0000 (22:14 +0100)
committerMiklos Szeredi <mszeredi@redhat.com>
Mon, 31 Mar 2025 12:59:27 +0000 (14:59 +0200)
Our file system has a translation capability for S3-to-posix.
The current value of 1kiB is enough to cover S3 keys, but
does not allow encoding of %xx escape characters.
The limit is increased to (PATH_MAX - 1), as we need
3 x 1024 and that is close to PATH_MAX (4kB) already.
-1 is used as the terminating null is not included in the
length calculation.

Testing large file names was hard with libfuse/example file systems,
so I created a new memfs that does not have a 255 file name length
limitation.
https://github.com/libfuse/libfuse/pull/1077

The connection is initialized with FUSE_NAME_LOW_MAX, which
is set to the previous value of FUSE_NAME_MAX of 1024. With
FUSE_MIN_READ_BUFFER of 8192 that is enough for two file names
+ fuse headers.
When FUSE_INIT reply sets max_pages to a value > 1 we know
that fuse daemon supports request buffers of at least 2 pages
(+ header) and can therefore hold 2 x PATH_MAX file names - operations
like rename or link that need two file names are no issue then.

Signed-off-by: Bernd Schubert <bschubert@ddn.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/fuse_i.h
fs/fuse/inode.c

index 45d15db3878772ba8a2fb80e6ed594e512378921..696ab0403120caa6c265a57fd6c52dddde166629 100644 (file)
@@ -1657,7 +1657,7 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
                goto err;
 
        err = -ENAMETOOLONG;
-       if (outarg.namelen > FUSE_NAME_MAX)
+       if (outarg.namelen > fc->name_max)
                goto err;
 
        err = -EINVAL;
@@ -1706,7 +1706,7 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
                goto err;
 
        err = -ENAMETOOLONG;
-       if (outarg.namelen > FUSE_NAME_MAX)
+       if (outarg.namelen > fc->name_max)
                goto err;
 
        err = -EINVAL;
index 83c56ce6ad206a9e9af9033bfd028114cb2d1737..493c5b096b4aebb75119e799e5acc3a2f7704658 100644 (file)
@@ -370,7 +370,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
 
        *inode = NULL;
        err = -ENAMETOOLONG;
-       if (name->len > FUSE_NAME_MAX)
+       if (name->len > fm->fc->name_max)
                goto out;
 
 
index 0bd1deabb289e5d3f7eb85a2d37fb60c4cc83c18..d56d4fd956db99ecd93052a9655428664882cb72 100644 (file)
 /** Bias for fi->writectr, meaning new writepages must not be sent */
 #define FUSE_NOWRITE INT_MIN
 
-/** It could be as large as PATH_MAX, but would that have any uses? */
-#define FUSE_NAME_MAX 1024
+/** Maximum length of a filename, not including terminating null */
+
+/* maximum, small enough for FUSE_MIN_READ_BUFFER*/
+#define FUSE_NAME_LOW_MAX 1024
+/* maximum, but needs a request buffer > FUSE_MIN_READ_BUFFER */
+#define FUSE_NAME_MAX (PATH_MAX - 1)
 
 /** Number of dentries for each connection in the control filesystem */
 #define FUSE_CTL_NUM_DENTRIES 5
@@ -924,6 +928,9 @@ struct fuse_conn {
        /** Version counter for evict inode */
        atomic64_t evict_ctr;
 
+       /* maximum file name length */
+       u32 name_max;
+
        /** Called on final put */
        void (*release)(struct fuse_conn *);
 
index 6e2b89fbcbb5a01c5b916acf4e4c7d1d7b8a55b1..fd48e8d37f2edc4b67c61e2551462650918b29a6 100644 (file)
@@ -982,6 +982,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
        fc->user_ns = get_user_ns(user_ns);
        fc->max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ;
        fc->max_pages_limit = fuse_max_pages_limit;
+       fc->name_max = FUSE_NAME_LOW_MAX;
        fc->timeout.req_timeout = 0;
 
        if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
@@ -1373,6 +1374,13 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
                                fc->max_pages =
                                        min_t(unsigned int, fc->max_pages_limit,
                                        max_t(unsigned int, arg->max_pages, 1));
+
+                               /*
+                                * PATH_MAX file names might need two pages for
+                                * ops like rename
+                                */
+                               if (fc->max_pages > 1)
+                                       fc->name_max = FUSE_NAME_MAX;
                        }
                        if (IS_ENABLED(CONFIG_FUSE_DAX)) {
                                if (flags & FUSE_MAP_ALIGNMENT &&