summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-05-09 11:17:05 -0400
committerDavid Howells <dhowells@redhat.com>2019-05-16 11:25:21 -0400
commit87182759cd6f94875d6aaaac74eaa52aa6aa6f98 (patch)
tree3a143ae4a411fd26b1d98bffff3f66770e027901
parentffba718e935402e7f42b8cd5d1e00e4a3907d361 (diff)
afs: Fix order-1 allocation in afs_do_lookup()
afs_do_lookup() will do an order-1 allocation to allocate status records if there are more than 39 vnodes to stat. Fix this by allocating an array of {status,callback} records for each vnode we want to examine using vmalloc() if larger than a page. This not only gets rid of the order-1 allocation, but makes it easier to grow beyond 50 records for YFS servers. It also allows us to move to {status,callback} tuples for other calls too and makes it easier to lock across the application of the status and the callback to the vnode. 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.h6
-rw-r--r--fs/afs/dir.c37
-rw-r--r--fs/afs/fsclient.c21
-rw-r--r--fs/afs/internal.h11
-rw-r--r--fs/afs/yfsclient.c20
5 files changed, 45 insertions, 50 deletions
diff --git a/fs/afs/afs.h b/fs/afs/afs.h
index 74913c707bba..8fa0dffff1cc 100644
--- a/fs/afs/afs.h
+++ b/fs/afs/afs.h
@@ -147,6 +147,12 @@ struct afs_file_status {
147 u32 abort_code; /* Abort if bulk-fetching this failed */ 147 u32 abort_code; /* Abort if bulk-fetching this failed */
148}; 148};
149 149
150struct afs_status_cb {
151 struct afs_file_status status;
152 struct afs_callback callback;
153 bool have_cb; /* True if cb record was retrieved */
154};
155
150/* 156/*
151 * AFS file status change request 157 * AFS file status change request
152 */ 158 */
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index c15550310f62..0f14bcfe233d 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -102,8 +102,7 @@ struct afs_lookup_cookie {
102 bool found; 102 bool found;
103 bool one_only; 103 bool one_only;
104 unsigned short nr_fids; 104 unsigned short nr_fids;
105 struct afs_file_status *statuses; 105 struct afs_status_cb *statuses;
106 struct afs_callback *callbacks;
107 struct afs_fid fids[50]; 106 struct afs_fid fids[50];
108}; 107};
109 108
@@ -640,6 +639,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
640 struct afs_lookup_cookie *cookie; 639 struct afs_lookup_cookie *cookie;
641 struct afs_cb_interest *cbi = NULL; 640 struct afs_cb_interest *cbi = NULL;
642 struct afs_super_info *as = dir->i_sb->s_fs_info; 641 struct afs_super_info *as = dir->i_sb->s_fs_info;
642 struct afs_status_cb *scb;
643 struct afs_iget_data data; 643 struct afs_iget_data data;
644 struct afs_fs_cursor fc; 644 struct afs_fs_cursor fc;
645 struct afs_vnode *dvnode = AFS_FS_I(dir); 645 struct afs_vnode *dvnode = AFS_FS_I(dir);
@@ -686,16 +686,11 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
686 686
687 /* Need space for examining all the selected files */ 687 /* Need space for examining all the selected files */
688 inode = ERR_PTR(-ENOMEM); 688 inode = ERR_PTR(-ENOMEM);
689 cookie->statuses = kcalloc(cookie->nr_fids, sizeof(struct afs_file_status), 689 cookie->statuses = kvcalloc(cookie->nr_fids, sizeof(struct afs_status_cb),
690 GFP_KERNEL); 690 GFP_KERNEL);
691 if (!cookie->statuses) 691 if (!cookie->statuses)
692 goto out; 692 goto out;
693 693
694 cookie->callbacks = kcalloc(cookie->nr_fids, sizeof(struct afs_callback),
695 GFP_KERNEL);
696 if (!cookie->callbacks)
697 goto out_s;
698
699 /* Try FS.InlineBulkStatus first. Abort codes for the individual 694 /* Try FS.InlineBulkStatus first. Abort codes for the individual
700 * lookups contained therein are stored in the reply without aborting 695 * lookups contained therein are stored in the reply without aborting
701 * the whole operation. 696 * the whole operation.
@@ -716,7 +711,6 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
716 afs_v2net(dvnode), 711 afs_v2net(dvnode),
717 cookie->fids, 712 cookie->fids,
718 cookie->statuses, 713 cookie->statuses,
719 cookie->callbacks,
720 cookie->nr_fids, NULL); 714 cookie->nr_fids, NULL);
721 } 715 }
722 716
@@ -741,11 +735,12 @@ no_inline_bulk_status:
741 inode = ERR_PTR(-ERESTARTSYS); 735 inode = ERR_PTR(-ERESTARTSYS);
742 if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { 736 if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
743 while (afs_select_fileserver(&fc)) { 737 while (afs_select_fileserver(&fc)) {
738 scb = &cookie->statuses[0];
744 afs_fs_fetch_status(&fc, 739 afs_fs_fetch_status(&fc,
745 afs_v2net(dvnode), 740 afs_v2net(dvnode),
746 cookie->fids, 741 cookie->fids,
747 cookie->statuses, 742 &scb->status,
748 cookie->callbacks, 743 &scb->callback,
749 NULL); 744 NULL);
750 } 745 }
751 746
@@ -758,24 +753,26 @@ no_inline_bulk_status:
758 goto out_c; 753 goto out_c;
759 754
760 for (i = 0; i < cookie->nr_fids; i++) 755 for (i = 0; i < cookie->nr_fids; i++)
761 cookie->statuses[i].abort_code = 0; 756 cookie->statuses[i].status.abort_code = 0;
762 757
763success: 758success:
764 /* Turn all the files into inodes and save the first one - which is the 759 /* Turn all the files into inodes and save the first one - which is the
765 * one we actually want. 760 * one we actually want.
766 */ 761 */
767 if (cookie->statuses[0].abort_code != 0) 762 scb = &cookie->statuses[0];
768 inode = ERR_PTR(afs_abort_to_error(cookie->statuses[0].abort_code)); 763 if (scb->status.abort_code != 0)
764 inode = ERR_PTR(afs_abort_to_error(scb->status.abort_code));
769 765
770 for (i = 0; i < cookie->nr_fids; i++) { 766 for (i = 0; i < cookie->nr_fids; i++) {
767 struct afs_status_cb *scb = &cookie->statuses[i];
771 struct inode *ti; 768 struct inode *ti;
772 769
773 if (cookie->statuses[i].abort_code != 0) 770 if (scb->status.abort_code != 0)
774 continue; 771 continue;
775 772
776 ti = afs_iget(dir->i_sb, key, &cookie->fids[i], 773 ti = afs_iget(dir->i_sb, key, &cookie->fids[i],
777 &cookie->statuses[i], 774 &scb->status,
778 &cookie->callbacks[i], 775 &scb->callback,
779 cbi, dvnode); 776 cbi, dvnode);
780 if (i == 0) { 777 if (i == 0) {
781 inode = ti; 778 inode = ti;
@@ -787,9 +784,7 @@ success:
787 784
788out_c: 785out_c:
789 afs_put_cb_interest(afs_v2net(dvnode), cbi); 786 afs_put_cb_interest(afs_v2net(dvnode), cbi);
790 kfree(cookie->callbacks); 787 kvfree(cookie->statuses);
791out_s:
792 kfree(cookie->statuses);
793out: 788out:
794 kfree(cookie); 789 kfree(cookie);
795 return inode; 790 return inode;
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 16bcc578e3b2..eeba2a359fb4 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -2209,8 +2209,7 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc,
2209 */ 2209 */
2210static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) 2210static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
2211{ 2211{
2212 struct afs_file_status *statuses; 2212 struct afs_status_cb *scb;
2213 struct afs_callback *callbacks;
2214 const __be32 *bp; 2213 const __be32 *bp;
2215 u32 tmp; 2214 u32 tmp;
2216 int ret; 2215 int ret;
@@ -2249,8 +2248,8 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
2249 return ret; 2248 return ret;
2250 2249
2251 bp = call->buffer; 2250 bp = call->buffer;
2252 statuses = call->out_extra_status; 2251 scb = &call->out_scb[call->count];
2253 ret = afs_decode_status(call, &bp, &statuses[call->count], 2252 ret = afs_decode_status(call, &bp, &scb->status,
2254 NULL, NULL, NULL); 2253 NULL, NULL, NULL);
2255 if (ret < 0) 2254 if (ret < 0)
2256 return ret; 2255 return ret;
@@ -2290,9 +2289,9 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
2290 2289
2291 _debug("unmarshall CB array"); 2290 _debug("unmarshall CB array");
2292 bp = call->buffer; 2291 bp = call->buffer;
2293 callbacks = call->out_cb; 2292 scb = &call->out_scb[call->count];
2294 xdr_decode_AFSCallBack_raw(call, &callbacks[call->count], &bp); 2293 xdr_decode_AFSCallBack_raw(call, &scb->callback, &bp);
2295 statuses = call->out_extra_status; 2294 scb->have_cb = true;
2296 call->count++; 2295 call->count++;
2297 if (call->count < call->count2) 2296 if (call->count < call->count2)
2298 goto more_cbs; 2297 goto more_cbs;
@@ -2335,8 +2334,7 @@ static const struct afs_call_type afs_RXFSInlineBulkStatus = {
2335int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, 2334int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
2336 struct afs_net *net, 2335 struct afs_net *net,
2337 struct afs_fid *fids, 2336 struct afs_fid *fids,
2338 struct afs_file_status *statuses, 2337 struct afs_status_cb *statuses,
2339 struct afs_callback *callbacks,
2340 unsigned int nr_fids, 2338 unsigned int nr_fids,
2341 struct afs_volsync *volsync) 2339 struct afs_volsync *volsync)
2342{ 2340{
@@ -2345,7 +2343,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
2345 int i; 2343 int i;
2346 2344
2347 if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) 2345 if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
2348 return yfs_fs_inline_bulk_status(fc, net, fids, statuses, callbacks, 2346 return yfs_fs_inline_bulk_status(fc, net, fids, statuses,
2349 nr_fids, volsync); 2347 nr_fids, volsync);
2350 2348
2351 _enter(",%x,{%llx:%llu},%u", 2349 _enter(",%x,{%llx:%llu},%u",
@@ -2360,8 +2358,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
2360 } 2358 }
2361 2359
2362 call->key = fc->key; 2360 call->key = fc->key;
2363 call->out_extra_status = statuses; 2361 call->out_scb = statuses;
2364 call->out_cb = callbacks;
2365 call->out_volsync = volsync; 2362 call->out_volsync = volsync;
2366 call->count2 = nr_fids; 2363 call->count2 = nr_fids;
2367 call->want_reply_time = true; 2364 call->want_reply_time = true;
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 705833eb2d45..2a100be91721 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -137,6 +137,7 @@ struct afs_call {
137 struct afs_file_status *out_vnode_status; 137 struct afs_file_status *out_vnode_status;
138 struct afs_file_status *out_extra_status; 138 struct afs_file_status *out_extra_status;
139 struct afs_callback *out_cb; 139 struct afs_callback *out_cb;
140 struct afs_status_cb *out_scb;
140 struct yfs_acl *out_yacl; 141 struct yfs_acl *out_yacl;
141 struct afs_volsync *out_volsync; 142 struct afs_volsync *out_volsync;
142 struct afs_volume_status *out_volstatus; 143 struct afs_volume_status *out_volstatus;
@@ -991,9 +992,8 @@ extern struct afs_call *afs_fs_get_capabilities(struct afs_net *, struct afs_ser
991 struct afs_addr_cursor *, struct key *, 992 struct afs_addr_cursor *, struct key *,
992 unsigned int); 993 unsigned int);
993extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, 994extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
994 struct afs_fid *, struct afs_file_status *, 995 struct afs_fid *, struct afs_status_cb *,
995 struct afs_callback *, unsigned int, 996 unsigned int, struct afs_volsync *);
996 struct afs_volsync *);
997extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, 997extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
998 struct afs_fid *, struct afs_file_status *, 998 struct afs_fid *, struct afs_file_status *,
999 struct afs_callback *, struct afs_volsync *); 999 struct afs_callback *, struct afs_volsync *);
@@ -1393,9 +1393,8 @@ extern int yfs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
1393 struct afs_fid *, struct afs_file_status *, 1393 struct afs_fid *, struct afs_file_status *,
1394 struct afs_callback *, struct afs_volsync *); 1394 struct afs_callback *, struct afs_volsync *);
1395extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, 1395extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
1396 struct afs_fid *, struct afs_file_status *, 1396 struct afs_fid *, struct afs_status_cb *,
1397 struct afs_callback *, unsigned int, 1397 unsigned int, struct afs_volsync *);
1398 struct afs_volsync *);
1399 1398
1400struct yfs_acl { 1399struct yfs_acl {
1401 struct afs_acl *acl; /* Dir/file/symlink ACL */ 1400 struct afs_acl *acl; /* Dir/file/symlink ACL */
diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c
index a815d22f62f1..1f1ccf7b7822 100644
--- a/fs/afs/yfsclient.c
+++ b/fs/afs/yfsclient.c
@@ -338,7 +338,7 @@ static void xdr_decode_YFSCallBack(struct afs_call *call,
338 struct afs_callback cb; 338 struct afs_callback cb;
339 339
340 xdr_decode_YFSCallBack_raw(call, &cb, _bp); 340 xdr_decode_YFSCallBack_raw(call, &cb, _bp);
341 341
342 write_seqlock(&vnode->cb_lock); 342 write_seqlock(&vnode->cb_lock);
343 343
344 if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) { 344 if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) {
@@ -2032,8 +2032,7 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc,
2032 */ 2032 */
2033static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) 2033static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
2034{ 2034{
2035 struct afs_file_status *statuses; 2035 struct afs_status_cb *scb;
2036 struct afs_callback *callbacks;
2037 const __be32 *bp; 2036 const __be32 *bp;
2038 u32 tmp; 2037 u32 tmp;
2039 int ret; 2038 int ret;
@@ -2072,8 +2071,8 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
2072 return ret; 2071 return ret;
2073 2072
2074 bp = call->buffer; 2073 bp = call->buffer;
2075 statuses = call->out_extra_status; 2074 scb = &call->out_scb[call->count];
2076 ret = yfs_decode_status(call, &bp, &statuses[call->count], 2075 ret = yfs_decode_status(call, &bp, &scb->status,
2077 NULL, NULL, NULL); 2076 NULL, NULL, NULL);
2078 if (ret < 0) 2077 if (ret < 0)
2079 return ret; 2078 return ret;
@@ -2113,8 +2112,9 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
2113 2112
2114 _debug("unmarshall CB array"); 2113 _debug("unmarshall CB array");
2115 bp = call->buffer; 2114 bp = call->buffer;
2116 callbacks = call->out_cb; 2115 scb = &call->out_scb[call->count];
2117 xdr_decode_YFSCallBack_raw(call, &callbacks[call->count], &bp); 2116 xdr_decode_YFSCallBack_raw(call, &scb->callback, &bp);
2117 scb->have_cb = true;
2118 call->count++; 2118 call->count++;
2119 if (call->count < call->count2) 2119 if (call->count < call->count2)
2120 goto more_cbs; 2120 goto more_cbs;
@@ -2158,8 +2158,7 @@ static const struct afs_call_type yfs_RXYFSInlineBulkStatus = {
2158int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, 2158int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
2159 struct afs_net *net, 2159 struct afs_net *net,
2160 struct afs_fid *fids, 2160 struct afs_fid *fids,
2161 struct afs_file_status *statuses, 2161 struct afs_status_cb *statuses,
2162 struct afs_callback *callbacks,
2163 unsigned int nr_fids, 2162 unsigned int nr_fids,
2164 struct afs_volsync *volsync) 2163 struct afs_volsync *volsync)
2165{ 2164{
@@ -2182,8 +2181,7 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
2182 } 2181 }
2183 2182
2184 call->key = fc->key; 2183 call->key = fc->key;
2185 call->out_extra_status = statuses; 2184 call->out_scb = statuses;
2186 call->out_cb = callbacks;
2187 call->out_volsync = volsync; 2185 call->out_volsync = volsync;
2188 call->count2 = nr_fids; 2186 call->count2 = nr_fids;
2189 2187