Merge tag 'armsoc-dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[sfrench/cifs-2.6.git] / fs / afs / fsclient.c
index 19f76ae36982df43be740c1bf73d396b1a81c77c..b90ef39ae914aa688580887a28d4aa433591da2c 100644 (file)
 #include "internal.h"
 #include "afs_fs.h"
 
+static const struct afs_fid afs_zero_fid;
+
 /*
  * We need somewhere to discard into in case the server helpfully returns more
  * than we asked for in FS.FetchData{,64}.
  */
 static u8 afs_discard_buffer[64];
 
+static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi)
+{
+       call->cbi = afs_get_cb_interest(cbi);
+}
+
 /*
  * decode an AFSFid block
  */
@@ -47,14 +54,18 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
        const __be32 *bp = *_bp;
        umode_t mode;
        u64 data_version, size;
-       u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
+       bool changed = false;
        kuid_t owner;
        kgid_t group;
 
+       if (vnode)
+               write_seqlock(&vnode->cb_lock);
+
 #define EXTRACT(DST)                           \
        do {                                    \
                u32 x = ntohl(*bp++);           \
-               changed |= DST - x;             \
+               if (DST != x)                   \
+                       changed |= true;        \
                DST = x;                        \
        } while (0)
 
@@ -70,8 +81,8 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
        EXTRACT(status->caller_access); /* call ticket dependent */
        EXTRACT(status->anon_access);
        EXTRACT(status->mode);
-       EXTRACT(status->parent.vnode);
-       EXTRACT(status->parent.unique);
+       bp++; /* parent.vnode */
+       bp++; /* parent.unique */
        bp++; /* seg size */
        status->mtime_client = ntohl(*bp++);
        status->mtime_server = ntohl(*bp++);
@@ -95,7 +106,6 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
               status->mtime_client, status->mtime_server);
 
        if (vnode) {
-               status->parent.vid = vnode->fid.vid;
                if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
                        _debug("vnode changed");
                        i_size_write(&vnode->vfs_inode, size);
@@ -127,25 +137,47 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
                        _debug("vnode modified %llx on {%x:%u}",
                               (unsigned long long) data_version,
                               vnode->fid.vid, vnode->fid.vnode);
-                       set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
+                       set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags);
                        set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
                }
        } else if (store_version) {
                status->data_version = data_version;
        }
+
+       if (vnode)
+               write_sequnlock(&vnode->cb_lock);
 }
 
 /*
  * decode an AFSCallBack block
  */
-static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
+static void xdr_decode_AFSCallBack(struct afs_call *call,
+                                  struct afs_vnode *vnode,
+                                  const __be32 **_bp)
 {
+       struct afs_cb_interest *old, *cbi = call->cbi;
        const __be32 *bp = *_bp;
+       u32 cb_expiry;
+
+       write_seqlock(&vnode->cb_lock);
+
+       if (call->cb_break == (vnode->cb_break + cbi->server->cb_s_break)) {
+               vnode->cb_version       = ntohl(*bp++);
+               cb_expiry               = ntohl(*bp++);
+               vnode->cb_type          = ntohl(*bp++);
+               vnode->cb_expires_at    = cb_expiry + ktime_get_real_seconds();
+               old = vnode->cb_interest;
+               if (old != call->cbi) {
+                       vnode->cb_interest = cbi;
+                       cbi = old;
+               }
+               set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
+       } else {
+               bp += 3;
+       }
 
-       vnode->cb_version       = ntohl(*bp++);
-       vnode->cb_expiry        = ntohl(*bp++);
-       vnode->cb_type          = ntohl(*bp++);
-       vnode->cb_expires       = vnode->cb_expiry + ktime_get_real_seconds();
+       write_sequnlock(&vnode->cb_lock);
+       call->cbi = cbi;
        *_bp = bp;
 }
 
@@ -243,22 +275,22 @@ static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
  */
 static int afs_deliver_fs_fetch_status(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply;
+       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
-       _enter("");
-
        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, &vnode->status, vnode, NULL);
-       xdr_decode_AFSCallBack(&bp, vnode);
-       if (call->reply2)
-               xdr_decode_AFSVolSync(&bp, call->reply2);
+       xdr_decode_AFSCallBack(call, vnode, &bp);
+       if (call->reply[1])
+               xdr_decode_AFSVolSync(&bp, call->reply[1]);
 
        _leave(" = 0 [done]");
        return 0;
@@ -269,35 +301,33 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call)
  */
 static const struct afs_call_type afs_RXFSFetchStatus = {
        .name           = "FS.FetchStatus",
+       .op             = afs_FS_FetchStatus,
        .deliver        = afs_deliver_fs_fetch_status,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 /*
  * fetch the status information for a file
  */
-int afs_fs_fetch_file_status(struct afs_server *server,
-                            struct key *key,
-                            struct afs_vnode *vnode,
-                            struct afs_volsync *volsync,
-                            bool async)
+int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
        _enter(",%x,{%x:%u},,",
-              key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
 
-       call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
-       if (!call)
+       call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
+       if (!call) {
+               fc->ac.error = -ENOMEM;
                return -ENOMEM;
+       }
 
-       call->key = key;
-       call->reply = vnode;
-       call->reply2 = volsync;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = vnode;
+       call->reply[1] = volsync;
 
        /* marshall the parameters */
        bp = call->request;
@@ -306,7 +336,10 @@ int afs_fs_fetch_file_status(struct afs_server *server,
        bp[2] = htonl(vnode->fid.vnode);
        bp[3] = htonl(vnode->fid.unique);
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       call->cb_break = fc->cb_break;
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
@@ -314,8 +347,8 @@ int afs_fs_fetch_file_status(struct afs_server *server,
  */
 static int afs_deliver_fs_fetch_data(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply;
-       struct afs_read *req = call->reply3;
+       struct afs_vnode *vnode = call->reply[0];
+       struct afs_read *req = call->reply[2];
        const __be32 *bp;
        unsigned int size;
        void *buffer;
@@ -431,9 +464,9 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 
                bp = call->buffer;
                xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
-               xdr_decode_AFSCallBack(&bp, vnode);
-               if (call->reply2)
-                       xdr_decode_AFSVolSync(&bp, call->reply2);
+               xdr_decode_AFSCallBack(call, vnode, &bp);
+               if (call->reply[1])
+                       xdr_decode_AFSVolSync(&bp, call->reply[1]);
 
                call->offset = 0;
                call->unmarshall++;
@@ -457,7 +490,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 
 static void afs_fetch_data_destructor(struct afs_call *call)
 {
-       struct afs_read *req = call->reply3;
+       struct afs_read *req = call->reply[2];
 
        afs_put_read(req);
        afs_flat_call_destructor(call);
@@ -468,43 +501,38 @@ static void afs_fetch_data_destructor(struct afs_call *call)
  */
 static const struct afs_call_type afs_RXFSFetchData = {
        .name           = "FS.FetchData",
+       .op             = afs_FS_FetchData,
        .deliver        = afs_deliver_fs_fetch_data,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_fetch_data_destructor,
 };
 
 static const struct afs_call_type afs_RXFSFetchData64 = {
        .name           = "FS.FetchData64",
+       .op             = afs_FS_FetchData64,
        .deliver        = afs_deliver_fs_fetch_data,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_fetch_data_destructor,
 };
 
 /*
  * fetch data from a very large file
  */
-static int afs_fs_fetch_data64(struct afs_server *server,
-                              struct key *key,
-                              struct afs_vnode *vnode,
-                              struct afs_read *req,
-                              bool async)
+static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
        _enter("");
 
-       call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
+       call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->reply2 = NULL; /* volsync */
-       call->reply3 = req;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
-       call->operation_ID = FSFETCHDATA64;
+       call->key = fc->key;
+       call->reply[0] = vnode;
+       call->reply[1] = NULL; /* volsync */
+       call->reply[2] = req;
 
        /* marshall the parameters */
        bp = call->request;
@@ -518,39 +546,37 @@ static int afs_fs_fetch_data64(struct afs_server *server,
        bp[7] = htonl(lower_32_bits(req->len));
 
        atomic_inc(&req->usage);
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       call->cb_break = fc->cb_break;
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
  * fetch data from a file
  */
-int afs_fs_fetch_data(struct afs_server *server,
-                     struct key *key,
-                     struct afs_vnode *vnode,
-                     struct afs_read *req,
-                     bool async)
+int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
        if (upper_32_bits(req->pos) ||
            upper_32_bits(req->len) ||
            upper_32_bits(req->pos + req->len))
-               return afs_fs_fetch_data64(server, key, vnode, req, async);
+               return afs_fs_fetch_data64(fc, req);
 
        _enter("");
 
-       call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
+       call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->reply2 = NULL; /* volsync */
-       call->reply3 = req;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
-       call->operation_ID = FSFETCHDATA;
+       call->key = fc->key;
+       call->reply[0] = vnode;
+       call->reply[1] = NULL; /* volsync */
+       call->reply[2] = req;
 
        /* marshall the parameters */
        bp = call->request;
@@ -562,90 +588,10 @@ int afs_fs_fetch_data(struct afs_server *server,
        bp[5] = htonl(lower_32_bits(req->len));
 
        atomic_inc(&req->usage);
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
-}
-
-/*
- * deliver reply data to an FS.GiveUpCallBacks
- */
-static int afs_deliver_fs_give_up_callbacks(struct afs_call *call)
-{
-       _enter("");
-
-       /* shouldn't be any reply data */
-       return afs_extract_data(call, NULL, 0, false);
-}
-
-/*
- * FS.GiveUpCallBacks operation type
- */
-static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
-       .name           = "FS.GiveUpCallBacks",
-       .deliver        = afs_deliver_fs_give_up_callbacks,
-       .abort_to_error = afs_abort_to_error,
-       .destructor     = afs_flat_call_destructor,
-};
-
-/*
- * give up a set of callbacks
- * - the callbacks are held in the server->cb_break ring
- */
-int afs_fs_give_up_callbacks(struct afs_server *server,
-                            bool async)
-{
-       struct afs_call *call;
-       size_t ncallbacks;
-       __be32 *bp, *tp;
-       int loop;
-
-       ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
-                             ARRAY_SIZE(server->cb_break));
-
-       _enter("{%zu},", ncallbacks);
-
-       if (ncallbacks == 0)
-               return 0;
-       if (ncallbacks > AFSCBMAX)
-               ncallbacks = AFSCBMAX;
-
-       _debug("break %zu callbacks", ncallbacks);
-
-       call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
-                                  12 + ncallbacks * 6 * 4, 0);
-       if (!call)
-               return -ENOMEM;
-
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
-
-       /* marshall the parameters */
-       bp = call->request;
-       tp = bp + 2 + ncallbacks * 3;
-       *bp++ = htonl(FSGIVEUPCALLBACKS);
-       *bp++ = htonl(ncallbacks);
-       *tp++ = htonl(ncallbacks);
-
-       atomic_sub(ncallbacks, &server->cb_break_n);
-       for (loop = ncallbacks; loop > 0; loop--) {
-               struct afs_callback *cb =
-                       &server->cb_break[server->cb_break_tail];
-
-               *bp++ = htonl(cb->fid.vid);
-               *bp++ = htonl(cb->fid.vnode);
-               *bp++ = htonl(cb->fid.unique);
-               *tp++ = htonl(cb->version);
-               *tp++ = htonl(cb->expiry);
-               *tp++ = htonl(cb->type);
-               smp_mb();
-               server->cb_break_tail =
-                       (server->cb_break_tail + 1) &
-                       (ARRAY_SIZE(server->cb_break) - 1);
-       }
-
-       ASSERT(ncallbacks > 0);
-       wake_up_nr(&server->cb_break_waitq, ncallbacks);
-
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       call->cb_break = fc->cb_break;
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
@@ -653,7 +599,7 @@ int afs_fs_give_up_callbacks(struct afs_server *server,
  */
 static int afs_deliver_fs_create_vnode(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply;
+       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -665,11 +611,11 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_AFSFid(&bp, call->reply2);
-       xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
+       xdr_decode_AFSFid(&bp, call->reply[1]);
+       xdr_decode_AFSFetchStatus(&bp, call->reply[2], NULL, NULL);
        xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
-       xdr_decode_AFSCallBack_raw(&bp, call->reply4);
-       /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+       xdr_decode_AFSCallBack_raw(&bp, call->reply[3]);
+       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
        _leave(" = 0 [done]");
        return 0;
@@ -678,27 +624,33 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call)
 /*
  * FS.CreateFile and FS.MakeDir operation type
  */
-static const struct afs_call_type afs_RXFSCreateXXXX = {
-       .name           = "FS.CreateXXXX",
+static const struct afs_call_type afs_RXFSCreateFile = {
+       .name           = "FS.CreateFile",
+       .op             = afs_FS_CreateFile,
+       .deliver        = afs_deliver_fs_create_vnode,
+       .destructor     = afs_flat_call_destructor,
+};
+
+static const struct afs_call_type afs_RXFSMakeDir = {
+       .name           = "FS.MakeDir",
+       .op             = afs_FS_MakeDir,
        .deliver        = afs_deliver_fs_create_vnode,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 /*
  * create a file or make a directory
  */
-int afs_fs_create(struct afs_server *server,
-                 struct key *key,
-                 struct afs_vnode *vnode,
+int afs_fs_create(struct afs_fs_cursor *fc,
                  const char *name,
                  umode_t mode,
                  struct afs_fid *newfid,
                  struct afs_file_status *newstatus,
-                 struct afs_callback *newcb,
-                 bool async)
+                 struct afs_callback *newcb)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        size_t namesz, reqsz, padsz;
        __be32 *bp;
 
@@ -708,18 +660,17 @@ int afs_fs_create(struct afs_server *server,
        padsz = (4 - (namesz & 3)) & 3;
        reqsz = (5 * 4) + namesz + padsz + (6 * 4);
 
-       call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
-                                  (3 + 21 + 21 + 3 + 6) * 4);
+       call = afs_alloc_flat_call(
+               net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile,
+               reqsz, (3 + 21 + 21 + 3 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->reply2 = newfid;
-       call->reply3 = newstatus;
-       call->reply4 = newcb;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = vnode;
+       call->reply[1] = newfid;
+       call->reply[2] = newstatus;
+       call->reply[3] = newcb;
 
        /* marshall the parameters */
        bp = call->request;
@@ -741,7 +692,9 @@ int afs_fs_create(struct afs_server *server,
        *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
        *bp++ = 0; /* segment size */
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
@@ -749,7 +702,7 @@ int afs_fs_create(struct afs_server *server,
  */
 static int afs_deliver_fs_remove(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply;
+       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -762,7 +715,7 @@ static int afs_deliver_fs_remove(struct afs_call *call)
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
        xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
-       /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
        _leave(" = 0 [done]");
        return 0;
@@ -771,24 +724,28 @@ static int afs_deliver_fs_remove(struct afs_call *call)
 /*
  * FS.RemoveDir/FS.RemoveFile operation type
  */
-static const struct afs_call_type afs_RXFSRemoveXXXX = {
-       .name           = "FS.RemoveXXXX",
+static const struct afs_call_type afs_RXFSRemoveFile = {
+       .name           = "FS.RemoveFile",
+       .op             = afs_FS_RemoveFile,
+       .deliver        = afs_deliver_fs_remove,
+       .destructor     = afs_flat_call_destructor,
+};
+
+static const struct afs_call_type afs_RXFSRemoveDir = {
+       .name           = "FS.RemoveDir",
+       .op             = afs_FS_RemoveDir,
        .deliver        = afs_deliver_fs_remove,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 /*
  * remove a file or directory
  */
-int afs_fs_remove(struct afs_server *server,
-                 struct key *key,
-                 struct afs_vnode *vnode,
-                 const char *name,
-                 bool isdir,
-                 bool async)
+int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        size_t namesz, reqsz, padsz;
        __be32 *bp;
 
@@ -798,14 +755,14 @@ int afs_fs_remove(struct afs_server *server,
        padsz = (4 - (namesz & 3)) & 3;
        reqsz = (5 * 4) + namesz + padsz;
 
-       call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
+       call = afs_alloc_flat_call(
+               net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile,
+               reqsz, (21 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = vnode;
 
        /* marshall the parameters */
        bp = call->request;
@@ -821,7 +778,9 @@ int afs_fs_remove(struct afs_server *server,
                bp = (void *) bp + padsz;
        }
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
@@ -829,7 +788,7 @@ int afs_fs_remove(struct afs_server *server,
  */
 static int afs_deliver_fs_link(struct afs_call *call)
 {
-       struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
+       struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1];
        const __be32 *bp;
        int ret;
 
@@ -843,7 +802,7 @@ static int afs_deliver_fs_link(struct afs_call *call)
        bp = call->buffer;
        xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
        xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
-       /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
        _leave(" = 0 [done]");
        return 0;
@@ -854,22 +813,20 @@ static int afs_deliver_fs_link(struct afs_call *call)
  */
 static const struct afs_call_type afs_RXFSLink = {
        .name           = "FS.Link",
+       .op             = afs_FS_Link,
        .deliver        = afs_deliver_fs_link,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 /*
  * make a hard link
  */
-int afs_fs_link(struct afs_server *server,
-               struct key *key,
-               struct afs_vnode *dvnode,
-               struct afs_vnode *vnode,
-               const char *name,
-               bool async)
+int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
+               const char *name)
 {
+       struct afs_vnode *dvnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        size_t namesz, reqsz, padsz;
        __be32 *bp;
 
@@ -879,15 +836,13 @@ int afs_fs_link(struct afs_server *server,
        padsz = (4 - (namesz & 3)) & 3;
        reqsz = (5 * 4) + namesz + padsz + (3 * 4);
 
-       call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
+       call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = dvnode;
-       call->reply2 = vnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = dvnode;
+       call->reply[1] = vnode;
 
        /* marshall the parameters */
        bp = call->request;
@@ -906,7 +861,9 @@ int afs_fs_link(struct afs_server *server,
        *bp++ = htonl(vnode->fid.vnode);
        *bp++ = htonl(vnode->fid.unique);
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
@@ -914,7 +871,7 @@ int afs_fs_link(struct afs_server *server,
  */
 static int afs_deliver_fs_symlink(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply;
+       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -926,10 +883,10 @@ static int afs_deliver_fs_symlink(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_AFSFid(&bp, call->reply2);
-       xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
+       xdr_decode_AFSFid(&bp, call->reply[1]);
+       xdr_decode_AFSFetchStatus(&bp, call->reply[2], NULL, NULL);
        xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
-       /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
        _leave(" = 0 [done]");
        return 0;
@@ -940,24 +897,23 @@ static int afs_deliver_fs_symlink(struct afs_call *call)
  */
 static const struct afs_call_type afs_RXFSSymlink = {
        .name           = "FS.Symlink",
+       .op             = afs_FS_Symlink,
        .deliver        = afs_deliver_fs_symlink,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 /*
  * create a symbolic link
  */
-int afs_fs_symlink(struct afs_server *server,
-                  struct key *key,
-                  struct afs_vnode *vnode,
+int afs_fs_symlink(struct afs_fs_cursor *fc,
                   const char *name,
                   const char *contents,
                   struct afs_fid *newfid,
-                  struct afs_file_status *newstatus,
-                  bool async)
+                  struct afs_file_status *newstatus)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        size_t namesz, reqsz, padsz, c_namesz, c_padsz;
        __be32 *bp;
 
@@ -971,17 +927,15 @@ int afs_fs_symlink(struct afs_server *server,
 
        reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
 
-       call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
+       call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz,
                                   (3 + 21 + 21 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->reply2 = newfid;
-       call->reply3 = newstatus;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = vnode;
+       call->reply[1] = newfid;
+       call->reply[2] = newstatus;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1010,7 +964,9 @@ int afs_fs_symlink(struct afs_server *server,
        *bp++ = htonl(S_IRWXUGO); /* unix mode */
        *bp++ = 0; /* segment size */
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
@@ -1018,7 +974,7 @@ int afs_fs_symlink(struct afs_server *server,
  */
 static int afs_deliver_fs_rename(struct afs_call *call)
 {
-       struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
+       struct afs_vnode *orig_dvnode = call->reply[0], *new_dvnode = call->reply[1];
        const __be32 *bp;
        int ret;
 
@@ -1034,7 +990,7 @@ static int afs_deliver_fs_rename(struct afs_call *call)
        if (new_dvnode != orig_dvnode)
                xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
                                          NULL);
-       /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
        _leave(" = 0 [done]");
        return 0;
@@ -1045,23 +1001,22 @@ static int afs_deliver_fs_rename(struct afs_call *call)
  */
 static const struct afs_call_type afs_RXFSRename = {
        .name           = "FS.Rename",
+       .op             = afs_FS_Rename,
        .deliver        = afs_deliver_fs_rename,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 /*
  * create a symbolic link
  */
-int afs_fs_rename(struct afs_server *server,
-                 struct key *key,
-                 struct afs_vnode *orig_dvnode,
+int afs_fs_rename(struct afs_fs_cursor *fc,
                  const char *orig_name,
                  struct afs_vnode *new_dvnode,
-                 const char *new_name,
-                 bool async)
+                 const char *new_name)
 {
+       struct afs_vnode *orig_dvnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(orig_dvnode);
        size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
        __be32 *bp;
 
@@ -1078,15 +1033,13 @@ int afs_fs_rename(struct afs_server *server,
                (3 * 4) +
                4 + n_namesz + n_padsz;
 
-       call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
+       call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = orig_dvnode;
-       call->reply2 = new_dvnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = orig_dvnode;
+       call->reply[1] = new_dvnode;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1113,7 +1066,9 @@ int afs_fs_rename(struct afs_server *server,
                bp = (void *) bp + n_padsz;
        }
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &orig_dvnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
@@ -1121,7 +1076,7 @@ int afs_fs_rename(struct afs_server *server,
  */
 static int afs_deliver_fs_store_data(struct afs_call *call)
 {
-       struct afs_vnode *vnode = call->reply;
+       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -1135,7 +1090,7 @@ static int afs_deliver_fs_store_data(struct afs_call *call)
        bp = call->buffer;
        xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
                                  &call->store_version);
-       /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
        afs_pages_written_back(vnode, call);
 
@@ -1148,47 +1103,44 @@ static int afs_deliver_fs_store_data(struct afs_call *call)
  */
 static const struct afs_call_type afs_RXFSStoreData = {
        .name           = "FS.StoreData",
+       .op             = afs_FS_StoreData,
        .deliver        = afs_deliver_fs_store_data,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 static const struct afs_call_type afs_RXFSStoreData64 = {
        .name           = "FS.StoreData64",
+       .op             = afs_FS_StoreData64,
        .deliver        = afs_deliver_fs_store_data,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 /*
  * store a set of pages to a very large file
  */
-static int afs_fs_store_data64(struct afs_server *server,
-                              struct afs_writeback *wb,
+static int afs_fs_store_data64(struct afs_fs_cursor *fc,
+                              struct address_space *mapping,
                               pgoff_t first, pgoff_t last,
                               unsigned offset, unsigned to,
-                              loff_t size, loff_t pos, loff_t i_size,
-                              bool async)
+                              loff_t size, loff_t pos, loff_t i_size)
 {
-       struct afs_vnode *vnode = wb->vnode;
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
        _enter(",%x,{%x:%u},,",
-              key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
 
-       call = afs_alloc_flat_call(&afs_RXFSStoreData64,
+       call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
                                   (4 + 6 + 3 * 2) * 4,
                                   (21 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->wb = wb;
-       call->key = wb->key;
-       call->reply = vnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
-       call->mapping = vnode->vfs_inode.i_mapping;
+       call->key = fc->key;
+       call->mapping = mapping;
+       call->reply[0] = vnode;
        call->first = first;
        call->last = last;
        call->first_offset = offset;
@@ -1217,24 +1169,25 @@ static int afs_fs_store_data64(struct afs_server *server,
        *bp++ = htonl(i_size >> 32);
        *bp++ = htonl((u32) i_size);
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
  * store a set of pages
  */
-int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
+int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
                      pgoff_t first, pgoff_t last,
-                     unsigned offset, unsigned to,
-                     bool async)
+                     unsigned offset, unsigned to)
 {
-       struct afs_vnode *vnode = wb->vnode;
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        loff_t size, pos, i_size;
        __be32 *bp;
 
        _enter(",%x,{%x:%u},,",
-              key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
 
        size = (loff_t)to - (loff_t)offset;
        if (first != last)
@@ -1251,21 +1204,18 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
               (unsigned long long) i_size);
 
        if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
-               return afs_fs_store_data64(server, wb, first, last, offset, to,
-                                          size, pos, i_size, async);
+               return afs_fs_store_data64(fc, mapping, first, last, offset, to,
+                                          size, pos, i_size);
 
-       call = afs_alloc_flat_call(&afs_RXFSStoreData,
+       call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
                                   (4 + 6 + 3) * 4,
                                   (21 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->wb = wb;
-       call->key = wb->key;
-       call->reply = vnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
-       call->mapping = vnode->vfs_inode.i_mapping;
+       call->key = fc->key;
+       call->mapping = mapping;
+       call->reply[0] = vnode;
        call->first = first;
        call->last = last;
        call->first_offset = offset;
@@ -1291,7 +1241,9 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
        *bp++ = htonl(size);
        *bp++ = htonl(i_size);
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
@@ -1300,7 +1252,7 @@ int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
 static int afs_deliver_fs_store_status(struct afs_call *call)
 {
        afs_dataversion_t *store_version;
-       struct afs_vnode *vnode = call->reply;
+       struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
        int ret;
 
@@ -1317,7 +1269,7 @@ static int afs_deliver_fs_store_status(struct afs_call *call)
 
        bp = call->buffer;
        xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
-       /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
        _leave(" = 0 [done]");
        return 0;
@@ -1328,22 +1280,22 @@ static int afs_deliver_fs_store_status(struct afs_call *call)
  */
 static const struct afs_call_type afs_RXFSStoreStatus = {
        .name           = "FS.StoreStatus",
+       .op             = afs_FS_StoreStatus,
        .deliver        = afs_deliver_fs_store_status,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 static const struct afs_call_type afs_RXFSStoreData_as_Status = {
        .name           = "FS.StoreData",
+       .op             = afs_FS_StoreData,
        .deliver        = afs_deliver_fs_store_status,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
        .name           = "FS.StoreData64",
+       .op             = afs_FS_StoreData64,
        .deliver        = afs_deliver_fs_store_status,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
@@ -1351,30 +1303,27 @@ static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
  * set the attributes on a very large file, using FS.StoreData rather than
  * FS.StoreStatus so as to alter the file size also
  */
-static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
-                                struct afs_vnode *vnode, struct iattr *attr,
-                                bool async)
+static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
        _enter(",%x,{%x:%u},,",
-              key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
 
        ASSERT(attr->ia_valid & ATTR_SIZE);
 
-       call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
+       call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status,
                                   (4 + 6 + 3 * 2) * 4,
                                   (21 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = vnode;
        call->store_version = vnode->status.data_version + 1;
-       call->operation_ID = FSSTOREDATA;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1392,40 +1341,38 @@ static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
        *bp++ = htonl(attr->ia_size >> 32);     /* new file length */
        *bp++ = htonl((u32) attr->ia_size);
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
  * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
  * so as to alter the file size also
  */
-static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
-                              struct afs_vnode *vnode, struct iattr *attr,
-                              bool async)
+static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
        _enter(",%x,{%x:%u},,",
-              key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
 
        ASSERT(attr->ia_valid & ATTR_SIZE);
        if (attr->ia_size >> 32)
-               return afs_fs_setattr_size64(server, key, vnode, attr,
-                                            async);
+               return afs_fs_setattr_size64(fc, attr);
 
-       call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
+       call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
                                   (4 + 6 + 3) * 4,
                                   (21 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = vnode;
        call->store_version = vnode->status.data_version + 1;
-       call->operation_ID = FSSTOREDATA;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1440,38 +1387,36 @@ static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
        *bp++ = 0;                              /* size of write */
        *bp++ = htonl(attr->ia_size);           /* new file length */
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
  * set the attributes on a file, using FS.StoreData if there's a change in file
  * size, and FS.StoreStatus otherwise
  */
-int afs_fs_setattr(struct afs_server *server, struct key *key,
-                  struct afs_vnode *vnode, struct iattr *attr,
-                  bool async)
+int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
        if (attr->ia_valid & ATTR_SIZE)
-               return afs_fs_setattr_size(server, key, vnode, attr,
-                                          async);
+               return afs_fs_setattr_size(fc, attr);
 
        _enter(",%x,{%x:%u},,",
-              key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
 
-       call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
+       call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus,
                                   (4 + 6) * 4,
                                   (21 + 6) * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
-       call->operation_ID = FSSTORESTATUS;
+       call->key = fc->key;
+       call->reply[0] = vnode;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1482,7 +1427,9 @@ int afs_fs_setattr(struct afs_server *server, struct key *key,
 
        xdr_encode_AFS_StoreStatus(&bp, attr);
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
@@ -1510,7 +1457,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2);
+               xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]);
                call->offset = 0;
                call->unmarshall++;
 
@@ -1531,13 +1478,13 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
        case 3:
                _debug("extract volname");
                if (call->count > 0) {
-                       ret = afs_extract_data(call, call->reply3,
+                       ret = afs_extract_data(call, call->reply[2],
                                               call->count, true);
                        if (ret < 0)
                                return ret;
                }
 
-               p = call->reply3;
+               p = call->reply[2];
                p[call->count] = 0;
                _debug("volname '%s'", p);
 
@@ -1578,13 +1525,13 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
        case 6:
                _debug("extract offline");
                if (call->count > 0) {
-                       ret = afs_extract_data(call, call->reply3,
+                       ret = afs_extract_data(call, call->reply[2],
                                               call->count, true);
                        if (ret < 0)
                                return ret;
                }
 
-               p = call->reply3;
+               p = call->reply[2];
                p[call->count] = 0;
                _debug("offline '%s'", p);
 
@@ -1625,13 +1572,13 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
        case 9:
                _debug("extract motd");
                if (call->count > 0) {
-                       ret = afs_extract_data(call, call->reply3,
+                       ret = afs_extract_data(call, call->reply[2],
                                               call->count, true);
                        if (ret < 0)
                                return ret;
                }
 
-               p = call->reply3;
+               p = call->reply[2];
                p[call->count] = 0;
                _debug("motd '%s'", p);
 
@@ -1662,8 +1609,8 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
  */
 static void afs_get_volume_status_call_destructor(struct afs_call *call)
 {
-       kfree(call->reply3);
-       call->reply3 = NULL;
+       kfree(call->reply[2]);
+       call->reply[2] = NULL;
        afs_flat_call_destructor(call);
 }
 
@@ -1672,21 +1619,20 @@ static void afs_get_volume_status_call_destructor(struct afs_call *call)
  */
 static const struct afs_call_type afs_RXFSGetVolumeStatus = {
        .name           = "FS.GetVolumeStatus",
+       .op             = afs_FS_GetVolumeStatus,
        .deliver        = afs_deliver_fs_get_volume_status,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_get_volume_status_call_destructor,
 };
 
 /*
  * fetch the status of a volume
  */
-int afs_fs_get_volume_status(struct afs_server *server,
-                            struct key *key,
-                            struct afs_vnode *vnode,
-                            struct afs_volume_status *vs,
-                            bool async)
+int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
+                            struct afs_volume_status *vs)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
        void *tmpbuf;
 
@@ -1696,25 +1642,25 @@ int afs_fs_get_volume_status(struct afs_server *server,
        if (!tmpbuf)
                return -ENOMEM;
 
-       call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
+       call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
        if (!call) {
                kfree(tmpbuf);
                return -ENOMEM;
        }
 
-       call->key = key;
-       call->reply = vnode;
-       call->reply2 = vs;
-       call->reply3 = tmpbuf;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = vnode;
+       call->reply[1] = vs;
+       call->reply[2] = tmpbuf;
 
        /* marshall the parameters */
        bp = call->request;
        bp[0] = htonl(FSGETVOLUMESTATUS);
        bp[1] = htonl(vnode->fid.vid);
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
@@ -1733,7 +1679,7 @@ static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+       /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
        _leave(" = 0 [done]");
        return 0;
@@ -1744,8 +1690,8 @@ static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
  */
 static const struct afs_call_type afs_RXFSSetLock = {
        .name           = "FS.SetLock",
+       .op             = afs_FS_SetLock,
        .deliver        = afs_deliver_fs_xxxx_lock,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
@@ -1754,8 +1700,8 @@ static const struct afs_call_type afs_RXFSSetLock = {
  */
 static const struct afs_call_type afs_RXFSExtendLock = {
        .name           = "FS.ExtendLock",
+       .op             = afs_FS_ExtendLock,
        .deliver        = afs_deliver_fs_xxxx_lock,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
@@ -1764,33 +1710,29 @@ static const struct afs_call_type afs_RXFSExtendLock = {
  */
 static const struct afs_call_type afs_RXFSReleaseLock = {
        .name           = "FS.ReleaseLock",
+       .op             = afs_FS_ReleaseLock,
        .deliver        = afs_deliver_fs_xxxx_lock,
-       .abort_to_error = afs_abort_to_error,
        .destructor     = afs_flat_call_destructor,
 };
 
 /*
- * get a lock on a file
+ * Set a lock on a file
  */
-int afs_fs_set_lock(struct afs_server *server,
-                   struct key *key,
-                   struct afs_vnode *vnode,
-                   afs_lock_type_t type,
-                   bool async)
+int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
        _enter("");
 
-       call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 6 * 4);
+       call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = vnode;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1800,30 +1742,29 @@ int afs_fs_set_lock(struct afs_server *server,
        *bp++ = htonl(vnode->fid.unique);
        *bp++ = htonl(type);
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
  * extend a lock on a file
  */
-int afs_fs_extend_lock(struct afs_server *server,
-                      struct key *key,
-                      struct afs_vnode *vnode,
-                      bool async)
+int afs_fs_extend_lock(struct afs_fs_cursor *fc)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
        _enter("");
 
-       call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 6 * 4);
+       call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = vnode;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1832,30 +1773,29 @@ int afs_fs_extend_lock(struct afs_server *server,
        *bp++ = htonl(vnode->fid.vnode);
        *bp++ = htonl(vnode->fid.unique);
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
 }
 
 /*
  * release a lock on a file
  */
-int afs_fs_release_lock(struct afs_server *server,
-                       struct key *key,
-                       struct afs_vnode *vnode,
-                       bool async)
+int afs_fs_release_lock(struct afs_fs_cursor *fc)
 {
+       struct afs_vnode *vnode = fc->vnode;
        struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
        __be32 *bp;
 
        _enter("");
 
-       call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 6 * 4);
+       call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
        if (!call)
                return -ENOMEM;
 
-       call->key = key;
-       call->reply = vnode;
-       call->service_id = FS_SERVICE;
-       call->port = htons(AFS_FS_PORT);
+       call->key = fc->key;
+       call->reply[0] = vnode;
 
        /* marshall the parameters */
        bp = call->request;
@@ -1864,5 +1804,145 @@ int afs_fs_release_lock(struct afs_server *server,
        *bp++ = htonl(vnode->fid.vnode);
        *bp++ = htonl(vnode->fid.unique);
 
-       return afs_make_call(&server->addr, call, GFP_NOFS, async);
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+}
+
+/*
+ * Deliver reply data to an FS.GiveUpAllCallBacks operation.
+ */
+static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
+{
+       return afs_transfer_reply(call);
+}
+
+/*
+ * FS.GiveUpAllCallBacks operation type
+ */
+static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
+       .name           = "FS.GiveUpAllCallBacks",
+       .op             = afs_FS_GiveUpAllCallBacks,
+       .deliver        = afs_deliver_fs_give_up_all_callbacks,
+       .destructor     = afs_flat_call_destructor,
+};
+
+/*
+ * Flush all the callbacks we have on a server.
+ */
+int afs_fs_give_up_all_callbacks(struct afs_net *net,
+                                struct afs_server *server,
+                                struct afs_addr_cursor *ac,
+                                struct key *key)
+{
+       struct afs_call *call;
+       __be32 *bp;
+
+       _enter("");
+
+       call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
+       if (!call)
+               return -ENOMEM;
+
+       call->key = key;
+
+       /* marshall the parameters */
+       bp = call->request;
+       *bp++ = htonl(FSGIVEUPALLCALLBACKS);
+
+       /* Can't take a ref on server */
+       return afs_make_call(ac, call, GFP_NOFS, false);
+}
+
+/*
+ * Deliver reply data to an FS.GetCapabilities operation.
+ */
+static int afs_deliver_fs_get_capabilities(struct afs_call *call)
+{
+       u32 count;
+       int ret;
+
+       _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
+
+again:
+       switch (call->unmarshall) {
+       case 0:
+               call->offset = 0;
+               call->unmarshall++;
+
+               /* Extract the capabilities word count */
+       case 1:
+               ret = afs_extract_data(call, &call->tmp,
+                                      1 * sizeof(__be32),
+                                      true);
+               if (ret < 0)
+                       return ret;
+
+               count = ntohl(call->tmp);
+
+               call->count = count;
+               call->count2 = count;
+               call->offset = 0;
+               call->unmarshall++;
+
+               /* Extract capabilities words */
+       case 2:
+               count = min(call->count, 16U);
+               ret = afs_extract_data(call, call->buffer,
+                                      count * sizeof(__be32),
+                                      call->count > 16);
+               if (ret < 0)
+                       return ret;
+
+               /* TODO: Examine capabilities */
+
+               call->count -= count;
+               if (call->count > 0)
+                       goto again;
+               call->offset = 0;
+               call->unmarshall++;
+               break;
+       }
+
+       _leave(" = 0 [done]");
+       return 0;
+}
+
+/*
+ * FS.GetCapabilities operation type
+ */
+static const struct afs_call_type afs_RXFSGetCapabilities = {
+       .name           = "FS.GetCapabilities",
+       .op             = afs_FS_GetCapabilities,
+       .deliver        = afs_deliver_fs_get_capabilities,
+       .destructor     = afs_flat_call_destructor,
+};
+
+/*
+ * Probe a fileserver for the capabilities that it supports.  This can
+ * return up to 196 words.
+ */
+int afs_fs_get_capabilities(struct afs_net *net,
+                           struct afs_server *server,
+                           struct afs_addr_cursor *ac,
+                           struct key *key)
+{
+       struct afs_call *call;
+       __be32 *bp;
+
+       _enter("");
+
+       call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
+       if (!call)
+               return -ENOMEM;
+
+       call->key = key;
+
+       /* marshall the parameters */
+       bp = call->request;
+       *bp++ = htonl(FSGETCAPABILITIES);
+
+       /* Can't take a ref on server */
+       trace_afs_make_fs_call(call, NULL);
+       return afs_make_call(ac, call, GFP_NOFS, false);
 }