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