Commit 5cf9dd55 authored by David Howells's avatar David Howells

afs: Prospectively look up extra files when doing a single lookup

When afs_lookup() is called, prospectively look up the next 50 uncached
fids also from that same directory and cache the results, rather than just
looking up the one file requested.

This allows us to use the FS.InlineBulkStatus RPC op to increase efficiency
by fetching up to 50 file statuses at a time.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 17814aef
......@@ -67,10 +67,14 @@ typedef enum {
} afs_callback_type_t;
struct afs_callback {
struct afs_fid fid; /* file identifier */
unsigned version; /* callback version */
unsigned expiry; /* time at which expires */
afs_callback_type_t type; /* type of callback */
unsigned version; /* Callback version */
unsigned expiry; /* Time at which expires */
afs_callback_type_t type; /* Type of callback */
};
struct afs_callback_break {
struct afs_fid fid; /* File identifier */
struct afs_callback cb; /* Callback details */
};
#define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */
......@@ -123,21 +127,22 @@ typedef u32 afs_access_t;
* AFS file status information
*/
struct afs_file_status {
u64 size; /* file size */
afs_dataversion_t data_version; /* current data version */
time_t mtime_client; /* last time client changed data */
time_t mtime_server; /* last time server changed data */
unsigned if_version; /* interface version */
#define AFS_FSTATUS_VERSION 1
unsigned abort_code; /* Abort if bulk-fetching this failed */
afs_file_type_t type; /* file type */
unsigned nlink; /* link count */
u64 size; /* file size */
afs_dataversion_t data_version; /* current data version */
u32 author; /* author ID */
kuid_t owner; /* owner ID */
kgid_t group; /* group ID */
afs_access_t caller_access; /* access rights for authenticated caller */
afs_access_t anon_access; /* access rights for unauthenticated caller */
umode_t mode; /* UNIX mode */
time_t mtime_client; /* last time client changed data */
time_t mtime_server; /* last time server changed data */
s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */
};
......
......@@ -31,10 +31,12 @@ enum AFS_FS_Operations {
FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */
FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */
FSGETROOTVOLUME = 151, /* AFS Get root volume name */
FSBULKSTATUS = 155, /* AFS Fetch multiple file statuses */
FSSETLOCK = 156, /* AFS Request a file lock */
FSEXTENDLOCK = 157, /* AFS Extend a file lock */
FSRELEASELOCK = 158, /* AFS Release a file lock */
FSLOOKUP = 161, /* AFS lookup file in directory */
FSINLINEBULKSTATUS = 65536, /* AFS Fetch multiple file statuses with inline errors */
FSFETCHDATA64 = 65537, /* AFS Fetch file data */
FSSTOREDATA64 = 65538, /* AFS Store file data */
FSGIVEUPALLCALLBACKS = 65539, /* AFS Give up all outstanding callbacks on a server */
......
......@@ -187,7 +187,7 @@ static void afs_break_one_callback(struct afs_server *server,
* allow the fileserver to break callback promises
*/
void afs_break_callbacks(struct afs_server *server, size_t count,
struct afs_callback callbacks[])
struct afs_callback_break *callbacks)
{
_enter("%p,%zu,", server, count);
......@@ -199,9 +199,9 @@ void afs_break_callbacks(struct afs_server *server, size_t count,
callbacks->fid.vid,
callbacks->fid.vnode,
callbacks->fid.unique,
callbacks->version,
callbacks->expiry,
callbacks->type
callbacks->cb.version,
callbacks->cb.expiry,
callbacks->cb.type
);
afs_break_one_callback(server, &callbacks->fid);
}
......
......@@ -178,8 +178,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
*/
static int afs_deliver_cb_callback(struct afs_call *call)
{
struct afs_callback_break *cb;
struct sockaddr_rxrpc srx;
struct afs_callback *cb;
struct afs_server *server;
__be32 *bp;
int ret, loop;
......@@ -218,7 +218,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
_debug("unmarshall FID array");
call->request = kcalloc(call->count,
sizeof(struct afs_callback),
sizeof(struct afs_callback_break),
GFP_KERNEL);
if (!call->request)
return -ENOMEM;
......@@ -229,7 +229,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
cb->fid.vid = ntohl(*bp++);
cb->fid.vnode = ntohl(*bp++);
cb->fid.unique = ntohl(*bp++);
cb->type = AFSCM_CB_UNTYPED;
cb->cb.type = AFSCM_CB_UNTYPED;
}
call->offset = 0;
......@@ -260,9 +260,9 @@ static int afs_deliver_cb_callback(struct afs_call *call)
cb = call->request;
bp = call->buffer;
for (loop = call->count2; loop > 0; loop--, cb++) {
cb->version = ntohl(*bp++);
cb->expiry = ntohl(*bp++);
cb->type = ntohl(*bp++);
cb->cb.version = ntohl(*bp++);
cb->cb.expiry = ntohl(*bp++);
cb->cb.type = ntohl(*bp++);
}
call->offset = 0;
......
This diff is collapsed.
......@@ -94,7 +94,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
data_version |= (u64) ntohl(*bp++) << 32;
EXTRACT(status->lock_count);
size |= (u64) ntohl(*bp++) << 32;
bp++; /* spare 4 */
EXTRACT(status->abort_code); /* spare 4 */
*_bp = bp;
if (size != status->size) {
......@@ -274,7 +274,7 @@ static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
/*
* deliver reply data to an FS.FetchStatus
*/
static int afs_deliver_fs_fetch_status(struct afs_call *call)
static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
{
struct afs_vnode *vnode = call->reply[0];
const __be32 *bp;
......@@ -300,10 +300,10 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call)
/*
* FS.FetchStatus operation type
*/
static const struct afs_call_type afs_RXFSFetchStatus = {
.name = "FS.FetchStatus",
static const struct afs_call_type afs_RXFSFetchStatus_vnode = {
.name = "FS.FetchStatus(vnode)",
.op = afs_FS_FetchStatus,
.deliver = afs_deliver_fs_fetch_status,
.deliver = afs_deliver_fs_fetch_status_vnode,
.destructor = afs_flat_call_destructor,
};
......@@ -320,7 +320,8 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy
_enter(",%x,{%x:%u},,",
key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode,
16, (21 + 3 + 6) * 4);
if (!call) {
fc->ac.error = -ENOMEM;
return -ENOMEM;
......@@ -1947,3 +1948,262 @@ int afs_fs_get_capabilities(struct afs_net *net,
trace_afs_make_fs_call(call, NULL);
return afs_make_call(ac, call, GFP_NOFS, false);
}
/*
* Deliver reply data to an FS.FetchStatus with no vnode.
*/
static int afs_deliver_fs_fetch_status(struct afs_call *call)
{
struct afs_file_status *status = call->reply[1];
struct afs_callback *callback = call->reply[2];
struct afs_volsync *volsync = call->reply[3];
struct afs_vnode *vnode = call->reply[0];
const __be32 *bp;
int ret;
ret = afs_transfer_reply(call);
if (ret < 0)
return ret;
_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
/* unmarshall the reply once we've received all of it */
bp = call->buffer;
xdr_decode_AFSFetchStatus(&bp, status, vnode, NULL);
callback[call->count].version = ntohl(bp[0]);
callback[call->count].expiry = ntohl(bp[1]);
callback[call->count].type = ntohl(bp[2]);
if (vnode)
xdr_decode_AFSCallBack(call, vnode, &bp);
else
bp += 3;
if (volsync)
xdr_decode_AFSVolSync(&bp, volsync);
_leave(" = 0 [done]");
return 0;
}
/*
* FS.FetchStatus operation type
*/
static const struct afs_call_type afs_RXFSFetchStatus = {
.name = "FS.FetchStatus",
.op = afs_FS_FetchStatus,
.deliver = afs_deliver_fs_fetch_status,
.destructor = afs_flat_call_destructor,
};
/*
* Fetch the status information for a fid without needing a vnode handle.
*/
int afs_fs_fetch_status(struct afs_fs_cursor *fc,
struct afs_net *net,
struct afs_fid *fid,
struct afs_file_status *status,
struct afs_callback *callback,
struct afs_volsync *volsync)
{
struct afs_call *call;
__be32 *bp;
_enter(",%x,{%x:%u},,",
key_serial(fc->key), fid->vid, fid->vnode);
call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
if (!call) {
fc->ac.error = -ENOMEM;
return -ENOMEM;
}
call->key = fc->key;
call->reply[0] = NULL; /* vnode for fid[0] */
call->reply[1] = status;
call->reply[2] = callback;
call->reply[3] = volsync;
/* marshall the parameters */
bp = call->request;
bp[0] = htonl(FSFETCHSTATUS);
bp[1] = htonl(fid->vid);
bp[2] = htonl(fid->vnode);
bp[3] = htonl(fid->unique);
call->cb_break = fc->cb_break;
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, fid);
return afs_make_call(&fc->ac, call, GFP_NOFS, false);
}
/*
* Deliver reply data to an FS.InlineBulkStatus call
*/
static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
{
struct afs_file_status *statuses;
struct afs_callback *callbacks;
struct afs_vnode *vnode = call->reply[0];
const __be32 *bp;
u32 tmp;
int ret;
_enter("{%u}", call->unmarshall);
switch (call->unmarshall) {
case 0:
call->offset = 0;
call->unmarshall++;
/* Extract the file status count and array in two steps */
case 1:
_debug("extract status count");
ret = afs_extract_data(call, &call->tmp, 4, true);
if (ret < 0)
return ret;
tmp = ntohl(call->tmp);
_debug("status count: %u/%u", tmp, call->count2);
if (tmp != call->count2)
return -EBADMSG;
call->count = 0;
call->unmarshall++;
more_counts:
call->offset = 0;
case 2:
_debug("extract status array %u", call->count);
ret = afs_extract_data(call, call->buffer, 21 * 4, true);
if (ret < 0)
return ret;
bp = call->buffer;
statuses = call->reply[1];
xdr_decode_AFSFetchStatus(&bp, &statuses[call->count],
call->count == 0 ? vnode : NULL,
NULL);
call->count++;
if (call->count < call->count2)
goto more_counts;
call->count = 0;
call->unmarshall++;
call->offset = 0;
/* Extract the callback count and array in two steps */
case 3:
_debug("extract CB count");
ret = afs_extract_data(call, &call->tmp, 4, true);
if (ret < 0)
return ret;
tmp = ntohl(call->tmp);
_debug("CB count: %u", tmp);
if (tmp != call->count2)
return -EBADMSG;
call->count = 0;
call->unmarshall++;
more_cbs:
call->offset = 0;
case 4:
_debug("extract CB array");
ret = afs_extract_data(call, call->buffer, 3 * 4, true);
if (ret < 0)
return ret;
_debug("unmarshall CB array");
bp = call->buffer;
callbacks = call->reply[2];
callbacks[call->count].version = ntohl(bp[0]);
callbacks[call->count].expiry = ntohl(bp[1]);
callbacks[call->count].type = ntohl(bp[2]);
statuses = call->reply[1];
if (call->count == 0 && vnode && statuses[0].abort_code == 0)
xdr_decode_AFSCallBack(call, vnode, &bp);
call->count++;
if (call->count < call->count2)
goto more_cbs;
call->offset = 0;
call->unmarshall++;
case 5:
ret = afs_extract_data(call, call->buffer, 6 * 4, false);
if (ret < 0)
return ret;
bp = call->buffer;
if (call->reply[3])
xdr_decode_AFSVolSync(&bp, call->reply[3]);
call->offset = 0;
call->unmarshall++;
case 6:
break;
}
_leave(" = 0 [done]");
return 0;
}
/*
* FS.InlineBulkStatus operation type
*/
static const struct afs_call_type afs_RXFSInlineBulkStatus = {
.name = "FS.InlineBulkStatus",
.op = afs_FS_InlineBulkStatus,
.deliver = afs_deliver_fs_inline_bulk_status,
.destructor = afs_flat_call_destructor,
};
/*
* Fetch the status information for up to 50 files
*/
int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
struct afs_net *net,
struct afs_fid *fids,
struct afs_file_status *statuses,
struct afs_callback *callbacks,
unsigned int nr_fids,
struct afs_volsync *volsync)
{
struct afs_call *call;
__be32 *bp;
int i;
_enter(",%x,{%x:%u},%u",
key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids);
call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus,
(2 + nr_fids * 3) * 4,
21 * 4);
if (!call) {
fc->ac.error = -ENOMEM;
return -ENOMEM;
}
call->key = fc->key;
call->reply[0] = NULL; /* vnode for fid[0] */
call->reply[1] = statuses;
call->reply[2] = callbacks;
call->reply[3] = volsync;
call->count2 = nr_fids;
/* marshall the parameters */
bp = call->request;
*bp++ = htonl(FSINLINEBULKSTATUS);
*bp++ = htonl(nr_fids);
for (i = 0; i < nr_fids; i++) {
*bp++ = htonl(fids[i].vid);
*bp++ = htonl(fids[i].vnode);
*bp++ = htonl(fids[i].unique);
}
call->cb_break = fc->cb_break;
afs_use_fs_server(call, fc->cbi);
trace_afs_make_fs_call(call, &fids[0]);
return afs_make_call(&fc->ac, call, GFP_NOFS, false);
}
......@@ -363,6 +363,7 @@ struct afs_server {
#define AFS_SERVER_FL_UPDATING 4
#define AFS_SERVER_FL_PROBED 5 /* The fileserver has been probed */
#define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */
#define AFS_SERVER_FL_NO_IBULK 7 /* Fileserver doesn't support FS.InlineBulkStatus */
atomic_t usage;
u32 addr_version; /* Address list version */
......@@ -611,7 +612,7 @@ extern struct fscache_cookie_def afs_vnode_cache_index_def;
*/
extern void afs_init_callback_state(struct afs_server *);
extern void afs_break_callback(struct afs_vnode *);
extern void afs_break_callbacks(struct afs_server *, size_t,struct afs_callback[]);
extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break*);
extern int afs_register_server_cb_interest(struct afs_vnode *, struct afs_server_entry *);
extern void afs_put_cb_interest(struct afs_net *, struct afs_cb_interest *);
......@@ -702,6 +703,13 @@ extern int afs_fs_give_up_all_callbacks(struct afs_net *, struct afs_server *,
struct afs_addr_cursor *, struct key *);
extern int afs_fs_get_capabilities(struct afs_net *, struct afs_server *,
struct afs_addr_cursor *, struct key *);
extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
struct afs_fid *, struct afs_file_status *,
struct afs_callback *, unsigned int,
struct afs_volsync *);
extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
struct afs_fid *, struct afs_file_status *,
struct afs_callback *, struct afs_volsync *);
/*
* inode.c
......
......@@ -49,6 +49,7 @@ enum afs_fs_operation {
afs_FS_ExtendLock = 157, /* AFS Extend a file lock */
afs_FS_ReleaseLock = 158, /* AFS Release a file lock */
afs_FS_Lookup = 161, /* AFS lookup file in directory */
afs_FS_InlineBulkStatus = 65536, /* AFS Fetch multiple file statuses with errors */
afs_FS_FetchData64 = 65537, /* AFS Fetch file data */
afs_FS_StoreData64 = 65538, /* AFS Store file data */
afs_FS_GiveUpAllCallBacks = 65539, /* AFS Give up all our callbacks on a server */
......@@ -93,6 +94,7 @@ enum afs_vl_operation {
EM(afs_FS_ExtendLock, "FS.ExtendLock") \
EM(afs_FS_ReleaseLock, "FS.ReleaseLock") \
EM(afs_FS_Lookup, "FS.Lookup") \
EM(afs_FS_InlineBulkStatus, "FS.InlineBulkStatus") \
EM(afs_FS_FetchData64, "FS.FetchData64") \
EM(afs_FS_StoreData64, "FS.StoreData64") \
EM(afs_FS_GiveUpAllCallBacks, "FS.GiveUpAllCallBacks") \
......
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