| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 1 | /* AFS File Server client stubs | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | * | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 3 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4 | * Written by David Howells (dhowells@redhat.com) | 
|  | 5 | * | 
|  | 6 | * This program is free software; you can redistribute it and/or | 
|  | 7 | * modify it under the terms of the GNU General Public License | 
|  | 8 | * as published by the Free Software Foundation; either version | 
|  | 9 | * 2 of the License, or (at your option) any later version. | 
|  | 10 | */ | 
|  | 11 |  | 
|  | 12 | #include <linux/init.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 13 | #include <linux/slab.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 | #include <linux/sched.h> | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 15 | #include <linux/circ_buf.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 16 | #include "internal.h" | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 17 | #include "afs_fs.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 | /* | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 20 | * decode an AFSFid block | 
|  | 21 | */ | 
|  | 22 | static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) | 
|  | 23 | { | 
|  | 24 | const __be32 *bp = *_bp; | 
|  | 25 |  | 
|  | 26 | fid->vid		= ntohl(*bp++); | 
|  | 27 | fid->vnode		= ntohl(*bp++); | 
|  | 28 | fid->unique		= ntohl(*bp++); | 
|  | 29 | *_bp = bp; | 
|  | 30 | } | 
|  | 31 |  | 
|  | 32 | /* | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 33 | * decode an AFSFetchStatus block | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 34 | */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 35 | static void xdr_decode_AFSFetchStatus(const __be32 **_bp, | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 36 | struct afs_file_status *status, | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 37 | struct afs_vnode *vnode, | 
|  | 38 | afs_dataversion_t *store_version) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 | { | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 40 | afs_dataversion_t expected_version; | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 41 | const __be32 *bp = *_bp; | 
|  | 42 | umode_t mode; | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 43 | u64 data_version, size; | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 44 | u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ | 
|  | 45 |  | 
|  | 46 | #define EXTRACT(DST)				\ | 
|  | 47 | do {					\ | 
|  | 48 | u32 x = ntohl(*bp++);		\ | 
|  | 49 | changed |= DST - x;		\ | 
|  | 50 | DST = x;			\ | 
|  | 51 | } while (0) | 
|  | 52 |  | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 53 | status->if_version = ntohl(*bp++); | 
|  | 54 | EXTRACT(status->type); | 
|  | 55 | EXTRACT(status->nlink); | 
|  | 56 | size = ntohl(*bp++); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 57 | data_version = ntohl(*bp++); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 58 | EXTRACT(status->author); | 
|  | 59 | EXTRACT(status->owner); | 
|  | 60 | EXTRACT(status->caller_access); /* call ticket dependent */ | 
|  | 61 | EXTRACT(status->anon_access); | 
|  | 62 | EXTRACT(status->mode); | 
|  | 63 | EXTRACT(status->parent.vnode); | 
|  | 64 | EXTRACT(status->parent.unique); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 65 | bp++; /* seg size */ | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 66 | status->mtime_client = ntohl(*bp++); | 
|  | 67 | status->mtime_server = ntohl(*bp++); | 
|  | 68 | EXTRACT(status->group); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 69 | bp++; /* sync counter */ | 
|  | 70 | data_version |= (u64) ntohl(*bp++) << 32; | 
| David Howells | e8d6c55 | 2007-07-15 23:40:12 -0700 | [diff] [blame] | 71 | EXTRACT(status->lock_count); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 72 | size |= (u64) ntohl(*bp++) << 32; | 
|  | 73 | bp++; /* spare 4 */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 74 | *_bp = bp; | 
|  | 75 |  | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 76 | if (size != status->size) { | 
|  | 77 | status->size = size; | 
|  | 78 | changed |= true; | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 79 | } | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 80 | status->mode &= S_IALLUGO; | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 81 |  | 
|  | 82 | _debug("vnode time %lx, %lx", | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 83 | status->mtime_client, status->mtime_server); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 84 |  | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 85 | if (vnode) { | 
|  | 86 | status->parent.vid = vnode->fid.vid; | 
|  | 87 | if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | 
|  | 88 | _debug("vnode changed"); | 
|  | 89 | i_size_write(&vnode->vfs_inode, size); | 
|  | 90 | vnode->vfs_inode.i_uid = status->owner; | 
|  | 91 | vnode->vfs_inode.i_gid = status->group; | 
| David Howells | d6e43f7 | 2011-06-14 00:45:44 +0100 | [diff] [blame] | 92 | vnode->vfs_inode.i_generation = vnode->fid.unique; | 
| Miklos Szeredi | bfe8684 | 2011-10-28 14:13:29 +0200 | [diff] [blame] | 93 | set_nlink(&vnode->vfs_inode, status->nlink); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 94 |  | 
|  | 95 | mode = vnode->vfs_inode.i_mode; | 
|  | 96 | mode &= ~S_IALLUGO; | 
|  | 97 | mode |= status->mode; | 
|  | 98 | barrier(); | 
|  | 99 | vnode->vfs_inode.i_mode = mode; | 
|  | 100 | } | 
|  | 101 |  | 
|  | 102 | vnode->vfs_inode.i_ctime.tv_sec	= status->mtime_server; | 
|  | 103 | vnode->vfs_inode.i_mtime	= vnode->vfs_inode.i_ctime; | 
|  | 104 | vnode->vfs_inode.i_atime	= vnode->vfs_inode.i_ctime; | 
| David Howells | d6e43f7 | 2011-06-14 00:45:44 +0100 | [diff] [blame] | 105 | vnode->vfs_inode.i_version	= data_version; | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 106 | } | 
|  | 107 |  | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 108 | expected_version = status->data_version; | 
|  | 109 | if (store_version) | 
|  | 110 | expected_version = *store_version; | 
|  | 111 |  | 
|  | 112 | if (expected_version != data_version) { | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 113 | status->data_version = data_version; | 
|  | 114 | if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | 
|  | 115 | _debug("vnode modified %llx on {%x:%u}", | 
| David S. Miller | ba3e0e1 | 2007-04-26 16:06:22 -0700 | [diff] [blame] | 116 | (unsigned long long) data_version, | 
|  | 117 | vnode->fid.vid, vnode->fid.vnode); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 118 | set_bit(AFS_VNODE_MODIFIED, &vnode->flags); | 
|  | 119 | set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); | 
|  | 120 | } | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 121 | } else if (store_version) { | 
|  | 122 | status->data_version = data_version; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 123 | } | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 124 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 126 | /* | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 127 | * decode an AFSCallBack block | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 128 | */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 129 | static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 130 | { | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 131 | const __be32 *bp = *_bp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 132 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 133 | vnode->cb_version	= ntohl(*bp++); | 
|  | 134 | vnode->cb_expiry	= ntohl(*bp++); | 
|  | 135 | vnode->cb_type		= ntohl(*bp++); | 
|  | 136 | vnode->cb_expires	= vnode->cb_expiry + get_seconds(); | 
|  | 137 | *_bp = bp; | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 138 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 139 |  | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 140 | static void xdr_decode_AFSCallBack_raw(const __be32 **_bp, | 
|  | 141 | struct afs_callback *cb) | 
|  | 142 | { | 
|  | 143 | const __be32 *bp = *_bp; | 
|  | 144 |  | 
|  | 145 | cb->version	= ntohl(*bp++); | 
|  | 146 | cb->expiry	= ntohl(*bp++); | 
|  | 147 | cb->type	= ntohl(*bp++); | 
|  | 148 | *_bp = bp; | 
|  | 149 | } | 
|  | 150 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 151 | /* | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 152 | * decode an AFSVolSync block | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 153 | */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 154 | static void xdr_decode_AFSVolSync(const __be32 **_bp, | 
|  | 155 | struct afs_volsync *volsync) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 156 | { | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 157 | const __be32 *bp = *_bp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 158 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 159 | volsync->creation = ntohl(*bp++); | 
|  | 160 | bp++; /* spare2 */ | 
|  | 161 | bp++; /* spare3 */ | 
|  | 162 | bp++; /* spare4 */ | 
|  | 163 | bp++; /* spare5 */ | 
|  | 164 | bp++; /* spare6 */ | 
|  | 165 | *_bp = bp; | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 166 | } | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 167 |  | 
|  | 168 | /* | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 169 | * encode the requested attributes into an AFSStoreStatus block | 
|  | 170 | */ | 
|  | 171 | static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) | 
|  | 172 | { | 
|  | 173 | __be32 *bp = *_bp; | 
|  | 174 | u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0; | 
|  | 175 |  | 
|  | 176 | mask = 0; | 
|  | 177 | if (attr->ia_valid & ATTR_MTIME) { | 
|  | 178 | mask |= AFS_SET_MTIME; | 
|  | 179 | mtime = attr->ia_mtime.tv_sec; | 
|  | 180 | } | 
|  | 181 |  | 
|  | 182 | if (attr->ia_valid & ATTR_UID) { | 
|  | 183 | mask |= AFS_SET_OWNER; | 
|  | 184 | owner = attr->ia_uid; | 
|  | 185 | } | 
|  | 186 |  | 
|  | 187 | if (attr->ia_valid & ATTR_GID) { | 
|  | 188 | mask |= AFS_SET_GROUP; | 
|  | 189 | group = attr->ia_gid; | 
|  | 190 | } | 
|  | 191 |  | 
|  | 192 | if (attr->ia_valid & ATTR_MODE) { | 
|  | 193 | mask |= AFS_SET_MODE; | 
|  | 194 | mode = attr->ia_mode & S_IALLUGO; | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | *bp++ = htonl(mask); | 
|  | 198 | *bp++ = htonl(mtime); | 
|  | 199 | *bp++ = htonl(owner); | 
|  | 200 | *bp++ = htonl(group); | 
|  | 201 | *bp++ = htonl(mode); | 
|  | 202 | *bp++ = 0;		/* segment size */ | 
|  | 203 | *_bp = bp; | 
|  | 204 | } | 
|  | 205 |  | 
|  | 206 | /* | 
| David Howells | 45222b9 | 2007-05-10 22:22:20 -0700 | [diff] [blame] | 207 | * decode an AFSFetchVolumeStatus block | 
|  | 208 | */ | 
|  | 209 | static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, | 
|  | 210 | struct afs_volume_status *vs) | 
|  | 211 | { | 
|  | 212 | const __be32 *bp = *_bp; | 
|  | 213 |  | 
|  | 214 | vs->vid			= ntohl(*bp++); | 
|  | 215 | vs->parent_id		= ntohl(*bp++); | 
|  | 216 | vs->online		= ntohl(*bp++); | 
|  | 217 | vs->in_service		= ntohl(*bp++); | 
|  | 218 | vs->blessed		= ntohl(*bp++); | 
|  | 219 | vs->needs_salvage	= ntohl(*bp++); | 
|  | 220 | vs->type		= ntohl(*bp++); | 
|  | 221 | vs->min_quota		= ntohl(*bp++); | 
|  | 222 | vs->max_quota		= ntohl(*bp++); | 
|  | 223 | vs->blocks_in_use	= ntohl(*bp++); | 
|  | 224 | vs->part_blocks_avail	= ntohl(*bp++); | 
|  | 225 | vs->part_max_blocks	= ntohl(*bp++); | 
|  | 226 | *_bp = bp; | 
|  | 227 | } | 
|  | 228 |  | 
|  | 229 | /* | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 230 | * deliver reply data to an FS.FetchStatus | 
|  | 231 | */ | 
|  | 232 | static int afs_deliver_fs_fetch_status(struct afs_call *call, | 
|  | 233 | struct sk_buff *skb, bool last) | 
|  | 234 | { | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 235 | struct afs_vnode *vnode = call->reply; | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 236 | const __be32 *bp; | 
|  | 237 |  | 
|  | 238 | _enter(",,%u", last); | 
|  | 239 |  | 
|  | 240 | afs_transfer_reply(call, skb); | 
|  | 241 | if (!last) | 
|  | 242 | return 0; | 
|  | 243 |  | 
|  | 244 | if (call->reply_size != call->reply_max) | 
|  | 245 | return -EBADMSG; | 
|  | 246 |  | 
|  | 247 | /* unmarshall the reply once we've received all of it */ | 
|  | 248 | bp = call->buffer; | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 249 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 250 | xdr_decode_AFSCallBack(&bp, vnode); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 251 | if (call->reply2) | 
|  | 252 | xdr_decode_AFSVolSync(&bp, call->reply2); | 
|  | 253 |  | 
|  | 254 | _leave(" = 0 [done]"); | 
|  | 255 | return 0; | 
|  | 256 | } | 
|  | 257 |  | 
|  | 258 | /* | 
|  | 259 | * FS.FetchStatus operation type | 
|  | 260 | */ | 
|  | 261 | static const struct afs_call_type afs_RXFSFetchStatus = { | 
| David Howells | 00d3b7a | 2007-04-26 15:57:07 -0700 | [diff] [blame] | 262 | .name		= "FS.FetchStatus", | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 263 | .deliver	= afs_deliver_fs_fetch_status, | 
|  | 264 | .abort_to_error	= afs_abort_to_error, | 
|  | 265 | .destructor	= afs_flat_call_destructor, | 
|  | 266 | }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 267 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 268 | /* | 
|  | 269 | * fetch the status information for a file | 
|  | 270 | */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 271 | int afs_fs_fetch_file_status(struct afs_server *server, | 
| David Howells | 00d3b7a | 2007-04-26 15:57:07 -0700 | [diff] [blame] | 272 | struct key *key, | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 273 | struct afs_vnode *vnode, | 
|  | 274 | struct afs_volsync *volsync, | 
|  | 275 | const struct afs_wait_mode *wait_mode) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 276 | { | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 277 | struct afs_call *call; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 278 | __be32 *bp; | 
|  | 279 |  | 
| David Howells | 416351f | 2007-05-09 02:33:45 -0700 | [diff] [blame] | 280 | _enter(",%x,{%x:%u},,", | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 281 | key_serial(key), vnode->fid.vid, vnode->fid.vnode); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 282 |  | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 283 | call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 284 | if (!call) | 
|  | 285 | return -ENOMEM; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 286 |  | 
| David Howells | 00d3b7a | 2007-04-26 15:57:07 -0700 | [diff] [blame] | 287 | call->key = key; | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 288 | call->reply = vnode; | 
|  | 289 | call->reply2 = volsync; | 
|  | 290 | call->service_id = FS_SERVICE; | 
|  | 291 | call->port = htons(AFS_FS_PORT); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 292 |  | 
|  | 293 | /* marshall the parameters */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 294 | bp = call->request; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 295 | bp[0] = htonl(FSFETCHSTATUS); | 
|  | 296 | bp[1] = htonl(vnode->fid.vid); | 
|  | 297 | bp[2] = htonl(vnode->fid.vnode); | 
|  | 298 | bp[3] = htonl(vnode->fid.unique); | 
|  | 299 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 300 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 301 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 302 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 303 | /* | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 304 | * deliver reply data to an FS.FetchData | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 305 | */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 306 | static int afs_deliver_fs_fetch_data(struct afs_call *call, | 
|  | 307 | struct sk_buff *skb, bool last) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 308 | { | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 309 | struct afs_vnode *vnode = call->reply; | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 310 | const __be32 *bp; | 
|  | 311 | struct page *page; | 
|  | 312 | void *buffer; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 313 | int ret; | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 314 |  | 
|  | 315 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | 
|  | 316 |  | 
|  | 317 | switch (call->unmarshall) { | 
|  | 318 | case 0: | 
|  | 319 | call->offset = 0; | 
|  | 320 | call->unmarshall++; | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 321 | if (call->operation_ID != FSFETCHDATA64) { | 
|  | 322 | call->unmarshall++; | 
|  | 323 | goto no_msw; | 
|  | 324 | } | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 325 |  | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 326 | /* extract the upper part of the returned data length of an | 
|  | 327 | * FSFETCHDATA64 op (which should always be 0 using this | 
|  | 328 | * client) */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 329 | case 1: | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 330 | _debug("extract data length (MSW)"); | 
|  | 331 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | 
|  | 332 | switch (ret) { | 
|  | 333 | case 0:		break; | 
|  | 334 | case -EAGAIN:	return 0; | 
|  | 335 | default:	return ret; | 
|  | 336 | } | 
|  | 337 |  | 
|  | 338 | call->count = ntohl(call->tmp); | 
|  | 339 | _debug("DATA length MSW: %u", call->count); | 
|  | 340 | if (call->count > 0) | 
|  | 341 | return -EBADMSG; | 
|  | 342 | call->offset = 0; | 
|  | 343 | call->unmarshall++; | 
|  | 344 |  | 
|  | 345 | no_msw: | 
|  | 346 | /* extract the returned data length */ | 
|  | 347 | case 2: | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 348 | _debug("extract data length"); | 
|  | 349 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | 
|  | 350 | switch (ret) { | 
|  | 351 | case 0:		break; | 
|  | 352 | case -EAGAIN:	return 0; | 
|  | 353 | default:	return ret; | 
|  | 354 | } | 
|  | 355 |  | 
|  | 356 | call->count = ntohl(call->tmp); | 
|  | 357 | _debug("DATA length: %u", call->count); | 
|  | 358 | if (call->count > PAGE_SIZE) | 
|  | 359 | return -EBADMSG; | 
|  | 360 | call->offset = 0; | 
|  | 361 | call->unmarshall++; | 
|  | 362 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 363 | /* extract the returned data */ | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 364 | case 3: | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 365 | _debug("extract data"); | 
| David Howells | 416351f | 2007-05-09 02:33:45 -0700 | [diff] [blame] | 366 | if (call->count > 0) { | 
|  | 367 | page = call->reply3; | 
| Cong Wang | da4aa36 | 2011-11-25 23:14:26 +0800 | [diff] [blame] | 368 | buffer = kmap_atomic(page); | 
| David Howells | 416351f | 2007-05-09 02:33:45 -0700 | [diff] [blame] | 369 | ret = afs_extract_data(call, skb, last, buffer, | 
|  | 370 | call->count); | 
| Cong Wang | da4aa36 | 2011-11-25 23:14:26 +0800 | [diff] [blame] | 371 | kunmap_atomic(buffer); | 
| David Howells | 416351f | 2007-05-09 02:33:45 -0700 | [diff] [blame] | 372 | switch (ret) { | 
|  | 373 | case 0:		break; | 
|  | 374 | case -EAGAIN:	return 0; | 
|  | 375 | default:	return ret; | 
|  | 376 | } | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 377 | } | 
|  | 378 |  | 
|  | 379 | call->offset = 0; | 
|  | 380 | call->unmarshall++; | 
|  | 381 |  | 
|  | 382 | /* extract the metadata */ | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 383 | case 4: | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 384 | ret = afs_extract_data(call, skb, last, call->buffer, | 
|  | 385 | (21 + 3 + 6) * 4); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 386 | switch (ret) { | 
|  | 387 | case 0:		break; | 
|  | 388 | case -EAGAIN:	return 0; | 
|  | 389 | default:	return ret; | 
|  | 390 | } | 
|  | 391 |  | 
|  | 392 | bp = call->buffer; | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 393 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 394 | xdr_decode_AFSCallBack(&bp, vnode); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 395 | if (call->reply2) | 
|  | 396 | xdr_decode_AFSVolSync(&bp, call->reply2); | 
|  | 397 |  | 
|  | 398 | call->offset = 0; | 
|  | 399 | call->unmarshall++; | 
|  | 400 |  | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 401 | case 5: | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 402 | _debug("trailer"); | 
|  | 403 | if (skb->len != 0) | 
|  | 404 | return -EBADMSG; | 
|  | 405 | break; | 
|  | 406 | } | 
|  | 407 |  | 
|  | 408 | if (!last) | 
|  | 409 | return 0; | 
|  | 410 |  | 
| David Howells | 416351f | 2007-05-09 02:33:45 -0700 | [diff] [blame] | 411 | if (call->count < PAGE_SIZE) { | 
|  | 412 | _debug("clear"); | 
|  | 413 | page = call->reply3; | 
| Cong Wang | da4aa36 | 2011-11-25 23:14:26 +0800 | [diff] [blame] | 414 | buffer = kmap_atomic(page); | 
| David Howells | 416351f | 2007-05-09 02:33:45 -0700 | [diff] [blame] | 415 | memset(buffer + call->count, 0, PAGE_SIZE - call->count); | 
| Cong Wang | da4aa36 | 2011-11-25 23:14:26 +0800 | [diff] [blame] | 416 | kunmap_atomic(buffer); | 
| David Howells | 416351f | 2007-05-09 02:33:45 -0700 | [diff] [blame] | 417 | } | 
|  | 418 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 419 | _leave(" = 0 [done]"); | 
|  | 420 | return 0; | 
|  | 421 | } | 
|  | 422 |  | 
|  | 423 | /* | 
|  | 424 | * FS.FetchData operation type | 
|  | 425 | */ | 
|  | 426 | static const struct afs_call_type afs_RXFSFetchData = { | 
| David Howells | 00d3b7a | 2007-04-26 15:57:07 -0700 | [diff] [blame] | 427 | .name		= "FS.FetchData", | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 428 | .deliver	= afs_deliver_fs_fetch_data, | 
|  | 429 | .abort_to_error	= afs_abort_to_error, | 
|  | 430 | .destructor	= afs_flat_call_destructor, | 
|  | 431 | }; | 
|  | 432 |  | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 433 | static const struct afs_call_type afs_RXFSFetchData64 = { | 
|  | 434 | .name		= "FS.FetchData64", | 
|  | 435 | .deliver	= afs_deliver_fs_fetch_data, | 
|  | 436 | .abort_to_error	= afs_abort_to_error, | 
|  | 437 | .destructor	= afs_flat_call_destructor, | 
|  | 438 | }; | 
|  | 439 |  | 
|  | 440 | /* | 
|  | 441 | * fetch data from a very large file | 
|  | 442 | */ | 
|  | 443 | static int afs_fs_fetch_data64(struct afs_server *server, | 
|  | 444 | struct key *key, | 
|  | 445 | struct afs_vnode *vnode, | 
|  | 446 | off_t offset, size_t length, | 
|  | 447 | struct page *buffer, | 
|  | 448 | const struct afs_wait_mode *wait_mode) | 
|  | 449 | { | 
|  | 450 | struct afs_call *call; | 
|  | 451 | __be32 *bp; | 
|  | 452 |  | 
|  | 453 | _enter(""); | 
|  | 454 |  | 
|  | 455 | ASSERTCMP(length, <, ULONG_MAX); | 
|  | 456 |  | 
|  | 457 | call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); | 
|  | 458 | if (!call) | 
|  | 459 | return -ENOMEM; | 
|  | 460 |  | 
|  | 461 | call->key = key; | 
|  | 462 | call->reply = vnode; | 
|  | 463 | call->reply2 = NULL; /* volsync */ | 
|  | 464 | call->reply3 = buffer; | 
|  | 465 | call->service_id = FS_SERVICE; | 
|  | 466 | call->port = htons(AFS_FS_PORT); | 
|  | 467 | call->operation_ID = FSFETCHDATA64; | 
|  | 468 |  | 
|  | 469 | /* marshall the parameters */ | 
|  | 470 | bp = call->request; | 
|  | 471 | bp[0] = htonl(FSFETCHDATA64); | 
|  | 472 | bp[1] = htonl(vnode->fid.vid); | 
|  | 473 | bp[2] = htonl(vnode->fid.vnode); | 
|  | 474 | bp[3] = htonl(vnode->fid.unique); | 
|  | 475 | bp[4] = htonl(upper_32_bits(offset)); | 
|  | 476 | bp[5] = htonl((u32) offset); | 
|  | 477 | bp[6] = 0; | 
|  | 478 | bp[7] = htonl((u32) length); | 
|  | 479 |  | 
|  | 480 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 481 | } | 
|  | 482 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 483 | /* | 
|  | 484 | * fetch data from a file | 
|  | 485 | */ | 
|  | 486 | int afs_fs_fetch_data(struct afs_server *server, | 
| David Howells | 00d3b7a | 2007-04-26 15:57:07 -0700 | [diff] [blame] | 487 | struct key *key, | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 488 | struct afs_vnode *vnode, | 
|  | 489 | off_t offset, size_t length, | 
|  | 490 | struct page *buffer, | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 491 | const struct afs_wait_mode *wait_mode) | 
|  | 492 | { | 
|  | 493 | struct afs_call *call; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 494 | __be32 *bp; | 
|  | 495 |  | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 496 | if (upper_32_bits(offset) || upper_32_bits(offset + length)) | 
|  | 497 | return afs_fs_fetch_data64(server, key, vnode, offset, length, | 
|  | 498 | buffer, wait_mode); | 
|  | 499 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 500 | _enter(""); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 501 |  | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 502 | call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 503 | if (!call) | 
|  | 504 | return -ENOMEM; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 505 |  | 
| David Howells | 00d3b7a | 2007-04-26 15:57:07 -0700 | [diff] [blame] | 506 | call->key = key; | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 507 | call->reply = vnode; | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 508 | call->reply2 = NULL; /* volsync */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 509 | call->reply3 = buffer; | 
|  | 510 | call->service_id = FS_SERVICE; | 
|  | 511 | call->port = htons(AFS_FS_PORT); | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 512 | call->operation_ID = FSFETCHDATA; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 513 |  | 
|  | 514 | /* marshall the parameters */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 515 | bp = call->request; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 516 | bp[0] = htonl(FSFETCHDATA); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 517 | bp[1] = htonl(vnode->fid.vid); | 
|  | 518 | bp[2] = htonl(vnode->fid.vnode); | 
|  | 519 | bp[3] = htonl(vnode->fid.unique); | 
|  | 520 | bp[4] = htonl(offset); | 
|  | 521 | bp[5] = htonl(length); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 522 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 523 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 524 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 525 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 526 | /* | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 527 | * deliver reply data to an FS.GiveUpCallBacks | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 528 | */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 529 | static int afs_deliver_fs_give_up_callbacks(struct afs_call *call, | 
|  | 530 | struct sk_buff *skb, bool last) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 531 | { | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 532 | _enter(",{%u},%d", skb->len, last); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 533 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 534 | if (skb->len > 0) | 
|  | 535 | return -EBADMSG; /* shouldn't be any reply data */ | 
|  | 536 | return 0; | 
|  | 537 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 538 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 539 | /* | 
|  | 540 | * FS.GiveUpCallBacks operation type | 
|  | 541 | */ | 
|  | 542 | static const struct afs_call_type afs_RXFSGiveUpCallBacks = { | 
| David Howells | 00d3b7a | 2007-04-26 15:57:07 -0700 | [diff] [blame] | 543 | .name		= "FS.GiveUpCallBacks", | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 544 | .deliver	= afs_deliver_fs_give_up_callbacks, | 
|  | 545 | .abort_to_error	= afs_abort_to_error, | 
|  | 546 | .destructor	= afs_flat_call_destructor, | 
|  | 547 | }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 548 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 549 | /* | 
|  | 550 | * give up a set of callbacks | 
|  | 551 | * - the callbacks are held in the server->cb_break ring | 
|  | 552 | */ | 
|  | 553 | int afs_fs_give_up_callbacks(struct afs_server *server, | 
|  | 554 | const struct afs_wait_mode *wait_mode) | 
|  | 555 | { | 
|  | 556 | struct afs_call *call; | 
|  | 557 | size_t ncallbacks; | 
|  | 558 | __be32 *bp, *tp; | 
|  | 559 | int loop; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 560 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 561 | ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail, | 
|  | 562 | ARRAY_SIZE(server->cb_break)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 563 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 564 | _enter("{%zu},", ncallbacks); | 
|  | 565 |  | 
|  | 566 | if (ncallbacks == 0) | 
|  | 567 | return 0; | 
|  | 568 | if (ncallbacks > AFSCBMAX) | 
|  | 569 | ncallbacks = AFSCBMAX; | 
|  | 570 |  | 
|  | 571 | _debug("break %zu callbacks", ncallbacks); | 
|  | 572 |  | 
|  | 573 | call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks, | 
|  | 574 | 12 + ncallbacks * 6 * 4, 0); | 
|  | 575 | if (!call) | 
|  | 576 | return -ENOMEM; | 
|  | 577 |  | 
|  | 578 | call->service_id = FS_SERVICE; | 
|  | 579 | call->port = htons(AFS_FS_PORT); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 580 |  | 
|  | 581 | /* marshall the parameters */ | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 582 | bp = call->request; | 
|  | 583 | tp = bp + 2 + ncallbacks * 3; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 584 | *bp++ = htonl(FSGIVEUPCALLBACKS); | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 585 | *bp++ = htonl(ncallbacks); | 
|  | 586 | *tp++ = htonl(ncallbacks); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 587 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 588 | atomic_sub(ncallbacks, &server->cb_break_n); | 
|  | 589 | for (loop = ncallbacks; loop > 0; loop--) { | 
|  | 590 | struct afs_callback *cb = | 
|  | 591 | &server->cb_break[server->cb_break_tail]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 592 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 593 | *bp++ = htonl(cb->fid.vid); | 
|  | 594 | *bp++ = htonl(cb->fid.vnode); | 
|  | 595 | *bp++ = htonl(cb->fid.unique); | 
|  | 596 | *tp++ = htonl(cb->version); | 
|  | 597 | *tp++ = htonl(cb->expiry); | 
|  | 598 | *tp++ = htonl(cb->type); | 
|  | 599 | smp_mb(); | 
|  | 600 | server->cb_break_tail = | 
|  | 601 | (server->cb_break_tail + 1) & | 
|  | 602 | (ARRAY_SIZE(server->cb_break) - 1); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 603 | } | 
|  | 604 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 605 | ASSERT(ncallbacks > 0); | 
|  | 606 | wake_up_nr(&server->cb_break_waitq, ncallbacks); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 607 |  | 
| David Howells | 08e0e7c | 2007-04-26 15:55:03 -0700 | [diff] [blame] | 608 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
| David Howells | ec26815 | 2007-04-26 15:49:28 -0700 | [diff] [blame] | 609 | } | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 610 |  | 
|  | 611 | /* | 
|  | 612 | * deliver reply data to an FS.CreateFile or an FS.MakeDir | 
|  | 613 | */ | 
|  | 614 | static int afs_deliver_fs_create_vnode(struct afs_call *call, | 
|  | 615 | struct sk_buff *skb, bool last) | 
|  | 616 | { | 
|  | 617 | struct afs_vnode *vnode = call->reply; | 
|  | 618 | const __be32 *bp; | 
|  | 619 |  | 
|  | 620 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | 
|  | 621 |  | 
|  | 622 | afs_transfer_reply(call, skb); | 
|  | 623 | if (!last) | 
|  | 624 | return 0; | 
|  | 625 |  | 
|  | 626 | if (call->reply_size != call->reply_max) | 
|  | 627 | return -EBADMSG; | 
|  | 628 |  | 
|  | 629 | /* unmarshall the reply once we've received all of it */ | 
|  | 630 | bp = call->buffer; | 
|  | 631 | xdr_decode_AFSFid(&bp, call->reply2); | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 632 | xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL); | 
|  | 633 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 634 | xdr_decode_AFSCallBack_raw(&bp, call->reply4); | 
|  | 635 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 
|  | 636 |  | 
|  | 637 | _leave(" = 0 [done]"); | 
|  | 638 | return 0; | 
|  | 639 | } | 
|  | 640 |  | 
|  | 641 | /* | 
|  | 642 | * FS.CreateFile and FS.MakeDir operation type | 
|  | 643 | */ | 
|  | 644 | static const struct afs_call_type afs_RXFSCreateXXXX = { | 
|  | 645 | .name		= "FS.CreateXXXX", | 
|  | 646 | .deliver	= afs_deliver_fs_create_vnode, | 
|  | 647 | .abort_to_error	= afs_abort_to_error, | 
|  | 648 | .destructor	= afs_flat_call_destructor, | 
|  | 649 | }; | 
|  | 650 |  | 
|  | 651 | /* | 
|  | 652 | * create a file or make a directory | 
|  | 653 | */ | 
|  | 654 | int afs_fs_create(struct afs_server *server, | 
|  | 655 | struct key *key, | 
|  | 656 | struct afs_vnode *vnode, | 
|  | 657 | const char *name, | 
|  | 658 | umode_t mode, | 
|  | 659 | struct afs_fid *newfid, | 
|  | 660 | struct afs_file_status *newstatus, | 
|  | 661 | struct afs_callback *newcb, | 
|  | 662 | const struct afs_wait_mode *wait_mode) | 
|  | 663 | { | 
|  | 664 | struct afs_call *call; | 
|  | 665 | size_t namesz, reqsz, padsz; | 
|  | 666 | __be32 *bp; | 
|  | 667 |  | 
|  | 668 | _enter(""); | 
|  | 669 |  | 
|  | 670 | namesz = strlen(name); | 
|  | 671 | padsz = (4 - (namesz & 3)) & 3; | 
|  | 672 | reqsz = (5 * 4) + namesz + padsz + (6 * 4); | 
|  | 673 |  | 
|  | 674 | call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz, | 
|  | 675 | (3 + 21 + 21 + 3 + 6) * 4); | 
|  | 676 | if (!call) | 
|  | 677 | return -ENOMEM; | 
|  | 678 |  | 
|  | 679 | call->key = key; | 
|  | 680 | call->reply = vnode; | 
|  | 681 | call->reply2 = newfid; | 
|  | 682 | call->reply3 = newstatus; | 
|  | 683 | call->reply4 = newcb; | 
|  | 684 | call->service_id = FS_SERVICE; | 
|  | 685 | call->port = htons(AFS_FS_PORT); | 
|  | 686 |  | 
|  | 687 | /* marshall the parameters */ | 
|  | 688 | bp = call->request; | 
|  | 689 | *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); | 
|  | 690 | *bp++ = htonl(vnode->fid.vid); | 
|  | 691 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 692 | *bp++ = htonl(vnode->fid.unique); | 
|  | 693 | *bp++ = htonl(namesz); | 
|  | 694 | memcpy(bp, name, namesz); | 
|  | 695 | bp = (void *) bp + namesz; | 
|  | 696 | if (padsz > 0) { | 
|  | 697 | memset(bp, 0, padsz); | 
|  | 698 | bp = (void *) bp + padsz; | 
|  | 699 | } | 
|  | 700 | *bp++ = htonl(AFS_SET_MODE); | 
|  | 701 | *bp++ = 0; /* mtime */ | 
|  | 702 | *bp++ = 0; /* owner */ | 
|  | 703 | *bp++ = 0; /* group */ | 
|  | 704 | *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ | 
|  | 705 | *bp++ = 0; /* segment size */ | 
|  | 706 |  | 
|  | 707 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 708 | } | 
|  | 709 |  | 
|  | 710 | /* | 
|  | 711 | * deliver reply data to an FS.RemoveFile or FS.RemoveDir | 
|  | 712 | */ | 
|  | 713 | static int afs_deliver_fs_remove(struct afs_call *call, | 
|  | 714 | struct sk_buff *skb, bool last) | 
|  | 715 | { | 
|  | 716 | struct afs_vnode *vnode = call->reply; | 
|  | 717 | const __be32 *bp; | 
|  | 718 |  | 
|  | 719 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | 
|  | 720 |  | 
|  | 721 | afs_transfer_reply(call, skb); | 
|  | 722 | if (!last) | 
|  | 723 | return 0; | 
|  | 724 |  | 
|  | 725 | if (call->reply_size != call->reply_max) | 
|  | 726 | return -EBADMSG; | 
|  | 727 |  | 
|  | 728 | /* unmarshall the reply once we've received all of it */ | 
|  | 729 | bp = call->buffer; | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 730 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 731 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 
|  | 732 |  | 
|  | 733 | _leave(" = 0 [done]"); | 
|  | 734 | return 0; | 
|  | 735 | } | 
|  | 736 |  | 
|  | 737 | /* | 
|  | 738 | * FS.RemoveDir/FS.RemoveFile operation type | 
|  | 739 | */ | 
|  | 740 | static const struct afs_call_type afs_RXFSRemoveXXXX = { | 
|  | 741 | .name		= "FS.RemoveXXXX", | 
|  | 742 | .deliver	= afs_deliver_fs_remove, | 
|  | 743 | .abort_to_error	= afs_abort_to_error, | 
|  | 744 | .destructor	= afs_flat_call_destructor, | 
|  | 745 | }; | 
|  | 746 |  | 
|  | 747 | /* | 
|  | 748 | * remove a file or directory | 
|  | 749 | */ | 
|  | 750 | int afs_fs_remove(struct afs_server *server, | 
|  | 751 | struct key *key, | 
|  | 752 | struct afs_vnode *vnode, | 
|  | 753 | const char *name, | 
|  | 754 | bool isdir, | 
|  | 755 | const struct afs_wait_mode *wait_mode) | 
|  | 756 | { | 
|  | 757 | struct afs_call *call; | 
|  | 758 | size_t namesz, reqsz, padsz; | 
|  | 759 | __be32 *bp; | 
|  | 760 |  | 
|  | 761 | _enter(""); | 
|  | 762 |  | 
|  | 763 | namesz = strlen(name); | 
|  | 764 | padsz = (4 - (namesz & 3)) & 3; | 
|  | 765 | reqsz = (5 * 4) + namesz + padsz; | 
|  | 766 |  | 
|  | 767 | call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4); | 
|  | 768 | if (!call) | 
|  | 769 | return -ENOMEM; | 
|  | 770 |  | 
|  | 771 | call->key = key; | 
|  | 772 | call->reply = vnode; | 
|  | 773 | call->service_id = FS_SERVICE; | 
|  | 774 | call->port = htons(AFS_FS_PORT); | 
|  | 775 |  | 
|  | 776 | /* marshall the parameters */ | 
|  | 777 | bp = call->request; | 
|  | 778 | *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); | 
|  | 779 | *bp++ = htonl(vnode->fid.vid); | 
|  | 780 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 781 | *bp++ = htonl(vnode->fid.unique); | 
|  | 782 | *bp++ = htonl(namesz); | 
|  | 783 | memcpy(bp, name, namesz); | 
|  | 784 | bp = (void *) bp + namesz; | 
|  | 785 | if (padsz > 0) { | 
|  | 786 | memset(bp, 0, padsz); | 
|  | 787 | bp = (void *) bp + padsz; | 
|  | 788 | } | 
|  | 789 |  | 
|  | 790 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 791 | } | 
|  | 792 |  | 
|  | 793 | /* | 
|  | 794 | * deliver reply data to an FS.Link | 
|  | 795 | */ | 
|  | 796 | static int afs_deliver_fs_link(struct afs_call *call, | 
|  | 797 | struct sk_buff *skb, bool last) | 
|  | 798 | { | 
|  | 799 | struct afs_vnode *dvnode = call->reply, *vnode = call->reply2; | 
|  | 800 | const __be32 *bp; | 
|  | 801 |  | 
|  | 802 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | 
|  | 803 |  | 
|  | 804 | afs_transfer_reply(call, skb); | 
|  | 805 | if (!last) | 
|  | 806 | return 0; | 
|  | 807 |  | 
|  | 808 | if (call->reply_size != call->reply_max) | 
|  | 809 | return -EBADMSG; | 
|  | 810 |  | 
|  | 811 | /* unmarshall the reply once we've received all of it */ | 
|  | 812 | bp = call->buffer; | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 813 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 
|  | 814 | xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 815 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 
|  | 816 |  | 
|  | 817 | _leave(" = 0 [done]"); | 
|  | 818 | return 0; | 
|  | 819 | } | 
|  | 820 |  | 
|  | 821 | /* | 
|  | 822 | * FS.Link operation type | 
|  | 823 | */ | 
|  | 824 | static const struct afs_call_type afs_RXFSLink = { | 
|  | 825 | .name		= "FS.Link", | 
|  | 826 | .deliver	= afs_deliver_fs_link, | 
|  | 827 | .abort_to_error	= afs_abort_to_error, | 
|  | 828 | .destructor	= afs_flat_call_destructor, | 
|  | 829 | }; | 
|  | 830 |  | 
|  | 831 | /* | 
|  | 832 | * make a hard link | 
|  | 833 | */ | 
|  | 834 | int afs_fs_link(struct afs_server *server, | 
|  | 835 | struct key *key, | 
|  | 836 | struct afs_vnode *dvnode, | 
|  | 837 | struct afs_vnode *vnode, | 
|  | 838 | const char *name, | 
|  | 839 | const struct afs_wait_mode *wait_mode) | 
|  | 840 | { | 
|  | 841 | struct afs_call *call; | 
|  | 842 | size_t namesz, reqsz, padsz; | 
|  | 843 | __be32 *bp; | 
|  | 844 |  | 
|  | 845 | _enter(""); | 
|  | 846 |  | 
|  | 847 | namesz = strlen(name); | 
|  | 848 | padsz = (4 - (namesz & 3)) & 3; | 
|  | 849 | reqsz = (5 * 4) + namesz + padsz + (3 * 4); | 
|  | 850 |  | 
|  | 851 | call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); | 
|  | 852 | if (!call) | 
|  | 853 | return -ENOMEM; | 
|  | 854 |  | 
|  | 855 | call->key = key; | 
|  | 856 | call->reply = dvnode; | 
|  | 857 | call->reply2 = vnode; | 
|  | 858 | call->service_id = FS_SERVICE; | 
|  | 859 | call->port = htons(AFS_FS_PORT); | 
|  | 860 |  | 
|  | 861 | /* marshall the parameters */ | 
|  | 862 | bp = call->request; | 
|  | 863 | *bp++ = htonl(FSLINK); | 
|  | 864 | *bp++ = htonl(dvnode->fid.vid); | 
|  | 865 | *bp++ = htonl(dvnode->fid.vnode); | 
|  | 866 | *bp++ = htonl(dvnode->fid.unique); | 
|  | 867 | *bp++ = htonl(namesz); | 
|  | 868 | memcpy(bp, name, namesz); | 
|  | 869 | bp = (void *) bp + namesz; | 
|  | 870 | if (padsz > 0) { | 
|  | 871 | memset(bp, 0, padsz); | 
|  | 872 | bp = (void *) bp + padsz; | 
|  | 873 | } | 
|  | 874 | *bp++ = htonl(vnode->fid.vid); | 
|  | 875 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 876 | *bp++ = htonl(vnode->fid.unique); | 
|  | 877 |  | 
|  | 878 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 879 | } | 
|  | 880 |  | 
|  | 881 | /* | 
|  | 882 | * deliver reply data to an FS.Symlink | 
|  | 883 | */ | 
|  | 884 | static int afs_deliver_fs_symlink(struct afs_call *call, | 
|  | 885 | struct sk_buff *skb, bool last) | 
|  | 886 | { | 
|  | 887 | struct afs_vnode *vnode = call->reply; | 
|  | 888 | const __be32 *bp; | 
|  | 889 |  | 
|  | 890 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | 
|  | 891 |  | 
|  | 892 | afs_transfer_reply(call, skb); | 
|  | 893 | if (!last) | 
|  | 894 | return 0; | 
|  | 895 |  | 
|  | 896 | if (call->reply_size != call->reply_max) | 
|  | 897 | return -EBADMSG; | 
|  | 898 |  | 
|  | 899 | /* unmarshall the reply once we've received all of it */ | 
|  | 900 | bp = call->buffer; | 
|  | 901 | xdr_decode_AFSFid(&bp, call->reply2); | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 902 | xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL); | 
|  | 903 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 904 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 
|  | 905 |  | 
|  | 906 | _leave(" = 0 [done]"); | 
|  | 907 | return 0; | 
|  | 908 | } | 
|  | 909 |  | 
|  | 910 | /* | 
|  | 911 | * FS.Symlink operation type | 
|  | 912 | */ | 
|  | 913 | static const struct afs_call_type afs_RXFSSymlink = { | 
|  | 914 | .name		= "FS.Symlink", | 
|  | 915 | .deliver	= afs_deliver_fs_symlink, | 
|  | 916 | .abort_to_error	= afs_abort_to_error, | 
|  | 917 | .destructor	= afs_flat_call_destructor, | 
|  | 918 | }; | 
|  | 919 |  | 
|  | 920 | /* | 
|  | 921 | * create a symbolic link | 
|  | 922 | */ | 
|  | 923 | int afs_fs_symlink(struct afs_server *server, | 
|  | 924 | struct key *key, | 
|  | 925 | struct afs_vnode *vnode, | 
|  | 926 | const char *name, | 
|  | 927 | const char *contents, | 
|  | 928 | struct afs_fid *newfid, | 
|  | 929 | struct afs_file_status *newstatus, | 
|  | 930 | const struct afs_wait_mode *wait_mode) | 
|  | 931 | { | 
|  | 932 | struct afs_call *call; | 
|  | 933 | size_t namesz, reqsz, padsz, c_namesz, c_padsz; | 
|  | 934 | __be32 *bp; | 
|  | 935 |  | 
|  | 936 | _enter(""); | 
|  | 937 |  | 
|  | 938 | namesz = strlen(name); | 
|  | 939 | padsz = (4 - (namesz & 3)) & 3; | 
|  | 940 |  | 
|  | 941 | c_namesz = strlen(contents); | 
|  | 942 | c_padsz = (4 - (c_namesz & 3)) & 3; | 
|  | 943 |  | 
|  | 944 | reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); | 
|  | 945 |  | 
|  | 946 | call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz, | 
|  | 947 | (3 + 21 + 21 + 6) * 4); | 
|  | 948 | if (!call) | 
|  | 949 | return -ENOMEM; | 
|  | 950 |  | 
|  | 951 | call->key = key; | 
|  | 952 | call->reply = vnode; | 
|  | 953 | call->reply2 = newfid; | 
|  | 954 | call->reply3 = newstatus; | 
|  | 955 | call->service_id = FS_SERVICE; | 
|  | 956 | call->port = htons(AFS_FS_PORT); | 
|  | 957 |  | 
|  | 958 | /* marshall the parameters */ | 
|  | 959 | bp = call->request; | 
|  | 960 | *bp++ = htonl(FSSYMLINK); | 
|  | 961 | *bp++ = htonl(vnode->fid.vid); | 
|  | 962 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 963 | *bp++ = htonl(vnode->fid.unique); | 
|  | 964 | *bp++ = htonl(namesz); | 
|  | 965 | memcpy(bp, name, namesz); | 
|  | 966 | bp = (void *) bp + namesz; | 
|  | 967 | if (padsz > 0) { | 
|  | 968 | memset(bp, 0, padsz); | 
|  | 969 | bp = (void *) bp + padsz; | 
|  | 970 | } | 
|  | 971 | *bp++ = htonl(c_namesz); | 
|  | 972 | memcpy(bp, contents, c_namesz); | 
|  | 973 | bp = (void *) bp + c_namesz; | 
|  | 974 | if (c_padsz > 0) { | 
|  | 975 | memset(bp, 0, c_padsz); | 
|  | 976 | bp = (void *) bp + c_padsz; | 
|  | 977 | } | 
|  | 978 | *bp++ = htonl(AFS_SET_MODE); | 
|  | 979 | *bp++ = 0; /* mtime */ | 
|  | 980 | *bp++ = 0; /* owner */ | 
|  | 981 | *bp++ = 0; /* group */ | 
|  | 982 | *bp++ = htonl(S_IRWXUGO); /* unix mode */ | 
|  | 983 | *bp++ = 0; /* segment size */ | 
|  | 984 |  | 
|  | 985 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 986 | } | 
|  | 987 |  | 
|  | 988 | /* | 
|  | 989 | * deliver reply data to an FS.Rename | 
|  | 990 | */ | 
|  | 991 | static int afs_deliver_fs_rename(struct afs_call *call, | 
|  | 992 | struct sk_buff *skb, bool last) | 
|  | 993 | { | 
|  | 994 | struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2; | 
|  | 995 | const __be32 *bp; | 
|  | 996 |  | 
|  | 997 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | 
|  | 998 |  | 
|  | 999 | afs_transfer_reply(call, skb); | 
|  | 1000 | if (!last) | 
|  | 1001 | return 0; | 
|  | 1002 |  | 
|  | 1003 | if (call->reply_size != call->reply_max) | 
|  | 1004 | return -EBADMSG; | 
|  | 1005 |  | 
|  | 1006 | /* unmarshall the reply once we've received all of it */ | 
|  | 1007 | bp = call->buffer; | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 1008 | xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 1009 | if (new_dvnode != orig_dvnode) | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 1010 | xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode, | 
|  | 1011 | NULL); | 
| David Howells | 260a980 | 2007-04-26 15:59:35 -0700 | [diff] [blame] | 1012 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 
|  | 1013 |  | 
|  | 1014 | _leave(" = 0 [done]"); | 
|  | 1015 | return 0; | 
|  | 1016 | } | 
|  | 1017 |  | 
|  | 1018 | /* | 
|  | 1019 | * FS.Rename operation type | 
|  | 1020 | */ | 
|  | 1021 | static const struct afs_call_type afs_RXFSRename = { | 
|  | 1022 | .name		= "FS.Rename", | 
|  | 1023 | .deliver	= afs_deliver_fs_rename, | 
|  | 1024 | .abort_to_error	= afs_abort_to_error, | 
|  | 1025 | .destructor	= afs_flat_call_destructor, | 
|  | 1026 | }; | 
|  | 1027 |  | 
|  | 1028 | /* | 
|  | 1029 | * create a symbolic link | 
|  | 1030 | */ | 
|  | 1031 | int afs_fs_rename(struct afs_server *server, | 
|  | 1032 | struct key *key, | 
|  | 1033 | struct afs_vnode *orig_dvnode, | 
|  | 1034 | const char *orig_name, | 
|  | 1035 | struct afs_vnode *new_dvnode, | 
|  | 1036 | const char *new_name, | 
|  | 1037 | const struct afs_wait_mode *wait_mode) | 
|  | 1038 | { | 
|  | 1039 | struct afs_call *call; | 
|  | 1040 | size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; | 
|  | 1041 | __be32 *bp; | 
|  | 1042 |  | 
|  | 1043 | _enter(""); | 
|  | 1044 |  | 
|  | 1045 | o_namesz = strlen(orig_name); | 
|  | 1046 | o_padsz = (4 - (o_namesz & 3)) & 3; | 
|  | 1047 |  | 
|  | 1048 | n_namesz = strlen(new_name); | 
|  | 1049 | n_padsz = (4 - (n_namesz & 3)) & 3; | 
|  | 1050 |  | 
|  | 1051 | reqsz = (4 * 4) + | 
|  | 1052 | 4 + o_namesz + o_padsz + | 
|  | 1053 | (3 * 4) + | 
|  | 1054 | 4 + n_namesz + n_padsz; | 
|  | 1055 |  | 
|  | 1056 | call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); | 
|  | 1057 | if (!call) | 
|  | 1058 | return -ENOMEM; | 
|  | 1059 |  | 
|  | 1060 | call->key = key; | 
|  | 1061 | call->reply = orig_dvnode; | 
|  | 1062 | call->reply2 = new_dvnode; | 
|  | 1063 | call->service_id = FS_SERVICE; | 
|  | 1064 | call->port = htons(AFS_FS_PORT); | 
|  | 1065 |  | 
|  | 1066 | /* marshall the parameters */ | 
|  | 1067 | bp = call->request; | 
|  | 1068 | *bp++ = htonl(FSRENAME); | 
|  | 1069 | *bp++ = htonl(orig_dvnode->fid.vid); | 
|  | 1070 | *bp++ = htonl(orig_dvnode->fid.vnode); | 
|  | 1071 | *bp++ = htonl(orig_dvnode->fid.unique); | 
|  | 1072 | *bp++ = htonl(o_namesz); | 
|  | 1073 | memcpy(bp, orig_name, o_namesz); | 
|  | 1074 | bp = (void *) bp + o_namesz; | 
|  | 1075 | if (o_padsz > 0) { | 
|  | 1076 | memset(bp, 0, o_padsz); | 
|  | 1077 | bp = (void *) bp + o_padsz; | 
|  | 1078 | } | 
|  | 1079 |  | 
|  | 1080 | *bp++ = htonl(new_dvnode->fid.vid); | 
|  | 1081 | *bp++ = htonl(new_dvnode->fid.vnode); | 
|  | 1082 | *bp++ = htonl(new_dvnode->fid.unique); | 
|  | 1083 | *bp++ = htonl(n_namesz); | 
|  | 1084 | memcpy(bp, new_name, n_namesz); | 
|  | 1085 | bp = (void *) bp + n_namesz; | 
|  | 1086 | if (n_padsz > 0) { | 
|  | 1087 | memset(bp, 0, n_padsz); | 
|  | 1088 | bp = (void *) bp + n_padsz; | 
|  | 1089 | } | 
|  | 1090 |  | 
|  | 1091 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 1092 | } | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 1093 |  | 
|  | 1094 | /* | 
|  | 1095 | * deliver reply data to an FS.StoreData | 
|  | 1096 | */ | 
|  | 1097 | static int afs_deliver_fs_store_data(struct afs_call *call, | 
|  | 1098 | struct sk_buff *skb, bool last) | 
|  | 1099 | { | 
|  | 1100 | struct afs_vnode *vnode = call->reply; | 
|  | 1101 | const __be32 *bp; | 
|  | 1102 |  | 
|  | 1103 | _enter(",,%u", last); | 
|  | 1104 |  | 
|  | 1105 | afs_transfer_reply(call, skb); | 
|  | 1106 | if (!last) { | 
|  | 1107 | _leave(" = 0 [more]"); | 
|  | 1108 | return 0; | 
|  | 1109 | } | 
|  | 1110 |  | 
|  | 1111 | if (call->reply_size != call->reply_max) { | 
|  | 1112 | _leave(" = -EBADMSG [%u != %u]", | 
|  | 1113 | call->reply_size, call->reply_max); | 
|  | 1114 | return -EBADMSG; | 
|  | 1115 | } | 
|  | 1116 |  | 
|  | 1117 | /* unmarshall the reply once we've received all of it */ | 
|  | 1118 | bp = call->buffer; | 
|  | 1119 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, | 
|  | 1120 | &call->store_version); | 
|  | 1121 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 
|  | 1122 |  | 
|  | 1123 | afs_pages_written_back(vnode, call); | 
|  | 1124 |  | 
|  | 1125 | _leave(" = 0 [done]"); | 
|  | 1126 | return 0; | 
|  | 1127 | } | 
|  | 1128 |  | 
|  | 1129 | /* | 
|  | 1130 | * FS.StoreData operation type | 
|  | 1131 | */ | 
|  | 1132 | static const struct afs_call_type afs_RXFSStoreData = { | 
|  | 1133 | .name		= "FS.StoreData", | 
|  | 1134 | .deliver	= afs_deliver_fs_store_data, | 
|  | 1135 | .abort_to_error	= afs_abort_to_error, | 
|  | 1136 | .destructor	= afs_flat_call_destructor, | 
|  | 1137 | }; | 
|  | 1138 |  | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 1139 | static const struct afs_call_type afs_RXFSStoreData64 = { | 
|  | 1140 | .name		= "FS.StoreData64", | 
|  | 1141 | .deliver	= afs_deliver_fs_store_data, | 
|  | 1142 | .abort_to_error	= afs_abort_to_error, | 
|  | 1143 | .destructor	= afs_flat_call_destructor, | 
|  | 1144 | }; | 
|  | 1145 |  | 
|  | 1146 | /* | 
|  | 1147 | * store a set of pages to a very large file | 
|  | 1148 | */ | 
|  | 1149 | static int afs_fs_store_data64(struct afs_server *server, | 
|  | 1150 | struct afs_writeback *wb, | 
|  | 1151 | pgoff_t first, pgoff_t last, | 
|  | 1152 | unsigned offset, unsigned to, | 
|  | 1153 | loff_t size, loff_t pos, loff_t i_size, | 
|  | 1154 | const struct afs_wait_mode *wait_mode) | 
|  | 1155 | { | 
|  | 1156 | struct afs_vnode *vnode = wb->vnode; | 
|  | 1157 | struct afs_call *call; | 
|  | 1158 | __be32 *bp; | 
|  | 1159 |  | 
|  | 1160 | _enter(",%x,{%x:%u},,", | 
|  | 1161 | key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); | 
|  | 1162 |  | 
|  | 1163 | call = afs_alloc_flat_call(&afs_RXFSStoreData64, | 
|  | 1164 | (4 + 6 + 3 * 2) * 4, | 
|  | 1165 | (21 + 6) * 4); | 
|  | 1166 | if (!call) | 
|  | 1167 | return -ENOMEM; | 
|  | 1168 |  | 
|  | 1169 | call->wb = wb; | 
|  | 1170 | call->key = wb->key; | 
|  | 1171 | call->reply = vnode; | 
|  | 1172 | call->service_id = FS_SERVICE; | 
|  | 1173 | call->port = htons(AFS_FS_PORT); | 
|  | 1174 | call->mapping = vnode->vfs_inode.i_mapping; | 
|  | 1175 | call->first = first; | 
|  | 1176 | call->last = last; | 
|  | 1177 | call->first_offset = offset; | 
|  | 1178 | call->last_to = to; | 
|  | 1179 | call->send_pages = true; | 
|  | 1180 | call->store_version = vnode->status.data_version + 1; | 
|  | 1181 |  | 
|  | 1182 | /* marshall the parameters */ | 
|  | 1183 | bp = call->request; | 
|  | 1184 | *bp++ = htonl(FSSTOREDATA64); | 
|  | 1185 | *bp++ = htonl(vnode->fid.vid); | 
|  | 1186 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 1187 | *bp++ = htonl(vnode->fid.unique); | 
|  | 1188 |  | 
|  | 1189 | *bp++ = 0; /* mask */ | 
|  | 1190 | *bp++ = 0; /* mtime */ | 
|  | 1191 | *bp++ = 0; /* owner */ | 
|  | 1192 | *bp++ = 0; /* group */ | 
|  | 1193 | *bp++ = 0; /* unix mode */ | 
|  | 1194 | *bp++ = 0; /* segment size */ | 
|  | 1195 |  | 
|  | 1196 | *bp++ = htonl(pos >> 32); | 
|  | 1197 | *bp++ = htonl((u32) pos); | 
|  | 1198 | *bp++ = htonl(size >> 32); | 
|  | 1199 | *bp++ = htonl((u32) size); | 
|  | 1200 | *bp++ = htonl(i_size >> 32); | 
|  | 1201 | *bp++ = htonl((u32) i_size); | 
|  | 1202 |  | 
|  | 1203 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 1204 | } | 
|  | 1205 |  | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 1206 | /* | 
|  | 1207 | * store a set of pages | 
|  | 1208 | */ | 
|  | 1209 | int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb, | 
|  | 1210 | pgoff_t first, pgoff_t last, | 
|  | 1211 | unsigned offset, unsigned to, | 
|  | 1212 | const struct afs_wait_mode *wait_mode) | 
|  | 1213 | { | 
|  | 1214 | struct afs_vnode *vnode = wb->vnode; | 
|  | 1215 | struct afs_call *call; | 
|  | 1216 | loff_t size, pos, i_size; | 
|  | 1217 | __be32 *bp; | 
|  | 1218 |  | 
|  | 1219 | _enter(",%x,{%x:%u},,", | 
|  | 1220 | key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); | 
|  | 1221 |  | 
|  | 1222 | size = to - offset; | 
|  | 1223 | if (first != last) | 
|  | 1224 | size += (loff_t)(last - first) << PAGE_SHIFT; | 
|  | 1225 | pos = (loff_t)first << PAGE_SHIFT; | 
|  | 1226 | pos += offset; | 
|  | 1227 |  | 
|  | 1228 | i_size = i_size_read(&vnode->vfs_inode); | 
|  | 1229 | if (pos + size > i_size) | 
|  | 1230 | i_size = size + pos; | 
|  | 1231 |  | 
|  | 1232 | _debug("size %llx, at %llx, i_size %llx", | 
|  | 1233 | (unsigned long long) size, (unsigned long long) pos, | 
|  | 1234 | (unsigned long long) i_size); | 
|  | 1235 |  | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 1236 | if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) | 
|  | 1237 | return afs_fs_store_data64(server, wb, first, last, offset, to, | 
|  | 1238 | size, pos, i_size, wait_mode); | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 1239 |  | 
|  | 1240 | call = afs_alloc_flat_call(&afs_RXFSStoreData, | 
|  | 1241 | (4 + 6 + 3) * 4, | 
|  | 1242 | (21 + 6) * 4); | 
|  | 1243 | if (!call) | 
|  | 1244 | return -ENOMEM; | 
|  | 1245 |  | 
|  | 1246 | call->wb = wb; | 
|  | 1247 | call->key = wb->key; | 
|  | 1248 | call->reply = vnode; | 
|  | 1249 | call->service_id = FS_SERVICE; | 
|  | 1250 | call->port = htons(AFS_FS_PORT); | 
|  | 1251 | call->mapping = vnode->vfs_inode.i_mapping; | 
|  | 1252 | call->first = first; | 
|  | 1253 | call->last = last; | 
|  | 1254 | call->first_offset = offset; | 
|  | 1255 | call->last_to = to; | 
|  | 1256 | call->send_pages = true; | 
|  | 1257 | call->store_version = vnode->status.data_version + 1; | 
|  | 1258 |  | 
|  | 1259 | /* marshall the parameters */ | 
|  | 1260 | bp = call->request; | 
|  | 1261 | *bp++ = htonl(FSSTOREDATA); | 
|  | 1262 | *bp++ = htonl(vnode->fid.vid); | 
|  | 1263 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 1264 | *bp++ = htonl(vnode->fid.unique); | 
|  | 1265 |  | 
|  | 1266 | *bp++ = 0; /* mask */ | 
|  | 1267 | *bp++ = 0; /* mtime */ | 
|  | 1268 | *bp++ = 0; /* owner */ | 
|  | 1269 | *bp++ = 0; /* group */ | 
|  | 1270 | *bp++ = 0; /* unix mode */ | 
|  | 1271 | *bp++ = 0; /* segment size */ | 
|  | 1272 |  | 
|  | 1273 | *bp++ = htonl(pos); | 
|  | 1274 | *bp++ = htonl(size); | 
|  | 1275 | *bp++ = htonl(i_size); | 
|  | 1276 |  | 
|  | 1277 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 1278 | } | 
|  | 1279 |  | 
|  | 1280 | /* | 
|  | 1281 | * deliver reply data to an FS.StoreStatus | 
|  | 1282 | */ | 
|  | 1283 | static int afs_deliver_fs_store_status(struct afs_call *call, | 
|  | 1284 | struct sk_buff *skb, bool last) | 
|  | 1285 | { | 
|  | 1286 | afs_dataversion_t *store_version; | 
|  | 1287 | struct afs_vnode *vnode = call->reply; | 
|  | 1288 | const __be32 *bp; | 
|  | 1289 |  | 
|  | 1290 | _enter(",,%u", last); | 
|  | 1291 |  | 
|  | 1292 | afs_transfer_reply(call, skb); | 
|  | 1293 | if (!last) { | 
|  | 1294 | _leave(" = 0 [more]"); | 
|  | 1295 | return 0; | 
|  | 1296 | } | 
|  | 1297 |  | 
|  | 1298 | if (call->reply_size != call->reply_max) { | 
|  | 1299 | _leave(" = -EBADMSG [%u != %u]", | 
|  | 1300 | call->reply_size, call->reply_max); | 
|  | 1301 | return -EBADMSG; | 
|  | 1302 | } | 
|  | 1303 |  | 
|  | 1304 | /* unmarshall the reply once we've received all of it */ | 
|  | 1305 | store_version = NULL; | 
|  | 1306 | if (call->operation_ID == FSSTOREDATA) | 
|  | 1307 | store_version = &call->store_version; | 
|  | 1308 |  | 
|  | 1309 | bp = call->buffer; | 
|  | 1310 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version); | 
|  | 1311 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 
|  | 1312 |  | 
|  | 1313 | _leave(" = 0 [done]"); | 
|  | 1314 | return 0; | 
|  | 1315 | } | 
|  | 1316 |  | 
|  | 1317 | /* | 
|  | 1318 | * FS.StoreStatus operation type | 
|  | 1319 | */ | 
|  | 1320 | static const struct afs_call_type afs_RXFSStoreStatus = { | 
|  | 1321 | .name		= "FS.StoreStatus", | 
|  | 1322 | .deliver	= afs_deliver_fs_store_status, | 
|  | 1323 | .abort_to_error	= afs_abort_to_error, | 
|  | 1324 | .destructor	= afs_flat_call_destructor, | 
|  | 1325 | }; | 
|  | 1326 |  | 
|  | 1327 | static const struct afs_call_type afs_RXFSStoreData_as_Status = { | 
|  | 1328 | .name		= "FS.StoreData", | 
|  | 1329 | .deliver	= afs_deliver_fs_store_status, | 
|  | 1330 | .abort_to_error	= afs_abort_to_error, | 
|  | 1331 | .destructor	= afs_flat_call_destructor, | 
|  | 1332 | }; | 
|  | 1333 |  | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 1334 | static const struct afs_call_type afs_RXFSStoreData64_as_Status = { | 
|  | 1335 | .name		= "FS.StoreData64", | 
|  | 1336 | .deliver	= afs_deliver_fs_store_status, | 
|  | 1337 | .abort_to_error	= afs_abort_to_error, | 
|  | 1338 | .destructor	= afs_flat_call_destructor, | 
|  | 1339 | }; | 
|  | 1340 |  | 
|  | 1341 | /* | 
|  | 1342 | * set the attributes on a very large file, using FS.StoreData rather than | 
|  | 1343 | * FS.StoreStatus so as to alter the file size also | 
|  | 1344 | */ | 
|  | 1345 | static int afs_fs_setattr_size64(struct afs_server *server, struct key *key, | 
|  | 1346 | struct afs_vnode *vnode, struct iattr *attr, | 
|  | 1347 | const struct afs_wait_mode *wait_mode) | 
|  | 1348 | { | 
|  | 1349 | struct afs_call *call; | 
|  | 1350 | __be32 *bp; | 
|  | 1351 |  | 
|  | 1352 | _enter(",%x,{%x:%u},,", | 
|  | 1353 | key_serial(key), vnode->fid.vid, vnode->fid.vnode); | 
|  | 1354 |  | 
|  | 1355 | ASSERT(attr->ia_valid & ATTR_SIZE); | 
|  | 1356 |  | 
|  | 1357 | call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status, | 
|  | 1358 | (4 + 6 + 3 * 2) * 4, | 
|  | 1359 | (21 + 6) * 4); | 
|  | 1360 | if (!call) | 
|  | 1361 | return -ENOMEM; | 
|  | 1362 |  | 
|  | 1363 | call->key = key; | 
|  | 1364 | call->reply = vnode; | 
|  | 1365 | call->service_id = FS_SERVICE; | 
|  | 1366 | call->port = htons(AFS_FS_PORT); | 
|  | 1367 | call->store_version = vnode->status.data_version + 1; | 
|  | 1368 | call->operation_ID = FSSTOREDATA; | 
|  | 1369 |  | 
|  | 1370 | /* marshall the parameters */ | 
|  | 1371 | bp = call->request; | 
|  | 1372 | *bp++ = htonl(FSSTOREDATA64); | 
|  | 1373 | *bp++ = htonl(vnode->fid.vid); | 
|  | 1374 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 1375 | *bp++ = htonl(vnode->fid.unique); | 
|  | 1376 |  | 
|  | 1377 | xdr_encode_AFS_StoreStatus(&bp, attr); | 
|  | 1378 |  | 
|  | 1379 | *bp++ = 0;				/* position of start of write */ | 
|  | 1380 | *bp++ = 0; | 
|  | 1381 | *bp++ = 0;				/* size of write */ | 
|  | 1382 | *bp++ = 0; | 
|  | 1383 | *bp++ = htonl(attr->ia_size >> 32);	/* new file length */ | 
|  | 1384 | *bp++ = htonl((u32) attr->ia_size); | 
|  | 1385 |  | 
|  | 1386 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 1387 | } | 
|  | 1388 |  | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 1389 | /* | 
|  | 1390 | * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus | 
|  | 1391 | * so as to alter the file size also | 
|  | 1392 | */ | 
|  | 1393 | static int afs_fs_setattr_size(struct afs_server *server, struct key *key, | 
|  | 1394 | struct afs_vnode *vnode, struct iattr *attr, | 
|  | 1395 | const struct afs_wait_mode *wait_mode) | 
|  | 1396 | { | 
|  | 1397 | struct afs_call *call; | 
|  | 1398 | __be32 *bp; | 
|  | 1399 |  | 
|  | 1400 | _enter(",%x,{%x:%u},,", | 
|  | 1401 | key_serial(key), vnode->fid.vid, vnode->fid.vnode); | 
|  | 1402 |  | 
|  | 1403 | ASSERT(attr->ia_valid & ATTR_SIZE); | 
| David Howells | b9b1f8d | 2007-05-10 03:15:21 -0700 | [diff] [blame] | 1404 | if (attr->ia_size >> 32) | 
|  | 1405 | return afs_fs_setattr_size64(server, key, vnode, attr, | 
|  | 1406 | wait_mode); | 
| David Howells | 31143d5 | 2007-05-09 02:33:46 -0700 | [diff] [blame] | 1407 |  | 
|  | 1408 | call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status, | 
|  | 1409 | (4 + 6 + 3) * 4, | 
|  | 1410 | (21 + 6) * 4); | 
|  | 1411 | if (!call) | 
|  | 1412 | return -ENOMEM; | 
|  | 1413 |  | 
|  | 1414 | call->key = key; | 
|  | 1415 | call->reply = vnode; | 
|  | 1416 | call->service_id = FS_SERVICE; | 
|  | 1417 | call->port = htons(AFS_FS_PORT); | 
|  | 1418 | call->store_version = vnode->status.data_version + 1; | 
|  | 1419 | call->operation_ID = FSSTOREDATA; | 
|  | 1420 |  | 
|  | 1421 | /* marshall the parameters */ | 
|  | 1422 | bp = call->request; | 
|  | 1423 | *bp++ = htonl(FSSTOREDATA); | 
|  | 1424 | *bp++ = htonl(vnode->fid.vid); | 
|  | 1425 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 1426 | *bp++ = htonl(vnode->fid.unique); | 
|  | 1427 |  | 
|  | 1428 | xdr_encode_AFS_StoreStatus(&bp, attr); | 
|  | 1429 |  | 
|  | 1430 | *bp++ = 0;				/* position of start of write */ | 
|  | 1431 | *bp++ = 0;				/* size of write */ | 
|  | 1432 | *bp++ = htonl(attr->ia_size);		/* new file length */ | 
|  | 1433 |  | 
|  | 1434 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 1435 | } | 
|  | 1436 |  | 
|  | 1437 | /* | 
|  | 1438 | * set the attributes on a file, using FS.StoreData if there's a change in file | 
|  | 1439 | * size, and FS.StoreStatus otherwise | 
|  | 1440 | */ | 
|  | 1441 | int afs_fs_setattr(struct afs_server *server, struct key *key, | 
|  | 1442 | struct afs_vnode *vnode, struct iattr *attr, | 
|  | 1443 | const struct afs_wait_mode *wait_mode) | 
|  | 1444 | { | 
|  | 1445 | struct afs_call *call; | 
|  | 1446 | __be32 *bp; | 
|  | 1447 |  | 
|  | 1448 | if (attr->ia_valid & ATTR_SIZE) | 
|  | 1449 | return afs_fs_setattr_size(server, key, vnode, attr, | 
|  | 1450 | wait_mode); | 
|  | 1451 |  | 
|  | 1452 | _enter(",%x,{%x:%u},,", | 
|  | 1453 | key_serial(key), vnode->fid.vid, vnode->fid.vnode); | 
|  | 1454 |  | 
|  | 1455 | call = afs_alloc_flat_call(&afs_RXFSStoreStatus, | 
|  | 1456 | (4 + 6) * 4, | 
|  | 1457 | (21 + 6) * 4); | 
|  | 1458 | if (!call) | 
|  | 1459 | return -ENOMEM; | 
|  | 1460 |  | 
|  | 1461 | call->key = key; | 
|  | 1462 | call->reply = vnode; | 
|  | 1463 | call->service_id = FS_SERVICE; | 
|  | 1464 | call->port = htons(AFS_FS_PORT); | 
|  | 1465 | call->operation_ID = FSSTORESTATUS; | 
|  | 1466 |  | 
|  | 1467 | /* marshall the parameters */ | 
|  | 1468 | bp = call->request; | 
|  | 1469 | *bp++ = htonl(FSSTORESTATUS); | 
|  | 1470 | *bp++ = htonl(vnode->fid.vid); | 
|  | 1471 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 1472 | *bp++ = htonl(vnode->fid.unique); | 
|  | 1473 |  | 
|  | 1474 | xdr_encode_AFS_StoreStatus(&bp, attr); | 
|  | 1475 |  | 
|  | 1476 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 1477 | } | 
| David Howells | 45222b9 | 2007-05-10 22:22:20 -0700 | [diff] [blame] | 1478 |  | 
|  | 1479 | /* | 
|  | 1480 | * deliver reply data to an FS.GetVolumeStatus | 
|  | 1481 | */ | 
|  | 1482 | static int afs_deliver_fs_get_volume_status(struct afs_call *call, | 
|  | 1483 | struct sk_buff *skb, bool last) | 
|  | 1484 | { | 
|  | 1485 | const __be32 *bp; | 
|  | 1486 | char *p; | 
|  | 1487 | int ret; | 
|  | 1488 |  | 
|  | 1489 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | 
|  | 1490 |  | 
|  | 1491 | switch (call->unmarshall) { | 
|  | 1492 | case 0: | 
|  | 1493 | call->offset = 0; | 
|  | 1494 | call->unmarshall++; | 
|  | 1495 |  | 
|  | 1496 | /* extract the returned status record */ | 
|  | 1497 | case 1: | 
|  | 1498 | _debug("extract status"); | 
|  | 1499 | ret = afs_extract_data(call, skb, last, call->buffer, | 
|  | 1500 | 12 * 4); | 
|  | 1501 | switch (ret) { | 
|  | 1502 | case 0:		break; | 
|  | 1503 | case -EAGAIN:	return 0; | 
|  | 1504 | default:	return ret; | 
|  | 1505 | } | 
|  | 1506 |  | 
|  | 1507 | bp = call->buffer; | 
|  | 1508 | xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2); | 
|  | 1509 | call->offset = 0; | 
|  | 1510 | call->unmarshall++; | 
|  | 1511 |  | 
|  | 1512 | /* extract the volume name length */ | 
|  | 1513 | case 2: | 
|  | 1514 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | 
|  | 1515 | switch (ret) { | 
|  | 1516 | case 0:		break; | 
|  | 1517 | case -EAGAIN:	return 0; | 
|  | 1518 | default:	return ret; | 
|  | 1519 | } | 
|  | 1520 |  | 
|  | 1521 | call->count = ntohl(call->tmp); | 
|  | 1522 | _debug("volname length: %u", call->count); | 
|  | 1523 | if (call->count >= AFSNAMEMAX) | 
|  | 1524 | return -EBADMSG; | 
|  | 1525 | call->offset = 0; | 
|  | 1526 | call->unmarshall++; | 
|  | 1527 |  | 
|  | 1528 | /* extract the volume name */ | 
|  | 1529 | case 3: | 
|  | 1530 | _debug("extract volname"); | 
|  | 1531 | if (call->count > 0) { | 
|  | 1532 | ret = afs_extract_data(call, skb, last, call->reply3, | 
|  | 1533 | call->count); | 
|  | 1534 | switch (ret) { | 
|  | 1535 | case 0:		break; | 
|  | 1536 | case -EAGAIN:	return 0; | 
|  | 1537 | default:	return ret; | 
|  | 1538 | } | 
|  | 1539 | } | 
|  | 1540 |  | 
|  | 1541 | p = call->reply3; | 
|  | 1542 | p[call->count] = 0; | 
|  | 1543 | _debug("volname '%s'", p); | 
|  | 1544 |  | 
|  | 1545 | call->offset = 0; | 
|  | 1546 | call->unmarshall++; | 
|  | 1547 |  | 
|  | 1548 | /* extract the volume name padding */ | 
|  | 1549 | if ((call->count & 3) == 0) { | 
|  | 1550 | call->unmarshall++; | 
|  | 1551 | goto no_volname_padding; | 
|  | 1552 | } | 
|  | 1553 | call->count = 4 - (call->count & 3); | 
|  | 1554 |  | 
|  | 1555 | case 4: | 
|  | 1556 | ret = afs_extract_data(call, skb, last, call->buffer, | 
|  | 1557 | call->count); | 
|  | 1558 | switch (ret) { | 
|  | 1559 | case 0:		break; | 
|  | 1560 | case -EAGAIN:	return 0; | 
|  | 1561 | default:	return ret; | 
|  | 1562 | } | 
|  | 1563 |  | 
|  | 1564 | call->offset = 0; | 
|  | 1565 | call->unmarshall++; | 
|  | 1566 | no_volname_padding: | 
|  | 1567 |  | 
|  | 1568 | /* extract the offline message length */ | 
|  | 1569 | case 5: | 
|  | 1570 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | 
|  | 1571 | switch (ret) { | 
|  | 1572 | case 0:		break; | 
|  | 1573 | case -EAGAIN:	return 0; | 
|  | 1574 | default:	return ret; | 
|  | 1575 | } | 
|  | 1576 |  | 
|  | 1577 | call->count = ntohl(call->tmp); | 
|  | 1578 | _debug("offline msg length: %u", call->count); | 
|  | 1579 | if (call->count >= AFSNAMEMAX) | 
|  | 1580 | return -EBADMSG; | 
|  | 1581 | call->offset = 0; | 
|  | 1582 | call->unmarshall++; | 
|  | 1583 |  | 
|  | 1584 | /* extract the offline message */ | 
|  | 1585 | case 6: | 
|  | 1586 | _debug("extract offline"); | 
|  | 1587 | if (call->count > 0) { | 
|  | 1588 | ret = afs_extract_data(call, skb, last, call->reply3, | 
|  | 1589 | call->count); | 
|  | 1590 | switch (ret) { | 
|  | 1591 | case 0:		break; | 
|  | 1592 | case -EAGAIN:	return 0; | 
|  | 1593 | default:	return ret; | 
|  | 1594 | } | 
|  | 1595 | } | 
|  | 1596 |  | 
|  | 1597 | p = call->reply3; | 
|  | 1598 | p[call->count] = 0; | 
|  | 1599 | _debug("offline '%s'", p); | 
|  | 1600 |  | 
|  | 1601 | call->offset = 0; | 
|  | 1602 | call->unmarshall++; | 
|  | 1603 |  | 
|  | 1604 | /* extract the offline message padding */ | 
|  | 1605 | if ((call->count & 3) == 0) { | 
|  | 1606 | call->unmarshall++; | 
|  | 1607 | goto no_offline_padding; | 
|  | 1608 | } | 
|  | 1609 | call->count = 4 - (call->count & 3); | 
|  | 1610 |  | 
|  | 1611 | case 7: | 
|  | 1612 | ret = afs_extract_data(call, skb, last, call->buffer, | 
|  | 1613 | call->count); | 
|  | 1614 | switch (ret) { | 
|  | 1615 | case 0:		break; | 
|  | 1616 | case -EAGAIN:	return 0; | 
|  | 1617 | default:	return ret; | 
|  | 1618 | } | 
|  | 1619 |  | 
|  | 1620 | call->offset = 0; | 
|  | 1621 | call->unmarshall++; | 
|  | 1622 | no_offline_padding: | 
|  | 1623 |  | 
|  | 1624 | /* extract the message of the day length */ | 
|  | 1625 | case 8: | 
|  | 1626 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | 
|  | 1627 | switch (ret) { | 
|  | 1628 | case 0:		break; | 
|  | 1629 | case -EAGAIN:	return 0; | 
|  | 1630 | default:	return ret; | 
|  | 1631 | } | 
|  | 1632 |  | 
|  | 1633 | call->count = ntohl(call->tmp); | 
|  | 1634 | _debug("motd length: %u", call->count); | 
|  | 1635 | if (call->count >= AFSNAMEMAX) | 
|  | 1636 | return -EBADMSG; | 
|  | 1637 | call->offset = 0; | 
|  | 1638 | call->unmarshall++; | 
|  | 1639 |  | 
|  | 1640 | /* extract the message of the day */ | 
|  | 1641 | case 9: | 
|  | 1642 | _debug("extract motd"); | 
|  | 1643 | if (call->count > 0) { | 
|  | 1644 | ret = afs_extract_data(call, skb, last, call->reply3, | 
|  | 1645 | call->count); | 
|  | 1646 | switch (ret) { | 
|  | 1647 | case 0:		break; | 
|  | 1648 | case -EAGAIN:	return 0; | 
|  | 1649 | default:	return ret; | 
|  | 1650 | } | 
|  | 1651 | } | 
|  | 1652 |  | 
|  | 1653 | p = call->reply3; | 
|  | 1654 | p[call->count] = 0; | 
|  | 1655 | _debug("motd '%s'", p); | 
|  | 1656 |  | 
|  | 1657 | call->offset = 0; | 
|  | 1658 | call->unmarshall++; | 
|  | 1659 |  | 
|  | 1660 | /* extract the message of the day padding */ | 
|  | 1661 | if ((call->count & 3) == 0) { | 
|  | 1662 | call->unmarshall++; | 
|  | 1663 | goto no_motd_padding; | 
|  | 1664 | } | 
|  | 1665 | call->count = 4 - (call->count & 3); | 
|  | 1666 |  | 
|  | 1667 | case 10: | 
|  | 1668 | ret = afs_extract_data(call, skb, last, call->buffer, | 
|  | 1669 | call->count); | 
|  | 1670 | switch (ret) { | 
|  | 1671 | case 0:		break; | 
|  | 1672 | case -EAGAIN:	return 0; | 
|  | 1673 | default:	return ret; | 
|  | 1674 | } | 
|  | 1675 |  | 
|  | 1676 | call->offset = 0; | 
|  | 1677 | call->unmarshall++; | 
|  | 1678 | no_motd_padding: | 
|  | 1679 |  | 
|  | 1680 | case 11: | 
|  | 1681 | _debug("trailer %d", skb->len); | 
|  | 1682 | if (skb->len != 0) | 
|  | 1683 | return -EBADMSG; | 
|  | 1684 | break; | 
|  | 1685 | } | 
|  | 1686 |  | 
|  | 1687 | if (!last) | 
|  | 1688 | return 0; | 
|  | 1689 |  | 
|  | 1690 | _leave(" = 0 [done]"); | 
|  | 1691 | return 0; | 
|  | 1692 | } | 
|  | 1693 |  | 
|  | 1694 | /* | 
|  | 1695 | * destroy an FS.GetVolumeStatus call | 
|  | 1696 | */ | 
|  | 1697 | static void afs_get_volume_status_call_destructor(struct afs_call *call) | 
|  | 1698 | { | 
|  | 1699 | kfree(call->reply3); | 
|  | 1700 | call->reply3 = NULL; | 
|  | 1701 | afs_flat_call_destructor(call); | 
|  | 1702 | } | 
|  | 1703 |  | 
|  | 1704 | /* | 
|  | 1705 | * FS.GetVolumeStatus operation type | 
|  | 1706 | */ | 
|  | 1707 | static const struct afs_call_type afs_RXFSGetVolumeStatus = { | 
|  | 1708 | .name		= "FS.GetVolumeStatus", | 
|  | 1709 | .deliver	= afs_deliver_fs_get_volume_status, | 
|  | 1710 | .abort_to_error	= afs_abort_to_error, | 
|  | 1711 | .destructor	= afs_get_volume_status_call_destructor, | 
|  | 1712 | }; | 
|  | 1713 |  | 
|  | 1714 | /* | 
|  | 1715 | * fetch the status of a volume | 
|  | 1716 | */ | 
|  | 1717 | int afs_fs_get_volume_status(struct afs_server *server, | 
|  | 1718 | struct key *key, | 
|  | 1719 | struct afs_vnode *vnode, | 
|  | 1720 | struct afs_volume_status *vs, | 
|  | 1721 | const struct afs_wait_mode *wait_mode) | 
|  | 1722 | { | 
|  | 1723 | struct afs_call *call; | 
|  | 1724 | __be32 *bp; | 
|  | 1725 | void *tmpbuf; | 
|  | 1726 |  | 
|  | 1727 | _enter(""); | 
|  | 1728 |  | 
|  | 1729 | tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); | 
|  | 1730 | if (!tmpbuf) | 
|  | 1731 | return -ENOMEM; | 
|  | 1732 |  | 
|  | 1733 | call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4); | 
|  | 1734 | if (!call) { | 
|  | 1735 | kfree(tmpbuf); | 
|  | 1736 | return -ENOMEM; | 
|  | 1737 | } | 
|  | 1738 |  | 
|  | 1739 | call->key = key; | 
|  | 1740 | call->reply = vnode; | 
|  | 1741 | call->reply2 = vs; | 
|  | 1742 | call->reply3 = tmpbuf; | 
|  | 1743 | call->service_id = FS_SERVICE; | 
|  | 1744 | call->port = htons(AFS_FS_PORT); | 
|  | 1745 |  | 
|  | 1746 | /* marshall the parameters */ | 
|  | 1747 | bp = call->request; | 
|  | 1748 | bp[0] = htonl(FSGETVOLUMESTATUS); | 
|  | 1749 | bp[1] = htonl(vnode->fid.vid); | 
|  | 1750 |  | 
|  | 1751 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 1752 | } | 
| David Howells | e8d6c55 | 2007-07-15 23:40:12 -0700 | [diff] [blame] | 1753 |  | 
|  | 1754 | /* | 
|  | 1755 | * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock | 
|  | 1756 | */ | 
|  | 1757 | static int afs_deliver_fs_xxxx_lock(struct afs_call *call, | 
|  | 1758 | struct sk_buff *skb, bool last) | 
|  | 1759 | { | 
|  | 1760 | const __be32 *bp; | 
|  | 1761 |  | 
|  | 1762 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | 
|  | 1763 |  | 
|  | 1764 | afs_transfer_reply(call, skb); | 
|  | 1765 | if (!last) | 
|  | 1766 | return 0; | 
|  | 1767 |  | 
|  | 1768 | if (call->reply_size != call->reply_max) | 
|  | 1769 | return -EBADMSG; | 
|  | 1770 |  | 
|  | 1771 | /* unmarshall the reply once we've received all of it */ | 
|  | 1772 | bp = call->buffer; | 
|  | 1773 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 
|  | 1774 |  | 
|  | 1775 | _leave(" = 0 [done]"); | 
|  | 1776 | return 0; | 
|  | 1777 | } | 
|  | 1778 |  | 
|  | 1779 | /* | 
|  | 1780 | * FS.SetLock operation type | 
|  | 1781 | */ | 
|  | 1782 | static const struct afs_call_type afs_RXFSSetLock = { | 
|  | 1783 | .name		= "FS.SetLock", | 
|  | 1784 | .deliver	= afs_deliver_fs_xxxx_lock, | 
|  | 1785 | .abort_to_error	= afs_abort_to_error, | 
|  | 1786 | .destructor	= afs_flat_call_destructor, | 
|  | 1787 | }; | 
|  | 1788 |  | 
|  | 1789 | /* | 
|  | 1790 | * FS.ExtendLock operation type | 
|  | 1791 | */ | 
|  | 1792 | static const struct afs_call_type afs_RXFSExtendLock = { | 
|  | 1793 | .name		= "FS.ExtendLock", | 
|  | 1794 | .deliver	= afs_deliver_fs_xxxx_lock, | 
|  | 1795 | .abort_to_error	= afs_abort_to_error, | 
|  | 1796 | .destructor	= afs_flat_call_destructor, | 
|  | 1797 | }; | 
|  | 1798 |  | 
|  | 1799 | /* | 
|  | 1800 | * FS.ReleaseLock operation type | 
|  | 1801 | */ | 
|  | 1802 | static const struct afs_call_type afs_RXFSReleaseLock = { | 
|  | 1803 | .name		= "FS.ReleaseLock", | 
|  | 1804 | .deliver	= afs_deliver_fs_xxxx_lock, | 
|  | 1805 | .abort_to_error	= afs_abort_to_error, | 
|  | 1806 | .destructor	= afs_flat_call_destructor, | 
|  | 1807 | }; | 
|  | 1808 |  | 
|  | 1809 | /* | 
|  | 1810 | * get a lock on a file | 
|  | 1811 | */ | 
|  | 1812 | int afs_fs_set_lock(struct afs_server *server, | 
|  | 1813 | struct key *key, | 
|  | 1814 | struct afs_vnode *vnode, | 
|  | 1815 | afs_lock_type_t type, | 
|  | 1816 | const struct afs_wait_mode *wait_mode) | 
|  | 1817 | { | 
|  | 1818 | struct afs_call *call; | 
|  | 1819 | __be32 *bp; | 
|  | 1820 |  | 
|  | 1821 | _enter(""); | 
|  | 1822 |  | 
|  | 1823 | call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 6 * 4); | 
|  | 1824 | if (!call) | 
|  | 1825 | return -ENOMEM; | 
|  | 1826 |  | 
|  | 1827 | call->key = key; | 
|  | 1828 | call->reply = vnode; | 
|  | 1829 | call->service_id = FS_SERVICE; | 
|  | 1830 | call->port = htons(AFS_FS_PORT); | 
|  | 1831 |  | 
|  | 1832 | /* marshall the parameters */ | 
|  | 1833 | bp = call->request; | 
|  | 1834 | *bp++ = htonl(FSSETLOCK); | 
|  | 1835 | *bp++ = htonl(vnode->fid.vid); | 
|  | 1836 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 1837 | *bp++ = htonl(vnode->fid.unique); | 
|  | 1838 | *bp++ = htonl(type); | 
|  | 1839 |  | 
|  | 1840 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 1841 | } | 
|  | 1842 |  | 
|  | 1843 | /* | 
|  | 1844 | * extend a lock on a file | 
|  | 1845 | */ | 
|  | 1846 | int afs_fs_extend_lock(struct afs_server *server, | 
|  | 1847 | struct key *key, | 
|  | 1848 | struct afs_vnode *vnode, | 
|  | 1849 | const struct afs_wait_mode *wait_mode) | 
|  | 1850 | { | 
|  | 1851 | struct afs_call *call; | 
|  | 1852 | __be32 *bp; | 
|  | 1853 |  | 
|  | 1854 | _enter(""); | 
|  | 1855 |  | 
|  | 1856 | call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 6 * 4); | 
|  | 1857 | if (!call) | 
|  | 1858 | return -ENOMEM; | 
|  | 1859 |  | 
|  | 1860 | call->key = key; | 
|  | 1861 | call->reply = vnode; | 
|  | 1862 | call->service_id = FS_SERVICE; | 
|  | 1863 | call->port = htons(AFS_FS_PORT); | 
|  | 1864 |  | 
|  | 1865 | /* marshall the parameters */ | 
|  | 1866 | bp = call->request; | 
|  | 1867 | *bp++ = htonl(FSEXTENDLOCK); | 
|  | 1868 | *bp++ = htonl(vnode->fid.vid); | 
|  | 1869 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 1870 | *bp++ = htonl(vnode->fid.unique); | 
|  | 1871 |  | 
|  | 1872 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 1873 | } | 
|  | 1874 |  | 
|  | 1875 | /* | 
|  | 1876 | * release a lock on a file | 
|  | 1877 | */ | 
|  | 1878 | int afs_fs_release_lock(struct afs_server *server, | 
|  | 1879 | struct key *key, | 
|  | 1880 | struct afs_vnode *vnode, | 
|  | 1881 | const struct afs_wait_mode *wait_mode) | 
|  | 1882 | { | 
|  | 1883 | struct afs_call *call; | 
|  | 1884 | __be32 *bp; | 
|  | 1885 |  | 
|  | 1886 | _enter(""); | 
|  | 1887 |  | 
|  | 1888 | call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 6 * 4); | 
|  | 1889 | if (!call) | 
|  | 1890 | return -ENOMEM; | 
|  | 1891 |  | 
|  | 1892 | call->key = key; | 
|  | 1893 | call->reply = vnode; | 
|  | 1894 | call->service_id = FS_SERVICE; | 
|  | 1895 | call->port = htons(AFS_FS_PORT); | 
|  | 1896 |  | 
|  | 1897 | /* marshall the parameters */ | 
|  | 1898 | bp = call->request; | 
|  | 1899 | *bp++ = htonl(FSRELEASELOCK); | 
|  | 1900 | *bp++ = htonl(vnode->fid.vid); | 
|  | 1901 | *bp++ = htonl(vnode->fid.vnode); | 
|  | 1902 | *bp++ = htonl(vnode->fid.unique); | 
|  | 1903 |  | 
|  | 1904 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 
|  | 1905 | } |