]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
afs: Fix application of the results of a inline bulk status fetch
authorDavid Howells <dhowells@redhat.com>
Tue, 14 May 2019 11:33:10 +0000 (12:33 +0100)
committerDavid Howells <dhowells@redhat.com>
Thu, 16 May 2019 21:23:21 +0000 (22:23 +0100)
Fix afs_do_lookup() such that when it does an inline bulk status fetch op,
it will update inodes that are already extant (something that afs_iget()
doesn't do) and to cache permits for each inode created (thereby avoiding a
follow up FS.FetchStatus call to determine this).

Extant inodes need looking up in advance so that their cb_break counters
before and after the operation can be compared.  To this end, the inode
pointers are cached so that they don't need looking up again after the op.

Fixes: 5cf9dd55a0ec ("afs: Prospectively look up extra files when doing a single lookup")
Signed-off-by: David Howells <dhowells@redhat.com>
fs/afs/afs.h
fs/afs/dir.c

index a7d3f902a91cc2bbf2bfbf6426c6cfcc8f65971b..3f4e460c6655ab3e259d7e17e6b6bbe8dfdb0036 100644 (file)
@@ -150,6 +150,7 @@ struct afs_file_status {
 struct afs_status_cb {
        struct afs_file_status  status;
        struct afs_callback     callback;
+       unsigned int            cb_break;       /* Pre-op callback break counter */
        bool                    have_status;    /* True if status record was retrieved */
        bool                    have_cb;        /* True if cb record was retrieved */
        bool                    have_error;     /* True if status.abort_code indicates an error */
index 9e42f6c75747047ab6368f4704371eca44fa4695..79d93a26759ae7cc0dcf633a79f85efd5a2c7711 100644 (file)
@@ -103,6 +103,7 @@ struct afs_lookup_cookie {
        bool                    found;
        bool                    one_only;
        unsigned short          nr_fids;
+       struct inode            **inodes;
        struct afs_status_cb    *statuses;
        struct afs_fid          fids[50];
 };
@@ -644,8 +645,8 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
        struct afs_iget_data iget_data;
        struct afs_fs_cursor fc;
        struct afs_server *server;
-       struct afs_vnode *dvnode = AFS_FS_I(dir);
-       struct inode *inode = NULL;
+       struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode;
+       struct inode *inode = NULL, *ti;
        int ret, i;
 
        _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
@@ -700,6 +701,27 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
        if (!cookie->statuses)
                goto out;
 
+       cookie->inodes = kcalloc(cookie->nr_fids, sizeof(struct inode *),
+                                GFP_KERNEL);
+       if (!cookie->inodes)
+               goto out_s;
+
+       for (i = 1; i < cookie->nr_fids; i++) {
+               scb = &cookie->statuses[i];
+
+               /* Find any inodes that already exist and get their
+                * callback counters.
+                */
+               iget_data.fid = cookie->fids[i];
+               ti = ilookup5_nowait(dir->i_sb, iget_data.fid.vnode,
+                                    afs_iget5_test, &iget_data);
+               if (!IS_ERR_OR_NULL(ti)) {
+                       vnode = AFS_FS_I(ti);
+                       scb->cb_break = afs_calc_vnode_cb_break(vnode);
+                       cookie->inodes[i] = ti;
+               }
+       }
+
        /* Try FS.InlineBulkStatus first.  Abort codes for the individual
         * lookups contained therein are stored in the reply without aborting
         * the whole operation.
@@ -742,7 +764,6 @@ no_inline_bulk_status:
         * any of the lookups fails - so, for the moment, revert to
         * FS.FetchStatus for just the primary fid.
         */
-       cookie->nr_fids = 1;
        inode = ERR_PTR(-ERESTARTSYS);
        if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
                while (afs_select_fileserver(&fc)) {
@@ -764,9 +785,6 @@ no_inline_bulk_status:
        if (IS_ERR(inode))
                goto out_c;
 
-       for (i = 0; i < cookie->nr_fids; i++)
-               cookie->statuses[i].status.abort_code = 0;
-
 success:
        /* Turn all the files into inodes and save the first one - which is the
         * one we actually want.
@@ -777,13 +795,26 @@ success:
 
        for (i = 0; i < cookie->nr_fids; i++) {
                struct afs_status_cb *scb = &cookie->statuses[i];
-               struct inode *ti;
+
+               if (!scb->have_status && !scb->have_error)
+                       continue;
+
+               if (cookie->inodes[i]) {
+                       afs_vnode_commit_status(&fc, AFS_FS_I(cookie->inodes[i]),
+                                               scb->cb_break, NULL, scb);
+                       continue;
+               }
 
                if (scb->status.abort_code != 0)
                        continue;
 
                iget_data.fid = cookie->fids[i];
                ti = afs_iget(dir->i_sb, key, &iget_data, scb, cbi, dvnode);
+               if (!IS_ERR(ti))
+                       afs_cache_permit(AFS_FS_I(ti), key,
+                                        0 /* Assume vnode->cb_break is 0 */ +
+                                        iget_data.cb_v_break,
+                                        scb);
                if (i == 0) {
                        inode = ti;
                } else {
@@ -794,6 +825,12 @@ success:
 
 out_c:
        afs_put_cb_interest(afs_v2net(dvnode), cbi);
+       if (cookie->inodes) {
+               for (i = 0; i < cookie->nr_fids; i++)
+                       iput(cookie->inodes[i]);
+               kfree(cookie->inodes);
+       }
+out_s:
        kvfree(cookie->statuses);
 out:
        kfree(cookie);