diff options
author | David Howells <dhowells@redhat.com> | 2019-05-14 07:33:10 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-05-16 17:23:21 -0400 |
commit | 39db9815da489b47b50b8e6e4fc7566a77bd18bf (patch) | |
tree | fbdb5d1e2e32e4a3ec9c695f000d295b36138c2e | |
parent | b8359153252d4465cb74f8de6c50e8c6295cbe2e (diff) |
afs: Fix application of the results of a inline bulk status fetch
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>
-rw-r--r-- | fs/afs/afs.h | 1 | ||||
-rw-r--r-- | fs/afs/dir.c | 51 |
2 files changed, 45 insertions, 7 deletions
diff --git a/fs/afs/afs.h b/fs/afs/afs.h index a7d3f902a91c..3f4e460c6655 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h | |||
@@ -150,6 +150,7 @@ struct afs_file_status { | |||
150 | struct afs_status_cb { | 150 | struct afs_status_cb { |
151 | struct afs_file_status status; | 151 | struct afs_file_status status; |
152 | struct afs_callback callback; | 152 | struct afs_callback callback; |
153 | unsigned int cb_break; /* Pre-op callback break counter */ | ||
153 | bool have_status; /* True if status record was retrieved */ | 154 | bool have_status; /* True if status record was retrieved */ |
154 | bool have_cb; /* True if cb record was retrieved */ | 155 | bool have_cb; /* True if cb record was retrieved */ |
155 | bool have_error; /* True if status.abort_code indicates an error */ | 156 | bool have_error; /* True if status.abort_code indicates an error */ |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 9e42f6c75747..79d93a26759a 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -103,6 +103,7 @@ struct afs_lookup_cookie { | |||
103 | bool found; | 103 | bool found; |
104 | bool one_only; | 104 | bool one_only; |
105 | unsigned short nr_fids; | 105 | unsigned short nr_fids; |
106 | struct inode **inodes; | ||
106 | struct afs_status_cb *statuses; | 107 | struct afs_status_cb *statuses; |
107 | struct afs_fid fids[50]; | 108 | struct afs_fid fids[50]; |
108 | }; | 109 | }; |
@@ -644,8 +645,8 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
644 | struct afs_iget_data iget_data; | 645 | struct afs_iget_data iget_data; |
645 | struct afs_fs_cursor fc; | 646 | struct afs_fs_cursor fc; |
646 | struct afs_server *server; | 647 | struct afs_server *server; |
647 | struct afs_vnode *dvnode = AFS_FS_I(dir); | 648 | struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; |
648 | struct inode *inode = NULL; | 649 | struct inode *inode = NULL, *ti; |
649 | int ret, i; | 650 | int ret, i; |
650 | 651 | ||
651 | _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); | 652 | _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, | |||
700 | if (!cookie->statuses) | 701 | if (!cookie->statuses) |
701 | goto out; | 702 | goto out; |
702 | 703 | ||
704 | cookie->inodes = kcalloc(cookie->nr_fids, sizeof(struct inode *), | ||
705 | GFP_KERNEL); | ||
706 | if (!cookie->inodes) | ||
707 | goto out_s; | ||
708 | |||
709 | for (i = 1; i < cookie->nr_fids; i++) { | ||
710 | scb = &cookie->statuses[i]; | ||
711 | |||
712 | /* Find any inodes that already exist and get their | ||
713 | * callback counters. | ||
714 | */ | ||
715 | iget_data.fid = cookie->fids[i]; | ||
716 | ti = ilookup5_nowait(dir->i_sb, iget_data.fid.vnode, | ||
717 | afs_iget5_test, &iget_data); | ||
718 | if (!IS_ERR_OR_NULL(ti)) { | ||
719 | vnode = AFS_FS_I(ti); | ||
720 | scb->cb_break = afs_calc_vnode_cb_break(vnode); | ||
721 | cookie->inodes[i] = ti; | ||
722 | } | ||
723 | } | ||
724 | |||
703 | /* Try FS.InlineBulkStatus first. Abort codes for the individual | 725 | /* Try FS.InlineBulkStatus first. Abort codes for the individual |
704 | * lookups contained therein are stored in the reply without aborting | 726 | * lookups contained therein are stored in the reply without aborting |
705 | * the whole operation. | 727 | * the whole operation. |
@@ -742,7 +764,6 @@ no_inline_bulk_status: | |||
742 | * any of the lookups fails - so, for the moment, revert to | 764 | * any of the lookups fails - so, for the moment, revert to |
743 | * FS.FetchStatus for just the primary fid. | 765 | * FS.FetchStatus for just the primary fid. |
744 | */ | 766 | */ |
745 | cookie->nr_fids = 1; | ||
746 | inode = ERR_PTR(-ERESTARTSYS); | 767 | inode = ERR_PTR(-ERESTARTSYS); |
747 | if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { | 768 | if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { |
748 | while (afs_select_fileserver(&fc)) { | 769 | while (afs_select_fileserver(&fc)) { |
@@ -764,9 +785,6 @@ no_inline_bulk_status: | |||
764 | if (IS_ERR(inode)) | 785 | if (IS_ERR(inode)) |
765 | goto out_c; | 786 | goto out_c; |
766 | 787 | ||
767 | for (i = 0; i < cookie->nr_fids; i++) | ||
768 | cookie->statuses[i].status.abort_code = 0; | ||
769 | |||
770 | success: | 788 | success: |
771 | /* Turn all the files into inodes and save the first one - which is the | 789 | /* Turn all the files into inodes and save the first one - which is the |
772 | * one we actually want. | 790 | * one we actually want. |
@@ -777,13 +795,26 @@ success: | |||
777 | 795 | ||
778 | for (i = 0; i < cookie->nr_fids; i++) { | 796 | for (i = 0; i < cookie->nr_fids; i++) { |
779 | struct afs_status_cb *scb = &cookie->statuses[i]; | 797 | struct afs_status_cb *scb = &cookie->statuses[i]; |
780 | struct inode *ti; | 798 | |
799 | if (!scb->have_status && !scb->have_error) | ||
800 | continue; | ||
801 | |||
802 | if (cookie->inodes[i]) { | ||
803 | afs_vnode_commit_status(&fc, AFS_FS_I(cookie->inodes[i]), | ||
804 | scb->cb_break, NULL, scb); | ||
805 | continue; | ||
806 | } | ||
781 | 807 | ||
782 | if (scb->status.abort_code != 0) | 808 | if (scb->status.abort_code != 0) |
783 | continue; | 809 | continue; |
784 | 810 | ||
785 | iget_data.fid = cookie->fids[i]; | 811 | iget_data.fid = cookie->fids[i]; |
786 | ti = afs_iget(dir->i_sb, key, &iget_data, scb, cbi, dvnode); | 812 | ti = afs_iget(dir->i_sb, key, &iget_data, scb, cbi, dvnode); |
813 | if (!IS_ERR(ti)) | ||
814 | afs_cache_permit(AFS_FS_I(ti), key, | ||
815 | 0 /* Assume vnode->cb_break is 0 */ + | ||
816 | iget_data.cb_v_break, | ||
817 | scb); | ||
787 | if (i == 0) { | 818 | if (i == 0) { |
788 | inode = ti; | 819 | inode = ti; |
789 | } else { | 820 | } else { |
@@ -794,6 +825,12 @@ success: | |||
794 | 825 | ||
795 | out_c: | 826 | out_c: |
796 | afs_put_cb_interest(afs_v2net(dvnode), cbi); | 827 | afs_put_cb_interest(afs_v2net(dvnode), cbi); |
828 | if (cookie->inodes) { | ||
829 | for (i = 0; i < cookie->nr_fids; i++) | ||
830 | iput(cookie->inodes[i]); | ||
831 | kfree(cookie->inodes); | ||
832 | } | ||
833 | out_s: | ||
797 | kvfree(cookie->statuses); | 834 | kvfree(cookie->statuses); |
798 | out: | 835 | out: |
799 | kfree(cookie); | 836 | kfree(cookie); |