Commit 87182759 authored by David Howells's avatar David Howells

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: 5cf9dd55 ("afs: Prospectively look up extra files when doing a single lookup")
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent ffba718e
...@@ -147,6 +147,12 @@ struct afs_file_status { ...@@ -147,6 +147,12 @@ struct afs_file_status {
u32 abort_code; /* Abort if bulk-fetching this failed */ u32 abort_code; /* Abort if bulk-fetching this failed */
}; };
struct afs_status_cb {
struct afs_file_status status;
struct afs_callback callback;
bool have_cb; /* True if cb record was retrieved */
};
/* /*
* AFS file status change request * AFS file status change request
*/ */
......
...@@ -102,8 +102,7 @@ struct afs_lookup_cookie { ...@@ -102,8 +102,7 @@ struct afs_lookup_cookie {
bool found; bool found;
bool one_only; bool one_only;
unsigned short nr_fids; unsigned short nr_fids;
struct afs_file_status *statuses; struct afs_status_cb *statuses;
struct afs_callback *callbacks;
struct afs_fid fids[50]; struct afs_fid fids[50];
}; };
...@@ -640,6 +639,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, ...@@ -640,6 +639,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
struct afs_lookup_cookie *cookie; struct afs_lookup_cookie *cookie;
struct afs_cb_interest *cbi = NULL; struct afs_cb_interest *cbi = NULL;
struct afs_super_info *as = dir->i_sb->s_fs_info; struct afs_super_info *as = dir->i_sb->s_fs_info;
struct afs_status_cb *scb;
struct afs_iget_data data; struct afs_iget_data data;
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
struct afs_vnode *dvnode = AFS_FS_I(dir); 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,16 +686,11 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
/* Need space for examining all the selected files */ /* Need space for examining all the selected files */
inode = ERR_PTR(-ENOMEM); inode = ERR_PTR(-ENOMEM);
cookie->statuses = kcalloc(cookie->nr_fids, sizeof(struct afs_file_status), cookie->statuses = kvcalloc(cookie->nr_fids, sizeof(struct afs_status_cb),
GFP_KERNEL); GFP_KERNEL);
if (!cookie->statuses) if (!cookie->statuses)
goto out; goto out;
cookie->callbacks = kcalloc(cookie->nr_fids, sizeof(struct afs_callback),
GFP_KERNEL);
if (!cookie->callbacks)
goto out_s;
/* Try FS.InlineBulkStatus first. Abort codes for the individual /* Try FS.InlineBulkStatus first. Abort codes for the individual
* lookups contained therein are stored in the reply without aborting * lookups contained therein are stored in the reply without aborting
* the whole operation. * the whole operation.
...@@ -716,7 +711,6 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, ...@@ -716,7 +711,6 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
afs_v2net(dvnode), afs_v2net(dvnode),
cookie->fids, cookie->fids,
cookie->statuses, cookie->statuses,
cookie->callbacks,
cookie->nr_fids, NULL); cookie->nr_fids, NULL);
} }
...@@ -741,11 +735,12 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, ...@@ -741,11 +735,12 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
inode = ERR_PTR(-ERESTARTSYS); inode = ERR_PTR(-ERESTARTSYS);
if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
scb = &cookie->statuses[0];
afs_fs_fetch_status(&fc, afs_fs_fetch_status(&fc,
afs_v2net(dvnode), afs_v2net(dvnode),
cookie->fids, cookie->fids,
cookie->statuses, &scb->status,
cookie->callbacks, &scb->callback,
NULL); NULL);
} }
...@@ -758,24 +753,26 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, ...@@ -758,24 +753,26 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
goto out_c; goto out_c;
for (i = 0; i < cookie->nr_fids; i++) for (i = 0; i < cookie->nr_fids; i++)
cookie->statuses[i].abort_code = 0; cookie->statuses[i].status.abort_code = 0;
success: success:
/* Turn all the files into inodes and save the first one - which is the /* Turn all the files into inodes and save the first one - which is the
* one we actually want. * one we actually want.
*/ */
if (cookie->statuses[0].abort_code != 0) scb = &cookie->statuses[0];
inode = ERR_PTR(afs_abort_to_error(cookie->statuses[0].abort_code)); if (scb->status.abort_code != 0)
inode = ERR_PTR(afs_abort_to_error(scb->status.abort_code));
for (i = 0; i < cookie->nr_fids; i++) { for (i = 0; i < cookie->nr_fids; i++) {
struct afs_status_cb *scb = &cookie->statuses[i];
struct inode *ti; struct inode *ti;
if (cookie->statuses[i].abort_code != 0) if (scb->status.abort_code != 0)
continue; continue;
ti = afs_iget(dir->i_sb, key, &cookie->fids[i], ti = afs_iget(dir->i_sb, key, &cookie->fids[i],
&cookie->statuses[i], &scb->status,
&cookie->callbacks[i], &scb->callback,
cbi, dvnode); cbi, dvnode);
if (i == 0) { if (i == 0) {
inode = ti; inode = ti;
...@@ -787,9 +784,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, ...@@ -787,9 +784,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
out_c: out_c:
afs_put_cb_interest(afs_v2net(dvnode), cbi); afs_put_cb_interest(afs_v2net(dvnode), cbi);
kfree(cookie->callbacks); kvfree(cookie->statuses);
out_s:
kfree(cookie->statuses);
out: out:
kfree(cookie); kfree(cookie);
return inode; return inode;
......
...@@ -2209,8 +2209,7 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc, ...@@ -2209,8 +2209,7 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc,
*/ */
static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
{ {
struct afs_file_status *statuses; struct afs_status_cb *scb;
struct afs_callback *callbacks;
const __be32 *bp; const __be32 *bp;
u32 tmp; u32 tmp;
int ret; int ret;
...@@ -2249,8 +2248,8 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) ...@@ -2249,8 +2248,8 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
return ret; return ret;
bp = call->buffer; bp = call->buffer;
statuses = call->out_extra_status; scb = &call->out_scb[call->count];
ret = afs_decode_status(call, &bp, &statuses[call->count], ret = afs_decode_status(call, &bp, &scb->status,
NULL, NULL, NULL); NULL, NULL, NULL);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -2290,9 +2289,9 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) ...@@ -2290,9 +2289,9 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
_debug("unmarshall CB array"); _debug("unmarshall CB array");
bp = call->buffer; bp = call->buffer;
callbacks = call->out_cb; scb = &call->out_scb[call->count];
xdr_decode_AFSCallBack_raw(call, &callbacks[call->count], &bp); xdr_decode_AFSCallBack_raw(call, &scb->callback, &bp);
statuses = call->out_extra_status; scb->have_cb = true;
call->count++; call->count++;
if (call->count < call->count2) if (call->count < call->count2)
goto more_cbs; goto more_cbs;
...@@ -2335,8 +2334,7 @@ static const struct afs_call_type afs_RXFSInlineBulkStatus = { ...@@ -2335,8 +2334,7 @@ static const struct afs_call_type afs_RXFSInlineBulkStatus = {
int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
struct afs_net *net, struct afs_net *net,
struct afs_fid *fids, struct afs_fid *fids,
struct afs_file_status *statuses, struct afs_status_cb *statuses,
struct afs_callback *callbacks,
unsigned int nr_fids, unsigned int nr_fids,
struct afs_volsync *volsync) struct afs_volsync *volsync)
{ {
...@@ -2345,7 +2343,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, ...@@ -2345,7 +2343,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
int i; int i;
if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
return yfs_fs_inline_bulk_status(fc, net, fids, statuses, callbacks, return yfs_fs_inline_bulk_status(fc, net, fids, statuses,
nr_fids, volsync); nr_fids, volsync);
_enter(",%x,{%llx:%llu},%u", _enter(",%x,{%llx:%llu},%u",
...@@ -2360,8 +2358,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, ...@@ -2360,8 +2358,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
} }
call->key = fc->key; call->key = fc->key;
call->out_extra_status = statuses; call->out_scb = statuses;
call->out_cb = callbacks;
call->out_volsync = volsync; call->out_volsync = volsync;
call->count2 = nr_fids; call->count2 = nr_fids;
call->want_reply_time = true; call->want_reply_time = true;
......
...@@ -137,6 +137,7 @@ struct afs_call { ...@@ -137,6 +137,7 @@ struct afs_call {
struct afs_file_status *out_vnode_status; struct afs_file_status *out_vnode_status;
struct afs_file_status *out_extra_status; struct afs_file_status *out_extra_status;
struct afs_callback *out_cb; struct afs_callback *out_cb;
struct afs_status_cb *out_scb;
struct yfs_acl *out_yacl; struct yfs_acl *out_yacl;
struct afs_volsync *out_volsync; struct afs_volsync *out_volsync;
struct afs_volume_status *out_volstatus; 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,9 +992,8 @@ extern struct afs_call *afs_fs_get_capabilities(struct afs_net *, struct afs_ser
struct afs_addr_cursor *, struct key *, struct afs_addr_cursor *, struct key *,
unsigned int); unsigned int);
extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
struct afs_fid *, struct afs_file_status *, struct afs_fid *, struct afs_status_cb *,
struct afs_callback *, unsigned int, unsigned int, struct afs_volsync *);
struct afs_volsync *);
extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
struct afs_fid *, struct afs_file_status *, struct afs_fid *, struct afs_file_status *,
struct afs_callback *, struct afs_volsync *); struct afs_callback *, struct afs_volsync *);
...@@ -1393,9 +1393,8 @@ extern int yfs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, ...@@ -1393,9 +1393,8 @@ extern int yfs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
struct afs_fid *, struct afs_file_status *, struct afs_fid *, struct afs_file_status *,
struct afs_callback *, struct afs_volsync *); struct afs_callback *, struct afs_volsync *);
extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
struct afs_fid *, struct afs_file_status *, struct afs_fid *, struct afs_status_cb *,
struct afs_callback *, unsigned int, unsigned int, struct afs_volsync *);
struct afs_volsync *);
struct yfs_acl { struct yfs_acl {
struct afs_acl *acl; /* Dir/file/symlink ACL */ struct afs_acl *acl; /* Dir/file/symlink ACL */
......
...@@ -2032,8 +2032,7 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc, ...@@ -2032,8 +2032,7 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc,
*/ */
static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
{ {
struct afs_file_status *statuses; struct afs_status_cb *scb;
struct afs_callback *callbacks;
const __be32 *bp; const __be32 *bp;
u32 tmp; u32 tmp;
int ret; int ret;
...@@ -2072,8 +2071,8 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) ...@@ -2072,8 +2071,8 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
return ret; return ret;
bp = call->buffer; bp = call->buffer;
statuses = call->out_extra_status; scb = &call->out_scb[call->count];
ret = yfs_decode_status(call, &bp, &statuses[call->count], ret = yfs_decode_status(call, &bp, &scb->status,
NULL, NULL, NULL); NULL, NULL, NULL);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -2113,8 +2112,9 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) ...@@ -2113,8 +2112,9 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
_debug("unmarshall CB array"); _debug("unmarshall CB array");
bp = call->buffer; bp = call->buffer;
callbacks = call->out_cb; scb = &call->out_scb[call->count];
xdr_decode_YFSCallBack_raw(call, &callbacks[call->count], &bp); xdr_decode_YFSCallBack_raw(call, &scb->callback, &bp);
scb->have_cb = true;
call->count++; call->count++;
if (call->count < call->count2) if (call->count < call->count2)
goto more_cbs; goto more_cbs;
...@@ -2158,8 +2158,7 @@ static const struct afs_call_type yfs_RXYFSInlineBulkStatus = { ...@@ -2158,8 +2158,7 @@ static const struct afs_call_type yfs_RXYFSInlineBulkStatus = {
int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
struct afs_net *net, struct afs_net *net,
struct afs_fid *fids, struct afs_fid *fids,
struct afs_file_status *statuses, struct afs_status_cb *statuses,
struct afs_callback *callbacks,
unsigned int nr_fids, unsigned int nr_fids,
struct afs_volsync *volsync) struct afs_volsync *volsync)
{ {
...@@ -2182,8 +2181,7 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, ...@@ -2182,8 +2181,7 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
} }
call->key = fc->key; call->key = fc->key;
call->out_extra_status = statuses; call->out_scb = statuses;
call->out_cb = callbacks;
call->out_volsync = volsync; call->out_volsync = volsync;
call->count2 = nr_fids; call->count2 = nr_fids;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment