108e0e7c8SDavid Howells /* AFS File Server client stubs 21da177e4SLinus Torvalds * 308e0e7c8SDavid Howells * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. 41da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/init.h> 131da177e4SLinus Torvalds #include <linux/sched.h> 1408e0e7c8SDavid Howells #include <linux/circ_buf.h> 151da177e4SLinus Torvalds #include "internal.h" 1608e0e7c8SDavid Howells #include "afs_fs.h" 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds /* 1908e0e7c8SDavid Howells * decode an AFSFetchStatus block 201da177e4SLinus Torvalds */ 2108e0e7c8SDavid Howells static void xdr_decode_AFSFetchStatus(const __be32 **_bp, 2208e0e7c8SDavid Howells struct afs_vnode *vnode) 231da177e4SLinus Torvalds { 2408e0e7c8SDavid Howells const __be32 *bp = *_bp; 2508e0e7c8SDavid Howells umode_t mode; 2608e0e7c8SDavid Howells u64 data_version; 2708e0e7c8SDavid Howells u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ 2808e0e7c8SDavid Howells 2908e0e7c8SDavid Howells #define EXTRACT(DST) \ 3008e0e7c8SDavid Howells do { \ 3108e0e7c8SDavid Howells u32 x = ntohl(*bp++); \ 3208e0e7c8SDavid Howells changed |= DST - x; \ 3308e0e7c8SDavid Howells DST = x; \ 3408e0e7c8SDavid Howells } while (0) 3508e0e7c8SDavid Howells 3608e0e7c8SDavid Howells vnode->status.if_version = ntohl(*bp++); 3708e0e7c8SDavid Howells EXTRACT(vnode->status.type); 3808e0e7c8SDavid Howells vnode->status.nlink = ntohl(*bp++); 3908e0e7c8SDavid Howells EXTRACT(vnode->status.size); 4008e0e7c8SDavid Howells data_version = ntohl(*bp++); 4108e0e7c8SDavid Howells EXTRACT(vnode->status.author); 4208e0e7c8SDavid Howells EXTRACT(vnode->status.owner); 4308e0e7c8SDavid Howells EXTRACT(vnode->status.caller_access); /* call ticket dependent */ 4408e0e7c8SDavid Howells EXTRACT(vnode->status.anon_access); 4508e0e7c8SDavid Howells EXTRACT(vnode->status.mode); 4608e0e7c8SDavid Howells vnode->status.parent.vid = vnode->fid.vid; 4708e0e7c8SDavid Howells EXTRACT(vnode->status.parent.vnode); 4808e0e7c8SDavid Howells EXTRACT(vnode->status.parent.unique); 4908e0e7c8SDavid Howells bp++; /* seg size */ 5008e0e7c8SDavid Howells vnode->status.mtime_client = ntohl(*bp++); 5108e0e7c8SDavid Howells vnode->status.mtime_server = ntohl(*bp++); 5208e0e7c8SDavid Howells bp++; /* group */ 5308e0e7c8SDavid Howells bp++; /* sync counter */ 5408e0e7c8SDavid Howells data_version |= (u64) ntohl(*bp++) << 32; 5508e0e7c8SDavid Howells bp++; /* spare2 */ 5608e0e7c8SDavid Howells bp++; /* spare3 */ 5708e0e7c8SDavid Howells bp++; /* spare4 */ 5808e0e7c8SDavid Howells *_bp = bp; 5908e0e7c8SDavid Howells 6008e0e7c8SDavid Howells if (changed) { 6108e0e7c8SDavid Howells _debug("vnode changed"); 6208e0e7c8SDavid Howells set_bit(AFS_VNODE_CHANGED, &vnode->flags); 6308e0e7c8SDavid Howells vnode->vfs_inode.i_uid = vnode->status.owner; 6408e0e7c8SDavid Howells vnode->vfs_inode.i_size = vnode->status.size; 6508e0e7c8SDavid Howells vnode->vfs_inode.i_version = vnode->fid.unique; 6608e0e7c8SDavid Howells 6708e0e7c8SDavid Howells vnode->status.mode &= S_IALLUGO; 6808e0e7c8SDavid Howells mode = vnode->vfs_inode.i_mode; 6908e0e7c8SDavid Howells mode &= ~S_IALLUGO; 7008e0e7c8SDavid Howells mode |= vnode->status.mode; 7108e0e7c8SDavid Howells vnode->vfs_inode.i_mode = mode; 7208e0e7c8SDavid Howells } 7308e0e7c8SDavid Howells 7408e0e7c8SDavid Howells _debug("vnode time %lx, %lx", 7508e0e7c8SDavid Howells vnode->status.mtime_client, vnode->status.mtime_server); 7608e0e7c8SDavid Howells vnode->vfs_inode.i_ctime.tv_sec = vnode->status.mtime_server; 7708e0e7c8SDavid Howells vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; 7808e0e7c8SDavid Howells vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; 7908e0e7c8SDavid Howells 8008e0e7c8SDavid Howells if (vnode->status.data_version != data_version) { 8108e0e7c8SDavid Howells _debug("vnode modified %llx", data_version); 8208e0e7c8SDavid Howells vnode->status.data_version = data_version; 8308e0e7c8SDavid Howells set_bit(AFS_VNODE_MODIFIED, &vnode->flags); 8408e0e7c8SDavid Howells set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 851da177e4SLinus Torvalds } 86ec26815aSDavid Howells } 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds /* 8908e0e7c8SDavid Howells * decode an AFSCallBack block 901da177e4SLinus Torvalds */ 9108e0e7c8SDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode) 921da177e4SLinus Torvalds { 9308e0e7c8SDavid Howells const __be32 *bp = *_bp; 941da177e4SLinus Torvalds 9508e0e7c8SDavid Howells vnode->cb_version = ntohl(*bp++); 9608e0e7c8SDavid Howells vnode->cb_expiry = ntohl(*bp++); 9708e0e7c8SDavid Howells vnode->cb_type = ntohl(*bp++); 9808e0e7c8SDavid Howells vnode->cb_expires = vnode->cb_expiry + get_seconds(); 9908e0e7c8SDavid Howells *_bp = bp; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds /* 10308e0e7c8SDavid Howells * decode an AFSVolSync block 1041da177e4SLinus Torvalds */ 10508e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp, 10608e0e7c8SDavid Howells struct afs_volsync *volsync) 1071da177e4SLinus Torvalds { 10808e0e7c8SDavid Howells const __be32 *bp = *_bp; 1091da177e4SLinus Torvalds 11008e0e7c8SDavid Howells volsync->creation = ntohl(*bp++); 11108e0e7c8SDavid Howells bp++; /* spare2 */ 11208e0e7c8SDavid Howells bp++; /* spare3 */ 11308e0e7c8SDavid Howells bp++; /* spare4 */ 11408e0e7c8SDavid Howells bp++; /* spare5 */ 11508e0e7c8SDavid Howells bp++; /* spare6 */ 11608e0e7c8SDavid Howells *_bp = bp; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 11908e0e7c8SDavid Howells /* 12008e0e7c8SDavid Howells * deliver reply data to an FS.FetchStatus 12108e0e7c8SDavid Howells */ 12208e0e7c8SDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call, 12308e0e7c8SDavid Howells struct sk_buff *skb, bool last) 12408e0e7c8SDavid Howells { 12508e0e7c8SDavid Howells const __be32 *bp; 1261da177e4SLinus Torvalds 12708e0e7c8SDavid Howells _enter(",,%u", last); 1281da177e4SLinus Torvalds 12908e0e7c8SDavid Howells afs_transfer_reply(call, skb); 13008e0e7c8SDavid Howells if (!last) 13108e0e7c8SDavid Howells return 0; 1321da177e4SLinus Torvalds 13308e0e7c8SDavid Howells if (call->reply_size != call->reply_max) 13408e0e7c8SDavid Howells return -EBADMSG; 1351da177e4SLinus Torvalds 13608e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */ 13708e0e7c8SDavid Howells bp = call->buffer; 13808e0e7c8SDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply); 13908e0e7c8SDavid Howells xdr_decode_AFSCallBack(&bp, call->reply); 14008e0e7c8SDavid Howells if (call->reply2) 14108e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 1421da177e4SLinus Torvalds 14308e0e7c8SDavid Howells _leave(" = 0 [done]"); 14408e0e7c8SDavid Howells return 0; 145ec26815aSDavid Howells } 14608e0e7c8SDavid Howells 14708e0e7c8SDavid Howells /* 14808e0e7c8SDavid Howells * FS.FetchStatus operation type 14908e0e7c8SDavid Howells */ 15008e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = { 15100d3b7a4SDavid Howells .name = "FS.FetchStatus", 15208e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_status, 15308e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 15408e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 15508e0e7c8SDavid Howells }; 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds /* 1581da177e4SLinus Torvalds * fetch the status information for a file 1591da177e4SLinus Torvalds */ 16008e0e7c8SDavid Howells int afs_fs_fetch_file_status(struct afs_server *server, 16100d3b7a4SDavid Howells struct key *key, 1621da177e4SLinus Torvalds struct afs_vnode *vnode, 16308e0e7c8SDavid Howells struct afs_volsync *volsync, 16408e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 1651da177e4SLinus Torvalds { 16608e0e7c8SDavid Howells struct afs_call *call; 1671da177e4SLinus Torvalds __be32 *bp; 1681da177e4SLinus Torvalds 16900d3b7a4SDavid Howells _enter(",%x,,,", key_serial(key)); 1701da177e4SLinus Torvalds 17108e0e7c8SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120); 17208e0e7c8SDavid Howells if (!call) 17308e0e7c8SDavid Howells return -ENOMEM; 1741da177e4SLinus Torvalds 17500d3b7a4SDavid Howells call->key = key; 17608e0e7c8SDavid Howells call->reply = vnode; 17708e0e7c8SDavid Howells call->reply2 = volsync; 17808e0e7c8SDavid Howells call->service_id = FS_SERVICE; 17908e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds /* marshall the parameters */ 18208e0e7c8SDavid Howells bp = call->request; 1831da177e4SLinus Torvalds bp[0] = htonl(FSFETCHSTATUS); 1841da177e4SLinus Torvalds bp[1] = htonl(vnode->fid.vid); 1851da177e4SLinus Torvalds bp[2] = htonl(vnode->fid.vnode); 1861da177e4SLinus Torvalds bp[3] = htonl(vnode->fid.unique); 1871da177e4SLinus Torvalds 18808e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 189ec26815aSDavid Howells } 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds /* 19208e0e7c8SDavid Howells * deliver reply data to an FS.FetchData 1931da177e4SLinus Torvalds */ 19408e0e7c8SDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call, 19508e0e7c8SDavid Howells struct sk_buff *skb, bool last) 1961da177e4SLinus Torvalds { 19708e0e7c8SDavid Howells const __be32 *bp; 19808e0e7c8SDavid Howells struct page *page; 19908e0e7c8SDavid Howells void *buffer; 2001da177e4SLinus Torvalds int ret; 2011da177e4SLinus Torvalds 20208e0e7c8SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 2031da177e4SLinus Torvalds 20408e0e7c8SDavid Howells switch (call->unmarshall) { 20508e0e7c8SDavid Howells case 0: 20608e0e7c8SDavid Howells call->offset = 0; 20708e0e7c8SDavid Howells call->unmarshall++; 2081da177e4SLinus Torvalds 20908e0e7c8SDavid Howells /* extract the returned data length */ 21008e0e7c8SDavid Howells case 1: 21108e0e7c8SDavid Howells _debug("extract data length"); 21208e0e7c8SDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 21308e0e7c8SDavid Howells switch (ret) { 21408e0e7c8SDavid Howells case 0: break; 21508e0e7c8SDavid Howells case -EAGAIN: return 0; 21608e0e7c8SDavid Howells default: return ret; 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 21908e0e7c8SDavid Howells call->count = ntohl(call->tmp); 22008e0e7c8SDavid Howells _debug("DATA length: %u", call->count); 22108e0e7c8SDavid Howells if (call->count > PAGE_SIZE) 22208e0e7c8SDavid Howells return -EBADMSG; 22308e0e7c8SDavid Howells call->offset = 0; 22408e0e7c8SDavid Howells call->unmarshall++; 2251da177e4SLinus Torvalds 22608e0e7c8SDavid Howells if (call->count < PAGE_SIZE) { 22708e0e7c8SDavid Howells buffer = kmap_atomic(call->reply3, KM_USER0); 22808e0e7c8SDavid Howells memset(buffer + PAGE_SIZE - call->count, 0, 22908e0e7c8SDavid Howells call->count); 23008e0e7c8SDavid Howells kunmap_atomic(buffer, KM_USER0); 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 23308e0e7c8SDavid Howells /* extract the returned data */ 23408e0e7c8SDavid Howells case 2: 23508e0e7c8SDavid Howells _debug("extract data"); 23608e0e7c8SDavid Howells page = call->reply3; 23708e0e7c8SDavid Howells buffer = kmap_atomic(page, KM_USER0); 23808e0e7c8SDavid Howells ret = afs_extract_data(call, skb, last, buffer, call->count); 23908e0e7c8SDavid Howells kunmap_atomic(buffer, KM_USER0); 24008e0e7c8SDavid Howells switch (ret) { 24108e0e7c8SDavid Howells case 0: break; 24208e0e7c8SDavid Howells case -EAGAIN: return 0; 24308e0e7c8SDavid Howells default: return ret; 2441da177e4SLinus Torvalds } 2451da177e4SLinus Torvalds 24608e0e7c8SDavid Howells call->offset = 0; 24708e0e7c8SDavid Howells call->unmarshall++; 24808e0e7c8SDavid Howells 24908e0e7c8SDavid Howells /* extract the metadata */ 25008e0e7c8SDavid Howells case 3: 25108e0e7c8SDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 120); 25208e0e7c8SDavid Howells switch (ret) { 25308e0e7c8SDavid Howells case 0: break; 25408e0e7c8SDavid Howells case -EAGAIN: return 0; 25508e0e7c8SDavid Howells default: return ret; 256ec26815aSDavid Howells } 2571da177e4SLinus Torvalds 25808e0e7c8SDavid Howells bp = call->buffer; 25908e0e7c8SDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply); 26008e0e7c8SDavid Howells xdr_decode_AFSCallBack(&bp, call->reply); 26108e0e7c8SDavid Howells if (call->reply2) 26208e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 2631da177e4SLinus Torvalds 26408e0e7c8SDavid Howells call->offset = 0; 26508e0e7c8SDavid Howells call->unmarshall++; 2661da177e4SLinus Torvalds 26708e0e7c8SDavid Howells case 4: 26808e0e7c8SDavid Howells _debug("trailer"); 26908e0e7c8SDavid Howells if (skb->len != 0) 27008e0e7c8SDavid Howells return -EBADMSG; 2711da177e4SLinus Torvalds break; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds 27408e0e7c8SDavid Howells if (!last) 27508e0e7c8SDavid Howells return 0; 2761da177e4SLinus Torvalds 27708e0e7c8SDavid Howells _leave(" = 0 [done]"); 27808e0e7c8SDavid Howells return 0; 279ec26815aSDavid Howells } 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds /* 28208e0e7c8SDavid Howells * FS.FetchData operation type 2831da177e4SLinus Torvalds */ 28408e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = { 28500d3b7a4SDavid Howells .name = "FS.FetchData", 28608e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_data, 28708e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 28808e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 28908e0e7c8SDavid Howells }; 29008e0e7c8SDavid Howells 29108e0e7c8SDavid Howells /* 29208e0e7c8SDavid Howells * fetch data from a file 29308e0e7c8SDavid Howells */ 29408e0e7c8SDavid Howells int afs_fs_fetch_data(struct afs_server *server, 29500d3b7a4SDavid Howells struct key *key, 2961da177e4SLinus Torvalds struct afs_vnode *vnode, 29708e0e7c8SDavid Howells off_t offset, size_t length, 29808e0e7c8SDavid Howells struct page *buffer, 29908e0e7c8SDavid Howells struct afs_volsync *volsync, 30008e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 3011da177e4SLinus Torvalds { 30208e0e7c8SDavid Howells struct afs_call *call; 30308e0e7c8SDavid Howells __be32 *bp; 3041da177e4SLinus Torvalds 30508e0e7c8SDavid Howells _enter(""); 3061da177e4SLinus Torvalds 30708e0e7c8SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, 120); 30808e0e7c8SDavid Howells if (!call) 30908e0e7c8SDavid Howells return -ENOMEM; 3101da177e4SLinus Torvalds 31100d3b7a4SDavid Howells call->key = key; 31208e0e7c8SDavid Howells call->reply = vnode; 31308e0e7c8SDavid Howells call->reply2 = volsync; 31408e0e7c8SDavid Howells call->reply3 = buffer; 31508e0e7c8SDavid Howells call->service_id = FS_SERVICE; 31608e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds /* marshall the parameters */ 31908e0e7c8SDavid Howells bp = call->request; 32008e0e7c8SDavid Howells bp[0] = htonl(FSFETCHDATA); 32108e0e7c8SDavid Howells bp[1] = htonl(vnode->fid.vid); 32208e0e7c8SDavid Howells bp[2] = htonl(vnode->fid.vnode); 32308e0e7c8SDavid Howells bp[3] = htonl(vnode->fid.unique); 32408e0e7c8SDavid Howells bp[4] = htonl(offset); 32508e0e7c8SDavid Howells bp[5] = htonl(length); 3261da177e4SLinus Torvalds 32708e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds 33008e0e7c8SDavid Howells /* 33108e0e7c8SDavid Howells * deliver reply data to an FS.GiveUpCallBacks 33208e0e7c8SDavid Howells */ 33308e0e7c8SDavid Howells static int afs_deliver_fs_give_up_callbacks(struct afs_call *call, 33408e0e7c8SDavid Howells struct sk_buff *skb, bool last) 33508e0e7c8SDavid Howells { 33608e0e7c8SDavid Howells _enter(",{%u},%d", skb->len, last); 3371da177e4SLinus Torvalds 33808e0e7c8SDavid Howells if (skb->len > 0) 33908e0e7c8SDavid Howells return -EBADMSG; /* shouldn't be any reply data */ 34008e0e7c8SDavid Howells return 0; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 34308e0e7c8SDavid Howells /* 34408e0e7c8SDavid Howells * FS.GiveUpCallBacks operation type 34508e0e7c8SDavid Howells */ 34608e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSGiveUpCallBacks = { 34700d3b7a4SDavid Howells .name = "FS.GiveUpCallBacks", 34808e0e7c8SDavid Howells .deliver = afs_deliver_fs_give_up_callbacks, 34908e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 35008e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 35108e0e7c8SDavid Howells }; 3521da177e4SLinus Torvalds 35308e0e7c8SDavid Howells /* 35408e0e7c8SDavid Howells * give up a set of callbacks 35508e0e7c8SDavid Howells * - the callbacks are held in the server->cb_break ring 35608e0e7c8SDavid Howells */ 35708e0e7c8SDavid Howells int afs_fs_give_up_callbacks(struct afs_server *server, 35808e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 35908e0e7c8SDavid Howells { 36008e0e7c8SDavid Howells struct afs_call *call; 36108e0e7c8SDavid Howells size_t ncallbacks; 36208e0e7c8SDavid Howells __be32 *bp, *tp; 36308e0e7c8SDavid Howells int loop; 3641da177e4SLinus Torvalds 36508e0e7c8SDavid Howells ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail, 36608e0e7c8SDavid Howells ARRAY_SIZE(server->cb_break)); 36708e0e7c8SDavid Howells 36808e0e7c8SDavid Howells _enter("{%zu},", ncallbacks); 36908e0e7c8SDavid Howells 37008e0e7c8SDavid Howells if (ncallbacks == 0) 37108e0e7c8SDavid Howells return 0; 37208e0e7c8SDavid Howells if (ncallbacks > AFSCBMAX) 37308e0e7c8SDavid Howells ncallbacks = AFSCBMAX; 37408e0e7c8SDavid Howells 37508e0e7c8SDavid Howells _debug("break %zu callbacks", ncallbacks); 37608e0e7c8SDavid Howells 37708e0e7c8SDavid Howells call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks, 37808e0e7c8SDavid Howells 12 + ncallbacks * 6 * 4, 0); 37908e0e7c8SDavid Howells if (!call) 38008e0e7c8SDavid Howells return -ENOMEM; 38108e0e7c8SDavid Howells 38208e0e7c8SDavid Howells call->service_id = FS_SERVICE; 38308e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 38408e0e7c8SDavid Howells 38508e0e7c8SDavid Howells /* marshall the parameters */ 38608e0e7c8SDavid Howells bp = call->request; 38708e0e7c8SDavid Howells tp = bp + 2 + ncallbacks * 3; 38808e0e7c8SDavid Howells *bp++ = htonl(FSGIVEUPCALLBACKS); 38908e0e7c8SDavid Howells *bp++ = htonl(ncallbacks); 39008e0e7c8SDavid Howells *tp++ = htonl(ncallbacks); 39108e0e7c8SDavid Howells 39208e0e7c8SDavid Howells atomic_sub(ncallbacks, &server->cb_break_n); 39308e0e7c8SDavid Howells for (loop = ncallbacks; loop > 0; loop--) { 39408e0e7c8SDavid Howells struct afs_callback *cb = 39508e0e7c8SDavid Howells &server->cb_break[server->cb_break_tail]; 39608e0e7c8SDavid Howells 39708e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vid); 39808e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vnode); 39908e0e7c8SDavid Howells *bp++ = htonl(cb->fid.unique); 40008e0e7c8SDavid Howells *tp++ = htonl(cb->version); 40108e0e7c8SDavid Howells *tp++ = htonl(cb->expiry); 40208e0e7c8SDavid Howells *tp++ = htonl(cb->type); 40308e0e7c8SDavid Howells smp_mb(); 40408e0e7c8SDavid Howells server->cb_break_tail = 40508e0e7c8SDavid Howells (server->cb_break_tail + 1) & 40608e0e7c8SDavid Howells (ARRAY_SIZE(server->cb_break) - 1); 407ec26815aSDavid Howells } 40808e0e7c8SDavid Howells 40908e0e7c8SDavid Howells ASSERT(ncallbacks > 0); 41008e0e7c8SDavid Howells wake_up_nr(&server->cb_break_waitq, ncallbacks); 41108e0e7c8SDavid Howells 41208e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 41308e0e7c8SDavid Howells } 414