]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
afs: Locally initialise the contents of a new symlink on creation
authorDavid Howells <dhowells@redhat.com>
Mon, 16 Dec 2024 20:41:20 +0000 (20:41 +0000)
committerChristian Brauner <brauner@kernel.org>
Fri, 20 Dec 2024 21:34:09 +0000 (22:34 +0100)
Since we know what the contents of a symlink will be when we create it on
the server, initialise its contents locally too to avoid the need to
download it.

Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20241216204124.3752367-31-dhowells@redhat.com
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/afs/dir.c
fs/afs/inode.c
fs/afs/internal.h
fs/netfs/buffered_read.c
fs/netfs/read_single.c

index dd0c98d25270fff76eaa5d61ba478d1a14228cef..a843c36fc471268502ee68688c555fcee5e7bd30 100644 (file)
@@ -1276,6 +1276,8 @@ static void afs_vnode_new_inode(struct afs_operation *op)
        set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
        if (S_ISDIR(inode->i_mode))
                afs_mkdir_init_dir(vnode, dvp->vnode);
+       else if (S_ISLNK(inode->i_mode))
+               afs_init_new_symlink(vnode, op);
        if (!afs_op_error(op))
                afs_cache_permit(vnode, op->key, vnode->cb_break, &vp->scb);
        d_instantiate(op->dentry, inode);
index 0e3c43c40632a28bfb955c782d7e04bc9575cfde..e9538e91f8484d943d70671fb374d34a2dc8f3e5 100644 (file)
 #include "internal.h"
 #include "afs_fs.h"
 
+void afs_init_new_symlink(struct afs_vnode *vnode, struct afs_operation *op)
+{
+       size_t size = strlen(op->create.symlink) + 1;
+       size_t dsize = 0;
+       char *p;
+
+       if (netfs_alloc_folioq_buffer(NULL, &vnode->directory, &dsize, size,
+                                     mapping_gfp_mask(vnode->netfs.inode.i_mapping)) < 0)
+               return;
+
+       vnode->directory_size = dsize;
+       p = kmap_local_folio(folioq_folio(vnode->directory, 0), 0);
+       memcpy(p, op->create.symlink, size);
+       kunmap_local(p);
+       set_bit(AFS_VNODE_DIR_READ, &vnode->flags);
+       netfs_single_mark_inode_dirty(&vnode->netfs.inode);
+}
+
 static void afs_put_link(void *arg)
 {
        struct folio *folio = virt_to_folio(arg);
@@ -41,15 +59,31 @@ const char *afs_get_link(struct dentry *dentry, struct inode *inode,
        char *content;
        ssize_t ret;
 
-       if (atomic64_read(&vnode->cb_expires_at) == AFS_NO_CB_PROMISE ||
-           !test_bit(AFS_VNODE_DIR_READ, &vnode->flags)) {
-               if (!dentry)
+       if (!dentry) {
+               /* RCU pathwalk. */
+               if (!test_bit(AFS_VNODE_DIR_READ, &vnode->flags) || !afs_check_validity(vnode))
                        return ERR_PTR(-ECHILD);
-               ret = afs_read_single(vnode, NULL);
-               if (ret < 0)
-                       return ERR_PTR(ret);
+               goto good;
        }
 
+       if (test_bit(AFS_VNODE_DIR_READ, &vnode->flags))
+               goto fetch;
+
+       ret = afs_validate(vnode, NULL);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       if (!test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) &&
+           test_bit(AFS_VNODE_DIR_READ, &vnode->flags))
+               goto good;
+
+fetch:
+       ret = afs_read_single(vnode, NULL);
+       if (ret < 0)
+               return ERR_PTR(ret);
+       set_bit(AFS_VNODE_DIR_READ, &vnode->flags);
+
+good:
        folio = folioq_folio(vnode->directory, 0);
        folio_get(folio);
        content = kmap_local_folio(folio, 0);
index b7d02c1053408895eef0ca98bb23a0f179242232..90f407774a9a17b490489a1657871dbc9ecf1f9c 100644 (file)
@@ -1221,6 +1221,7 @@ extern void afs_fs_probe_cleanup(struct afs_net *);
  */
 extern const struct afs_operation_ops afs_fetch_status_operation;
 
+void afs_init_new_symlink(struct afs_vnode *vnode, struct afs_operation *op);
 const char *afs_get_link(struct dentry *dentry, struct inode *inode,
                         struct delayed_call *callback);
 int afs_readlink(struct dentry *dentry, char __user *buffer, int buflen);
index 0245943d974dec138170aedd56316c9777523e9f..f761d44b34362ceaaf4acec23feeb8a7ad26efe3 100644 (file)
@@ -210,7 +210,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq)
 
        do {
                struct netfs_io_subrequest *subreq;
-               enum netfs_io_source source = NETFS_DOWNLOAD_FROM_SERVER;
+               enum netfs_io_source source = NETFS_SOURCE_UNKNOWN;
                ssize_t slice;
 
                subreq = netfs_alloc_subrequest(rreq);
index 14bc611071821814b37a361722e6ab41efceaef9..fea0ecdecc539746fc9eb8fa1ebf400313e35df3 100644 (file)
@@ -97,7 +97,7 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq)
        if (!subreq)
                return -ENOMEM;
 
-       subreq->source  = NETFS_DOWNLOAD_FROM_SERVER;
+       subreq->source  = NETFS_SOURCE_UNKNOWN;
        subreq->start   = 0;
        subreq->len     = rreq->len;
        subreq->io_iter = rreq->buffer.iter;