diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-06-17 20:59:58 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-06-17 20:59:58 -0400 |
| commit | 301933a0acfdec837fd8b4884093b3f0fff01d8a (patch) | |
| tree | 1f2412a30d710493179b1b3743cf30302872df15 | |
| parent | 3fe0344faf7fdcb158bd5c1a9aec960a8d70c8e8 (diff) | |
| parent | 68f3f90133d56e0c38f04f991e662c2b21592b31 (diff) | |
Merge commit 'linux-pnfs/nfs41-for-2.6.31' into nfsv41-for-2.6.31
38 files changed, 4589 insertions, 374 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index e67f3ec07736..5d6d6f415935 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
| @@ -74,6 +74,15 @@ config NFS_V4 | |||
| 74 | 74 | ||
| 75 | If unsure, say N. | 75 | If unsure, say N. |
| 76 | 76 | ||
| 77 | config NFS_V4_1 | ||
| 78 | bool "NFS client support for NFSv4.1 (DEVELOPER ONLY)" | ||
| 79 | depends on NFS_V4 && EXPERIMENTAL | ||
| 80 | help | ||
| 81 | This option enables support for minor version 1 of the NFSv4 protocol | ||
| 82 | (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client. | ||
| 83 | |||
| 84 | Unless you're an NFS developer, say N. | ||
| 85 | |||
| 77 | config ROOT_NFS | 86 | config ROOT_NFS |
| 78 | bool "Root file system on NFS" | 87 | bool "Root file system on NFS" |
| 79 | depends on NFS_FS=y && IP_PNP | 88 | depends on NFS_FS=y && IP_PNP |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index a886e692ddd0..e69b8f61189e 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
| @@ -17,6 +17,9 @@ | |||
| 17 | #include <linux/freezer.h> | 17 | #include <linux/freezer.h> |
| 18 | #include <linux/kthread.h> | 18 | #include <linux/kthread.h> |
| 19 | #include <linux/sunrpc/svcauth_gss.h> | 19 | #include <linux/sunrpc/svcauth_gss.h> |
| 20 | #if defined(CONFIG_NFS_V4_1) | ||
| 21 | #include <linux/sunrpc/bc_xprt.h> | ||
| 22 | #endif | ||
| 20 | 23 | ||
| 21 | #include <net/inet_sock.h> | 24 | #include <net/inet_sock.h> |
| 22 | 25 | ||
| @@ -28,11 +31,12 @@ | |||
| 28 | 31 | ||
| 29 | struct nfs_callback_data { | 32 | struct nfs_callback_data { |
| 30 | unsigned int users; | 33 | unsigned int users; |
| 34 | struct svc_serv *serv; | ||
| 31 | struct svc_rqst *rqst; | 35 | struct svc_rqst *rqst; |
| 32 | struct task_struct *task; | 36 | struct task_struct *task; |
| 33 | }; | 37 | }; |
| 34 | 38 | ||
| 35 | static struct nfs_callback_data nfs_callback_info; | 39 | static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1]; |
| 36 | static DEFINE_MUTEX(nfs_callback_mutex); | 40 | static DEFINE_MUTEX(nfs_callback_mutex); |
| 37 | static struct svc_program nfs4_callback_program; | 41 | static struct svc_program nfs4_callback_program; |
| 38 | 42 | ||
| @@ -56,10 +60,10 @@ module_param_call(callback_tcpport, param_set_port, param_get_int, | |||
| 56 | &nfs_callback_set_tcpport, 0644); | 60 | &nfs_callback_set_tcpport, 0644); |
| 57 | 61 | ||
| 58 | /* | 62 | /* |
| 59 | * This is the callback kernel thread. | 63 | * This is the NFSv4 callback kernel thread. |
| 60 | */ | 64 | */ |
| 61 | static int | 65 | static int |
| 62 | nfs_callback_svc(void *vrqstp) | 66 | nfs4_callback_svc(void *vrqstp) |
| 63 | { | 67 | { |
| 64 | int err, preverr = 0; | 68 | int err, preverr = 0; |
| 65 | struct svc_rqst *rqstp = vrqstp; | 69 | struct svc_rqst *rqstp = vrqstp; |
| @@ -97,20 +101,12 @@ nfs_callback_svc(void *vrqstp) | |||
| 97 | } | 101 | } |
| 98 | 102 | ||
| 99 | /* | 103 | /* |
| 100 | * Bring up the callback thread if it is not already up. | 104 | * Prepare to bring up the NFSv4 callback service |
| 101 | */ | 105 | */ |
| 102 | int nfs_callback_up(void) | 106 | struct svc_rqst * |
| 107 | nfs4_callback_up(struct svc_serv *serv) | ||
| 103 | { | 108 | { |
| 104 | struct svc_serv *serv = NULL; | 109 | int ret; |
| 105 | int ret = 0; | ||
| 106 | |||
| 107 | mutex_lock(&nfs_callback_mutex); | ||
| 108 | if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) | ||
| 109 | goto out; | ||
| 110 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | ||
| 111 | ret = -ENOMEM; | ||
| 112 | if (!serv) | ||
| 113 | goto out_err; | ||
| 114 | 110 | ||
| 115 | ret = svc_create_xprt(serv, "tcp", PF_INET, | 111 | ret = svc_create_xprt(serv, "tcp", PF_INET, |
| 116 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 112 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
| @@ -131,23 +127,168 @@ int nfs_callback_up(void) | |||
| 131 | goto out_err; | 127 | goto out_err; |
| 132 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ | 128 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ |
| 133 | 129 | ||
| 134 | nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); | 130 | return svc_prepare_thread(serv, &serv->sv_pools[0]); |
| 135 | if (IS_ERR(nfs_callback_info.rqst)) { | 131 | |
| 136 | ret = PTR_ERR(nfs_callback_info.rqst); | 132 | out_err: |
| 137 | nfs_callback_info.rqst = NULL; | 133 | if (ret == 0) |
| 134 | ret = -ENOMEM; | ||
| 135 | return ERR_PTR(ret); | ||
| 136 | } | ||
| 137 | |||
| 138 | #if defined(CONFIG_NFS_V4_1) | ||
| 139 | /* | ||
| 140 | * The callback service for NFSv4.1 callbacks | ||
| 141 | */ | ||
| 142 | static int | ||
| 143 | nfs41_callback_svc(void *vrqstp) | ||
| 144 | { | ||
| 145 | struct svc_rqst *rqstp = vrqstp; | ||
| 146 | struct svc_serv *serv = rqstp->rq_server; | ||
| 147 | struct rpc_rqst *req; | ||
| 148 | int error; | ||
| 149 | DEFINE_WAIT(wq); | ||
| 150 | |||
| 151 | set_freezable(); | ||
| 152 | |||
| 153 | /* | ||
| 154 | * FIXME: do we really need to run this under the BKL? If so, please | ||
| 155 | * add a comment about what it's intended to protect. | ||
| 156 | */ | ||
| 157 | lock_kernel(); | ||
| 158 | while (!kthread_should_stop()) { | ||
| 159 | prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); | ||
| 160 | spin_lock_bh(&serv->sv_cb_lock); | ||
| 161 | if (!list_empty(&serv->sv_cb_list)) { | ||
| 162 | req = list_first_entry(&serv->sv_cb_list, | ||
| 163 | struct rpc_rqst, rq_bc_list); | ||
| 164 | list_del(&req->rq_bc_list); | ||
| 165 | spin_unlock_bh(&serv->sv_cb_lock); | ||
| 166 | dprintk("Invoking bc_svc_process()\n"); | ||
| 167 | error = bc_svc_process(serv, req, rqstp); | ||
| 168 | dprintk("bc_svc_process() returned w/ error code= %d\n", | ||
| 169 | error); | ||
| 170 | } else { | ||
| 171 | spin_unlock_bh(&serv->sv_cb_lock); | ||
| 172 | schedule(); | ||
| 173 | } | ||
| 174 | finish_wait(&serv->sv_cb_waitq, &wq); | ||
| 175 | } | ||
| 176 | unlock_kernel(); | ||
| 177 | return 0; | ||
| 178 | } | ||
| 179 | |||
| 180 | /* | ||
| 181 | * Bring up the NFSv4.1 callback service | ||
| 182 | */ | ||
| 183 | struct svc_rqst * | ||
| 184 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) | ||
| 185 | { | ||
| 186 | struct svc_xprt *bc_xprt; | ||
| 187 | struct svc_rqst *rqstp = ERR_PTR(-ENOMEM); | ||
| 188 | |||
| 189 | dprintk("--> %s\n", __func__); | ||
| 190 | /* Create a svc_sock for the service */ | ||
| 191 | bc_xprt = svc_sock_create(serv, xprt->prot); | ||
| 192 | if (!bc_xprt) | ||
| 193 | goto out; | ||
| 194 | |||
| 195 | /* | ||
| 196 | * Save the svc_serv in the transport so that it can | ||
| 197 | * be referenced when the session backchannel is initialized | ||
| 198 | */ | ||
| 199 | serv->bc_xprt = bc_xprt; | ||
| 200 | xprt->bc_serv = serv; | ||
| 201 | |||
| 202 | INIT_LIST_HEAD(&serv->sv_cb_list); | ||
| 203 | spin_lock_init(&serv->sv_cb_lock); | ||
| 204 | init_waitqueue_head(&serv->sv_cb_waitq); | ||
| 205 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); | ||
| 206 | if (IS_ERR(rqstp)) | ||
| 207 | svc_sock_destroy(bc_xprt); | ||
| 208 | out: | ||
| 209 | dprintk("--> %s return %p\n", __func__, rqstp); | ||
| 210 | return rqstp; | ||
| 211 | } | ||
| 212 | |||
| 213 | static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, | ||
| 214 | struct svc_serv *serv, struct rpc_xprt *xprt, | ||
| 215 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | ||
| 216 | { | ||
| 217 | if (minorversion) { | ||
| 218 | *rqstpp = nfs41_callback_up(serv, xprt); | ||
| 219 | *callback_svc = nfs41_callback_svc; | ||
| 220 | } | ||
| 221 | return minorversion; | ||
| 222 | } | ||
| 223 | |||
| 224 | static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | ||
| 225 | struct nfs_callback_data *cb_info) | ||
| 226 | { | ||
| 227 | if (minorversion) | ||
| 228 | xprt->bc_serv = cb_info->serv; | ||
| 229 | } | ||
| 230 | #else | ||
| 231 | static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, | ||
| 232 | struct svc_serv *serv, struct rpc_xprt *xprt, | ||
| 233 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | ||
| 234 | { | ||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | |||
| 238 | static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | ||
| 239 | struct nfs_callback_data *cb_info) | ||
| 240 | { | ||
| 241 | } | ||
| 242 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 243 | |||
| 244 | /* | ||
| 245 | * Bring up the callback thread if it is not already up. | ||
| 246 | */ | ||
| 247 | int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) | ||
| 248 | { | ||
| 249 | struct svc_serv *serv = NULL; | ||
| 250 | struct svc_rqst *rqstp; | ||
| 251 | int (*callback_svc)(void *vrqstp); | ||
| 252 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | ||
| 253 | char svc_name[12]; | ||
| 254 | int ret = 0; | ||
| 255 | int minorversion_setup; | ||
| 256 | |||
| 257 | mutex_lock(&nfs_callback_mutex); | ||
| 258 | if (cb_info->users++ || cb_info->task != NULL) { | ||
| 259 | nfs_callback_bc_serv(minorversion, xprt, cb_info); | ||
| 260 | goto out; | ||
| 261 | } | ||
| 262 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | ||
| 263 | if (!serv) { | ||
| 264 | ret = -ENOMEM; | ||
| 265 | goto out_err; | ||
| 266 | } | ||
| 267 | |||
| 268 | minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, | ||
| 269 | serv, xprt, &rqstp, &callback_svc); | ||
| 270 | if (!minorversion_setup) { | ||
| 271 | /* v4.0 callback setup */ | ||
| 272 | rqstp = nfs4_callback_up(serv); | ||
| 273 | callback_svc = nfs4_callback_svc; | ||
| 274 | } | ||
| 275 | |||
| 276 | if (IS_ERR(rqstp)) { | ||
| 277 | ret = PTR_ERR(rqstp); | ||
| 138 | goto out_err; | 278 | goto out_err; |
| 139 | } | 279 | } |
| 140 | 280 | ||
| 141 | svc_sock_update_bufs(serv); | 281 | svc_sock_update_bufs(serv); |
| 142 | 282 | ||
| 143 | nfs_callback_info.task = kthread_run(nfs_callback_svc, | 283 | sprintf(svc_name, "nfsv4.%u-svc", minorversion); |
| 144 | nfs_callback_info.rqst, | 284 | cb_info->serv = serv; |
| 145 | "nfsv4-svc"); | 285 | cb_info->rqst = rqstp; |
| 146 | if (IS_ERR(nfs_callback_info.task)) { | 286 | cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name); |
| 147 | ret = PTR_ERR(nfs_callback_info.task); | 287 | if (IS_ERR(cb_info->task)) { |
| 148 | svc_exit_thread(nfs_callback_info.rqst); | 288 | ret = PTR_ERR(cb_info->task); |
| 149 | nfs_callback_info.rqst = NULL; | 289 | svc_exit_thread(cb_info->rqst); |
| 150 | nfs_callback_info.task = NULL; | 290 | cb_info->rqst = NULL; |
| 291 | cb_info->task = NULL; | ||
| 151 | goto out_err; | 292 | goto out_err; |
| 152 | } | 293 | } |
| 153 | out: | 294 | out: |
| @@ -164,22 +305,25 @@ out: | |||
| 164 | out_err: | 305 | out_err: |
| 165 | dprintk("NFS: Couldn't create callback socket or server thread; " | 306 | dprintk("NFS: Couldn't create callback socket or server thread; " |
| 166 | "err = %d\n", ret); | 307 | "err = %d\n", ret); |
| 167 | nfs_callback_info.users--; | 308 | cb_info->users--; |
| 168 | goto out; | 309 | goto out; |
| 169 | } | 310 | } |
| 170 | 311 | ||
| 171 | /* | 312 | /* |
| 172 | * Kill the callback thread if it's no longer being used. | 313 | * Kill the callback thread if it's no longer being used. |
| 173 | */ | 314 | */ |
| 174 | void nfs_callback_down(void) | 315 | void nfs_callback_down(int minorversion) |
| 175 | { | 316 | { |
| 317 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | ||
| 318 | |||
| 176 | mutex_lock(&nfs_callback_mutex); | 319 | mutex_lock(&nfs_callback_mutex); |
| 177 | nfs_callback_info.users--; | 320 | cb_info->users--; |
| 178 | if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) { | 321 | if (cb_info->users == 0 && cb_info->task != NULL) { |
| 179 | kthread_stop(nfs_callback_info.task); | 322 | kthread_stop(cb_info->task); |
| 180 | svc_exit_thread(nfs_callback_info.rqst); | 323 | svc_exit_thread(cb_info->rqst); |
| 181 | nfs_callback_info.rqst = NULL; | 324 | cb_info->serv = NULL; |
| 182 | nfs_callback_info.task = NULL; | 325 | cb_info->rqst = NULL; |
| 326 | cb_info->task = NULL; | ||
| 183 | } | 327 | } |
| 184 | mutex_unlock(&nfs_callback_mutex); | 328 | mutex_unlock(&nfs_callback_mutex); |
| 185 | } | 329 | } |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index e110e286a262..07baa8254ca1 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
| @@ -20,13 +20,24 @@ enum nfs4_callback_procnum { | |||
| 20 | enum nfs4_callback_opnum { | 20 | enum nfs4_callback_opnum { |
| 21 | OP_CB_GETATTR = 3, | 21 | OP_CB_GETATTR = 3, |
| 22 | OP_CB_RECALL = 4, | 22 | OP_CB_RECALL = 4, |
| 23 | /* Callback operations new to NFSv4.1 */ | ||
| 24 | OP_CB_LAYOUTRECALL = 5, | ||
| 25 | OP_CB_NOTIFY = 6, | ||
| 26 | OP_CB_PUSH_DELEG = 7, | ||
| 27 | OP_CB_RECALL_ANY = 8, | ||
| 28 | OP_CB_RECALLABLE_OBJ_AVAIL = 9, | ||
| 29 | OP_CB_RECALL_SLOT = 10, | ||
| 30 | OP_CB_SEQUENCE = 11, | ||
| 31 | OP_CB_WANTS_CANCELLED = 12, | ||
| 32 | OP_CB_NOTIFY_LOCK = 13, | ||
| 33 | OP_CB_NOTIFY_DEVICEID = 14, | ||
| 23 | OP_CB_ILLEGAL = 10044, | 34 | OP_CB_ILLEGAL = 10044, |
| 24 | }; | 35 | }; |
| 25 | 36 | ||
| 26 | struct cb_compound_hdr_arg { | 37 | struct cb_compound_hdr_arg { |
| 27 | unsigned int taglen; | 38 | unsigned int taglen; |
| 28 | const char *tag; | 39 | const char *tag; |
| 29 | unsigned int callback_ident; | 40 | unsigned int minorversion; |
| 30 | unsigned nops; | 41 | unsigned nops; |
| 31 | }; | 42 | }; |
| 32 | 43 | ||
| @@ -59,16 +70,59 @@ struct cb_recallargs { | |||
| 59 | uint32_t truncate; | 70 | uint32_t truncate; |
| 60 | }; | 71 | }; |
| 61 | 72 | ||
| 73 | #if defined(CONFIG_NFS_V4_1) | ||
| 74 | |||
| 75 | struct referring_call { | ||
| 76 | uint32_t rc_sequenceid; | ||
| 77 | uint32_t rc_slotid; | ||
| 78 | }; | ||
| 79 | |||
| 80 | struct referring_call_list { | ||
| 81 | struct nfs4_sessionid rcl_sessionid; | ||
| 82 | uint32_t rcl_nrefcalls; | ||
| 83 | struct referring_call *rcl_refcalls; | ||
| 84 | }; | ||
| 85 | |||
| 86 | struct cb_sequenceargs { | ||
| 87 | struct sockaddr *csa_addr; | ||
| 88 | struct nfs4_sessionid csa_sessionid; | ||
| 89 | uint32_t csa_sequenceid; | ||
| 90 | uint32_t csa_slotid; | ||
| 91 | uint32_t csa_highestslotid; | ||
| 92 | uint32_t csa_cachethis; | ||
| 93 | uint32_t csa_nrclists; | ||
| 94 | struct referring_call_list *csa_rclists; | ||
| 95 | }; | ||
| 96 | |||
| 97 | struct cb_sequenceres { | ||
| 98 | __be32 csr_status; | ||
| 99 | struct nfs4_sessionid csr_sessionid; | ||
| 100 | uint32_t csr_sequenceid; | ||
| 101 | uint32_t csr_slotid; | ||
| 102 | uint32_t csr_highestslotid; | ||
| 103 | uint32_t csr_target_highestslotid; | ||
| 104 | }; | ||
| 105 | |||
| 106 | extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
| 107 | struct cb_sequenceres *res); | ||
| 108 | |||
| 109 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 110 | |||
| 62 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); | 111 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
| 63 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); | 112 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); |
| 64 | 113 | ||
| 65 | #ifdef CONFIG_NFS_V4 | 114 | #ifdef CONFIG_NFS_V4 |
| 66 | extern int nfs_callback_up(void); | 115 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); |
| 67 | extern void nfs_callback_down(void); | 116 | extern void nfs_callback_down(int minorversion); |
| 68 | #else | 117 | #endif /* CONFIG_NFS_V4 */ |
| 69 | #define nfs_callback_up() (0) | 118 | |
| 70 | #define nfs_callback_down() do {} while(0) | 119 | /* |
| 71 | #endif | 120 | * nfs41: Callbacks are expected to not cause substantial latency, |
| 121 | * so we limit their concurrency to 1 by setting up the maximum number | ||
| 122 | * of slots for the backchannel. | ||
| 123 | */ | ||
| 124 | #define NFS41_BC_MIN_CALLBACKS 1 | ||
| 125 | #define NFS41_BC_MAX_CALLBACKS 1 | ||
| 72 | 126 | ||
| 73 | extern unsigned int nfs_callback_set_tcpport; | 127 | extern unsigned int nfs_callback_set_tcpport; |
| 74 | extern unsigned short nfs_callback_tcpport; | 128 | extern unsigned short nfs_callback_tcpport; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index f7e83e23cf9f..b7da1f54da68 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
| @@ -101,3 +101,130 @@ out: | |||
| 101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); | 101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); |
| 102 | return res; | 102 | return res; |
| 103 | } | 103 | } |
| 104 | |||
| 105 | #if defined(CONFIG_NFS_V4_1) | ||
| 106 | |||
| 107 | /* | ||
| 108 | * Validate the sequenceID sent by the server. | ||
| 109 | * Return success if the sequenceID is one more than what we last saw on | ||
| 110 | * this slot, accounting for wraparound. Increments the slot's sequence. | ||
| 111 | * | ||
| 112 | * We don't yet implement a duplicate request cache, so at this time | ||
| 113 | * we will log replays, and process them as if we had not seen them before, | ||
| 114 | * but we don't bump the sequence in the slot. Not too worried about it, | ||
| 115 | * since we only currently implement idempotent callbacks anyway. | ||
| 116 | * | ||
| 117 | * We have a single slot backchannel at this time, so we don't bother | ||
| 118 | * checking the used_slots bit array on the table. The lower layer guarantees | ||
| 119 | * a single outstanding callback request at a time. | ||
| 120 | */ | ||
| 121 | static int | ||
| 122 | validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid) | ||
| 123 | { | ||
| 124 | struct nfs4_slot *slot; | ||
| 125 | |||
| 126 | dprintk("%s enter. slotid %d seqid %d\n", | ||
| 127 | __func__, slotid, seqid); | ||
| 128 | |||
| 129 | if (slotid > NFS41_BC_MAX_CALLBACKS) | ||
| 130 | return htonl(NFS4ERR_BADSLOT); | ||
| 131 | |||
| 132 | slot = tbl->slots + slotid; | ||
| 133 | dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr); | ||
| 134 | |||
| 135 | /* Normal */ | ||
| 136 | if (likely(seqid == slot->seq_nr + 1)) { | ||
| 137 | slot->seq_nr++; | ||
| 138 | return htonl(NFS4_OK); | ||
| 139 | } | ||
| 140 | |||
| 141 | /* Replay */ | ||
| 142 | if (seqid == slot->seq_nr) { | ||
| 143 | dprintk("%s seqid %d is a replay - no DRC available\n", | ||
| 144 | __func__, seqid); | ||
| 145 | return htonl(NFS4_OK); | ||
| 146 | } | ||
| 147 | |||
| 148 | /* Wraparound */ | ||
| 149 | if (seqid == 1 && (slot->seq_nr + 1) == 0) { | ||
| 150 | slot->seq_nr = 1; | ||
| 151 | return htonl(NFS4_OK); | ||
| 152 | } | ||
| 153 | |||
| 154 | /* Misordered request */ | ||
| 155 | return htonl(NFS4ERR_SEQ_MISORDERED); | ||
| 156 | } | ||
| 157 | |||
| 158 | /* | ||
| 159 | * Returns a pointer to a held 'struct nfs_client' that matches the server's | ||
| 160 | * address, major version number, and session ID. It is the caller's | ||
| 161 | * responsibility to release the returned reference. | ||
| 162 | * | ||
| 163 | * Returns NULL if there are no connections with sessions, or if no session | ||
| 164 | * matches the one of interest. | ||
| 165 | */ | ||
| 166 | static struct nfs_client *find_client_with_session( | ||
| 167 | const struct sockaddr *addr, u32 nfsversion, | ||
| 168 | struct nfs4_sessionid *sessionid) | ||
| 169 | { | ||
| 170 | struct nfs_client *clp; | ||
| 171 | |||
| 172 | clp = nfs_find_client(addr, 4); | ||
| 173 | if (clp == NULL) | ||
| 174 | return NULL; | ||
| 175 | |||
| 176 | do { | ||
| 177 | struct nfs_client *prev = clp; | ||
| 178 | |||
| 179 | if (clp->cl_session != NULL) { | ||
| 180 | if (memcmp(clp->cl_session->sess_id.data, | ||
| 181 | sessionid->data, | ||
| 182 | NFS4_MAX_SESSIONID_LEN) == 0) { | ||
| 183 | /* Returns a held reference to clp */ | ||
| 184 | return clp; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | clp = nfs_find_client_next(prev); | ||
| 188 | nfs_put_client(prev); | ||
| 189 | } while (clp != NULL); | ||
| 190 | |||
| 191 | return NULL; | ||
| 192 | } | ||
| 193 | |||
| 194 | /* FIXME: referring calls should be processed */ | ||
| 195 | unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
| 196 | struct cb_sequenceres *res) | ||
| 197 | { | ||
| 198 | struct nfs_client *clp; | ||
| 199 | int i, status; | ||
| 200 | |||
| 201 | for (i = 0; i < args->csa_nrclists; i++) | ||
| 202 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
| 203 | kfree(args->csa_rclists); | ||
| 204 | |||
| 205 | status = htonl(NFS4ERR_BADSESSION); | ||
| 206 | clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid); | ||
| 207 | if (clp == NULL) | ||
| 208 | goto out; | ||
| 209 | |||
| 210 | status = validate_seqid(&clp->cl_session->bc_slot_table, | ||
| 211 | args->csa_slotid, args->csa_sequenceid); | ||
| 212 | if (status) | ||
| 213 | goto out_putclient; | ||
| 214 | |||
| 215 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | ||
| 216 | sizeof(res->csr_sessionid)); | ||
| 217 | res->csr_sequenceid = args->csa_sequenceid; | ||
| 218 | res->csr_slotid = args->csa_slotid; | ||
| 219 | res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
| 220 | res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
| 221 | |||
| 222 | out_putclient: | ||
| 223 | nfs_put_client(clp); | ||
| 224 | out: | ||
| 225 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
| 226 | res->csr_status = status; | ||
| 227 | return res->csr_status; | ||
| 228 | } | ||
| 229 | |||
| 230 | #endif /* CONFIG_NFS_V4_1 */ | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index dd0ef34b5845..e5a2dac5f715 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
| @@ -20,6 +20,11 @@ | |||
| 20 | 2 + 2 + 3 + 3) | 20 | 2 + 2 + 3 + 3) |
| 21 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 21 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
| 22 | 22 | ||
| 23 | #if defined(CONFIG_NFS_V4_1) | ||
| 24 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | ||
| 25 | 4 + 1 + 3) | ||
| 26 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 27 | |||
| 23 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 28 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
| 24 | 29 | ||
| 25 | typedef __be32 (*callback_process_op_t)(void *, void *); | 30 | typedef __be32 (*callback_process_op_t)(void *, void *); |
| @@ -132,7 +137,6 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) | |||
| 132 | static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) | 137 | static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) |
| 133 | { | 138 | { |
| 134 | __be32 *p; | 139 | __be32 *p; |
| 135 | unsigned int minor_version; | ||
| 136 | __be32 status; | 140 | __be32 status; |
| 137 | 141 | ||
| 138 | status = decode_string(xdr, &hdr->taglen, &hdr->tag); | 142 | status = decode_string(xdr, &hdr->taglen, &hdr->tag); |
| @@ -147,15 +151,19 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
| 147 | p = read_buf(xdr, 12); | 151 | p = read_buf(xdr, 12); |
| 148 | if (unlikely(p == NULL)) | 152 | if (unlikely(p == NULL)) |
| 149 | return htonl(NFS4ERR_RESOURCE); | 153 | return htonl(NFS4ERR_RESOURCE); |
| 150 | minor_version = ntohl(*p++); | 154 | hdr->minorversion = ntohl(*p++); |
| 151 | /* Check minor version is zero. */ | 155 | /* Check minor version is zero or one. */ |
| 152 | if (minor_version != 0) { | 156 | if (hdr->minorversion <= 1) { |
| 153 | printk(KERN_WARNING "%s: NFSv4 server callback with illegal minor version %u!\n", | 157 | p++; /* skip callback_ident */ |
| 154 | __func__, minor_version); | 158 | } else { |
| 159 | printk(KERN_WARNING "%s: NFSv4 server callback with " | ||
| 160 | "illegal minor version %u!\n", | ||
| 161 | __func__, hdr->minorversion); | ||
| 155 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | 162 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); |
| 156 | } | 163 | } |
| 157 | hdr->callback_ident = ntohl(*p++); | ||
| 158 | hdr->nops = ntohl(*p); | 164 | hdr->nops = ntohl(*p); |
| 165 | dprintk("%s: minorversion %d nops %d\n", __func__, | ||
| 166 | hdr->minorversion, hdr->nops); | ||
| 159 | return 0; | 167 | return 0; |
| 160 | } | 168 | } |
| 161 | 169 | ||
| @@ -204,6 +212,122 @@ out: | |||
| 204 | return status; | 212 | return status; |
| 205 | } | 213 | } |
| 206 | 214 | ||
| 215 | #if defined(CONFIG_NFS_V4_1) | ||
| 216 | |||
| 217 | static unsigned decode_sessionid(struct xdr_stream *xdr, | ||
| 218 | struct nfs4_sessionid *sid) | ||
| 219 | { | ||
| 220 | uint32_t *p; | ||
| 221 | int len = NFS4_MAX_SESSIONID_LEN; | ||
| 222 | |||
| 223 | p = read_buf(xdr, len); | ||
| 224 | if (unlikely(p == NULL)) | ||
| 225 | return htonl(NFS4ERR_RESOURCE);; | ||
| 226 | |||
| 227 | memcpy(sid->data, p, len); | ||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static unsigned decode_rc_list(struct xdr_stream *xdr, | ||
| 232 | struct referring_call_list *rc_list) | ||
| 233 | { | ||
| 234 | uint32_t *p; | ||
| 235 | int i; | ||
| 236 | unsigned status; | ||
| 237 | |||
| 238 | status = decode_sessionid(xdr, &rc_list->rcl_sessionid); | ||
| 239 | if (status) | ||
| 240 | goto out; | ||
| 241 | |||
| 242 | status = htonl(NFS4ERR_RESOURCE); | ||
| 243 | p = read_buf(xdr, sizeof(uint32_t)); | ||
| 244 | if (unlikely(p == NULL)) | ||
| 245 | goto out; | ||
| 246 | |||
| 247 | rc_list->rcl_nrefcalls = ntohl(*p++); | ||
| 248 | if (rc_list->rcl_nrefcalls) { | ||
| 249 | p = read_buf(xdr, | ||
| 250 | rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t)); | ||
| 251 | if (unlikely(p == NULL)) | ||
| 252 | goto out; | ||
| 253 | rc_list->rcl_refcalls = kmalloc(rc_list->rcl_nrefcalls * | ||
| 254 | sizeof(*rc_list->rcl_refcalls), | ||
| 255 | GFP_KERNEL); | ||
| 256 | if (unlikely(rc_list->rcl_refcalls == NULL)) | ||
| 257 | goto out; | ||
| 258 | for (i = 0; i < rc_list->rcl_nrefcalls; i++) { | ||
| 259 | rc_list->rcl_refcalls[i].rc_sequenceid = ntohl(*p++); | ||
| 260 | rc_list->rcl_refcalls[i].rc_slotid = ntohl(*p++); | ||
| 261 | } | ||
| 262 | } | ||
| 263 | status = 0; | ||
| 264 | |||
| 265 | out: | ||
| 266 | return status; | ||
| 267 | } | ||
| 268 | |||
| 269 | static unsigned decode_cb_sequence_args(struct svc_rqst *rqstp, | ||
| 270 | struct xdr_stream *xdr, | ||
| 271 | struct cb_sequenceargs *args) | ||
| 272 | { | ||
| 273 | uint32_t *p; | ||
| 274 | int i; | ||
| 275 | unsigned status; | ||
| 276 | |||
| 277 | status = decode_sessionid(xdr, &args->csa_sessionid); | ||
| 278 | if (status) | ||
| 279 | goto out; | ||
| 280 | |||
| 281 | status = htonl(NFS4ERR_RESOURCE); | ||
| 282 | p = read_buf(xdr, 5 * sizeof(uint32_t)); | ||
| 283 | if (unlikely(p == NULL)) | ||
| 284 | goto out; | ||
| 285 | |||
| 286 | args->csa_addr = svc_addr(rqstp); | ||
| 287 | args->csa_sequenceid = ntohl(*p++); | ||
| 288 | args->csa_slotid = ntohl(*p++); | ||
| 289 | args->csa_highestslotid = ntohl(*p++); | ||
| 290 | args->csa_cachethis = ntohl(*p++); | ||
| 291 | args->csa_nrclists = ntohl(*p++); | ||
| 292 | args->csa_rclists = NULL; | ||
| 293 | if (args->csa_nrclists) { | ||
| 294 | args->csa_rclists = kmalloc(args->csa_nrclists * | ||
| 295 | sizeof(*args->csa_rclists), | ||
| 296 | GFP_KERNEL); | ||
| 297 | if (unlikely(args->csa_rclists == NULL)) | ||
| 298 | goto out; | ||
| 299 | |||
| 300 | for (i = 0; i < args->csa_nrclists; i++) { | ||
| 301 | status = decode_rc_list(xdr, &args->csa_rclists[i]); | ||
| 302 | if (status) | ||
| 303 | goto out_free; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | status = 0; | ||
| 307 | |||
| 308 | dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u slotid %u " | ||
| 309 | "highestslotid %u cachethis %d nrclists %u\n", | ||
| 310 | __func__, | ||
| 311 | ((u32 *)&args->csa_sessionid)[0], | ||
| 312 | ((u32 *)&args->csa_sessionid)[1], | ||
| 313 | ((u32 *)&args->csa_sessionid)[2], | ||
| 314 | ((u32 *)&args->csa_sessionid)[3], | ||
| 315 | args->csa_sequenceid, args->csa_slotid, | ||
| 316 | args->csa_highestslotid, args->csa_cachethis, | ||
| 317 | args->csa_nrclists); | ||
| 318 | out: | ||
| 319 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
| 320 | return status; | ||
| 321 | |||
| 322 | out_free: | ||
| 323 | for (i = 0; i < args->csa_nrclists; i++) | ||
| 324 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
| 325 | kfree(args->csa_rclists); | ||
| 326 | goto out; | ||
| 327 | } | ||
| 328 | |||
| 329 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 330 | |||
| 207 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 331 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
| 208 | { | 332 | { |
| 209 | __be32 *p; | 333 | __be32 *p; |
| @@ -353,31 +477,134 @@ out: | |||
| 353 | return status; | 477 | return status; |
| 354 | } | 478 | } |
| 355 | 479 | ||
| 356 | static __be32 process_op(struct svc_rqst *rqstp, | 480 | #if defined(CONFIG_NFS_V4_1) |
| 481 | |||
| 482 | static unsigned encode_sessionid(struct xdr_stream *xdr, | ||
| 483 | const struct nfs4_sessionid *sid) | ||
| 484 | { | ||
| 485 | uint32_t *p; | ||
| 486 | int len = NFS4_MAX_SESSIONID_LEN; | ||
| 487 | |||
| 488 | p = xdr_reserve_space(xdr, len); | ||
| 489 | if (unlikely(p == NULL)) | ||
| 490 | return htonl(NFS4ERR_RESOURCE); | ||
| 491 | |||
| 492 | memcpy(p, sid, len); | ||
| 493 | return 0; | ||
| 494 | } | ||
| 495 | |||
| 496 | static unsigned encode_cb_sequence_res(struct svc_rqst *rqstp, | ||
| 497 | struct xdr_stream *xdr, | ||
| 498 | const struct cb_sequenceres *res) | ||
| 499 | { | ||
| 500 | uint32_t *p; | ||
| 501 | unsigned status = res->csr_status; | ||
| 502 | |||
| 503 | if (unlikely(status != 0)) | ||
| 504 | goto out; | ||
| 505 | |||
| 506 | encode_sessionid(xdr, &res->csr_sessionid); | ||
| 507 | |||
| 508 | p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t)); | ||
| 509 | if (unlikely(p == NULL)) | ||
| 510 | return htonl(NFS4ERR_RESOURCE); | ||
| 511 | |||
| 512 | *p++ = htonl(res->csr_sequenceid); | ||
| 513 | *p++ = htonl(res->csr_slotid); | ||
| 514 | *p++ = htonl(res->csr_highestslotid); | ||
| 515 | *p++ = htonl(res->csr_target_highestslotid); | ||
| 516 | out: | ||
| 517 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
| 518 | return status; | ||
| 519 | } | ||
| 520 | |||
| 521 | static __be32 | ||
| 522 | preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
| 523 | { | ||
| 524 | if (op_nr == OP_CB_SEQUENCE) { | ||
| 525 | if (nop != 0) | ||
| 526 | return htonl(NFS4ERR_SEQUENCE_POS); | ||
| 527 | } else { | ||
| 528 | if (nop == 0) | ||
| 529 | return htonl(NFS4ERR_OP_NOT_IN_SESSION); | ||
| 530 | } | ||
| 531 | |||
| 532 | switch (op_nr) { | ||
| 533 | case OP_CB_GETATTR: | ||
| 534 | case OP_CB_RECALL: | ||
| 535 | case OP_CB_SEQUENCE: | ||
| 536 | *op = &callback_ops[op_nr]; | ||
| 537 | break; | ||
| 538 | |||
| 539 | case OP_CB_LAYOUTRECALL: | ||
| 540 | case OP_CB_NOTIFY_DEVICEID: | ||
| 541 | case OP_CB_NOTIFY: | ||
| 542 | case OP_CB_PUSH_DELEG: | ||
| 543 | case OP_CB_RECALL_ANY: | ||
| 544 | case OP_CB_RECALLABLE_OBJ_AVAIL: | ||
| 545 | case OP_CB_RECALL_SLOT: | ||
| 546 | case OP_CB_WANTS_CANCELLED: | ||
| 547 | case OP_CB_NOTIFY_LOCK: | ||
| 548 | return htonl(NFS4ERR_NOTSUPP); | ||
| 549 | |||
| 550 | default: | ||
| 551 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
| 552 | } | ||
| 553 | |||
| 554 | return htonl(NFS_OK); | ||
| 555 | } | ||
| 556 | |||
| 557 | #else /* CONFIG_NFS_V4_1 */ | ||
| 558 | |||
| 559 | static __be32 | ||
| 560 | preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
| 561 | { | ||
| 562 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | ||
| 563 | } | ||
| 564 | |||
| 565 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 566 | |||
| 567 | static __be32 | ||
| 568 | preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | ||
| 569 | { | ||
| 570 | switch (op_nr) { | ||
| 571 | case OP_CB_GETATTR: | ||
| 572 | case OP_CB_RECALL: | ||
| 573 | *op = &callback_ops[op_nr]; | ||
| 574 | break; | ||
| 575 | default: | ||
| 576 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
| 577 | } | ||
| 578 | |||
| 579 | return htonl(NFS_OK); | ||
| 580 | } | ||
| 581 | |||
| 582 | static __be32 process_op(uint32_t minorversion, int nop, | ||
| 583 | struct svc_rqst *rqstp, | ||
| 357 | struct xdr_stream *xdr_in, void *argp, | 584 | struct xdr_stream *xdr_in, void *argp, |
| 358 | struct xdr_stream *xdr_out, void *resp) | 585 | struct xdr_stream *xdr_out, void *resp) |
| 359 | { | 586 | { |
| 360 | struct callback_op *op = &callback_ops[0]; | 587 | struct callback_op *op = &callback_ops[0]; |
| 361 | unsigned int op_nr = OP_CB_ILLEGAL; | 588 | unsigned int op_nr = OP_CB_ILLEGAL; |
| 362 | __be32 status = 0; | 589 | __be32 status; |
| 363 | long maxlen; | 590 | long maxlen; |
| 364 | __be32 res; | 591 | __be32 res; |
| 365 | 592 | ||
| 366 | dprintk("%s: start\n", __func__); | 593 | dprintk("%s: start\n", __func__); |
| 367 | status = decode_op_hdr(xdr_in, &op_nr); | 594 | status = decode_op_hdr(xdr_in, &op_nr); |
| 368 | if (likely(status == 0)) { | 595 | if (unlikely(status)) { |
| 369 | switch (op_nr) { | 596 | status = htonl(NFS4ERR_OP_ILLEGAL); |
| 370 | case OP_CB_GETATTR: | 597 | goto out; |
| 371 | case OP_CB_RECALL: | ||
| 372 | op = &callback_ops[op_nr]; | ||
| 373 | break; | ||
| 374 | default: | ||
| 375 | op_nr = OP_CB_ILLEGAL; | ||
| 376 | op = &callback_ops[0]; | ||
| 377 | status = htonl(NFS4ERR_OP_ILLEGAL); | ||
| 378 | } | ||
| 379 | } | 598 | } |
| 380 | 599 | ||
| 600 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", | ||
| 601 | __func__, minorversion, nop, op_nr); | ||
| 602 | |||
| 603 | status = minorversion ? preprocess_nfs41_op(nop, op_nr, &op) : | ||
| 604 | preprocess_nfs4_op(op_nr, &op); | ||
| 605 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) | ||
| 606 | op_nr = OP_CB_ILLEGAL; | ||
| 607 | out: | ||
| 381 | maxlen = xdr_out->end - xdr_out->p; | 608 | maxlen = xdr_out->end - xdr_out->p; |
| 382 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 609 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
| 383 | if (likely(status == 0 && op->decode_args != NULL)) | 610 | if (likely(status == 0 && op->decode_args != NULL)) |
| @@ -425,7 +652,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
| 425 | return rpc_system_err; | 652 | return rpc_system_err; |
| 426 | 653 | ||
| 427 | while (status == 0 && nops != hdr_arg.nops) { | 654 | while (status == 0 && nops != hdr_arg.nops) { |
| 428 | status = process_op(rqstp, &xdr_in, argp, &xdr_out, resp); | 655 | status = process_op(hdr_arg.minorversion, nops, |
| 656 | rqstp, &xdr_in, argp, &xdr_out, resp); | ||
| 429 | nops++; | 657 | nops++; |
| 430 | } | 658 | } |
| 431 | 659 | ||
| @@ -452,7 +680,15 @@ static struct callback_op callback_ops[] = { | |||
| 452 | .process_op = (callback_process_op_t)nfs4_callback_recall, | 680 | .process_op = (callback_process_op_t)nfs4_callback_recall, |
| 453 | .decode_args = (callback_decode_arg_t)decode_recall_args, | 681 | .decode_args = (callback_decode_arg_t)decode_recall_args, |
| 454 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, | 682 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, |
| 455 | } | 683 | }, |
| 684 | #if defined(CONFIG_NFS_V4_1) | ||
| 685 | [OP_CB_SEQUENCE] = { | ||
| 686 | .process_op = (callback_process_op_t)nfs4_callback_sequence, | ||
| 687 | .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, | ||
| 688 | .encode_res = (callback_encode_res_t)encode_cb_sequence_res, | ||
| 689 | .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ, | ||
| 690 | }, | ||
| 691 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 456 | }; | 692 | }; |
| 457 | 693 | ||
| 458 | /* | 694 | /* |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 75c9cd2aa119..4f75ec593be8 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/in6.h> | 37 | #include <linux/in6.h> |
| 38 | #include <net/ipv6.h> | 38 | #include <net/ipv6.h> |
| 39 | #include <linux/nfs_xdr.h> | 39 | #include <linux/nfs_xdr.h> |
| 40 | #include <linux/sunrpc/bc_xprt.h> | ||
| 40 | 41 | ||
| 41 | #include <asm/system.h> | 42 | #include <asm/system.h> |
| 42 | 43 | ||
| @@ -102,6 +103,7 @@ struct nfs_client_initdata { | |||
| 102 | size_t addrlen; | 103 | size_t addrlen; |
| 103 | const struct nfs_rpc_ops *rpc_ops; | 104 | const struct nfs_rpc_ops *rpc_ops; |
| 104 | int proto; | 105 | int proto; |
| 106 | u32 minorversion; | ||
| 105 | }; | 107 | }; |
| 106 | 108 | ||
| 107 | /* | 109 | /* |
| @@ -120,12 +122,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
| 120 | 122 | ||
| 121 | clp->rpc_ops = cl_init->rpc_ops; | 123 | clp->rpc_ops = cl_init->rpc_ops; |
| 122 | 124 | ||
| 123 | if (cl_init->rpc_ops->version == 4) { | ||
| 124 | if (nfs_callback_up() < 0) | ||
| 125 | goto error_2; | ||
| 126 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
| 127 | } | ||
| 128 | |||
| 129 | atomic_set(&clp->cl_count, 1); | 125 | atomic_set(&clp->cl_count, 1); |
| 130 | clp->cl_cons_state = NFS_CS_INITING; | 126 | clp->cl_cons_state = NFS_CS_INITING; |
| 131 | 127 | ||
| @@ -135,7 +131,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
| 135 | if (cl_init->hostname) { | 131 | if (cl_init->hostname) { |
| 136 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); | 132 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); |
| 137 | if (!clp->cl_hostname) | 133 | if (!clp->cl_hostname) |
| 138 | goto error_3; | 134 | goto error_cleanup; |
| 139 | } | 135 | } |
| 140 | 136 | ||
| 141 | INIT_LIST_HEAD(&clp->cl_superblocks); | 137 | INIT_LIST_HEAD(&clp->cl_superblocks); |
| @@ -150,6 +146,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
| 150 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | 146 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); |
| 151 | clp->cl_boot_time = CURRENT_TIME; | 147 | clp->cl_boot_time = CURRENT_TIME; |
| 152 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 148 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
| 149 | clp->cl_minorversion = cl_init->minorversion; | ||
| 153 | #endif | 150 | #endif |
| 154 | cred = rpc_lookup_machine_cred(); | 151 | cred = rpc_lookup_machine_cred(); |
| 155 | if (!IS_ERR(cred)) | 152 | if (!IS_ERR(cred)) |
| @@ -159,10 +156,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
| 159 | 156 | ||
| 160 | return clp; | 157 | return clp; |
| 161 | 158 | ||
| 162 | error_3: | 159 | error_cleanup: |
| 163 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
| 164 | nfs_callback_down(); | ||
| 165 | error_2: | ||
| 166 | kfree(clp); | 160 | kfree(clp); |
| 167 | error_0: | 161 | error_0: |
| 168 | return NULL; | 162 | return NULL; |
| @@ -182,12 +176,42 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
| 182 | } | 176 | } |
| 183 | 177 | ||
| 184 | /* | 178 | /* |
| 179 | * Destroy the NFS4 callback service | ||
| 180 | */ | ||
| 181 | static void nfs4_destroy_callback(struct nfs_client *clp) | ||
| 182 | { | ||
| 183 | #ifdef CONFIG_NFS_V4 | ||
| 184 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
| 185 | nfs_callback_down(clp->cl_minorversion); | ||
| 186 | #endif /* CONFIG_NFS_V4 */ | ||
| 187 | } | ||
| 188 | |||
| 189 | /* | ||
| 190 | * Clears/puts all minor version specific parts from an nfs_client struct | ||
| 191 | * reverting it to minorversion 0. | ||
| 192 | */ | ||
| 193 | static void nfs4_clear_client_minor_version(struct nfs_client *clp) | ||
| 194 | { | ||
| 195 | #ifdef CONFIG_NFS_V4_1 | ||
| 196 | if (nfs4_has_session(clp)) { | ||
| 197 | nfs4_destroy_session(clp->cl_session); | ||
| 198 | clp->cl_session = NULL; | ||
| 199 | } | ||
| 200 | |||
| 201 | clp->cl_call_sync = _nfs4_call_sync; | ||
| 202 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 203 | |||
| 204 | nfs4_destroy_callback(clp); | ||
| 205 | } | ||
| 206 | |||
| 207 | /* | ||
| 185 | * Destroy a shared client record | 208 | * Destroy a shared client record |
| 186 | */ | 209 | */ |
| 187 | static void nfs_free_client(struct nfs_client *clp) | 210 | static void nfs_free_client(struct nfs_client *clp) |
| 188 | { | 211 | { |
| 189 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); | 212 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
| 190 | 213 | ||
| 214 | nfs4_clear_client_minor_version(clp); | ||
| 191 | nfs4_shutdown_client(clp); | 215 | nfs4_shutdown_client(clp); |
| 192 | 216 | ||
| 193 | nfs_fscache_release_client_cookie(clp); | 217 | nfs_fscache_release_client_cookie(clp); |
| @@ -196,9 +220,6 @@ static void nfs_free_client(struct nfs_client *clp) | |||
| 196 | if (!IS_ERR(clp->cl_rpcclient)) | 220 | if (!IS_ERR(clp->cl_rpcclient)) |
| 197 | rpc_shutdown_client(clp->cl_rpcclient); | 221 | rpc_shutdown_client(clp->cl_rpcclient); |
| 198 | 222 | ||
| 199 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
| 200 | nfs_callback_down(); | ||
| 201 | |||
| 202 | if (clp->cl_machine_cred != NULL) | 223 | if (clp->cl_machine_cred != NULL) |
| 203 | put_rpccred(clp->cl_machine_cred); | 224 | put_rpccred(clp->cl_machine_cred); |
| 204 | 225 | ||
| @@ -347,7 +368,8 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) | |||
| 347 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 368 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
| 348 | 369 | ||
| 349 | /* Don't match clients that failed to initialise properly */ | 370 | /* Don't match clients that failed to initialise properly */ |
| 350 | if (clp->cl_cons_state != NFS_CS_READY) | 371 | if (!(clp->cl_cons_state == NFS_CS_READY || |
| 372 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) | ||
| 351 | continue; | 373 | continue; |
| 352 | 374 | ||
| 353 | /* Different NFS versions cannot share the same nfs_client */ | 375 | /* Different NFS versions cannot share the same nfs_client */ |
| @@ -420,7 +442,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat | |||
| 420 | 442 | ||
| 421 | if (clp->cl_proto != data->proto) | 443 | if (clp->cl_proto != data->proto) |
| 422 | continue; | 444 | continue; |
| 423 | 445 | /* Match nfsv4 minorversion */ | |
| 446 | if (clp->cl_minorversion != data->minorversion) | ||
| 447 | continue; | ||
| 424 | /* Match the full socket address */ | 448 | /* Match the full socket address */ |
| 425 | if (!nfs_sockaddr_cmp(sap, clap)) | 449 | if (!nfs_sockaddr_cmp(sap, clap)) |
| 426 | continue; | 450 | continue; |
| @@ -478,7 +502,7 @@ found_client: | |||
| 478 | nfs_free_client(new); | 502 | nfs_free_client(new); |
| 479 | 503 | ||
| 480 | error = wait_event_killable(nfs_client_active_wq, | 504 | error = wait_event_killable(nfs_client_active_wq, |
| 481 | clp->cl_cons_state != NFS_CS_INITING); | 505 | clp->cl_cons_state < NFS_CS_INITING); |
| 482 | if (error < 0) { | 506 | if (error < 0) { |
| 483 | nfs_put_client(clp); | 507 | nfs_put_client(clp); |
| 484 | return ERR_PTR(-ERESTARTSYS); | 508 | return ERR_PTR(-ERESTARTSYS); |
| @@ -499,13 +523,29 @@ found_client: | |||
| 499 | /* | 523 | /* |
| 500 | * Mark a server as ready or failed | 524 | * Mark a server as ready or failed |
| 501 | */ | 525 | */ |
| 502 | static void nfs_mark_client_ready(struct nfs_client *clp, int state) | 526 | void nfs_mark_client_ready(struct nfs_client *clp, int state) |
| 503 | { | 527 | { |
| 504 | clp->cl_cons_state = state; | 528 | clp->cl_cons_state = state; |
| 505 | wake_up_all(&nfs_client_active_wq); | 529 | wake_up_all(&nfs_client_active_wq); |
| 506 | } | 530 | } |
| 507 | 531 | ||
| 508 | /* | 532 | /* |
| 533 | * With sessions, the client is not marked ready until after a | ||
| 534 | * successful EXCHANGE_ID and CREATE_SESSION. | ||
| 535 | * | ||
| 536 | * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate | ||
| 537 | * other versions of NFS can be tried. | ||
| 538 | */ | ||
| 539 | int nfs4_check_client_ready(struct nfs_client *clp) | ||
| 540 | { | ||
| 541 | if (!nfs4_has_session(clp)) | ||
| 542 | return 0; | ||
| 543 | if (clp->cl_cons_state < NFS_CS_READY) | ||
| 544 | return -EPROTONOSUPPORT; | ||
| 545 | return 0; | ||
| 546 | } | ||
| 547 | |||
| 548 | /* | ||
| 509 | * Initialise the timeout values for a connection | 549 | * Initialise the timeout values for a connection |
| 510 | */ | 550 | */ |
| 511 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | 551 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, |
| @@ -1050,6 +1090,61 @@ error: | |||
| 1050 | 1090 | ||
| 1051 | #ifdef CONFIG_NFS_V4 | 1091 | #ifdef CONFIG_NFS_V4 |
| 1052 | /* | 1092 | /* |
| 1093 | * Initialize the NFS4 callback service | ||
| 1094 | */ | ||
| 1095 | static int nfs4_init_callback(struct nfs_client *clp) | ||
| 1096 | { | ||
| 1097 | int error; | ||
| 1098 | |||
| 1099 | if (clp->rpc_ops->version == 4) { | ||
| 1100 | if (nfs4_has_session(clp)) { | ||
| 1101 | error = xprt_setup_backchannel( | ||
| 1102 | clp->cl_rpcclient->cl_xprt, | ||
| 1103 | NFS41_BC_MIN_CALLBACKS); | ||
| 1104 | if (error < 0) | ||
| 1105 | return error; | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | error = nfs_callback_up(clp->cl_minorversion, | ||
| 1109 | clp->cl_rpcclient->cl_xprt); | ||
| 1110 | if (error < 0) { | ||
| 1111 | dprintk("%s: failed to start callback. Error = %d\n", | ||
| 1112 | __func__, error); | ||
| 1113 | return error; | ||
| 1114 | } | ||
| 1115 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
| 1116 | } | ||
| 1117 | return 0; | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | /* | ||
| 1121 | * Initialize the minor version specific parts of an NFS4 client record | ||
| 1122 | */ | ||
| 1123 | static int nfs4_init_client_minor_version(struct nfs_client *clp) | ||
| 1124 | { | ||
| 1125 | clp->cl_call_sync = _nfs4_call_sync; | ||
| 1126 | |||
| 1127 | #if defined(CONFIG_NFS_V4_1) | ||
| 1128 | if (clp->cl_minorversion) { | ||
| 1129 | struct nfs4_session *session = NULL; | ||
| 1130 | /* | ||
| 1131 | * Create the session and mark it expired. | ||
| 1132 | * When a SEQUENCE operation encounters the expired session | ||
| 1133 | * it will do session recovery to initialize it. | ||
| 1134 | */ | ||
| 1135 | session = nfs4_alloc_session(clp); | ||
| 1136 | if (!session) | ||
| 1137 | return -ENOMEM; | ||
| 1138 | |||
| 1139 | clp->cl_session = session; | ||
| 1140 | clp->cl_call_sync = _nfs4_call_sync_session; | ||
| 1141 | } | ||
| 1142 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1143 | |||
| 1144 | return nfs4_init_callback(clp); | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | /* | ||
| 1053 | * Initialise an NFS4 client record | 1148 | * Initialise an NFS4 client record |
| 1054 | */ | 1149 | */ |
| 1055 | static int nfs4_init_client(struct nfs_client *clp, | 1150 | static int nfs4_init_client(struct nfs_client *clp, |
| @@ -1083,7 +1178,12 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
| 1083 | } | 1178 | } |
| 1084 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); | 1179 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); |
| 1085 | 1180 | ||
| 1086 | nfs_mark_client_ready(clp, NFS_CS_READY); | 1181 | error = nfs4_init_client_minor_version(clp); |
| 1182 | if (error < 0) | ||
| 1183 | goto error; | ||
| 1184 | |||
| 1185 | if (!nfs4_has_session(clp)) | ||
| 1186 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
| 1087 | return 0; | 1187 | return 0; |
| 1088 | 1188 | ||
| 1089 | error: | 1189 | error: |
| @@ -1101,7 +1201,8 @@ static int nfs4_set_client(struct nfs_server *server, | |||
| 1101 | const size_t addrlen, | 1201 | const size_t addrlen, |
| 1102 | const char *ip_addr, | 1202 | const char *ip_addr, |
| 1103 | rpc_authflavor_t authflavour, | 1203 | rpc_authflavor_t authflavour, |
| 1104 | int proto, const struct rpc_timeout *timeparms) | 1204 | int proto, const struct rpc_timeout *timeparms, |
| 1205 | u32 minorversion) | ||
| 1105 | { | 1206 | { |
| 1106 | struct nfs_client_initdata cl_init = { | 1207 | struct nfs_client_initdata cl_init = { |
| 1107 | .hostname = hostname, | 1208 | .hostname = hostname, |
| @@ -1109,6 +1210,7 @@ static int nfs4_set_client(struct nfs_server *server, | |||
| 1109 | .addrlen = addrlen, | 1210 | .addrlen = addrlen, |
| 1110 | .rpc_ops = &nfs_v4_clientops, | 1211 | .rpc_ops = &nfs_v4_clientops, |
| 1111 | .proto = proto, | 1212 | .proto = proto, |
| 1213 | .minorversion = minorversion, | ||
| 1112 | }; | 1214 | }; |
| 1113 | struct nfs_client *clp; | 1215 | struct nfs_client *clp; |
| 1114 | int error; | 1216 | int error; |
| @@ -1138,6 +1240,36 @@ error: | |||
| 1138 | } | 1240 | } |
| 1139 | 1241 | ||
| 1140 | /* | 1242 | /* |
| 1243 | * Initialize a session. | ||
| 1244 | * Note: save the mount rsize and wsize for create_server negotiation. | ||
| 1245 | */ | ||
| 1246 | static void nfs4_init_session(struct nfs_client *clp, | ||
| 1247 | unsigned int wsize, unsigned int rsize) | ||
| 1248 | { | ||
| 1249 | #if defined(CONFIG_NFS_V4_1) | ||
| 1250 | if (nfs4_has_session(clp)) { | ||
| 1251 | clp->cl_session->fc_attrs.max_rqst_sz = wsize; | ||
| 1252 | clp->cl_session->fc_attrs.max_resp_sz = rsize; | ||
| 1253 | } | ||
| 1254 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | /* | ||
| 1258 | * Session has been established, and the client marked ready. | ||
| 1259 | * Set the mount rsize and wsize with negotiated fore channel | ||
| 1260 | * attributes which will be bound checked in nfs_server_set_fsinfo. | ||
| 1261 | */ | ||
| 1262 | static void nfs4_session_set_rwsize(struct nfs_server *server) | ||
| 1263 | { | ||
| 1264 | #ifdef CONFIG_NFS_V4_1 | ||
| 1265 | if (!nfs4_has_session(server->nfs_client)) | ||
| 1266 | return; | ||
| 1267 | server->rsize = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | ||
| 1268 | server->wsize = server->nfs_client->cl_session->fc_attrs.max_rqst_sz; | ||
| 1269 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | /* | ||
| 1141 | * Create a version 4 volume record | 1273 | * Create a version 4 volume record |
| 1142 | */ | 1274 | */ |
| 1143 | static int nfs4_init_server(struct nfs_server *server, | 1275 | static int nfs4_init_server(struct nfs_server *server, |
| @@ -1164,7 +1296,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
| 1164 | data->client_address, | 1296 | data->client_address, |
| 1165 | data->auth_flavors[0], | 1297 | data->auth_flavors[0], |
| 1166 | data->nfs_server.protocol, | 1298 | data->nfs_server.protocol, |
| 1167 | &timeparms); | 1299 | &timeparms, |
| 1300 | data->minorversion); | ||
| 1168 | if (error < 0) | 1301 | if (error < 0) |
| 1169 | goto error; | 1302 | goto error; |
| 1170 | 1303 | ||
| @@ -1214,6 +1347,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1214 | BUG_ON(!server->nfs_client->rpc_ops); | 1347 | BUG_ON(!server->nfs_client->rpc_ops); |
| 1215 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | 1348 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
| 1216 | 1349 | ||
| 1350 | nfs4_init_session(server->nfs_client, server->wsize, server->rsize); | ||
| 1351 | |||
| 1217 | /* Probe the root fh to retrieve its FSID */ | 1352 | /* Probe the root fh to retrieve its FSID */ |
| 1218 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); | 1353 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); |
| 1219 | if (error < 0) | 1354 | if (error < 0) |
| @@ -1224,6 +1359,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1224 | (unsigned long long) server->fsid.minor); | 1359 | (unsigned long long) server->fsid.minor); |
| 1225 | dprintk("Mount FH: %d\n", mntfh->size); | 1360 | dprintk("Mount FH: %d\n", mntfh->size); |
| 1226 | 1361 | ||
| 1362 | nfs4_session_set_rwsize(server); | ||
| 1363 | |||
| 1227 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | 1364 | error = nfs_probe_fsinfo(server, mntfh, &fattr); |
| 1228 | if (error < 0) | 1365 | if (error < 0) |
| 1229 | goto error; | 1366 | goto error; |
| @@ -1282,7 +1419,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1282 | parent_client->cl_ipaddr, | 1419 | parent_client->cl_ipaddr, |
| 1283 | data->authflavor, | 1420 | data->authflavor, |
| 1284 | parent_server->client->cl_xprt->prot, | 1421 | parent_server->client->cl_xprt->prot, |
| 1285 | parent_server->client->cl_timeout); | 1422 | parent_server->client->cl_timeout, |
| 1423 | parent_client->cl_minorversion); | ||
| 1286 | if (error < 0) | 1424 | if (error < 0) |
| 1287 | goto error; | 1425 | goto error; |
| 1288 | 1426 | ||
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 08f6b040d289..489fc01a3204 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -259,6 +259,9 @@ static void nfs_direct_read_release(void *calldata) | |||
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | static const struct rpc_call_ops nfs_read_direct_ops = { | 261 | static const struct rpc_call_ops nfs_read_direct_ops = { |
| 262 | #if defined(CONFIG_NFS_V4_1) | ||
| 263 | .rpc_call_prepare = nfs_read_prepare, | ||
| 264 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 262 | .rpc_call_done = nfs_direct_read_result, | 265 | .rpc_call_done = nfs_direct_read_result, |
| 263 | .rpc_release = nfs_direct_read_release, | 266 | .rpc_release = nfs_direct_read_release, |
| 264 | }; | 267 | }; |
| @@ -535,6 +538,9 @@ static void nfs_direct_commit_release(void *calldata) | |||
| 535 | } | 538 | } |
| 536 | 539 | ||
| 537 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 540 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
| 541 | #if defined(CONFIG_NFS_V4_1) | ||
| 542 | .rpc_call_prepare = nfs_write_prepare, | ||
| 543 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 538 | .rpc_call_done = nfs_direct_commit_result, | 544 | .rpc_call_done = nfs_direct_commit_result, |
| 539 | .rpc_release = nfs_direct_commit_release, | 545 | .rpc_release = nfs_direct_commit_release, |
| 540 | }; | 546 | }; |
| @@ -673,6 +679,9 @@ out_unlock: | |||
| 673 | } | 679 | } |
| 674 | 680 | ||
| 675 | static const struct rpc_call_ops nfs_write_direct_ops = { | 681 | static const struct rpc_call_ops nfs_write_direct_ops = { |
| 682 | #if defined(CONFIG_NFS_V4_1) | ||
| 683 | .rpc_call_prepare = nfs_write_prepare, | ||
| 684 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 676 | .rpc_call_done = nfs_direct_write_result, | 685 | .rpc_call_done = nfs_direct_write_result, |
| 677 | .rpc_release = nfs_direct_write_release, | 686 | .rpc_release = nfs_direct_write_release, |
| 678 | }; | 687 | }; |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index e4d6a8348adf..acee3274d275 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * NFS internal definitions | 2 | * NFS internal definitions |
| 3 | */ | 3 | */ |
| 4 | 4 | ||
| 5 | #include "nfs4_fs.h" | ||
| 5 | #include <linux/mount.h> | 6 | #include <linux/mount.h> |
| 6 | #include <linux/security.h> | 7 | #include <linux/security.h> |
| 7 | 8 | ||
| @@ -17,6 +18,18 @@ struct nfs_string; | |||
| 17 | */ | 18 | */ |
| 18 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) | 19 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) |
| 19 | 20 | ||
| 21 | /* | ||
| 22 | * Determine if sessions are in use. | ||
| 23 | */ | ||
| 24 | static inline int nfs4_has_session(const struct nfs_client *clp) | ||
| 25 | { | ||
| 26 | #ifdef CONFIG_NFS_V4_1 | ||
| 27 | if (clp->cl_session) | ||
| 28 | return 1; | ||
| 29 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 30 | return 0; | ||
| 31 | } | ||
| 32 | |||
| 20 | struct nfs_clone_mount { | 33 | struct nfs_clone_mount { |
| 21 | const struct super_block *sb; | 34 | const struct super_block *sb; |
| 22 | const struct dentry *dentry; | 35 | const struct dentry *dentry; |
| @@ -44,6 +57,7 @@ struct nfs_parsed_mount_data { | |||
| 44 | unsigned int auth_flavor_len; | 57 | unsigned int auth_flavor_len; |
| 45 | rpc_authflavor_t auth_flavors[1]; | 58 | rpc_authflavor_t auth_flavors[1]; |
| 46 | char *client_address; | 59 | char *client_address; |
| 60 | unsigned int minorversion; | ||
| 47 | char *fscache_uniq; | 61 | char *fscache_uniq; |
| 48 | 62 | ||
| 49 | struct { | 63 | struct { |
| @@ -99,6 +113,8 @@ extern void nfs_free_server(struct nfs_server *server); | |||
| 99 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | 113 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, |
| 100 | struct nfs_fh *, | 114 | struct nfs_fh *, |
| 101 | struct nfs_fattr *); | 115 | struct nfs_fattr *); |
| 116 | extern void nfs_mark_client_ready(struct nfs_client *clp, int state); | ||
| 117 | extern int nfs4_check_client_ready(struct nfs_client *clp); | ||
| 102 | #ifdef CONFIG_PROC_FS | 118 | #ifdef CONFIG_PROC_FS |
| 103 | extern int __init nfs_fs_proc_init(void); | 119 | extern int __init nfs_fs_proc_init(void); |
| 104 | extern void nfs_fs_proc_exit(void); | 120 | extern void nfs_fs_proc_exit(void); |
| @@ -146,6 +162,20 @@ extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int); | |||
| 146 | extern struct rpc_procinfo nfs3_procedures[]; | 162 | extern struct rpc_procinfo nfs3_procedures[]; |
| 147 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); | 163 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); |
| 148 | 164 | ||
| 165 | /* nfs4proc.c */ | ||
| 166 | static inline void nfs4_restart_rpc(struct rpc_task *task, | ||
| 167 | const struct nfs_client *clp) | ||
| 168 | { | ||
| 169 | #ifdef CONFIG_NFS_V4_1 | ||
| 170 | if (nfs4_has_session(clp) && | ||
| 171 | test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
| 172 | rpc_restart_call_prepare(task); | ||
| 173 | return; | ||
| 174 | } | ||
| 175 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 176 | rpc_restart_call(task); | ||
| 177 | } | ||
| 178 | |||
| 149 | /* nfs4xdr.c */ | 179 | /* nfs4xdr.c */ |
| 150 | #ifdef CONFIG_NFS_V4 | 180 | #ifdef CONFIG_NFS_V4 |
| 151 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); | 181 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); |
| @@ -205,6 +235,38 @@ extern int nfs4_path_walk(struct nfs_server *server, | |||
| 205 | const char *path); | 235 | const char *path); |
| 206 | #endif | 236 | #endif |
| 207 | 237 | ||
| 238 | /* read.c */ | ||
| 239 | extern void nfs_read_prepare(struct rpc_task *task, void *calldata); | ||
| 240 | |||
| 241 | /* write.c */ | ||
| 242 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); | ||
| 243 | |||
| 244 | /* nfs4proc.c */ | ||
| 245 | extern int _nfs4_call_sync(struct nfs_server *server, | ||
| 246 | struct rpc_message *msg, | ||
| 247 | struct nfs4_sequence_args *args, | ||
| 248 | struct nfs4_sequence_res *res, | ||
| 249 | int cache_reply); | ||
| 250 | extern int _nfs4_call_sync_session(struct nfs_server *server, | ||
| 251 | struct rpc_message *msg, | ||
| 252 | struct nfs4_sequence_args *args, | ||
| 253 | struct nfs4_sequence_res *res, | ||
| 254 | int cache_reply); | ||
| 255 | |||
| 256 | #ifdef CONFIG_NFS_V4_1 | ||
| 257 | extern void nfs41_sequence_free_slot(const struct nfs_client *, | ||
| 258 | struct nfs4_sequence_res *res); | ||
| 259 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 260 | |||
| 261 | static inline void nfs4_sequence_free_slot(const struct nfs_client *clp, | ||
| 262 | struct nfs4_sequence_res *res) | ||
| 263 | { | ||
| 264 | #ifdef CONFIG_NFS_V4_1 | ||
| 265 | if (nfs4_has_session(clp)) | ||
| 266 | nfs41_sequence_free_slot(clp, res); | ||
| 267 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 268 | } | ||
| 269 | |||
| 208 | /* | 270 | /* |
| 209 | * Determine the device name as a string | 271 | * Determine the device name as a string |
| 210 | */ | 272 | */ |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 84345deab26f..61bc3a32e1e2 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -44,6 +44,7 @@ enum nfs4_client_state { | |||
| 44 | NFS4CLNT_RECLAIM_REBOOT, | 44 | NFS4CLNT_RECLAIM_REBOOT, |
| 45 | NFS4CLNT_RECLAIM_NOGRACE, | 45 | NFS4CLNT_RECLAIM_NOGRACE, |
| 46 | NFS4CLNT_DELEGRETURN, | 46 | NFS4CLNT_DELEGRETURN, |
| 47 | NFS4CLNT_SESSION_SETUP, | ||
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 49 | /* | 50 | /* |
| @@ -177,6 +178,14 @@ struct nfs4_state_recovery_ops { | |||
| 177 | int state_flag_bit; | 178 | int state_flag_bit; |
| 178 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); | 179 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); |
| 179 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | 180 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); |
| 181 | int (*establish_clid)(struct nfs_client *, struct rpc_cred *); | ||
| 182 | struct rpc_cred * (*get_clid_cred)(struct nfs_client *); | ||
| 183 | }; | ||
| 184 | |||
| 185 | struct nfs4_state_maintenance_ops { | ||
| 186 | int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *); | ||
| 187 | struct rpc_cred * (*get_state_renewal_cred_locked)(struct nfs_client *); | ||
| 188 | int (*renew_lease)(struct nfs_client *, struct rpc_cred *); | ||
| 180 | }; | 189 | }; |
| 181 | 190 | ||
| 182 | extern const struct dentry_operations nfs4_dentry_operations; | 191 | extern const struct dentry_operations nfs4_dentry_operations; |
| @@ -193,6 +202,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc | |||
| 193 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | 202 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); |
| 194 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | 203 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
| 195 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | 204 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
| 205 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | ||
| 196 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); | 206 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); |
| 197 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 207 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
| 198 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 208 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
| @@ -200,8 +210,26 @@ extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh | |||
| 200 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 210 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, |
| 201 | struct nfs4_fs_locations *fs_locations, struct page *page); | 211 | struct nfs4_fs_locations *fs_locations, struct page *page); |
| 202 | 212 | ||
| 203 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | 213 | extern struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[]; |
| 204 | extern struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops; | 214 | extern struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[]; |
| 215 | #if defined(CONFIG_NFS_V4_1) | ||
| 216 | extern int nfs4_setup_sequence(struct nfs_client *clp, | ||
| 217 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | ||
| 218 | int cache_reply, struct rpc_task *task); | ||
| 219 | extern void nfs4_destroy_session(struct nfs4_session *session); | ||
| 220 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | ||
| 221 | extern int nfs4_proc_create_session(struct nfs_client *, int reset); | ||
| 222 | extern int nfs4_proc_destroy_session(struct nfs4_session *); | ||
| 223 | #else /* CONFIG_NFS_v4_1 */ | ||
| 224 | static inline int nfs4_setup_sequence(struct nfs_client *clp, | ||
| 225 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | ||
| 226 | int cache_reply, struct rpc_task *task) | ||
| 227 | { | ||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 231 | |||
| 232 | extern struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[]; | ||
| 205 | 233 | ||
| 206 | extern const u32 nfs4_fattr_bitmap[2]; | 234 | extern const u32 nfs4_fattr_bitmap[2]; |
| 207 | extern const u32 nfs4_statfs_bitmap[2]; | 235 | extern const u32 nfs4_statfs_bitmap[2]; |
| @@ -216,7 +244,12 @@ extern void nfs4_kill_renewd(struct nfs_client *); | |||
| 216 | extern void nfs4_renew_state(struct work_struct *); | 244 | extern void nfs4_renew_state(struct work_struct *); |
| 217 | 245 | ||
| 218 | /* nfs4state.c */ | 246 | /* nfs4state.c */ |
| 247 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp); | ||
| 219 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); | 248 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); |
| 249 | #if defined(CONFIG_NFS_V4_1) | ||
| 250 | struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp); | ||
| 251 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp); | ||
| 252 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 220 | 253 | ||
| 221 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 254 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); |
| 222 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | 255 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4674f8092da8..57dabb8a048e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -48,11 +48,14 @@ | |||
| 48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
| 49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
| 50 | #include <linux/mount.h> | 50 | #include <linux/mount.h> |
| 51 | #include <linux/module.h> | ||
| 52 | #include <linux/sunrpc/bc_xprt.h> | ||
| 51 | 53 | ||
| 52 | #include "nfs4_fs.h" | 54 | #include "nfs4_fs.h" |
| 53 | #include "delegation.h" | 55 | #include "delegation.h" |
| 54 | #include "internal.h" | 56 | #include "internal.h" |
| 55 | #include "iostat.h" | 57 | #include "iostat.h" |
| 58 | #include "callback.h" | ||
| 56 | 59 | ||
| 57 | #define NFSDBG_FACILITY NFSDBG_PROC | 60 | #define NFSDBG_FACILITY NFSDBG_PROC |
| 58 | 61 | ||
| @@ -247,7 +250,25 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
| 247 | ret = nfs4_wait_clnt_recover(clp); | 250 | ret = nfs4_wait_clnt_recover(clp); |
| 248 | if (ret == 0) | 251 | if (ret == 0) |
| 249 | exception->retry = 1; | 252 | exception->retry = 1; |
| 253 | #if !defined(CONFIG_NFS_V4_1) | ||
| 250 | break; | 254 | break; |
| 255 | #else /* !defined(CONFIG_NFS_V4_1) */ | ||
| 256 | if (!nfs4_has_session(server->nfs_client)) | ||
| 257 | break; | ||
| 258 | /* FALLTHROUGH */ | ||
| 259 | case -NFS4ERR_BADSESSION: | ||
| 260 | case -NFS4ERR_BADSLOT: | ||
| 261 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
| 262 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
| 263 | case -NFS4ERR_DEADSESSION: | ||
| 264 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
| 265 | case -NFS4ERR_SEQ_MISORDERED: | ||
| 266 | dprintk("%s ERROR: %d Reset session\n", __func__, | ||
| 267 | errorcode); | ||
| 268 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
| 269 | exception->retry = 1; | ||
| 270 | /* FALLTHROUGH */ | ||
| 271 | #endif /* !defined(CONFIG_NFS_V4_1) */ | ||
| 251 | case -NFS4ERR_FILE_OPEN: | 272 | case -NFS4ERR_FILE_OPEN: |
| 252 | case -NFS4ERR_GRACE: | 273 | case -NFS4ERR_GRACE: |
| 253 | case -NFS4ERR_DELAY: | 274 | case -NFS4ERR_DELAY: |
| @@ -271,6 +292,353 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
| 271 | spin_unlock(&clp->cl_lock); | 292 | spin_unlock(&clp->cl_lock); |
| 272 | } | 293 | } |
| 273 | 294 | ||
| 295 | #if defined(CONFIG_NFS_V4_1) | ||
| 296 | |||
| 297 | /* | ||
| 298 | * nfs4_free_slot - free a slot and efficiently update slot table. | ||
| 299 | * | ||
| 300 | * freeing a slot is trivially done by clearing its respective bit | ||
| 301 | * in the bitmap. | ||
| 302 | * If the freed slotid equals highest_used_slotid we want to update it | ||
| 303 | * so that the server would be able to size down the slot table if needed, | ||
| 304 | * otherwise we know that the highest_used_slotid is still in use. | ||
| 305 | * When updating highest_used_slotid there may be "holes" in the bitmap | ||
| 306 | * so we need to scan down from highest_used_slotid to 0 looking for the now | ||
| 307 | * highest slotid in use. | ||
| 308 | * If none found, highest_used_slotid is set to -1. | ||
| 309 | */ | ||
| 310 | static void | ||
| 311 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | ||
| 312 | { | ||
| 313 | int slotid = free_slotid; | ||
| 314 | |||
| 315 | spin_lock(&tbl->slot_tbl_lock); | ||
| 316 | /* clear used bit in bitmap */ | ||
| 317 | __clear_bit(slotid, tbl->used_slots); | ||
| 318 | |||
| 319 | /* update highest_used_slotid when it is freed */ | ||
| 320 | if (slotid == tbl->highest_used_slotid) { | ||
| 321 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); | ||
| 322 | if (slotid >= 0 && slotid < tbl->max_slots) | ||
| 323 | tbl->highest_used_slotid = slotid; | ||
| 324 | else | ||
| 325 | tbl->highest_used_slotid = -1; | ||
| 326 | } | ||
| 327 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
| 328 | spin_unlock(&tbl->slot_tbl_lock); | ||
| 329 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, | ||
| 330 | free_slotid, tbl->highest_used_slotid); | ||
| 331 | } | ||
| 332 | |||
| 333 | void nfs41_sequence_free_slot(const struct nfs_client *clp, | ||
| 334 | struct nfs4_sequence_res *res) | ||
| 335 | { | ||
| 336 | struct nfs4_slot_table *tbl; | ||
| 337 | |||
| 338 | if (!nfs4_has_session(clp)) { | ||
| 339 | dprintk("%s: No session\n", __func__); | ||
| 340 | return; | ||
| 341 | } | ||
| 342 | tbl = &clp->cl_session->fc_slot_table; | ||
| 343 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | ||
| 344 | dprintk("%s: No slot\n", __func__); | ||
| 345 | /* just wake up the next guy waiting since | ||
| 346 | * we may have not consumed a slot after all */ | ||
| 347 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
| 348 | return; | ||
| 349 | } | ||
| 350 | nfs4_free_slot(tbl, res->sr_slotid); | ||
| 351 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 352 | } | ||
| 353 | |||
| 354 | static void nfs41_sequence_done(struct nfs_client *clp, | ||
| 355 | struct nfs4_sequence_res *res, | ||
| 356 | int rpc_status) | ||
| 357 | { | ||
| 358 | unsigned long timestamp; | ||
| 359 | struct nfs4_slot_table *tbl; | ||
| 360 | struct nfs4_slot *slot; | ||
| 361 | |||
| 362 | /* | ||
| 363 | * sr_status remains 1 if an RPC level error occurred. The server | ||
| 364 | * may or may not have processed the sequence operation.. | ||
| 365 | * Proceed as if the server received and processed the sequence | ||
| 366 | * operation. | ||
| 367 | */ | ||
| 368 | if (res->sr_status == 1) | ||
| 369 | res->sr_status = NFS_OK; | ||
| 370 | |||
| 371 | /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ | ||
| 372 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | ||
| 373 | goto out; | ||
| 374 | |||
| 375 | tbl = &clp->cl_session->fc_slot_table; | ||
| 376 | slot = tbl->slots + res->sr_slotid; | ||
| 377 | |||
| 378 | if (res->sr_status == 0) { | ||
| 379 | /* Update the slot's sequence and clientid lease timer */ | ||
| 380 | ++slot->seq_nr; | ||
| 381 | timestamp = res->sr_renewal_time; | ||
| 382 | spin_lock(&clp->cl_lock); | ||
| 383 | if (time_before(clp->cl_last_renewal, timestamp)) | ||
| 384 | clp->cl_last_renewal = timestamp; | ||
| 385 | spin_unlock(&clp->cl_lock); | ||
| 386 | return; | ||
| 387 | } | ||
| 388 | out: | ||
| 389 | /* The session may be reset by one of the error handlers. */ | ||
| 390 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | ||
| 391 | nfs41_sequence_free_slot(clp, res); | ||
| 392 | } | ||
| 393 | |||
| 394 | /* | ||
| 395 | * nfs4_find_slot - efficiently look for a free slot | ||
| 396 | * | ||
| 397 | * nfs4_find_slot looks for an unset bit in the used_slots bitmap. | ||
| 398 | * If found, we mark the slot as used, update the highest_used_slotid, | ||
| 399 | * and respectively set up the sequence operation args. | ||
| 400 | * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise. | ||
| 401 | * | ||
| 402 | * Note: must be called with under the slot_tbl_lock. | ||
| 403 | */ | ||
| 404 | static u8 | ||
| 405 | nfs4_find_slot(struct nfs4_slot_table *tbl, struct rpc_task *task) | ||
| 406 | { | ||
| 407 | int slotid; | ||
| 408 | u8 ret_id = NFS4_MAX_SLOT_TABLE; | ||
| 409 | BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE); | ||
| 410 | |||
| 411 | dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d\n", | ||
| 412 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | ||
| 413 | tbl->max_slots); | ||
| 414 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots); | ||
| 415 | if (slotid >= tbl->max_slots) | ||
| 416 | goto out; | ||
| 417 | __set_bit(slotid, tbl->used_slots); | ||
| 418 | if (slotid > tbl->highest_used_slotid) | ||
| 419 | tbl->highest_used_slotid = slotid; | ||
| 420 | ret_id = slotid; | ||
| 421 | out: | ||
| 422 | dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", | ||
| 423 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, ret_id); | ||
| 424 | return ret_id; | ||
| 425 | } | ||
| 426 | |||
| 427 | static int nfs4_recover_session(struct nfs4_session *session) | ||
| 428 | { | ||
| 429 | struct nfs_client *clp = session->clp; | ||
| 430 | int ret; | ||
| 431 | |||
| 432 | for (;;) { | ||
| 433 | ret = nfs4_wait_clnt_recover(clp); | ||
| 434 | if (ret != 0) | ||
| 435 | return ret; | ||
| 436 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
| 437 | break; | ||
| 438 | nfs4_schedule_state_manager(clp); | ||
| 439 | } | ||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | |||
| 443 | static int nfs41_setup_sequence(struct nfs4_session *session, | ||
| 444 | struct nfs4_sequence_args *args, | ||
| 445 | struct nfs4_sequence_res *res, | ||
| 446 | int cache_reply, | ||
| 447 | struct rpc_task *task) | ||
| 448 | { | ||
| 449 | struct nfs4_slot *slot; | ||
| 450 | struct nfs4_slot_table *tbl; | ||
| 451 | int status = 0; | ||
| 452 | u8 slotid; | ||
| 453 | |||
| 454 | dprintk("--> %s\n", __func__); | ||
| 455 | /* slot already allocated? */ | ||
| 456 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | ||
| 457 | return 0; | ||
| 458 | |||
| 459 | memset(res, 0, sizeof(*res)); | ||
| 460 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 461 | tbl = &session->fc_slot_table; | ||
| 462 | |||
| 463 | spin_lock(&tbl->slot_tbl_lock); | ||
| 464 | if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) { | ||
| 465 | if (tbl->highest_used_slotid != -1) { | ||
| 466 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
| 467 | spin_unlock(&tbl->slot_tbl_lock); | ||
| 468 | dprintk("<-- %s: Session reset: draining\n", __func__); | ||
| 469 | return -EAGAIN; | ||
| 470 | } | ||
| 471 | |||
| 472 | /* The slot table is empty; start the reset thread */ | ||
| 473 | dprintk("%s Session Reset\n", __func__); | ||
| 474 | spin_unlock(&tbl->slot_tbl_lock); | ||
| 475 | status = nfs4_recover_session(session); | ||
| 476 | if (status) | ||
| 477 | return status; | ||
| 478 | spin_lock(&tbl->slot_tbl_lock); | ||
| 479 | } | ||
| 480 | |||
| 481 | slotid = nfs4_find_slot(tbl, task); | ||
| 482 | if (slotid == NFS4_MAX_SLOT_TABLE) { | ||
| 483 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
| 484 | spin_unlock(&tbl->slot_tbl_lock); | ||
| 485 | dprintk("<-- %s: no free slots\n", __func__); | ||
| 486 | return -EAGAIN; | ||
| 487 | } | ||
| 488 | spin_unlock(&tbl->slot_tbl_lock); | ||
| 489 | |||
| 490 | slot = tbl->slots + slotid; | ||
| 491 | args->sa_session = session; | ||
| 492 | args->sa_slotid = slotid; | ||
| 493 | args->sa_cache_this = cache_reply; | ||
| 494 | |||
| 495 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); | ||
| 496 | |||
| 497 | res->sr_session = session; | ||
| 498 | res->sr_slotid = slotid; | ||
| 499 | res->sr_renewal_time = jiffies; | ||
| 500 | /* | ||
| 501 | * sr_status is only set in decode_sequence, and so will remain | ||
| 502 | * set to 1 if an rpc level failure occurs. | ||
| 503 | */ | ||
| 504 | res->sr_status = 1; | ||
| 505 | return 0; | ||
| 506 | } | ||
| 507 | |||
| 508 | int nfs4_setup_sequence(struct nfs_client *clp, | ||
| 509 | struct nfs4_sequence_args *args, | ||
| 510 | struct nfs4_sequence_res *res, | ||
| 511 | int cache_reply, | ||
| 512 | struct rpc_task *task) | ||
| 513 | { | ||
| 514 | int ret = 0; | ||
| 515 | |||
| 516 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | ||
| 517 | __func__, clp, clp->cl_session, res->sr_slotid); | ||
| 518 | |||
| 519 | if (!nfs4_has_session(clp)) | ||
| 520 | goto out; | ||
| 521 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | ||
| 522 | task); | ||
| 523 | if (ret != -EAGAIN) { | ||
| 524 | /* terminate rpc task */ | ||
| 525 | task->tk_status = ret; | ||
| 526 | task->tk_action = NULL; | ||
| 527 | } | ||
| 528 | out: | ||
| 529 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
| 530 | return ret; | ||
| 531 | } | ||
| 532 | |||
| 533 | struct nfs41_call_sync_data { | ||
| 534 | struct nfs_client *clp; | ||
| 535 | struct nfs4_sequence_args *seq_args; | ||
| 536 | struct nfs4_sequence_res *seq_res; | ||
| 537 | int cache_reply; | ||
| 538 | }; | ||
| 539 | |||
| 540 | static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | ||
| 541 | { | ||
| 542 | struct nfs41_call_sync_data *data = calldata; | ||
| 543 | |||
| 544 | dprintk("--> %s data->clp->cl_session %p\n", __func__, | ||
| 545 | data->clp->cl_session); | ||
| 546 | if (nfs4_setup_sequence(data->clp, data->seq_args, | ||
| 547 | data->seq_res, data->cache_reply, task)) | ||
| 548 | return; | ||
| 549 | rpc_call_start(task); | ||
| 550 | } | ||
| 551 | |||
| 552 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | ||
| 553 | { | ||
| 554 | struct nfs41_call_sync_data *data = calldata; | ||
| 555 | |||
| 556 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | ||
| 557 | nfs41_sequence_free_slot(data->clp, data->seq_res); | ||
| 558 | } | ||
| 559 | |||
| 560 | struct rpc_call_ops nfs41_call_sync_ops = { | ||
| 561 | .rpc_call_prepare = nfs41_call_sync_prepare, | ||
| 562 | .rpc_call_done = nfs41_call_sync_done, | ||
| 563 | }; | ||
| 564 | |||
| 565 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | ||
| 566 | struct rpc_clnt *clnt, | ||
| 567 | struct rpc_message *msg, | ||
| 568 | struct nfs4_sequence_args *args, | ||
| 569 | struct nfs4_sequence_res *res, | ||
| 570 | int cache_reply) | ||
| 571 | { | ||
| 572 | int ret; | ||
| 573 | struct rpc_task *task; | ||
| 574 | struct nfs41_call_sync_data data = { | ||
| 575 | .clp = clp, | ||
| 576 | .seq_args = args, | ||
| 577 | .seq_res = res, | ||
| 578 | .cache_reply = cache_reply, | ||
| 579 | }; | ||
| 580 | struct rpc_task_setup task_setup = { | ||
| 581 | .rpc_client = clnt, | ||
| 582 | .rpc_message = msg, | ||
| 583 | .callback_ops = &nfs41_call_sync_ops, | ||
| 584 | .callback_data = &data | ||
| 585 | }; | ||
| 586 | |||
| 587 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 588 | task = rpc_run_task(&task_setup); | ||
| 589 | if (IS_ERR(task)) | ||
| 590 | ret = PTR_ERR(task); | ||
| 591 | else { | ||
| 592 | ret = task->tk_status; | ||
| 593 | rpc_put_task(task); | ||
| 594 | } | ||
| 595 | return ret; | ||
| 596 | } | ||
| 597 | |||
| 598 | int _nfs4_call_sync_session(struct nfs_server *server, | ||
| 599 | struct rpc_message *msg, | ||
| 600 | struct nfs4_sequence_args *args, | ||
| 601 | struct nfs4_sequence_res *res, | ||
| 602 | int cache_reply) | ||
| 603 | { | ||
| 604 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | ||
| 605 | msg, args, res, cache_reply); | ||
| 606 | } | ||
| 607 | |||
| 608 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 609 | |||
| 610 | int _nfs4_call_sync(struct nfs_server *server, | ||
| 611 | struct rpc_message *msg, | ||
| 612 | struct nfs4_sequence_args *args, | ||
| 613 | struct nfs4_sequence_res *res, | ||
| 614 | int cache_reply) | ||
| 615 | { | ||
| 616 | args->sa_session = res->sr_session = NULL; | ||
| 617 | return rpc_call_sync(server->client, msg, 0); | ||
| 618 | } | ||
| 619 | |||
| 620 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | ||
| 621 | (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \ | ||
| 622 | &(res)->seq_res, (cache_reply)) | ||
| 623 | |||
| 624 | static void nfs4_sequence_done(const struct nfs_server *server, | ||
| 625 | struct nfs4_sequence_res *res, int rpc_status) | ||
| 626 | { | ||
| 627 | #ifdef CONFIG_NFS_V4_1 | ||
| 628 | if (nfs4_has_session(server->nfs_client)) | ||
| 629 | nfs41_sequence_done(server->nfs_client, res, rpc_status); | ||
| 630 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 631 | } | ||
| 632 | |||
| 633 | /* no restart, therefore free slot here */ | ||
| 634 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, | ||
| 635 | struct nfs4_sequence_res *res, | ||
| 636 | int rpc_status) | ||
| 637 | { | ||
| 638 | nfs4_sequence_done(server, res, rpc_status); | ||
| 639 | nfs4_sequence_free_slot(server->nfs_client, res); | ||
| 640 | } | ||
| 641 | |||
| 274 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 642 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
| 275 | { | 643 | { |
| 276 | struct nfs_inode *nfsi = NFS_I(dir); | 644 | struct nfs_inode *nfsi = NFS_I(dir); |
| @@ -343,6 +711,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
| 343 | p->o_arg.server = server; | 711 | p->o_arg.server = server; |
| 344 | p->o_arg.bitmask = server->attr_bitmask; | 712 | p->o_arg.bitmask = server->attr_bitmask; |
| 345 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 713 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
| 714 | p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 346 | if (flags & O_EXCL) { | 715 | if (flags & O_EXCL) { |
| 347 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | 716 | u32 *s = (u32 *) p->o_arg.u.verifier.data; |
| 348 | s[0] = jiffies; | 717 | s[0] = jiffies; |
| @@ -929,6 +1298,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
| 929 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 1298 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
| 930 | } | 1299 | } |
| 931 | data->timestamp = jiffies; | 1300 | data->timestamp = jiffies; |
| 1301 | if (nfs4_setup_sequence(data->o_arg.server->nfs_client, | ||
| 1302 | &data->o_arg.seq_args, | ||
| 1303 | &data->o_res.seq_res, 1, task)) | ||
| 1304 | return; | ||
| 932 | rpc_call_start(task); | 1305 | rpc_call_start(task); |
| 933 | return; | 1306 | return; |
| 934 | out_no_action: | 1307 | out_no_action: |
| @@ -941,6 +1314,10 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
| 941 | struct nfs4_opendata *data = calldata; | 1314 | struct nfs4_opendata *data = calldata; |
| 942 | 1315 | ||
| 943 | data->rpc_status = task->tk_status; | 1316 | data->rpc_status = task->tk_status; |
| 1317 | |||
| 1318 | nfs4_sequence_done_free_slot(data->o_arg.server, &data->o_res.seq_res, | ||
| 1319 | task->tk_status); | ||
| 1320 | |||
| 944 | if (RPC_ASSASSINATED(task)) | 1321 | if (RPC_ASSASSINATED(task)) |
| 945 | return; | 1322 | return; |
| 946 | if (task->tk_status == 0) { | 1323 | if (task->tk_status == 0) { |
| @@ -1269,7 +1646,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
| 1269 | } else | 1646 | } else |
| 1270 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1647 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
| 1271 | 1648 | ||
| 1272 | status = rpc_call_sync(server->client, &msg, 0); | 1649 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
| 1273 | if (status == 0 && state != NULL) | 1650 | if (status == 0 && state != NULL) |
| 1274 | renew_lease(server, timestamp); | 1651 | renew_lease(server, timestamp); |
| 1275 | return status; | 1652 | return status; |
| @@ -1318,6 +1695,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 1318 | struct nfs4_state *state = calldata->state; | 1695 | struct nfs4_state *state = calldata->state; |
| 1319 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1696 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
| 1320 | 1697 | ||
| 1698 | nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status); | ||
| 1321 | if (RPC_ASSASSINATED(task)) | 1699 | if (RPC_ASSASSINATED(task)) |
| 1322 | return; | 1700 | return; |
| 1323 | /* hmm. we are done with the inode, and in the process of freeing | 1701 | /* hmm. we are done with the inode, and in the process of freeing |
| @@ -1336,10 +1714,11 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 1336 | break; | 1714 | break; |
| 1337 | default: | 1715 | default: |
| 1338 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1716 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
| 1339 | rpc_restart_call(task); | 1717 | nfs4_restart_rpc(task, server->nfs_client); |
| 1340 | return; | 1718 | return; |
| 1341 | } | 1719 | } |
| 1342 | } | 1720 | } |
| 1721 | nfs4_sequence_free_slot(server->nfs_client, &calldata->res.seq_res); | ||
| 1343 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1722 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
| 1344 | } | 1723 | } |
| 1345 | 1724 | ||
| @@ -1380,6 +1759,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 1380 | calldata->arg.fmode = FMODE_WRITE; | 1759 | calldata->arg.fmode = FMODE_WRITE; |
| 1381 | } | 1760 | } |
| 1382 | calldata->timestamp = jiffies; | 1761 | calldata->timestamp = jiffies; |
| 1762 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | ||
| 1763 | &calldata->arg.seq_args, &calldata->res.seq_res, | ||
| 1764 | 1, task)) | ||
| 1765 | return; | ||
| 1383 | rpc_call_start(task); | 1766 | rpc_call_start(task); |
| 1384 | } | 1767 | } |
| 1385 | 1768 | ||
| @@ -1419,13 +1802,15 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
| 1419 | }; | 1802 | }; |
| 1420 | int status = -ENOMEM; | 1803 | int status = -ENOMEM; |
| 1421 | 1804 | ||
| 1422 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 1805 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); |
| 1423 | if (calldata == NULL) | 1806 | if (calldata == NULL) |
| 1424 | goto out; | 1807 | goto out; |
| 1425 | calldata->inode = state->inode; | 1808 | calldata->inode = state->inode; |
| 1426 | calldata->state = state; | 1809 | calldata->state = state; |
| 1427 | calldata->arg.fh = NFS_FH(state->inode); | 1810 | calldata->arg.fh = NFS_FH(state->inode); |
| 1428 | calldata->arg.stateid = &state->open_stateid; | 1811 | calldata->arg.stateid = &state->open_stateid; |
| 1812 | if (nfs4_has_session(server->nfs_client)) | ||
| 1813 | memset(calldata->arg.stateid->data, 0, 4); /* clear seqid */ | ||
| 1429 | /* Serialization for the sequence id */ | 1814 | /* Serialization for the sequence id */ |
| 1430 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1815 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
| 1431 | if (calldata->arg.seqid == NULL) | 1816 | if (calldata->arg.seqid == NULL) |
| @@ -1435,6 +1820,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
| 1435 | calldata->res.fattr = &calldata->fattr; | 1820 | calldata->res.fattr = &calldata->fattr; |
| 1436 | calldata->res.seqid = calldata->arg.seqid; | 1821 | calldata->res.seqid = calldata->arg.seqid; |
| 1437 | calldata->res.server = server; | 1822 | calldata->res.server = server; |
| 1823 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 1438 | calldata->path.mnt = mntget(path->mnt); | 1824 | calldata->path.mnt = mntget(path->mnt); |
| 1439 | calldata->path.dentry = dget(path->dentry); | 1825 | calldata->path.dentry = dget(path->dentry); |
| 1440 | 1826 | ||
| @@ -1584,15 +1970,18 @@ void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | |||
| 1584 | 1970 | ||
| 1585 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | 1971 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) |
| 1586 | { | 1972 | { |
| 1973 | struct nfs4_server_caps_arg args = { | ||
| 1974 | .fhandle = fhandle, | ||
| 1975 | }; | ||
| 1587 | struct nfs4_server_caps_res res = {}; | 1976 | struct nfs4_server_caps_res res = {}; |
| 1588 | struct rpc_message msg = { | 1977 | struct rpc_message msg = { |
| 1589 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], | 1978 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], |
| 1590 | .rpc_argp = fhandle, | 1979 | .rpc_argp = &args, |
| 1591 | .rpc_resp = &res, | 1980 | .rpc_resp = &res, |
| 1592 | }; | 1981 | }; |
| 1593 | int status; | 1982 | int status; |
| 1594 | 1983 | ||
| 1595 | status = rpc_call_sync(server->client, &msg, 0); | 1984 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
| 1596 | if (status == 0) { | 1985 | if (status == 0) { |
| 1597 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 1986 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
| 1598 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) | 1987 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) |
| @@ -1606,6 +1995,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
| 1606 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 1995 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
| 1607 | server->acl_bitmask = res.acl_bitmask; | 1996 | server->acl_bitmask = res.acl_bitmask; |
| 1608 | } | 1997 | } |
| 1998 | |||
| 1609 | return status; | 1999 | return status; |
| 1610 | } | 2000 | } |
| 1611 | 2001 | ||
| @@ -1637,8 +2027,15 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
| 1637 | .rpc_argp = &args, | 2027 | .rpc_argp = &args, |
| 1638 | .rpc_resp = &res, | 2028 | .rpc_resp = &res, |
| 1639 | }; | 2029 | }; |
| 2030 | int status; | ||
| 2031 | |||
| 1640 | nfs_fattr_init(info->fattr); | 2032 | nfs_fattr_init(info->fattr); |
| 1641 | return rpc_call_sync(server->client, &msg, 0); | 2033 | status = nfs4_recover_expired_lease(server); |
| 2034 | if (!status) | ||
| 2035 | status = nfs4_check_client_ready(server->nfs_client); | ||
| 2036 | if (!status) | ||
| 2037 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | ||
| 2038 | return status; | ||
| 1642 | } | 2039 | } |
| 1643 | 2040 | ||
| 1644 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2041 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, |
| @@ -1728,7 +2125,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
| 1728 | }; | 2125 | }; |
| 1729 | 2126 | ||
| 1730 | nfs_fattr_init(fattr); | 2127 | nfs_fattr_init(fattr); |
| 1731 | return rpc_call_sync(server->client, &msg, 0); | 2128 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
| 1732 | } | 2129 | } |
| 1733 | 2130 | ||
| 1734 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2131 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
| @@ -1812,7 +2209,7 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *d | |||
| 1812 | nfs_fattr_init(fattr); | 2209 | nfs_fattr_init(fattr); |
| 1813 | 2210 | ||
| 1814 | dprintk("NFS call lookupfh %s\n", name->name); | 2211 | dprintk("NFS call lookupfh %s\n", name->name); |
| 1815 | status = rpc_call_sync(server->client, &msg, 0); | 2212 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
| 1816 | dprintk("NFS reply lookupfh: %d\n", status); | 2213 | dprintk("NFS reply lookupfh: %d\n", status); |
| 1817 | return status; | 2214 | return status; |
| 1818 | } | 2215 | } |
| @@ -1898,7 +2295,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
| 1898 | args.access |= NFS4_ACCESS_EXECUTE; | 2295 | args.access |= NFS4_ACCESS_EXECUTE; |
| 1899 | } | 2296 | } |
| 1900 | nfs_fattr_init(&fattr); | 2297 | nfs_fattr_init(&fattr); |
| 1901 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2298 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
| 1902 | if (!status) { | 2299 | if (!status) { |
| 1903 | entry->mask = 0; | 2300 | entry->mask = 0; |
| 1904 | if (res.access & NFS4_ACCESS_READ) | 2301 | if (res.access & NFS4_ACCESS_READ) |
| @@ -1957,13 +2354,14 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
| 1957 | .pglen = pglen, | 2354 | .pglen = pglen, |
| 1958 | .pages = &page, | 2355 | .pages = &page, |
| 1959 | }; | 2356 | }; |
| 2357 | struct nfs4_readlink_res res; | ||
| 1960 | struct rpc_message msg = { | 2358 | struct rpc_message msg = { |
| 1961 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], | 2359 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], |
| 1962 | .rpc_argp = &args, | 2360 | .rpc_argp = &args, |
| 1963 | .rpc_resp = NULL, | 2361 | .rpc_resp = &res, |
| 1964 | }; | 2362 | }; |
| 1965 | 2363 | ||
| 1966 | return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2364 | return nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
| 1967 | } | 2365 | } |
| 1968 | 2366 | ||
| 1969 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, | 2367 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, |
| @@ -2057,7 +2455,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
| 2057 | int status; | 2455 | int status; |
| 2058 | 2456 | ||
| 2059 | nfs_fattr_init(&res.dir_attr); | 2457 | nfs_fattr_init(&res.dir_attr); |
| 2060 | status = rpc_call_sync(server->client, &msg, 0); | 2458 | status = nfs4_call_sync(server, &msg, &args, &res, 1); |
| 2061 | if (status == 0) { | 2459 | if (status == 0) { |
| 2062 | update_changeattr(dir, &res.cinfo); | 2460 | update_changeattr(dir, &res.cinfo); |
| 2063 | nfs_post_op_update_inode(dir, &res.dir_attr); | 2461 | nfs_post_op_update_inode(dir, &res.dir_attr); |
| @@ -2092,8 +2490,10 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
| 2092 | { | 2490 | { |
| 2093 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2491 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
| 2094 | 2492 | ||
| 2493 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | ||
| 2095 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2494 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
| 2096 | return 0; | 2495 | return 0; |
| 2496 | nfs4_sequence_free_slot(res->server->nfs_client, &res->seq_res); | ||
| 2097 | update_changeattr(dir, &res->cinfo); | 2497 | update_changeattr(dir, &res->cinfo); |
| 2098 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2498 | nfs_post_op_update_inode(dir, &res->dir_attr); |
| 2099 | return 1; | 2499 | return 1; |
| @@ -2125,7 +2525,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
| 2125 | 2525 | ||
| 2126 | nfs_fattr_init(res.old_fattr); | 2526 | nfs_fattr_init(res.old_fattr); |
| 2127 | nfs_fattr_init(res.new_fattr); | 2527 | nfs_fattr_init(res.new_fattr); |
| 2128 | status = rpc_call_sync(server->client, &msg, 0); | 2528 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
| 2129 | 2529 | ||
| 2130 | if (!status) { | 2530 | if (!status) { |
| 2131 | update_changeattr(old_dir, &res.old_cinfo); | 2531 | update_changeattr(old_dir, &res.old_cinfo); |
| @@ -2174,7 +2574,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
| 2174 | 2574 | ||
| 2175 | nfs_fattr_init(res.fattr); | 2575 | nfs_fattr_init(res.fattr); |
| 2176 | nfs_fattr_init(res.dir_attr); | 2576 | nfs_fattr_init(res.dir_attr); |
| 2177 | status = rpc_call_sync(server->client, &msg, 0); | 2577 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
| 2178 | if (!status) { | 2578 | if (!status) { |
| 2179 | update_changeattr(dir, &res.cinfo); | 2579 | update_changeattr(dir, &res.cinfo); |
| 2180 | nfs_post_op_update_inode(dir, res.dir_attr); | 2580 | nfs_post_op_update_inode(dir, res.dir_attr); |
| @@ -2235,7 +2635,8 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | |||
| 2235 | 2635 | ||
| 2236 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) | 2636 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) |
| 2237 | { | 2637 | { |
| 2238 | int status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); | 2638 | int status = nfs4_call_sync(NFS_SERVER(dir), &data->msg, |
| 2639 | &data->arg, &data->res, 1); | ||
| 2239 | if (status == 0) { | 2640 | if (status == 0) { |
| 2240 | update_changeattr(dir, &data->res.dir_cinfo); | 2641 | update_changeattr(dir, &data->res.dir_cinfo); |
| 2241 | nfs_post_op_update_inode(dir, data->res.dir_fattr); | 2642 | nfs_post_op_update_inode(dir, data->res.dir_fattr); |
| @@ -2344,7 +2745,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
| 2344 | (unsigned long long)cookie); | 2745 | (unsigned long long)cookie); |
| 2345 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 2746 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
| 2346 | res.pgbase = args.pgbase; | 2747 | res.pgbase = args.pgbase; |
| 2347 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2748 | status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); |
| 2348 | if (status == 0) | 2749 | if (status == 0) |
| 2349 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 2750 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
| 2350 | 2751 | ||
| @@ -2422,14 +2823,17 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | |||
| 2422 | .fh = fhandle, | 2823 | .fh = fhandle, |
| 2423 | .bitmask = server->attr_bitmask, | 2824 | .bitmask = server->attr_bitmask, |
| 2424 | }; | 2825 | }; |
| 2826 | struct nfs4_statfs_res res = { | ||
| 2827 | .fsstat = fsstat, | ||
| 2828 | }; | ||
| 2425 | struct rpc_message msg = { | 2829 | struct rpc_message msg = { |
| 2426 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], | 2830 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], |
| 2427 | .rpc_argp = &args, | 2831 | .rpc_argp = &args, |
| 2428 | .rpc_resp = fsstat, | 2832 | .rpc_resp = &res, |
| 2429 | }; | 2833 | }; |
| 2430 | 2834 | ||
| 2431 | nfs_fattr_init(fsstat->fattr); | 2835 | nfs_fattr_init(fsstat->fattr); |
| 2432 | return rpc_call_sync(server->client, &msg, 0); | 2836 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
| 2433 | } | 2837 | } |
| 2434 | 2838 | ||
| 2435 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) | 2839 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) |
| @@ -2451,13 +2855,16 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
| 2451 | .fh = fhandle, | 2855 | .fh = fhandle, |
| 2452 | .bitmask = server->attr_bitmask, | 2856 | .bitmask = server->attr_bitmask, |
| 2453 | }; | 2857 | }; |
| 2858 | struct nfs4_fsinfo_res res = { | ||
| 2859 | .fsinfo = fsinfo, | ||
| 2860 | }; | ||
| 2454 | struct rpc_message msg = { | 2861 | struct rpc_message msg = { |
| 2455 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], | 2862 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], |
| 2456 | .rpc_argp = &args, | 2863 | .rpc_argp = &args, |
| 2457 | .rpc_resp = fsinfo, | 2864 | .rpc_resp = &res, |
| 2458 | }; | 2865 | }; |
| 2459 | 2866 | ||
| 2460 | return rpc_call_sync(server->client, &msg, 0); | 2867 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
| 2461 | } | 2868 | } |
| 2462 | 2869 | ||
| 2463 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 2870 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
| @@ -2486,10 +2893,13 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
| 2486 | .fh = fhandle, | 2893 | .fh = fhandle, |
| 2487 | .bitmask = server->attr_bitmask, | 2894 | .bitmask = server->attr_bitmask, |
| 2488 | }; | 2895 | }; |
| 2896 | struct nfs4_pathconf_res res = { | ||
| 2897 | .pathconf = pathconf, | ||
| 2898 | }; | ||
| 2489 | struct rpc_message msg = { | 2899 | struct rpc_message msg = { |
| 2490 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], | 2900 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], |
| 2491 | .rpc_argp = &args, | 2901 | .rpc_argp = &args, |
| 2492 | .rpc_resp = pathconf, | 2902 | .rpc_resp = &res, |
| 2493 | }; | 2903 | }; |
| 2494 | 2904 | ||
| 2495 | /* None of the pathconf attributes are mandatory to implement */ | 2905 | /* None of the pathconf attributes are mandatory to implement */ |
| @@ -2499,7 +2909,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
| 2499 | } | 2909 | } |
| 2500 | 2910 | ||
| 2501 | nfs_fattr_init(pathconf->fattr); | 2911 | nfs_fattr_init(pathconf->fattr); |
| 2502 | return rpc_call_sync(server->client, &msg, 0); | 2912 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
| 2503 | } | 2913 | } |
| 2504 | 2914 | ||
| 2505 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | 2915 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, |
| @@ -2520,8 +2930,13 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
| 2520 | { | 2930 | { |
| 2521 | struct nfs_server *server = NFS_SERVER(data->inode); | 2931 | struct nfs_server *server = NFS_SERVER(data->inode); |
| 2522 | 2932 | ||
| 2933 | dprintk("--> %s\n", __func__); | ||
| 2934 | |||
| 2935 | /* nfs4_sequence_free_slot called in the read rpc_call_done */ | ||
| 2936 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | ||
| 2937 | |||
| 2523 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 2938 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
| 2524 | rpc_restart_call(task); | 2939 | nfs4_restart_rpc(task, server->nfs_client); |
| 2525 | return -EAGAIN; | 2940 | return -EAGAIN; |
| 2526 | } | 2941 | } |
| 2527 | 2942 | ||
| @@ -2541,8 +2956,12 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 2541 | { | 2956 | { |
| 2542 | struct inode *inode = data->inode; | 2957 | struct inode *inode = data->inode; |
| 2543 | 2958 | ||
| 2959 | /* slot is freed in nfs_writeback_done */ | ||
| 2960 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
| 2961 | task->tk_status); | ||
| 2962 | |||
| 2544 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 2963 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
| 2545 | rpc_restart_call(task); | 2964 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
| 2546 | return -EAGAIN; | 2965 | return -EAGAIN; |
| 2547 | } | 2966 | } |
| 2548 | if (task->tk_status >= 0) { | 2967 | if (task->tk_status >= 0) { |
| @@ -2567,10 +2986,14 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 2567 | { | 2986 | { |
| 2568 | struct inode *inode = data->inode; | 2987 | struct inode *inode = data->inode; |
| 2569 | 2988 | ||
| 2989 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
| 2990 | task->tk_status); | ||
| 2570 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 2991 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
| 2571 | rpc_restart_call(task); | 2992 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
| 2572 | return -EAGAIN; | 2993 | return -EAGAIN; |
| 2573 | } | 2994 | } |
| 2995 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, | ||
| 2996 | &data->res.seq_res); | ||
| 2574 | nfs_refresh_inode(inode, data->res.fattr); | 2997 | nfs_refresh_inode(inode, data->res.fattr); |
| 2575 | return 0; | 2998 | return 0; |
| 2576 | } | 2999 | } |
| @@ -2603,6 +3026,9 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
| 2603 | if (time_before(clp->cl_last_renewal,timestamp)) | 3026 | if (time_before(clp->cl_last_renewal,timestamp)) |
| 2604 | clp->cl_last_renewal = timestamp; | 3027 | clp->cl_last_renewal = timestamp; |
| 2605 | spin_unlock(&clp->cl_lock); | 3028 | spin_unlock(&clp->cl_lock); |
| 3029 | dprintk("%s calling put_rpccred on rpc_cred %p\n", __func__, | ||
| 3030 | task->tk_msg.rpc_cred); | ||
| 3031 | put_rpccred(task->tk_msg.rpc_cred); | ||
| 2606 | } | 3032 | } |
| 2607 | 3033 | ||
| 2608 | static const struct rpc_call_ops nfs4_renew_ops = { | 3034 | static const struct rpc_call_ops nfs4_renew_ops = { |
| @@ -2742,12 +3168,14 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
| 2742 | .acl_pages = pages, | 3168 | .acl_pages = pages, |
| 2743 | .acl_len = buflen, | 3169 | .acl_len = buflen, |
| 2744 | }; | 3170 | }; |
| 2745 | size_t resp_len = buflen; | 3171 | struct nfs_getaclres res = { |
| 3172 | .acl_len = buflen, | ||
| 3173 | }; | ||
| 2746 | void *resp_buf; | 3174 | void *resp_buf; |
| 2747 | struct rpc_message msg = { | 3175 | struct rpc_message msg = { |
| 2748 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | 3176 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], |
| 2749 | .rpc_argp = &args, | 3177 | .rpc_argp = &args, |
| 2750 | .rpc_resp = &resp_len, | 3178 | .rpc_resp = &res, |
| 2751 | }; | 3179 | }; |
| 2752 | struct page *localpage = NULL; | 3180 | struct page *localpage = NULL; |
| 2753 | int ret; | 3181 | int ret; |
| @@ -2761,26 +3189,26 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
| 2761 | return -ENOMEM; | 3189 | return -ENOMEM; |
| 2762 | args.acl_pages[0] = localpage; | 3190 | args.acl_pages[0] = localpage; |
| 2763 | args.acl_pgbase = 0; | 3191 | args.acl_pgbase = 0; |
| 2764 | resp_len = args.acl_len = PAGE_SIZE; | 3192 | args.acl_len = PAGE_SIZE; |
| 2765 | } else { | 3193 | } else { |
| 2766 | resp_buf = buf; | 3194 | resp_buf = buf; |
| 2767 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | 3195 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); |
| 2768 | } | 3196 | } |
| 2769 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3197 | ret = nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
| 2770 | if (ret) | 3198 | if (ret) |
| 2771 | goto out_free; | 3199 | goto out_free; |
| 2772 | if (resp_len > args.acl_len) | 3200 | if (res.acl_len > args.acl_len) |
| 2773 | nfs4_write_cached_acl(inode, NULL, resp_len); | 3201 | nfs4_write_cached_acl(inode, NULL, res.acl_len); |
| 2774 | else | 3202 | else |
| 2775 | nfs4_write_cached_acl(inode, resp_buf, resp_len); | 3203 | nfs4_write_cached_acl(inode, resp_buf, res.acl_len); |
| 2776 | if (buf) { | 3204 | if (buf) { |
| 2777 | ret = -ERANGE; | 3205 | ret = -ERANGE; |
| 2778 | if (resp_len > buflen) | 3206 | if (res.acl_len > buflen) |
| 2779 | goto out_free; | 3207 | goto out_free; |
| 2780 | if (localpage) | 3208 | if (localpage) |
| 2781 | memcpy(buf, resp_buf, resp_len); | 3209 | memcpy(buf, resp_buf, res.acl_len); |
| 2782 | } | 3210 | } |
| 2783 | ret = resp_len; | 3211 | ret = res.acl_len; |
| 2784 | out_free: | 3212 | out_free: |
| 2785 | if (localpage) | 3213 | if (localpage) |
| 2786 | __free_page(localpage); | 3214 | __free_page(localpage); |
| @@ -2827,10 +3255,11 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
| 2827 | .acl_pages = pages, | 3255 | .acl_pages = pages, |
| 2828 | .acl_len = buflen, | 3256 | .acl_len = buflen, |
| 2829 | }; | 3257 | }; |
| 3258 | struct nfs_setaclres res; | ||
| 2830 | struct rpc_message msg = { | 3259 | struct rpc_message msg = { |
| 2831 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], | 3260 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], |
| 2832 | .rpc_argp = &arg, | 3261 | .rpc_argp = &arg, |
| 2833 | .rpc_resp = NULL, | 3262 | .rpc_resp = &res, |
| 2834 | }; | 3263 | }; |
| 2835 | int ret; | 3264 | int ret; |
| 2836 | 3265 | ||
| @@ -2838,7 +3267,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
| 2838 | return -EOPNOTSUPP; | 3267 | return -EOPNOTSUPP; |
| 2839 | nfs_inode_return_delegation(inode); | 3268 | nfs_inode_return_delegation(inode); |
| 2840 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3269 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
| 2841 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3270 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); |
| 2842 | nfs_access_zap_cache(inode); | 3271 | nfs_access_zap_cache(inode); |
| 2843 | nfs_zap_acl_cache(inode); | 3272 | nfs_zap_acl_cache(inode); |
| 2844 | return ret; | 3273 | return ret; |
| @@ -2857,10 +3286,8 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
| 2857 | } | 3286 | } |
| 2858 | 3287 | ||
| 2859 | static int | 3288 | static int |
| 2860 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | 3289 | _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state) |
| 2861 | { | 3290 | { |
| 2862 | struct nfs_client *clp = server->nfs_client; | ||
| 2863 | |||
| 2864 | if (!clp || task->tk_status >= 0) | 3291 | if (!clp || task->tk_status >= 0) |
| 2865 | return 0; | 3292 | return 0; |
| 2866 | switch(task->tk_status) { | 3293 | switch(task->tk_status) { |
| @@ -2879,8 +3306,23 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
| 2879 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | 3306 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
| 2880 | task->tk_status = 0; | 3307 | task->tk_status = 0; |
| 2881 | return -EAGAIN; | 3308 | return -EAGAIN; |
| 3309 | #if defined(CONFIG_NFS_V4_1) | ||
| 3310 | case -NFS4ERR_BADSESSION: | ||
| 3311 | case -NFS4ERR_BADSLOT: | ||
| 3312 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
| 3313 | case -NFS4ERR_DEADSESSION: | ||
| 3314 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
| 3315 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
| 3316 | case -NFS4ERR_SEQ_MISORDERED: | ||
| 3317 | dprintk("%s ERROR %d, Reset session\n", __func__, | ||
| 3318 | task->tk_status); | ||
| 3319 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
| 3320 | task->tk_status = 0; | ||
| 3321 | return -EAGAIN; | ||
| 3322 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 2882 | case -NFS4ERR_DELAY: | 3323 | case -NFS4ERR_DELAY: |
| 2883 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 3324 | if (server) |
| 3325 | nfs_inc_server_stats(server, NFSIOS_DELAY); | ||
| 2884 | case -NFS4ERR_GRACE: | 3326 | case -NFS4ERR_GRACE: |
| 2885 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3327 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
| 2886 | task->tk_status = 0; | 3328 | task->tk_status = 0; |
| @@ -2893,6 +3335,12 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
| 2893 | return 0; | 3335 | return 0; |
| 2894 | } | 3336 | } |
| 2895 | 3337 | ||
| 3338 | static int | ||
| 3339 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | ||
| 3340 | { | ||
| 3341 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | ||
| 3342 | } | ||
| 3343 | |||
| 2896 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 3344 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
| 2897 | { | 3345 | { |
| 2898 | nfs4_verifier sc_verifier; | 3346 | nfs4_verifier sc_verifier; |
| @@ -3000,6 +3448,10 @@ struct nfs4_delegreturndata { | |||
| 3000 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | 3448 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
| 3001 | { | 3449 | { |
| 3002 | struct nfs4_delegreturndata *data = calldata; | 3450 | struct nfs4_delegreturndata *data = calldata; |
| 3451 | |||
| 3452 | nfs4_sequence_done_free_slot(data->res.server, &data->res.seq_res, | ||
| 3453 | task->tk_status); | ||
| 3454 | |||
| 3003 | data->rpc_status = task->tk_status; | 3455 | data->rpc_status = task->tk_status; |
| 3004 | if (data->rpc_status == 0) | 3456 | if (data->rpc_status == 0) |
| 3005 | renew_lease(data->res.server, data->timestamp); | 3457 | renew_lease(data->res.server, data->timestamp); |
| @@ -3010,7 +3462,25 @@ static void nfs4_delegreturn_release(void *calldata) | |||
| 3010 | kfree(calldata); | 3462 | kfree(calldata); |
| 3011 | } | 3463 | } |
| 3012 | 3464 | ||
| 3465 | #if defined(CONFIG_NFS_V4_1) | ||
| 3466 | static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | ||
| 3467 | { | ||
| 3468 | struct nfs4_delegreturndata *d_data; | ||
| 3469 | |||
| 3470 | d_data = (struct nfs4_delegreturndata *)data; | ||
| 3471 | |||
| 3472 | if (nfs4_setup_sequence(d_data->res.server->nfs_client, | ||
| 3473 | &d_data->args.seq_args, | ||
| 3474 | &d_data->res.seq_res, 1, task)) | ||
| 3475 | return; | ||
| 3476 | rpc_call_start(task); | ||
| 3477 | } | ||
| 3478 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 3479 | |||
| 3013 | static const struct rpc_call_ops nfs4_delegreturn_ops = { | 3480 | static const struct rpc_call_ops nfs4_delegreturn_ops = { |
| 3481 | #if defined(CONFIG_NFS_V4_1) | ||
| 3482 | .rpc_call_prepare = nfs4_delegreturn_prepare, | ||
| 3483 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 3014 | .rpc_call_done = nfs4_delegreturn_done, | 3484 | .rpc_call_done = nfs4_delegreturn_done, |
| 3015 | .rpc_release = nfs4_delegreturn_release, | 3485 | .rpc_release = nfs4_delegreturn_release, |
| 3016 | }; | 3486 | }; |
| @@ -3032,7 +3502,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
| 3032 | }; | 3502 | }; |
| 3033 | int status = 0; | 3503 | int status = 0; |
| 3034 | 3504 | ||
| 3035 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 3505 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
| 3036 | if (data == NULL) | 3506 | if (data == NULL) |
| 3037 | return -ENOMEM; | 3507 | return -ENOMEM; |
| 3038 | data->args.fhandle = &data->fh; | 3508 | data->args.fhandle = &data->fh; |
| @@ -3042,6 +3512,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
| 3042 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 3512 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); |
| 3043 | data->res.fattr = &data->fattr; | 3513 | data->res.fattr = &data->fattr; |
| 3044 | data->res.server = server; | 3514 | data->res.server = server; |
| 3515 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 3045 | nfs_fattr_init(data->res.fattr); | 3516 | nfs_fattr_init(data->res.fattr); |
| 3046 | data->timestamp = jiffies; | 3517 | data->timestamp = jiffies; |
| 3047 | data->rpc_status = 0; | 3518 | data->rpc_status = 0; |
| @@ -3127,7 +3598,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
| 3127 | goto out; | 3598 | goto out; |
| 3128 | lsp = request->fl_u.nfs4_fl.owner; | 3599 | lsp = request->fl_u.nfs4_fl.owner; |
| 3129 | arg.lock_owner.id = lsp->ls_id.id; | 3600 | arg.lock_owner.id = lsp->ls_id.id; |
| 3130 | status = rpc_call_sync(server->client, &msg, 0); | 3601 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
| 3131 | switch (status) { | 3602 | switch (status) { |
| 3132 | case 0: | 3603 | case 0: |
| 3133 | request->fl_type = F_UNLCK; | 3604 | request->fl_type = F_UNLCK; |
| @@ -3187,13 +3658,14 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
| 3187 | struct nfs4_unlockdata *p; | 3658 | struct nfs4_unlockdata *p; |
| 3188 | struct inode *inode = lsp->ls_state->inode; | 3659 | struct inode *inode = lsp->ls_state->inode; |
| 3189 | 3660 | ||
| 3190 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 3661 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
| 3191 | if (p == NULL) | 3662 | if (p == NULL) |
| 3192 | return NULL; | 3663 | return NULL; |
| 3193 | p->arg.fh = NFS_FH(inode); | 3664 | p->arg.fh = NFS_FH(inode); |
| 3194 | p->arg.fl = &p->fl; | 3665 | p->arg.fl = &p->fl; |
| 3195 | p->arg.seqid = seqid; | 3666 | p->arg.seqid = seqid; |
| 3196 | p->res.seqid = seqid; | 3667 | p->res.seqid = seqid; |
| 3668 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 3197 | p->arg.stateid = &lsp->ls_stateid; | 3669 | p->arg.stateid = &lsp->ls_stateid; |
| 3198 | p->lsp = lsp; | 3670 | p->lsp = lsp; |
| 3199 | atomic_inc(&lsp->ls_count); | 3671 | atomic_inc(&lsp->ls_count); |
| @@ -3217,6 +3689,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
| 3217 | { | 3689 | { |
| 3218 | struct nfs4_unlockdata *calldata = data; | 3690 | struct nfs4_unlockdata *calldata = data; |
| 3219 | 3691 | ||
| 3692 | nfs4_sequence_done(calldata->server, &calldata->res.seq_res, | ||
| 3693 | task->tk_status); | ||
| 3220 | if (RPC_ASSASSINATED(task)) | 3694 | if (RPC_ASSASSINATED(task)) |
| 3221 | return; | 3695 | return; |
| 3222 | switch (task->tk_status) { | 3696 | switch (task->tk_status) { |
| @@ -3233,8 +3707,11 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
| 3233 | break; | 3707 | break; |
| 3234 | default: | 3708 | default: |
| 3235 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 3709 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
| 3236 | rpc_restart_call(task); | 3710 | nfs4_restart_rpc(task, |
| 3711 | calldata->server->nfs_client); | ||
| 3237 | } | 3712 | } |
| 3713 | nfs4_sequence_free_slot(calldata->server->nfs_client, | ||
| 3714 | &calldata->res.seq_res); | ||
| 3238 | } | 3715 | } |
| 3239 | 3716 | ||
| 3240 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3717 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
| @@ -3249,6 +3726,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
| 3249 | return; | 3726 | return; |
| 3250 | } | 3727 | } |
| 3251 | calldata->timestamp = jiffies; | 3728 | calldata->timestamp = jiffies; |
| 3729 | if (nfs4_setup_sequence(calldata->server->nfs_client, | ||
| 3730 | &calldata->arg.seq_args, | ||
| 3731 | &calldata->res.seq_res, 1, task)) | ||
| 3732 | return; | ||
| 3252 | rpc_call_start(task); | 3733 | rpc_call_start(task); |
| 3253 | } | 3734 | } |
| 3254 | 3735 | ||
| @@ -3341,6 +3822,7 @@ struct nfs4_lockdata { | |||
| 3341 | unsigned long timestamp; | 3822 | unsigned long timestamp; |
| 3342 | int rpc_status; | 3823 | int rpc_status; |
| 3343 | int cancelled; | 3824 | int cancelled; |
| 3825 | struct nfs_server *server; | ||
| 3344 | }; | 3826 | }; |
| 3345 | 3827 | ||
| 3346 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | 3828 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, |
| @@ -3366,7 +3848,9 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
| 3366 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3848 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
| 3367 | p->arg.lock_owner.id = lsp->ls_id.id; | 3849 | p->arg.lock_owner.id = lsp->ls_id.id; |
| 3368 | p->res.lock_seqid = p->arg.lock_seqid; | 3850 | p->res.lock_seqid = p->arg.lock_seqid; |
| 3851 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 3369 | p->lsp = lsp; | 3852 | p->lsp = lsp; |
| 3853 | p->server = server; | ||
| 3370 | atomic_inc(&lsp->ls_count); | 3854 | atomic_inc(&lsp->ls_count); |
| 3371 | p->ctx = get_nfs_open_context(ctx); | 3855 | p->ctx = get_nfs_open_context(ctx); |
| 3372 | memcpy(&p->fl, fl, sizeof(p->fl)); | 3856 | memcpy(&p->fl, fl, sizeof(p->fl)); |
| @@ -3396,6 +3880,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
| 3396 | } else | 3880 | } else |
| 3397 | data->arg.new_lock_owner = 0; | 3881 | data->arg.new_lock_owner = 0; |
| 3398 | data->timestamp = jiffies; | 3882 | data->timestamp = jiffies; |
| 3883 | if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args, | ||
| 3884 | &data->res.seq_res, 1, task)) | ||
| 3885 | return; | ||
| 3399 | rpc_call_start(task); | 3886 | rpc_call_start(task); |
| 3400 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 3887 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
| 3401 | } | 3888 | } |
| @@ -3406,6 +3893,9 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
| 3406 | 3893 | ||
| 3407 | dprintk("%s: begin!\n", __func__); | 3894 | dprintk("%s: begin!\n", __func__); |
| 3408 | 3895 | ||
| 3896 | nfs4_sequence_done_free_slot(data->server, &data->res.seq_res, | ||
| 3897 | task->tk_status); | ||
| 3898 | |||
| 3409 | data->rpc_status = task->tk_status; | 3899 | data->rpc_status = task->tk_status; |
| 3410 | if (RPC_ASSASSINATED(task)) | 3900 | if (RPC_ASSASSINATED(task)) |
| 3411 | goto out; | 3901 | goto out; |
| @@ -3706,10 +4196,13 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
| 3706 | .page = page, | 4196 | .page = page, |
| 3707 | .bitmask = bitmask, | 4197 | .bitmask = bitmask, |
| 3708 | }; | 4198 | }; |
| 4199 | struct nfs4_fs_locations_res res = { | ||
| 4200 | .fs_locations = fs_locations, | ||
| 4201 | }; | ||
| 3709 | struct rpc_message msg = { | 4202 | struct rpc_message msg = { |
| 3710 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], | 4203 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], |
| 3711 | .rpc_argp = &args, | 4204 | .rpc_argp = &args, |
| 3712 | .rpc_resp = fs_locations, | 4205 | .rpc_resp = &res, |
| 3713 | }; | 4206 | }; |
| 3714 | int status; | 4207 | int status; |
| 3715 | 4208 | ||
| @@ -3717,24 +4210,720 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
| 3717 | nfs_fattr_init(&fs_locations->fattr); | 4210 | nfs_fattr_init(&fs_locations->fattr); |
| 3718 | fs_locations->server = server; | 4211 | fs_locations->server = server; |
| 3719 | fs_locations->nlocations = 0; | 4212 | fs_locations->nlocations = 0; |
| 3720 | status = rpc_call_sync(server->client, &msg, 0); | 4213 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
| 3721 | nfs_fixup_referral_attributes(&fs_locations->fattr); | 4214 | nfs_fixup_referral_attributes(&fs_locations->fattr); |
| 3722 | dprintk("%s: returned status = %d\n", __func__, status); | 4215 | dprintk("%s: returned status = %d\n", __func__, status); |
| 3723 | return status; | 4216 | return status; |
| 3724 | } | 4217 | } |
| 3725 | 4218 | ||
| 3726 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 4219 | #ifdef CONFIG_NFS_V4_1 |
| 4220 | /* | ||
| 4221 | * nfs4_proc_exchange_id() | ||
| 4222 | * | ||
| 4223 | * Since the clientid has expired, all compounds using sessions | ||
| 4224 | * associated with the stale clientid will be returning | ||
| 4225 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | ||
| 4226 | * be in some phase of session reset. | ||
| 4227 | */ | ||
| 4228 | static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | ||
| 4229 | { | ||
| 4230 | nfs4_verifier verifier; | ||
| 4231 | struct nfs41_exchange_id_args args = { | ||
| 4232 | .client = clp, | ||
| 4233 | .flags = clp->cl_exchange_flags, | ||
| 4234 | }; | ||
| 4235 | struct nfs41_exchange_id_res res = { | ||
| 4236 | .client = clp, | ||
| 4237 | }; | ||
| 4238 | int status; | ||
| 4239 | struct rpc_message msg = { | ||
| 4240 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID], | ||
| 4241 | .rpc_argp = &args, | ||
| 4242 | .rpc_resp = &res, | ||
| 4243 | .rpc_cred = cred, | ||
| 4244 | }; | ||
| 4245 | __be32 *p; | ||
| 4246 | |||
| 4247 | dprintk("--> %s\n", __func__); | ||
| 4248 | BUG_ON(clp == NULL); | ||
| 4249 | |||
| 4250 | p = (u32 *)verifier.data; | ||
| 4251 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
| 4252 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
| 4253 | args.verifier = &verifier; | ||
| 4254 | |||
| 4255 | while (1) { | ||
| 4256 | args.id_len = scnprintf(args.id, sizeof(args.id), | ||
| 4257 | "%s/%s %u", | ||
| 4258 | clp->cl_ipaddr, | ||
| 4259 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
| 4260 | RPC_DISPLAY_ADDR), | ||
| 4261 | clp->cl_id_uniquifier); | ||
| 4262 | |||
| 4263 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | ||
| 4264 | |||
| 4265 | if (status != NFS4ERR_CLID_INUSE) | ||
| 4266 | break; | ||
| 4267 | |||
| 4268 | if (signalled()) | ||
| 4269 | break; | ||
| 4270 | |||
| 4271 | if (++clp->cl_id_uniquifier == 0) | ||
| 4272 | break; | ||
| 4273 | } | ||
| 4274 | |||
| 4275 | dprintk("<-- %s status= %d\n", __func__, status); | ||
| 4276 | return status; | ||
| 4277 | } | ||
| 4278 | |||
| 4279 | struct nfs4_get_lease_time_data { | ||
| 4280 | struct nfs4_get_lease_time_args *args; | ||
| 4281 | struct nfs4_get_lease_time_res *res; | ||
| 4282 | struct nfs_client *clp; | ||
| 4283 | }; | ||
| 4284 | |||
| 4285 | static void nfs4_get_lease_time_prepare(struct rpc_task *task, | ||
| 4286 | void *calldata) | ||
| 4287 | { | ||
| 4288 | int ret; | ||
| 4289 | struct nfs4_get_lease_time_data *data = | ||
| 4290 | (struct nfs4_get_lease_time_data *)calldata; | ||
| 4291 | |||
| 4292 | dprintk("--> %s\n", __func__); | ||
| 4293 | /* just setup sequence, do not trigger session recovery | ||
| 4294 | since we're invoked within one */ | ||
| 4295 | ret = nfs41_setup_sequence(data->clp->cl_session, | ||
| 4296 | &data->args->la_seq_args, | ||
| 4297 | &data->res->lr_seq_res, 0, task); | ||
| 4298 | |||
| 4299 | BUG_ON(ret == -EAGAIN); | ||
| 4300 | rpc_call_start(task); | ||
| 4301 | dprintk("<-- %s\n", __func__); | ||
| 4302 | } | ||
| 4303 | |||
| 4304 | /* | ||
| 4305 | * Called from nfs4_state_manager thread for session setup, so don't recover | ||
| 4306 | * from sequence operation or clientid errors. | ||
| 4307 | */ | ||
| 4308 | static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | ||
| 4309 | { | ||
| 4310 | struct nfs4_get_lease_time_data *data = | ||
| 4311 | (struct nfs4_get_lease_time_data *)calldata; | ||
| 4312 | |||
| 4313 | dprintk("--> %s\n", __func__); | ||
| 4314 | nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status); | ||
| 4315 | switch (task->tk_status) { | ||
| 4316 | case -NFS4ERR_DELAY: | ||
| 4317 | case -NFS4ERR_GRACE: | ||
| 4318 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | ||
| 4319 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | ||
| 4320 | task->tk_status = 0; | ||
| 4321 | nfs4_restart_rpc(task, data->clp); | ||
| 4322 | return; | ||
| 4323 | } | ||
| 4324 | nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res); | ||
| 4325 | dprintk("<-- %s\n", __func__); | ||
| 4326 | } | ||
| 4327 | |||
| 4328 | struct rpc_call_ops nfs4_get_lease_time_ops = { | ||
| 4329 | .rpc_call_prepare = nfs4_get_lease_time_prepare, | ||
| 4330 | .rpc_call_done = nfs4_get_lease_time_done, | ||
| 4331 | }; | ||
| 4332 | |||
| 4333 | int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | ||
| 4334 | { | ||
| 4335 | struct rpc_task *task; | ||
| 4336 | struct nfs4_get_lease_time_args args; | ||
| 4337 | struct nfs4_get_lease_time_res res = { | ||
| 4338 | .lr_fsinfo = fsinfo, | ||
| 4339 | }; | ||
| 4340 | struct nfs4_get_lease_time_data data = { | ||
| 4341 | .args = &args, | ||
| 4342 | .res = &res, | ||
| 4343 | .clp = clp, | ||
| 4344 | }; | ||
| 4345 | struct rpc_message msg = { | ||
| 4346 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GET_LEASE_TIME], | ||
| 4347 | .rpc_argp = &args, | ||
| 4348 | .rpc_resp = &res, | ||
| 4349 | }; | ||
| 4350 | struct rpc_task_setup task_setup = { | ||
| 4351 | .rpc_client = clp->cl_rpcclient, | ||
| 4352 | .rpc_message = &msg, | ||
| 4353 | .callback_ops = &nfs4_get_lease_time_ops, | ||
| 4354 | .callback_data = &data | ||
| 4355 | }; | ||
| 4356 | int status; | ||
| 4357 | |||
| 4358 | res.lr_seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 4359 | dprintk("--> %s\n", __func__); | ||
| 4360 | task = rpc_run_task(&task_setup); | ||
| 4361 | |||
| 4362 | if (IS_ERR(task)) | ||
| 4363 | status = PTR_ERR(task); | ||
| 4364 | else { | ||
| 4365 | status = task->tk_status; | ||
| 4366 | rpc_put_task(task); | ||
| 4367 | } | ||
| 4368 | dprintk("<-- %s return %d\n", __func__, status); | ||
| 4369 | |||
| 4370 | return status; | ||
| 4371 | } | ||
| 4372 | |||
| 4373 | /* | ||
| 4374 | * Reset a slot table | ||
| 4375 | */ | ||
| 4376 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | ||
| 4377 | int old_max_slots, int ivalue) | ||
| 4378 | { | ||
| 4379 | int i; | ||
| 4380 | int ret = 0; | ||
| 4381 | |||
| 4382 | dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl); | ||
| 4383 | |||
| 4384 | /* | ||
| 4385 | * Until we have dynamic slot table adjustment, insist | ||
| 4386 | * upon the same slot table size | ||
| 4387 | */ | ||
| 4388 | if (max_slots != old_max_slots) { | ||
| 4389 | dprintk("%s reset slot table does't match old\n", | ||
| 4390 | __func__); | ||
| 4391 | ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */ | ||
| 4392 | goto out; | ||
| 4393 | } | ||
| 4394 | spin_lock(&tbl->slot_tbl_lock); | ||
| 4395 | for (i = 0; i < max_slots; ++i) | ||
| 4396 | tbl->slots[i].seq_nr = ivalue; | ||
| 4397 | tbl->highest_used_slotid = -1; | ||
| 4398 | spin_unlock(&tbl->slot_tbl_lock); | ||
| 4399 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
| 4400 | tbl, tbl->slots, tbl->max_slots); | ||
| 4401 | out: | ||
| 4402 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
| 4403 | return ret; | ||
| 4404 | } | ||
| 4405 | |||
| 4406 | /* | ||
| 4407 | * Reset the forechannel and backchannel slot tables | ||
| 4408 | */ | ||
| 4409 | static int nfs4_reset_slot_tables(struct nfs4_session *session) | ||
| 4410 | { | ||
| 4411 | int status; | ||
| 4412 | |||
| 4413 | status = nfs4_reset_slot_table(&session->fc_slot_table, | ||
| 4414 | session->fc_attrs.max_reqs, | ||
| 4415 | session->fc_slot_table.max_slots, | ||
| 4416 | 1); | ||
| 4417 | if (status) | ||
| 4418 | return status; | ||
| 4419 | |||
| 4420 | status = nfs4_reset_slot_table(&session->bc_slot_table, | ||
| 4421 | session->bc_attrs.max_reqs, | ||
| 4422 | session->bc_slot_table.max_slots, | ||
| 4423 | 0); | ||
| 4424 | return status; | ||
| 4425 | } | ||
| 4426 | |||
| 4427 | /* Destroy the slot table */ | ||
| 4428 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | ||
| 4429 | { | ||
| 4430 | if (session->fc_slot_table.slots != NULL) { | ||
| 4431 | kfree(session->fc_slot_table.slots); | ||
| 4432 | session->fc_slot_table.slots = NULL; | ||
| 4433 | } | ||
| 4434 | if (session->bc_slot_table.slots != NULL) { | ||
| 4435 | kfree(session->bc_slot_table.slots); | ||
| 4436 | session->bc_slot_table.slots = NULL; | ||
| 4437 | } | ||
| 4438 | return; | ||
| 4439 | } | ||
| 4440 | |||
| 4441 | /* | ||
| 4442 | * Initialize slot table | ||
| 4443 | */ | ||
| 4444 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | ||
| 4445 | int max_slots, int ivalue) | ||
| 4446 | { | ||
| 4447 | int i; | ||
| 4448 | struct nfs4_slot *slot; | ||
| 4449 | int ret = -ENOMEM; | ||
| 4450 | |||
| 4451 | BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE); | ||
| 4452 | |||
| 4453 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | ||
| 4454 | |||
| 4455 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | ||
| 4456 | if (!slot) | ||
| 4457 | goto out; | ||
| 4458 | for (i = 0; i < max_slots; ++i) | ||
| 4459 | slot[i].seq_nr = ivalue; | ||
| 4460 | ret = 0; | ||
| 4461 | |||
| 4462 | spin_lock(&tbl->slot_tbl_lock); | ||
| 4463 | if (tbl->slots != NULL) { | ||
| 4464 | spin_unlock(&tbl->slot_tbl_lock); | ||
| 4465 | dprintk("%s: slot table already initialized. tbl=%p slots=%p\n", | ||
| 4466 | __func__, tbl, tbl->slots); | ||
| 4467 | WARN_ON(1); | ||
| 4468 | goto out_free; | ||
| 4469 | } | ||
| 4470 | tbl->max_slots = max_slots; | ||
| 4471 | tbl->slots = slot; | ||
| 4472 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | ||
| 4473 | spin_unlock(&tbl->slot_tbl_lock); | ||
| 4474 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
| 4475 | tbl, tbl->slots, tbl->max_slots); | ||
| 4476 | out: | ||
| 4477 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
| 4478 | return ret; | ||
| 4479 | |||
| 4480 | out_free: | ||
| 4481 | kfree(slot); | ||
| 4482 | goto out; | ||
| 4483 | } | ||
| 4484 | |||
| 4485 | /* | ||
| 4486 | * Initialize the forechannel and backchannel tables | ||
| 4487 | */ | ||
| 4488 | static int nfs4_init_slot_tables(struct nfs4_session *session) | ||
| 4489 | { | ||
| 4490 | int status; | ||
| 4491 | |||
| 4492 | status = nfs4_init_slot_table(&session->fc_slot_table, | ||
| 4493 | session->fc_attrs.max_reqs, 1); | ||
| 4494 | if (status) | ||
| 4495 | return status; | ||
| 4496 | |||
| 4497 | status = nfs4_init_slot_table(&session->bc_slot_table, | ||
| 4498 | session->bc_attrs.max_reqs, 0); | ||
| 4499 | if (status) | ||
| 4500 | nfs4_destroy_slot_tables(session); | ||
| 4501 | |||
| 4502 | return status; | ||
| 4503 | } | ||
| 4504 | |||
| 4505 | struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | ||
| 4506 | { | ||
| 4507 | struct nfs4_session *session; | ||
| 4508 | struct nfs4_slot_table *tbl; | ||
| 4509 | |||
| 4510 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); | ||
| 4511 | if (!session) | ||
| 4512 | return NULL; | ||
| 4513 | |||
| 4514 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
| 4515 | /* | ||
| 4516 | * The create session reply races with the server back | ||
| 4517 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
| 4518 | * so that the client back channel can find the | ||
| 4519 | * nfs_client struct | ||
| 4520 | */ | ||
| 4521 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
| 4522 | |||
| 4523 | tbl = &session->fc_slot_table; | ||
| 4524 | spin_lock_init(&tbl->slot_tbl_lock); | ||
| 4525 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | ||
| 4526 | |||
| 4527 | tbl = &session->bc_slot_table; | ||
| 4528 | spin_lock_init(&tbl->slot_tbl_lock); | ||
| 4529 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | ||
| 4530 | |||
| 4531 | session->clp = clp; | ||
| 4532 | return session; | ||
| 4533 | } | ||
| 4534 | |||
| 4535 | void nfs4_destroy_session(struct nfs4_session *session) | ||
| 4536 | { | ||
| 4537 | nfs4_proc_destroy_session(session); | ||
| 4538 | dprintk("%s Destroy backchannel for xprt %p\n", | ||
| 4539 | __func__, session->clp->cl_rpcclient->cl_xprt); | ||
| 4540 | xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, | ||
| 4541 | NFS41_BC_MIN_CALLBACKS); | ||
| 4542 | nfs4_destroy_slot_tables(session); | ||
| 4543 | kfree(session); | ||
| 4544 | } | ||
| 4545 | |||
| 4546 | /* | ||
| 4547 | * Initialize the values to be used by the client in CREATE_SESSION | ||
| 4548 | * If nfs4_init_session set the fore channel request and response sizes, | ||
| 4549 | * use them. | ||
| 4550 | * | ||
| 4551 | * Set the back channel max_resp_sz_cached to zero to force the client to | ||
| 4552 | * always set csa_cachethis to FALSE because the current implementation | ||
| 4553 | * of the back channel DRC only supports caching the CB_SEQUENCE operation. | ||
| 4554 | */ | ||
| 4555 | static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | ||
| 4556 | { | ||
| 4557 | struct nfs4_session *session = args->client->cl_session; | ||
| 4558 | unsigned int mxrqst_sz = session->fc_attrs.max_rqst_sz, | ||
| 4559 | mxresp_sz = session->fc_attrs.max_resp_sz; | ||
| 4560 | |||
| 4561 | if (mxrqst_sz == 0) | ||
| 4562 | mxrqst_sz = NFS_MAX_FILE_IO_SIZE; | ||
| 4563 | if (mxresp_sz == 0) | ||
| 4564 | mxresp_sz = NFS_MAX_FILE_IO_SIZE; | ||
| 4565 | /* Fore channel attributes */ | ||
| 4566 | args->fc_attrs.headerpadsz = 0; | ||
| 4567 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | ||
| 4568 | args->fc_attrs.max_resp_sz = mxresp_sz; | ||
| 4569 | args->fc_attrs.max_resp_sz_cached = mxresp_sz; | ||
| 4570 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | ||
| 4571 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | ||
| 4572 | |||
| 4573 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
| 4574 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
| 4575 | __func__, | ||
| 4576 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, | ||
| 4577 | args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops, | ||
| 4578 | args->fc_attrs.max_reqs); | ||
| 4579 | |||
| 4580 | /* Back channel attributes */ | ||
| 4581 | args->bc_attrs.headerpadsz = 0; | ||
| 4582 | args->bc_attrs.max_rqst_sz = PAGE_SIZE; | ||
| 4583 | args->bc_attrs.max_resp_sz = PAGE_SIZE; | ||
| 4584 | args->bc_attrs.max_resp_sz_cached = 0; | ||
| 4585 | args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS; | ||
| 4586 | args->bc_attrs.max_reqs = 1; | ||
| 4587 | |||
| 4588 | dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
| 4589 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
| 4590 | __func__, | ||
| 4591 | args->bc_attrs.max_rqst_sz, args->bc_attrs.max_resp_sz, | ||
| 4592 | args->bc_attrs.max_resp_sz_cached, args->bc_attrs.max_ops, | ||
| 4593 | args->bc_attrs.max_reqs); | ||
| 4594 | } | ||
| 4595 | |||
| 4596 | static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd) | ||
| 4597 | { | ||
| 4598 | if (rcvd <= sent) | ||
| 4599 | return 0; | ||
| 4600 | printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. " | ||
| 4601 | "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd); | ||
| 4602 | return -EINVAL; | ||
| 4603 | } | ||
| 4604 | |||
| 4605 | #define _verify_fore_channel_attr(_name_) \ | ||
| 4606 | _verify_channel_attr("fore", #_name_, \ | ||
| 4607 | args->fc_attrs._name_, \ | ||
| 4608 | session->fc_attrs._name_) | ||
| 4609 | |||
| 4610 | #define _verify_back_channel_attr(_name_) \ | ||
| 4611 | _verify_channel_attr("back", #_name_, \ | ||
| 4612 | args->bc_attrs._name_, \ | ||
| 4613 | session->bc_attrs._name_) | ||
| 4614 | |||
| 4615 | /* | ||
| 4616 | * The server is not allowed to increase the fore channel header pad size, | ||
| 4617 | * maximum response size, or maximum number of operations. | ||
| 4618 | * | ||
| 4619 | * The back channel attributes are only negotiatied down: We send what the | ||
| 4620 | * (back channel) server insists upon. | ||
| 4621 | */ | ||
| 4622 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | ||
| 4623 | struct nfs4_session *session) | ||
| 4624 | { | ||
| 4625 | int ret = 0; | ||
| 4626 | |||
| 4627 | ret |= _verify_fore_channel_attr(headerpadsz); | ||
| 4628 | ret |= _verify_fore_channel_attr(max_resp_sz); | ||
| 4629 | ret |= _verify_fore_channel_attr(max_ops); | ||
| 4630 | |||
| 4631 | ret |= _verify_back_channel_attr(headerpadsz); | ||
| 4632 | ret |= _verify_back_channel_attr(max_rqst_sz); | ||
| 4633 | ret |= _verify_back_channel_attr(max_resp_sz); | ||
| 4634 | ret |= _verify_back_channel_attr(max_resp_sz_cached); | ||
| 4635 | ret |= _verify_back_channel_attr(max_ops); | ||
| 4636 | ret |= _verify_back_channel_attr(max_reqs); | ||
| 4637 | |||
| 4638 | return ret; | ||
| 4639 | } | ||
| 4640 | |||
| 4641 | static int _nfs4_proc_create_session(struct nfs_client *clp) | ||
| 4642 | { | ||
| 4643 | struct nfs4_session *session = clp->cl_session; | ||
| 4644 | struct nfs41_create_session_args args = { | ||
| 4645 | .client = clp, | ||
| 4646 | .cb_program = NFS4_CALLBACK, | ||
| 4647 | }; | ||
| 4648 | struct nfs41_create_session_res res = { | ||
| 4649 | .client = clp, | ||
| 4650 | }; | ||
| 4651 | struct rpc_message msg = { | ||
| 4652 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION], | ||
| 4653 | .rpc_argp = &args, | ||
| 4654 | .rpc_resp = &res, | ||
| 4655 | }; | ||
| 4656 | int status; | ||
| 4657 | |||
| 4658 | nfs4_init_channel_attrs(&args); | ||
| 4659 | args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); | ||
| 4660 | |||
| 4661 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
| 4662 | |||
| 4663 | if (!status) | ||
| 4664 | /* Verify the session's negotiated channel_attrs values */ | ||
| 4665 | status = nfs4_verify_channel_attrs(&args, session); | ||
| 4666 | if (!status) { | ||
| 4667 | /* Increment the clientid slot sequence id */ | ||
| 4668 | clp->cl_seqid++; | ||
| 4669 | } | ||
| 4670 | |||
| 4671 | return status; | ||
| 4672 | } | ||
| 4673 | |||
| 4674 | /* | ||
| 4675 | * Issues a CREATE_SESSION operation to the server. | ||
| 4676 | * It is the responsibility of the caller to verify the session is | ||
| 4677 | * expired before calling this routine. | ||
| 4678 | */ | ||
| 4679 | int nfs4_proc_create_session(struct nfs_client *clp, int reset) | ||
| 4680 | { | ||
| 4681 | int status; | ||
| 4682 | unsigned *ptr; | ||
| 4683 | struct nfs_fsinfo fsinfo; | ||
| 4684 | struct nfs4_session *session = clp->cl_session; | ||
| 4685 | |||
| 4686 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | ||
| 4687 | |||
| 4688 | status = _nfs4_proc_create_session(clp); | ||
| 4689 | if (status) | ||
| 4690 | goto out; | ||
| 4691 | |||
| 4692 | /* Init or reset the fore channel */ | ||
| 4693 | if (reset) | ||
| 4694 | status = nfs4_reset_slot_tables(session); | ||
| 4695 | else | ||
| 4696 | status = nfs4_init_slot_tables(session); | ||
| 4697 | dprintk("fore channel slot table initialization returned %d\n", status); | ||
| 4698 | if (status) | ||
| 4699 | goto out; | ||
| 4700 | |||
| 4701 | ptr = (unsigned *)&session->sess_id.data[0]; | ||
| 4702 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, | ||
| 4703 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); | ||
| 4704 | |||
| 4705 | if (reset) | ||
| 4706 | /* Lease time is aleady set */ | ||
| 4707 | goto out; | ||
| 4708 | |||
| 4709 | /* Get the lease time */ | ||
| 4710 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | ||
| 4711 | if (status == 0) { | ||
| 4712 | /* Update lease time and schedule renewal */ | ||
| 4713 | spin_lock(&clp->cl_lock); | ||
| 4714 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
| 4715 | clp->cl_last_renewal = jiffies; | ||
| 4716 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
| 4717 | spin_unlock(&clp->cl_lock); | ||
| 4718 | |||
| 4719 | nfs4_schedule_state_renewal(clp); | ||
| 4720 | } | ||
| 4721 | out: | ||
| 4722 | dprintk("<-- %s\n", __func__); | ||
| 4723 | return status; | ||
| 4724 | } | ||
| 4725 | |||
| 4726 | /* | ||
| 4727 | * Issue the over-the-wire RPC DESTROY_SESSION. | ||
| 4728 | * The caller must serialize access to this routine. | ||
| 4729 | */ | ||
| 4730 | int nfs4_proc_destroy_session(struct nfs4_session *session) | ||
| 4731 | { | ||
| 4732 | int status = 0; | ||
| 4733 | struct rpc_message msg; | ||
| 4734 | |||
| 4735 | dprintk("--> nfs4_proc_destroy_session\n"); | ||
| 4736 | |||
| 4737 | /* session is still being setup */ | ||
| 4738 | if (session->clp->cl_cons_state != NFS_CS_READY) | ||
| 4739 | return status; | ||
| 4740 | |||
| 4741 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION]; | ||
| 4742 | msg.rpc_argp = session; | ||
| 4743 | msg.rpc_resp = NULL; | ||
| 4744 | msg.rpc_cred = NULL; | ||
| 4745 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
| 4746 | |||
| 4747 | if (status) | ||
| 4748 | printk(KERN_WARNING | ||
| 4749 | "Got error %d from the server on DESTROY_SESSION. " | ||
| 4750 | "Session has been destroyed regardless...\n", status); | ||
| 4751 | |||
| 4752 | dprintk("<-- nfs4_proc_destroy_session\n"); | ||
| 4753 | return status; | ||
| 4754 | } | ||
| 4755 | |||
| 4756 | /* | ||
| 4757 | * Renew the cl_session lease. | ||
| 4758 | */ | ||
| 4759 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
| 4760 | { | ||
| 4761 | struct nfs4_sequence_args args; | ||
| 4762 | struct nfs4_sequence_res res; | ||
| 4763 | |||
| 4764 | struct rpc_message msg = { | ||
| 4765 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
| 4766 | .rpc_argp = &args, | ||
| 4767 | .rpc_resp = &res, | ||
| 4768 | .rpc_cred = cred, | ||
| 4769 | }; | ||
| 4770 | |||
| 4771 | args.sa_cache_this = 0; | ||
| 4772 | |||
| 4773 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | ||
| 4774 | &res, 0); | ||
| 4775 | } | ||
| 4776 | |||
| 4777 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | ||
| 4778 | { | ||
| 4779 | struct nfs_client *clp = (struct nfs_client *)data; | ||
| 4780 | |||
| 4781 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | ||
| 4782 | |||
| 4783 | if (task->tk_status < 0) { | ||
| 4784 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | ||
| 4785 | |||
| 4786 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | ||
| 4787 | == -EAGAIN) { | ||
| 4788 | nfs4_restart_rpc(task, clp); | ||
| 4789 | return; | ||
| 4790 | } | ||
| 4791 | } | ||
| 4792 | nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp); | ||
| 4793 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | ||
| 4794 | |||
| 4795 | put_rpccred(task->tk_msg.rpc_cred); | ||
| 4796 | kfree(task->tk_msg.rpc_argp); | ||
| 4797 | kfree(task->tk_msg.rpc_resp); | ||
| 4798 | |||
| 4799 | dprintk("<-- %s\n", __func__); | ||
| 4800 | } | ||
| 4801 | |||
| 4802 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | ||
| 4803 | { | ||
| 4804 | struct nfs_client *clp; | ||
| 4805 | struct nfs4_sequence_args *args; | ||
| 4806 | struct nfs4_sequence_res *res; | ||
| 4807 | |||
| 4808 | clp = (struct nfs_client *)data; | ||
| 4809 | args = task->tk_msg.rpc_argp; | ||
| 4810 | res = task->tk_msg.rpc_resp; | ||
| 4811 | |||
| 4812 | if (nfs4_setup_sequence(clp, args, res, 0, task)) | ||
| 4813 | return; | ||
| 4814 | rpc_call_start(task); | ||
| 4815 | } | ||
| 4816 | |||
| 4817 | static const struct rpc_call_ops nfs41_sequence_ops = { | ||
| 4818 | .rpc_call_done = nfs41_sequence_call_done, | ||
| 4819 | .rpc_call_prepare = nfs41_sequence_prepare, | ||
| 4820 | }; | ||
| 4821 | |||
| 4822 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | ||
| 4823 | struct rpc_cred *cred) | ||
| 4824 | { | ||
| 4825 | struct nfs4_sequence_args *args; | ||
| 4826 | struct nfs4_sequence_res *res; | ||
| 4827 | struct rpc_message msg = { | ||
| 4828 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
| 4829 | .rpc_cred = cred, | ||
| 4830 | }; | ||
| 4831 | |||
| 4832 | args = kzalloc(sizeof(*args), GFP_KERNEL); | ||
| 4833 | if (!args) | ||
| 4834 | return -ENOMEM; | ||
| 4835 | res = kzalloc(sizeof(*res), GFP_KERNEL); | ||
| 4836 | if (!res) { | ||
| 4837 | kfree(args); | ||
| 4838 | return -ENOMEM; | ||
| 4839 | } | ||
| 4840 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 4841 | msg.rpc_argp = args; | ||
| 4842 | msg.rpc_resp = res; | ||
| 4843 | |||
| 4844 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | ||
| 4845 | &nfs41_sequence_ops, (void *)clp); | ||
| 4846 | } | ||
| 4847 | |||
| 4848 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 4849 | |||
| 4850 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | ||
| 3727 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | 4851 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, |
| 3728 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 4852 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
| 3729 | .recover_open = nfs4_open_reclaim, | 4853 | .recover_open = nfs4_open_reclaim, |
| 3730 | .recover_lock = nfs4_lock_reclaim, | 4854 | .recover_lock = nfs4_lock_reclaim, |
| 4855 | .establish_clid = nfs4_init_clientid, | ||
| 4856 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
| 3731 | }; | 4857 | }; |
| 3732 | 4858 | ||
| 3733 | struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = { | 4859 | #if defined(CONFIG_NFS_V4_1) |
| 4860 | struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | ||
| 4861 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | ||
| 4862 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | ||
| 4863 | .recover_open = nfs4_open_reclaim, | ||
| 4864 | .recover_lock = nfs4_lock_reclaim, | ||
| 4865 | .establish_clid = nfs4_proc_exchange_id, | ||
| 4866 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
| 4867 | }; | ||
| 4868 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 4869 | |||
| 4870 | struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | ||
| 3734 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 4871 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
| 3735 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 4872 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
| 3736 | .recover_open = nfs4_open_expired, | 4873 | .recover_open = nfs4_open_expired, |
| 3737 | .recover_lock = nfs4_lock_expired, | 4874 | .recover_lock = nfs4_lock_expired, |
| 4875 | .establish_clid = nfs4_init_clientid, | ||
| 4876 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
| 4877 | }; | ||
| 4878 | |||
| 4879 | #if defined(CONFIG_NFS_V4_1) | ||
| 4880 | struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | ||
| 4881 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | ||
| 4882 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | ||
| 4883 | .recover_open = nfs4_open_expired, | ||
| 4884 | .recover_lock = nfs4_lock_expired, | ||
| 4885 | .establish_clid = nfs4_proc_exchange_id, | ||
| 4886 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
| 4887 | }; | ||
| 4888 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 4889 | |||
| 4890 | struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = { | ||
| 4891 | .sched_state_renewal = nfs4_proc_async_renew, | ||
| 4892 | .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked, | ||
| 4893 | .renew_lease = nfs4_proc_renew, | ||
| 4894 | }; | ||
| 4895 | |||
| 4896 | #if defined(CONFIG_NFS_V4_1) | ||
| 4897 | struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | ||
| 4898 | .sched_state_renewal = nfs41_proc_async_sequence, | ||
| 4899 | .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked, | ||
| 4900 | .renew_lease = nfs4_proc_sequence, | ||
| 4901 | }; | ||
| 4902 | #endif | ||
| 4903 | |||
| 4904 | /* | ||
| 4905 | * Per minor version reboot and network partition recovery ops | ||
| 4906 | */ | ||
| 4907 | |||
| 4908 | struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = { | ||
| 4909 | &nfs40_reboot_recovery_ops, | ||
| 4910 | #if defined(CONFIG_NFS_V4_1) | ||
| 4911 | &nfs41_reboot_recovery_ops, | ||
| 4912 | #endif | ||
| 4913 | }; | ||
| 4914 | |||
| 4915 | struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = { | ||
| 4916 | &nfs40_nograce_recovery_ops, | ||
| 4917 | #if defined(CONFIG_NFS_V4_1) | ||
| 4918 | &nfs41_nograce_recovery_ops, | ||
| 4919 | #endif | ||
| 4920 | }; | ||
| 4921 | |||
| 4922 | struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = { | ||
| 4923 | &nfs40_state_renewal_ops, | ||
| 4924 | #if defined(CONFIG_NFS_V4_1) | ||
| 4925 | &nfs41_state_renewal_ops, | ||
| 4926 | #endif | ||
| 3738 | }; | 4927 | }; |
| 3739 | 4928 | ||
| 3740 | static const struct inode_operations nfs4_file_inode_operations = { | 4929 | static const struct inode_operations nfs4_file_inode_operations = { |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index f524e932ff7b..e27c6cef18f2 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
| @@ -59,12 +59,14 @@ | |||
| 59 | void | 59 | void |
| 60 | nfs4_renew_state(struct work_struct *work) | 60 | nfs4_renew_state(struct work_struct *work) |
| 61 | { | 61 | { |
| 62 | struct nfs4_state_maintenance_ops *ops; | ||
| 62 | struct nfs_client *clp = | 63 | struct nfs_client *clp = |
| 63 | container_of(work, struct nfs_client, cl_renewd.work); | 64 | container_of(work, struct nfs_client, cl_renewd.work); |
| 64 | struct rpc_cred *cred; | 65 | struct rpc_cred *cred; |
| 65 | long lease, timeout; | 66 | long lease, timeout; |
| 66 | unsigned long last, now; | 67 | unsigned long last, now; |
| 67 | 68 | ||
| 69 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; | ||
| 68 | dprintk("%s: start\n", __func__); | 70 | dprintk("%s: start\n", __func__); |
| 69 | /* Are there any active superblocks? */ | 71 | /* Are there any active superblocks? */ |
| 70 | if (list_empty(&clp->cl_superblocks)) | 72 | if (list_empty(&clp->cl_superblocks)) |
| @@ -76,7 +78,7 @@ nfs4_renew_state(struct work_struct *work) | |||
| 76 | timeout = (2 * lease) / 3 + (long)last - (long)now; | 78 | timeout = (2 * lease) / 3 + (long)last - (long)now; |
| 77 | /* Are we close to a lease timeout? */ | 79 | /* Are we close to a lease timeout? */ |
| 78 | if (time_after(now, last + lease/3)) { | 80 | if (time_after(now, last + lease/3)) { |
| 79 | cred = nfs4_get_renew_cred_locked(clp); | 81 | cred = ops->get_state_renewal_cred_locked(clp); |
| 80 | spin_unlock(&clp->cl_lock); | 82 | spin_unlock(&clp->cl_lock); |
| 81 | if (cred == NULL) { | 83 | if (cred == NULL) { |
| 82 | if (list_empty(&clp->cl_delegations)) { | 84 | if (list_empty(&clp->cl_delegations)) { |
| @@ -86,7 +88,7 @@ nfs4_renew_state(struct work_struct *work) | |||
| 86 | nfs_expire_all_delegations(clp); | 88 | nfs_expire_all_delegations(clp); |
| 87 | } else { | 89 | } else { |
| 88 | /* Queue an asynchronous RENEW. */ | 90 | /* Queue an asynchronous RENEW. */ |
| 89 | nfs4_proc_async_renew(clp, cred); | 91 | ops->sched_state_renewal(clp, cred); |
| 90 | put_rpccred(cred); | 92 | put_rpccred(cred); |
| 91 | } | 93 | } |
| 92 | timeout = (2 * lease) / 3; | 94 | timeout = (2 * lease) / 3; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0298e909559f..2cfca9929c9a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -60,7 +60,7 @@ const nfs4_stateid zero_stateid; | |||
| 60 | 60 | ||
| 61 | static LIST_HEAD(nfs4_clientid_list); | 61 | static LIST_HEAD(nfs4_clientid_list); |
| 62 | 62 | ||
| 63 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | 63 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
| 64 | { | 64 | { |
| 65 | unsigned short port; | 65 | unsigned short port; |
| 66 | int status; | 66 | int status; |
| @@ -77,7 +77,7 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 77 | return status; | 77 | return status; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) | 80 | struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) |
| 81 | { | 81 | { |
| 82 | struct rpc_cred *cred = NULL; | 82 | struct rpc_cred *cred = NULL; |
| 83 | 83 | ||
| @@ -114,17 +114,21 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | |||
| 114 | return cred; | 114 | return cred; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | static struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | 117 | #if defined(CONFIG_NFS_V4_1) |
| 118 | |||
| 119 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp) | ||
| 118 | { | 120 | { |
| 119 | struct rpc_cred *cred; | 121 | struct rpc_cred *cred; |
| 120 | 122 | ||
| 121 | spin_lock(&clp->cl_lock); | 123 | spin_lock(&clp->cl_lock); |
| 122 | cred = nfs4_get_renew_cred_locked(clp); | 124 | cred = nfs4_get_machine_cred_locked(clp); |
| 123 | spin_unlock(&clp->cl_lock); | 125 | spin_unlock(&clp->cl_lock); |
| 124 | return cred; | 126 | return cred; |
| 125 | } | 127 | } |
| 126 | 128 | ||
| 127 | static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | 129 | #endif /* CONFIG_NFS_V4_1 */ |
| 130 | |||
| 131 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | ||
| 128 | { | 132 | { |
| 129 | struct nfs4_state_owner *sp; | 133 | struct nfs4_state_owner *sp; |
| 130 | struct rb_node *pos; | 134 | struct rb_node *pos; |
| @@ -738,12 +742,14 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) | |||
| 738 | 742 | ||
| 739 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) | 743 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) |
| 740 | { | 744 | { |
| 741 | if (status == -NFS4ERR_BAD_SEQID) { | 745 | struct nfs4_state_owner *sp = container_of(seqid->sequence, |
| 742 | struct nfs4_state_owner *sp = container_of(seqid->sequence, | 746 | struct nfs4_state_owner, so_seqid); |
| 743 | struct nfs4_state_owner, so_seqid); | 747 | struct nfs_server *server = sp->so_server; |
| 748 | |||
| 749 | if (status == -NFS4ERR_BAD_SEQID) | ||
| 744 | nfs4_drop_state_owner(sp); | 750 | nfs4_drop_state_owner(sp); |
| 745 | } | 751 | if (!nfs4_has_session(server->nfs_client)) |
| 746 | nfs_increment_seqid(status, seqid); | 752 | nfs_increment_seqid(status, seqid); |
| 747 | } | 753 | } |
| 748 | 754 | ||
| 749 | /* | 755 | /* |
| @@ -1042,6 +1048,14 @@ static void nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
| 1042 | case -NFS4ERR_EXPIRED: | 1048 | case -NFS4ERR_EXPIRED: |
| 1043 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1049 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
| 1044 | nfs4_state_start_reclaim_nograce(clp); | 1050 | nfs4_state_start_reclaim_nograce(clp); |
| 1051 | case -NFS4ERR_BADSESSION: | ||
| 1052 | case -NFS4ERR_BADSLOT: | ||
| 1053 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
| 1054 | case -NFS4ERR_DEADSESSION: | ||
| 1055 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
| 1056 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
| 1057 | case -NFS4ERR_SEQ_MISORDERED: | ||
| 1058 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
| 1045 | } | 1059 | } |
| 1046 | } | 1060 | } |
| 1047 | 1061 | ||
| @@ -1075,18 +1089,22 @@ restart: | |||
| 1075 | static int nfs4_check_lease(struct nfs_client *clp) | 1089 | static int nfs4_check_lease(struct nfs_client *clp) |
| 1076 | { | 1090 | { |
| 1077 | struct rpc_cred *cred; | 1091 | struct rpc_cred *cred; |
| 1092 | struct nfs4_state_maintenance_ops *ops = | ||
| 1093 | nfs4_state_renewal_ops[clp->cl_minorversion]; | ||
| 1078 | int status = -NFS4ERR_EXPIRED; | 1094 | int status = -NFS4ERR_EXPIRED; |
| 1079 | 1095 | ||
| 1080 | /* Is the client already known to have an expired lease? */ | 1096 | /* Is the client already known to have an expired lease? */ |
| 1081 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1097 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
| 1082 | return 0; | 1098 | return 0; |
| 1083 | cred = nfs4_get_renew_cred(clp); | 1099 | spin_lock(&clp->cl_lock); |
| 1100 | cred = ops->get_state_renewal_cred_locked(clp); | ||
| 1101 | spin_unlock(&clp->cl_lock); | ||
| 1084 | if (cred == NULL) { | 1102 | if (cred == NULL) { |
| 1085 | cred = nfs4_get_setclientid_cred(clp); | 1103 | cred = nfs4_get_setclientid_cred(clp); |
| 1086 | if (cred == NULL) | 1104 | if (cred == NULL) |
| 1087 | goto out; | 1105 | goto out; |
| 1088 | } | 1106 | } |
| 1089 | status = nfs4_proc_renew(clp, cred); | 1107 | status = ops->renew_lease(clp, cred); |
| 1090 | put_rpccred(cred); | 1108 | put_rpccred(cred); |
| 1091 | out: | 1109 | out: |
| 1092 | nfs4_recovery_handle_error(clp, status); | 1110 | nfs4_recovery_handle_error(clp, status); |
| @@ -1096,21 +1114,98 @@ out: | |||
| 1096 | static int nfs4_reclaim_lease(struct nfs_client *clp) | 1114 | static int nfs4_reclaim_lease(struct nfs_client *clp) |
| 1097 | { | 1115 | { |
| 1098 | struct rpc_cred *cred; | 1116 | struct rpc_cred *cred; |
| 1117 | struct nfs4_state_recovery_ops *ops = | ||
| 1118 | nfs4_reboot_recovery_ops[clp->cl_minorversion]; | ||
| 1099 | int status = -ENOENT; | 1119 | int status = -ENOENT; |
| 1100 | 1120 | ||
| 1101 | cred = nfs4_get_setclientid_cred(clp); | 1121 | cred = ops->get_clid_cred(clp); |
| 1102 | if (cred != NULL) { | 1122 | if (cred != NULL) { |
| 1103 | status = nfs4_init_client(clp, cred); | 1123 | status = ops->establish_clid(clp, cred); |
| 1104 | put_rpccred(cred); | 1124 | put_rpccred(cred); |
| 1105 | /* Handle case where the user hasn't set up machine creds */ | 1125 | /* Handle case where the user hasn't set up machine creds */ |
| 1106 | if (status == -EACCES && cred == clp->cl_machine_cred) { | 1126 | if (status == -EACCES && cred == clp->cl_machine_cred) { |
| 1107 | nfs4_clear_machine_cred(clp); | 1127 | nfs4_clear_machine_cred(clp); |
| 1108 | status = -EAGAIN; | 1128 | status = -EAGAIN; |
| 1109 | } | 1129 | } |
| 1130 | if (status == -NFS4ERR_MINOR_VERS_MISMATCH) | ||
| 1131 | status = -EPROTONOSUPPORT; | ||
| 1110 | } | 1132 | } |
| 1111 | return status; | 1133 | return status; |
| 1112 | } | 1134 | } |
| 1113 | 1135 | ||
| 1136 | #ifdef CONFIG_NFS_V4_1 | ||
| 1137 | static void nfs4_session_recovery_handle_error(struct nfs_client *clp, int err) | ||
| 1138 | { | ||
| 1139 | switch (err) { | ||
| 1140 | case -NFS4ERR_STALE_CLIENTID: | ||
| 1141 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
| 1142 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
| 1143 | } | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | static int nfs4_reset_session(struct nfs_client *clp) | ||
| 1147 | { | ||
| 1148 | int status; | ||
| 1149 | |||
| 1150 | status = nfs4_proc_destroy_session(clp->cl_session); | ||
| 1151 | if (status && status != -NFS4ERR_BADSESSION && | ||
| 1152 | status != -NFS4ERR_DEADSESSION) { | ||
| 1153 | nfs4_session_recovery_handle_error(clp, status); | ||
| 1154 | goto out; | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN); | ||
| 1158 | status = nfs4_proc_create_session(clp, 1); | ||
| 1159 | if (status) | ||
| 1160 | nfs4_session_recovery_handle_error(clp, status); | ||
| 1161 | /* fall through*/ | ||
| 1162 | out: | ||
| 1163 | /* Wake up the next rpc task even on error */ | ||
| 1164 | rpc_wake_up_next(&clp->cl_session->fc_slot_table.slot_tbl_waitq); | ||
| 1165 | return status; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | static int nfs4_initialize_session(struct nfs_client *clp) | ||
| 1169 | { | ||
| 1170 | int status; | ||
| 1171 | |||
| 1172 | status = nfs4_proc_create_session(clp, 0); | ||
| 1173 | if (!status) { | ||
| 1174 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
| 1175 | } else if (status == -NFS4ERR_STALE_CLIENTID) { | ||
| 1176 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
| 1177 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
| 1178 | } else { | ||
| 1179 | nfs_mark_client_ready(clp, status); | ||
| 1180 | } | ||
| 1181 | return status; | ||
| 1182 | } | ||
| 1183 | #else /* CONFIG_NFS_V4_1 */ | ||
| 1184 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } | ||
| 1185 | static int nfs4_initialize_session(struct nfs_client *clp) { return 0; } | ||
| 1186 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1187 | |||
| 1188 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors | ||
| 1189 | * on EXCHANGE_ID for v4.1 | ||
| 1190 | */ | ||
| 1191 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) | ||
| 1192 | { | ||
| 1193 | if (nfs4_has_session(clp)) { | ||
| 1194 | switch (status) { | ||
| 1195 | case -NFS4ERR_DELAY: | ||
| 1196 | case -NFS4ERR_CLID_INUSE: | ||
| 1197 | case -EAGAIN: | ||
| 1198 | break; | ||
| 1199 | |||
| 1200 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | ||
| 1201 | * in nfs4_exchange_id */ | ||
| 1202 | default: | ||
| 1203 | return; | ||
| 1204 | } | ||
| 1205 | } | ||
| 1206 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
| 1207 | } | ||
| 1208 | |||
| 1114 | static void nfs4_state_manager(struct nfs_client *clp) | 1209 | static void nfs4_state_manager(struct nfs_client *clp) |
| 1115 | { | 1210 | { |
| 1116 | int status = 0; | 1211 | int status = 0; |
| @@ -1121,9 +1216,12 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
| 1121 | /* We're going to have to re-establish a clientid */ | 1216 | /* We're going to have to re-establish a clientid */ |
| 1122 | status = nfs4_reclaim_lease(clp); | 1217 | status = nfs4_reclaim_lease(clp); |
| 1123 | if (status) { | 1218 | if (status) { |
| 1124 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1219 | nfs4_set_lease_expired(clp, status); |
| 1125 | if (status == -EAGAIN) | 1220 | if (status == -EAGAIN) |
| 1126 | continue; | 1221 | continue; |
| 1222 | if (clp->cl_cons_state == | ||
| 1223 | NFS_CS_SESSION_INITING) | ||
| 1224 | nfs_mark_client_ready(clp, status); | ||
| 1127 | goto out_error; | 1225 | goto out_error; |
| 1128 | } | 1226 | } |
| 1129 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1227 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
| @@ -1134,25 +1232,44 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
| 1134 | if (status != 0) | 1232 | if (status != 0) |
| 1135 | continue; | 1233 | continue; |
| 1136 | } | 1234 | } |
| 1137 | 1235 | /* Initialize or reset the session */ | |
| 1236 | if (nfs4_has_session(clp) && | ||
| 1237 | test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
| 1238 | if (clp->cl_cons_state == NFS_CS_SESSION_INITING) | ||
| 1239 | status = nfs4_initialize_session(clp); | ||
| 1240 | else | ||
| 1241 | status = nfs4_reset_session(clp); | ||
| 1242 | if (status) { | ||
| 1243 | if (status == -NFS4ERR_STALE_CLIENTID) | ||
| 1244 | continue; | ||
| 1245 | goto out_error; | ||
| 1246 | } | ||
| 1247 | } | ||
| 1138 | /* First recover reboot state... */ | 1248 | /* First recover reboot state... */ |
| 1139 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | 1249 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { |
| 1140 | status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops); | 1250 | status = nfs4_do_reclaim(clp, |
| 1251 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | ||
| 1141 | if (status == -NFS4ERR_STALE_CLIENTID) | 1252 | if (status == -NFS4ERR_STALE_CLIENTID) |
| 1142 | continue; | 1253 | continue; |
| 1254 | if (test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
| 1255 | continue; | ||
| 1143 | nfs4_state_end_reclaim_reboot(clp); | 1256 | nfs4_state_end_reclaim_reboot(clp); |
| 1144 | continue; | 1257 | continue; |
| 1145 | } | 1258 | } |
| 1146 | 1259 | ||
| 1147 | /* Now recover expired state... */ | 1260 | /* Now recover expired state... */ |
| 1148 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { | 1261 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { |
| 1149 | status = nfs4_do_reclaim(clp, &nfs4_nograce_recovery_ops); | 1262 | status = nfs4_do_reclaim(clp, |
| 1263 | nfs4_nograce_recovery_ops[clp->cl_minorversion]); | ||
| 1150 | if (status < 0) { | 1264 | if (status < 0) { |
| 1151 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); | 1265 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); |
| 1152 | if (status == -NFS4ERR_STALE_CLIENTID) | 1266 | if (status == -NFS4ERR_STALE_CLIENTID) |
| 1153 | continue; | 1267 | continue; |
| 1154 | if (status == -NFS4ERR_EXPIRED) | 1268 | if (status == -NFS4ERR_EXPIRED) |
| 1155 | continue; | 1269 | continue; |
| 1270 | if (test_bit(NFS4CLNT_SESSION_SETUP, | ||
| 1271 | &clp->cl_state)) | ||
| 1272 | continue; | ||
| 1156 | goto out_error; | 1273 | goto out_error; |
| 1157 | } else | 1274 | } else |
| 1158 | nfs4_state_end_reclaim_nograce(clp); | 1275 | nfs4_state_end_reclaim_nograce(clp); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1690f0e44b91..617273e7d47f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -192,12 +192,16 @@ static int nfs4_stat_to_errno(int); | |||
| 192 | decode_verifier_maxsz) | 192 | decode_verifier_maxsz) |
| 193 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ | 193 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ |
| 194 | nfs4_name_maxsz) | 194 | nfs4_name_maxsz) |
| 195 | #define decode_remove_maxsz (op_decode_hdr_maxsz + \ | ||
| 196 | decode_change_info_maxsz) | ||
| 195 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ | 197 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ |
| 196 | 2 * nfs4_name_maxsz) | 198 | 2 * nfs4_name_maxsz) |
| 197 | #define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5) | 199 | #define decode_rename_maxsz (op_decode_hdr_maxsz + \ |
| 200 | decode_change_info_maxsz + \ | ||
| 201 | decode_change_info_maxsz) | ||
| 198 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ | 202 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ |
| 199 | nfs4_name_maxsz) | 203 | nfs4_name_maxsz) |
| 200 | #define decode_link_maxsz (op_decode_hdr_maxsz + 5) | 204 | #define decode_link_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz) |
| 201 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ | 205 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ |
| 202 | 7 + \ | 206 | 7 + \ |
| 203 | 1 + encode_stateid_maxsz + 8) | 207 | 1 + encode_stateid_maxsz + 8) |
| @@ -240,43 +244,115 @@ static int nfs4_stat_to_errno(int); | |||
| 240 | (encode_getattr_maxsz) | 244 | (encode_getattr_maxsz) |
| 241 | #define decode_fs_locations_maxsz \ | 245 | #define decode_fs_locations_maxsz \ |
| 242 | (0) | 246 | (0) |
| 247 | |||
| 248 | #if defined(CONFIG_NFS_V4_1) | ||
| 249 | #define NFS4_MAX_MACHINE_NAME_LEN (64) | ||
| 250 | |||
| 251 | #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \ | ||
| 252 | encode_verifier_maxsz + \ | ||
| 253 | 1 /* co_ownerid.len */ + \ | ||
| 254 | XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \ | ||
| 255 | 1 /* flags */ + \ | ||
| 256 | 1 /* spa_how */ + \ | ||
| 257 | 0 /* SP4_NONE (for now) */ + \ | ||
| 258 | 1 /* zero implemetation id array */) | ||
| 259 | #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \ | ||
| 260 | 2 /* eir_clientid */ + \ | ||
| 261 | 1 /* eir_sequenceid */ + \ | ||
| 262 | 1 /* eir_flags */ + \ | ||
| 263 | 1 /* spr_how */ + \ | ||
| 264 | 0 /* SP4_NONE (for now) */ + \ | ||
| 265 | 2 /* eir_server_owner.so_minor_id */ + \ | ||
| 266 | /* eir_server_owner.so_major_id<> */ \ | ||
| 267 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
| 268 | /* eir_server_scope<> */ \ | ||
| 269 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
| 270 | 1 /* eir_server_impl_id array length */ + \ | ||
| 271 | 0 /* ignored eir_server_impl_id contents */) | ||
| 272 | #define encode_channel_attrs_maxsz (6 + 1 /* ca_rdma_ird.len (0) */) | ||
| 273 | #define decode_channel_attrs_maxsz (6 + \ | ||
| 274 | 1 /* ca_rdma_ird.len */ + \ | ||
| 275 | 1 /* ca_rdma_ird */) | ||
| 276 | #define encode_create_session_maxsz (op_encode_hdr_maxsz + \ | ||
| 277 | 2 /* csa_clientid */ + \ | ||
| 278 | 1 /* csa_sequence */ + \ | ||
| 279 | 1 /* csa_flags */ + \ | ||
| 280 | encode_channel_attrs_maxsz + \ | ||
| 281 | encode_channel_attrs_maxsz + \ | ||
| 282 | 1 /* csa_cb_program */ + \ | ||
| 283 | 1 /* csa_sec_parms.len (1) */ + \ | ||
| 284 | 1 /* cb_secflavor (AUTH_SYS) */ + \ | ||
| 285 | 1 /* stamp */ + \ | ||
| 286 | 1 /* machinename.len */ + \ | ||
| 287 | XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \ | ||
| 288 | 1 /* uid */ + \ | ||
| 289 | 1 /* gid */ + \ | ||
| 290 | 1 /* gids.len (0) */) | ||
| 291 | #define decode_create_session_maxsz (op_decode_hdr_maxsz + \ | ||
| 292 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ | ||
| 293 | 1 /* csr_sequence */ + \ | ||
| 294 | 1 /* csr_flags */ + \ | ||
| 295 | decode_channel_attrs_maxsz + \ | ||
| 296 | decode_channel_attrs_maxsz) | ||
| 297 | #define encode_destroy_session_maxsz (op_encode_hdr_maxsz + 4) | ||
| 298 | #define decode_destroy_session_maxsz (op_decode_hdr_maxsz) | ||
| 299 | #define encode_sequence_maxsz (op_encode_hdr_maxsz + \ | ||
| 300 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4) | ||
| 301 | #define decode_sequence_maxsz (op_decode_hdr_maxsz + \ | ||
| 302 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) | ||
| 303 | #else /* CONFIG_NFS_V4_1 */ | ||
| 304 | #define encode_sequence_maxsz 0 | ||
| 305 | #define decode_sequence_maxsz 0 | ||
| 306 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 307 | |||
| 243 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ | 308 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ |
| 244 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ | 309 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ |
| 245 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ | 310 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ |
| 311 | encode_sequence_maxsz + \ | ||
| 246 | encode_putfh_maxsz + \ | 312 | encode_putfh_maxsz + \ |
| 247 | encode_read_maxsz) | 313 | encode_read_maxsz) |
| 248 | #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ | 314 | #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ |
| 315 | decode_sequence_maxsz + \ | ||
| 249 | decode_putfh_maxsz + \ | 316 | decode_putfh_maxsz + \ |
| 250 | decode_read_maxsz) | 317 | decode_read_maxsz) |
| 251 | #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ | 318 | #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ |
| 319 | encode_sequence_maxsz + \ | ||
| 252 | encode_putfh_maxsz + \ | 320 | encode_putfh_maxsz + \ |
| 253 | encode_readlink_maxsz) | 321 | encode_readlink_maxsz) |
| 254 | #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ | 322 | #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ |
| 323 | decode_sequence_maxsz + \ | ||
| 255 | decode_putfh_maxsz + \ | 324 | decode_putfh_maxsz + \ |
| 256 | decode_readlink_maxsz) | 325 | decode_readlink_maxsz) |
| 257 | #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ | 326 | #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ |
| 327 | encode_sequence_maxsz + \ | ||
| 258 | encode_putfh_maxsz + \ | 328 | encode_putfh_maxsz + \ |
| 259 | encode_readdir_maxsz) | 329 | encode_readdir_maxsz) |
| 260 | #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ | 330 | #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ |
| 331 | decode_sequence_maxsz + \ | ||
| 261 | decode_putfh_maxsz + \ | 332 | decode_putfh_maxsz + \ |
| 262 | decode_readdir_maxsz) | 333 | decode_readdir_maxsz) |
| 263 | #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ | 334 | #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ |
| 335 | encode_sequence_maxsz + \ | ||
| 264 | encode_putfh_maxsz + \ | 336 | encode_putfh_maxsz + \ |
| 265 | encode_write_maxsz + \ | 337 | encode_write_maxsz + \ |
| 266 | encode_getattr_maxsz) | 338 | encode_getattr_maxsz) |
| 267 | #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ | 339 | #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ |
| 340 | decode_sequence_maxsz + \ | ||
| 268 | decode_putfh_maxsz + \ | 341 | decode_putfh_maxsz + \ |
| 269 | decode_write_maxsz + \ | 342 | decode_write_maxsz + \ |
| 270 | decode_getattr_maxsz) | 343 | decode_getattr_maxsz) |
| 271 | #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ | 344 | #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ |
| 345 | encode_sequence_maxsz + \ | ||
| 272 | encode_putfh_maxsz + \ | 346 | encode_putfh_maxsz + \ |
| 273 | encode_commit_maxsz + \ | 347 | encode_commit_maxsz + \ |
| 274 | encode_getattr_maxsz) | 348 | encode_getattr_maxsz) |
| 275 | #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ | 349 | #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ |
| 350 | decode_sequence_maxsz + \ | ||
| 276 | decode_putfh_maxsz + \ | 351 | decode_putfh_maxsz + \ |
| 277 | decode_commit_maxsz + \ | 352 | decode_commit_maxsz + \ |
| 278 | decode_getattr_maxsz) | 353 | decode_getattr_maxsz) |
| 279 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ | 354 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ |
| 355 | encode_sequence_maxsz + \ | ||
| 280 | encode_putfh_maxsz + \ | 356 | encode_putfh_maxsz + \ |
| 281 | encode_savefh_maxsz + \ | 357 | encode_savefh_maxsz + \ |
| 282 | encode_open_maxsz + \ | 358 | encode_open_maxsz + \ |
| @@ -285,6 +361,7 @@ static int nfs4_stat_to_errno(int); | |||
| 285 | encode_restorefh_maxsz + \ | 361 | encode_restorefh_maxsz + \ |
| 286 | encode_getattr_maxsz) | 362 | encode_getattr_maxsz) |
| 287 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ | 363 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ |
| 364 | decode_sequence_maxsz + \ | ||
| 288 | decode_putfh_maxsz + \ | 365 | decode_putfh_maxsz + \ |
| 289 | decode_savefh_maxsz + \ | 366 | decode_savefh_maxsz + \ |
| 290 | decode_open_maxsz + \ | 367 | decode_open_maxsz + \ |
| @@ -301,43 +378,53 @@ static int nfs4_stat_to_errno(int); | |||
| 301 | decode_putfh_maxsz + \ | 378 | decode_putfh_maxsz + \ |
| 302 | decode_open_confirm_maxsz) | 379 | decode_open_confirm_maxsz) |
| 303 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ | 380 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ |
| 381 | encode_sequence_maxsz + \ | ||
| 304 | encode_putfh_maxsz + \ | 382 | encode_putfh_maxsz + \ |
| 305 | encode_open_maxsz + \ | 383 | encode_open_maxsz + \ |
| 306 | encode_getattr_maxsz) | 384 | encode_getattr_maxsz) |
| 307 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ | 385 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ |
| 386 | decode_sequence_maxsz + \ | ||
| 308 | decode_putfh_maxsz + \ | 387 | decode_putfh_maxsz + \ |
| 309 | decode_open_maxsz + \ | 388 | decode_open_maxsz + \ |
| 310 | decode_getattr_maxsz) | 389 | decode_getattr_maxsz) |
| 311 | #define NFS4_enc_open_downgrade_sz \ | 390 | #define NFS4_enc_open_downgrade_sz \ |
| 312 | (compound_encode_hdr_maxsz + \ | 391 | (compound_encode_hdr_maxsz + \ |
| 392 | encode_sequence_maxsz + \ | ||
| 313 | encode_putfh_maxsz + \ | 393 | encode_putfh_maxsz + \ |
| 314 | encode_open_downgrade_maxsz + \ | 394 | encode_open_downgrade_maxsz + \ |
| 315 | encode_getattr_maxsz) | 395 | encode_getattr_maxsz) |
| 316 | #define NFS4_dec_open_downgrade_sz \ | 396 | #define NFS4_dec_open_downgrade_sz \ |
| 317 | (compound_decode_hdr_maxsz + \ | 397 | (compound_decode_hdr_maxsz + \ |
| 398 | decode_sequence_maxsz + \ | ||
| 318 | decode_putfh_maxsz + \ | 399 | decode_putfh_maxsz + \ |
| 319 | decode_open_downgrade_maxsz + \ | 400 | decode_open_downgrade_maxsz + \ |
| 320 | decode_getattr_maxsz) | 401 | decode_getattr_maxsz) |
| 321 | #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ | 402 | #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ |
| 403 | encode_sequence_maxsz + \ | ||
| 322 | encode_putfh_maxsz + \ | 404 | encode_putfh_maxsz + \ |
| 323 | encode_close_maxsz + \ | 405 | encode_close_maxsz + \ |
| 324 | encode_getattr_maxsz) | 406 | encode_getattr_maxsz) |
| 325 | #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ | 407 | #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ |
| 408 | decode_sequence_maxsz + \ | ||
| 326 | decode_putfh_maxsz + \ | 409 | decode_putfh_maxsz + \ |
| 327 | decode_close_maxsz + \ | 410 | decode_close_maxsz + \ |
| 328 | decode_getattr_maxsz) | 411 | decode_getattr_maxsz) |
| 329 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ | 412 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ |
| 413 | encode_sequence_maxsz + \ | ||
| 330 | encode_putfh_maxsz + \ | 414 | encode_putfh_maxsz + \ |
| 331 | encode_setattr_maxsz + \ | 415 | encode_setattr_maxsz + \ |
| 332 | encode_getattr_maxsz) | 416 | encode_getattr_maxsz) |
| 333 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ | 417 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ |
| 418 | decode_sequence_maxsz + \ | ||
| 334 | decode_putfh_maxsz + \ | 419 | decode_putfh_maxsz + \ |
| 335 | decode_setattr_maxsz + \ | 420 | decode_setattr_maxsz + \ |
| 336 | decode_getattr_maxsz) | 421 | decode_getattr_maxsz) |
| 337 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ | 422 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ |
| 423 | encode_sequence_maxsz + \ | ||
| 338 | encode_putfh_maxsz + \ | 424 | encode_putfh_maxsz + \ |
| 339 | encode_fsinfo_maxsz) | 425 | encode_fsinfo_maxsz) |
| 340 | #define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ | 426 | #define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ |
| 427 | decode_sequence_maxsz + \ | ||
| 341 | decode_putfh_maxsz + \ | 428 | decode_putfh_maxsz + \ |
| 342 | decode_fsinfo_maxsz) | 429 | decode_fsinfo_maxsz) |
| 343 | #define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ | 430 | #define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ |
| @@ -359,64 +446,81 @@ static int nfs4_stat_to_errno(int); | |||
| 359 | decode_putrootfh_maxsz + \ | 446 | decode_putrootfh_maxsz + \ |
| 360 | decode_fsinfo_maxsz) | 447 | decode_fsinfo_maxsz) |
| 361 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ | 448 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ |
| 449 | encode_sequence_maxsz + \ | ||
| 362 | encode_putfh_maxsz + \ | 450 | encode_putfh_maxsz + \ |
| 363 | encode_lock_maxsz) | 451 | encode_lock_maxsz) |
| 364 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ | 452 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ |
| 453 | decode_sequence_maxsz + \ | ||
| 365 | decode_putfh_maxsz + \ | 454 | decode_putfh_maxsz + \ |
| 366 | decode_lock_maxsz) | 455 | decode_lock_maxsz) |
| 367 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ | 456 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ |
| 457 | encode_sequence_maxsz + \ | ||
| 368 | encode_putfh_maxsz + \ | 458 | encode_putfh_maxsz + \ |
| 369 | encode_lockt_maxsz) | 459 | encode_lockt_maxsz) |
| 370 | #define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ | 460 | #define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ |
| 461 | decode_sequence_maxsz + \ | ||
| 371 | decode_putfh_maxsz + \ | 462 | decode_putfh_maxsz + \ |
| 372 | decode_lockt_maxsz) | 463 | decode_lockt_maxsz) |
| 373 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ | 464 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ |
| 465 | encode_sequence_maxsz + \ | ||
| 374 | encode_putfh_maxsz + \ | 466 | encode_putfh_maxsz + \ |
| 375 | encode_locku_maxsz) | 467 | encode_locku_maxsz) |
| 376 | #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ | 468 | #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ |
| 469 | decode_sequence_maxsz + \ | ||
| 377 | decode_putfh_maxsz + \ | 470 | decode_putfh_maxsz + \ |
| 378 | decode_locku_maxsz) | 471 | decode_locku_maxsz) |
| 379 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ | 472 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ |
| 473 | encode_sequence_maxsz + \ | ||
| 380 | encode_putfh_maxsz + \ | 474 | encode_putfh_maxsz + \ |
| 381 | encode_access_maxsz + \ | 475 | encode_access_maxsz + \ |
| 382 | encode_getattr_maxsz) | 476 | encode_getattr_maxsz) |
| 383 | #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ | 477 | #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ |
| 478 | decode_sequence_maxsz + \ | ||
| 384 | decode_putfh_maxsz + \ | 479 | decode_putfh_maxsz + \ |
| 385 | decode_access_maxsz + \ | 480 | decode_access_maxsz + \ |
| 386 | decode_getattr_maxsz) | 481 | decode_getattr_maxsz) |
| 387 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ | 482 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ |
| 483 | encode_sequence_maxsz + \ | ||
| 388 | encode_putfh_maxsz + \ | 484 | encode_putfh_maxsz + \ |
| 389 | encode_getattr_maxsz) | 485 | encode_getattr_maxsz) |
| 390 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ | 486 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ |
| 487 | decode_sequence_maxsz + \ | ||
| 391 | decode_putfh_maxsz + \ | 488 | decode_putfh_maxsz + \ |
| 392 | decode_getattr_maxsz) | 489 | decode_getattr_maxsz) |
| 393 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ | 490 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ |
| 491 | encode_sequence_maxsz + \ | ||
| 394 | encode_putfh_maxsz + \ | 492 | encode_putfh_maxsz + \ |
| 395 | encode_lookup_maxsz + \ | 493 | encode_lookup_maxsz + \ |
| 396 | encode_getattr_maxsz + \ | 494 | encode_getattr_maxsz + \ |
| 397 | encode_getfh_maxsz) | 495 | encode_getfh_maxsz) |
| 398 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ | 496 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ |
| 497 | decode_sequence_maxsz + \ | ||
| 399 | decode_putfh_maxsz + \ | 498 | decode_putfh_maxsz + \ |
| 400 | decode_lookup_maxsz + \ | 499 | decode_lookup_maxsz + \ |
| 401 | decode_getattr_maxsz + \ | 500 | decode_getattr_maxsz + \ |
| 402 | decode_getfh_maxsz) | 501 | decode_getfh_maxsz) |
| 403 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ | 502 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ |
| 503 | encode_sequence_maxsz + \ | ||
| 404 | encode_putrootfh_maxsz + \ | 504 | encode_putrootfh_maxsz + \ |
| 405 | encode_getattr_maxsz + \ | 505 | encode_getattr_maxsz + \ |
| 406 | encode_getfh_maxsz) | 506 | encode_getfh_maxsz) |
| 407 | #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ | 507 | #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ |
| 508 | decode_sequence_maxsz + \ | ||
| 408 | decode_putrootfh_maxsz + \ | 509 | decode_putrootfh_maxsz + \ |
| 409 | decode_getattr_maxsz + \ | 510 | decode_getattr_maxsz + \ |
| 410 | decode_getfh_maxsz) | 511 | decode_getfh_maxsz) |
| 411 | #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ | 512 | #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ |
| 513 | encode_sequence_maxsz + \ | ||
| 412 | encode_putfh_maxsz + \ | 514 | encode_putfh_maxsz + \ |
| 413 | encode_remove_maxsz + \ | 515 | encode_remove_maxsz + \ |
| 414 | encode_getattr_maxsz) | 516 | encode_getattr_maxsz) |
| 415 | #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ | 517 | #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ |
| 518 | decode_sequence_maxsz + \ | ||
| 416 | decode_putfh_maxsz + \ | 519 | decode_putfh_maxsz + \ |
| 417 | op_decode_hdr_maxsz + 5 + \ | 520 | decode_remove_maxsz + \ |
| 418 | decode_getattr_maxsz) | 521 | decode_getattr_maxsz) |
| 419 | #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ | 522 | #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ |
| 523 | encode_sequence_maxsz + \ | ||
| 420 | encode_putfh_maxsz + \ | 524 | encode_putfh_maxsz + \ |
| 421 | encode_savefh_maxsz + \ | 525 | encode_savefh_maxsz + \ |
| 422 | encode_putfh_maxsz + \ | 526 | encode_putfh_maxsz + \ |
| @@ -425,6 +529,7 @@ static int nfs4_stat_to_errno(int); | |||
| 425 | encode_restorefh_maxsz + \ | 529 | encode_restorefh_maxsz + \ |
| 426 | encode_getattr_maxsz) | 530 | encode_getattr_maxsz) |
| 427 | #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ | 531 | #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ |
| 532 | decode_sequence_maxsz + \ | ||
| 428 | decode_putfh_maxsz + \ | 533 | decode_putfh_maxsz + \ |
| 429 | decode_savefh_maxsz + \ | 534 | decode_savefh_maxsz + \ |
| 430 | decode_putfh_maxsz + \ | 535 | decode_putfh_maxsz + \ |
| @@ -433,6 +538,7 @@ static int nfs4_stat_to_errno(int); | |||
| 433 | decode_restorefh_maxsz + \ | 538 | decode_restorefh_maxsz + \ |
| 434 | decode_getattr_maxsz) | 539 | decode_getattr_maxsz) |
| 435 | #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ | 540 | #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ |
| 541 | encode_sequence_maxsz + \ | ||
| 436 | encode_putfh_maxsz + \ | 542 | encode_putfh_maxsz + \ |
| 437 | encode_savefh_maxsz + \ | 543 | encode_savefh_maxsz + \ |
| 438 | encode_putfh_maxsz + \ | 544 | encode_putfh_maxsz + \ |
| @@ -441,6 +547,7 @@ static int nfs4_stat_to_errno(int); | |||
| 441 | encode_restorefh_maxsz + \ | 547 | encode_restorefh_maxsz + \ |
| 442 | decode_getattr_maxsz) | 548 | decode_getattr_maxsz) |
| 443 | #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ | 549 | #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ |
| 550 | decode_sequence_maxsz + \ | ||
| 444 | decode_putfh_maxsz + \ | 551 | decode_putfh_maxsz + \ |
| 445 | decode_savefh_maxsz + \ | 552 | decode_savefh_maxsz + \ |
| 446 | decode_putfh_maxsz + \ | 553 | decode_putfh_maxsz + \ |
| @@ -449,16 +556,19 @@ static int nfs4_stat_to_errno(int); | |||
| 449 | decode_restorefh_maxsz + \ | 556 | decode_restorefh_maxsz + \ |
| 450 | decode_getattr_maxsz) | 557 | decode_getattr_maxsz) |
| 451 | #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ | 558 | #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ |
| 559 | encode_sequence_maxsz + \ | ||
| 452 | encode_putfh_maxsz + \ | 560 | encode_putfh_maxsz + \ |
| 453 | encode_symlink_maxsz + \ | 561 | encode_symlink_maxsz + \ |
| 454 | encode_getattr_maxsz + \ | 562 | encode_getattr_maxsz + \ |
| 455 | encode_getfh_maxsz) | 563 | encode_getfh_maxsz) |
| 456 | #define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \ | 564 | #define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \ |
| 565 | decode_sequence_maxsz + \ | ||
| 457 | decode_putfh_maxsz + \ | 566 | decode_putfh_maxsz + \ |
| 458 | decode_symlink_maxsz + \ | 567 | decode_symlink_maxsz + \ |
| 459 | decode_getattr_maxsz + \ | 568 | decode_getattr_maxsz + \ |
| 460 | decode_getfh_maxsz) | 569 | decode_getfh_maxsz) |
| 461 | #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ | 570 | #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ |
| 571 | encode_sequence_maxsz + \ | ||
| 462 | encode_putfh_maxsz + \ | 572 | encode_putfh_maxsz + \ |
| 463 | encode_savefh_maxsz + \ | 573 | encode_savefh_maxsz + \ |
| 464 | encode_create_maxsz + \ | 574 | encode_create_maxsz + \ |
| @@ -467,6 +577,7 @@ static int nfs4_stat_to_errno(int); | |||
| 467 | encode_restorefh_maxsz + \ | 577 | encode_restorefh_maxsz + \ |
| 468 | encode_getattr_maxsz) | 578 | encode_getattr_maxsz) |
| 469 | #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ | 579 | #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ |
| 580 | decode_sequence_maxsz + \ | ||
| 470 | decode_putfh_maxsz + \ | 581 | decode_putfh_maxsz + \ |
| 471 | decode_savefh_maxsz + \ | 582 | decode_savefh_maxsz + \ |
| 472 | decode_create_maxsz + \ | 583 | decode_create_maxsz + \ |
| @@ -475,52 +586,98 @@ static int nfs4_stat_to_errno(int); | |||
| 475 | decode_restorefh_maxsz + \ | 586 | decode_restorefh_maxsz + \ |
| 476 | decode_getattr_maxsz) | 587 | decode_getattr_maxsz) |
| 477 | #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ | 588 | #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ |
| 589 | encode_sequence_maxsz + \ | ||
| 478 | encode_putfh_maxsz + \ | 590 | encode_putfh_maxsz + \ |
| 479 | encode_getattr_maxsz) | 591 | encode_getattr_maxsz) |
| 480 | #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ | 592 | #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ |
| 593 | decode_sequence_maxsz + \ | ||
| 481 | decode_putfh_maxsz + \ | 594 | decode_putfh_maxsz + \ |
| 482 | decode_getattr_maxsz) | 595 | decode_getattr_maxsz) |
| 483 | #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ | 596 | #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ |
| 597 | encode_sequence_maxsz + \ | ||
| 484 | encode_putfh_maxsz + \ | 598 | encode_putfh_maxsz + \ |
| 485 | encode_statfs_maxsz) | 599 | encode_statfs_maxsz) |
| 486 | #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ | 600 | #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ |
| 601 | decode_sequence_maxsz + \ | ||
| 487 | decode_putfh_maxsz + \ | 602 | decode_putfh_maxsz + \ |
| 488 | decode_statfs_maxsz) | 603 | decode_statfs_maxsz) |
| 489 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ | 604 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ |
| 605 | encode_sequence_maxsz + \ | ||
| 490 | encode_putfh_maxsz + \ | 606 | encode_putfh_maxsz + \ |
| 491 | encode_getattr_maxsz) | 607 | encode_getattr_maxsz) |
| 492 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ | 608 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ |
| 609 | decode_sequence_maxsz + \ | ||
| 493 | decode_putfh_maxsz + \ | 610 | decode_putfh_maxsz + \ |
| 494 | decode_getattr_maxsz) | 611 | decode_getattr_maxsz) |
| 495 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ | 612 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ |
| 613 | encode_sequence_maxsz + \ | ||
| 496 | encode_putfh_maxsz + \ | 614 | encode_putfh_maxsz + \ |
| 497 | encode_delegreturn_maxsz + \ | 615 | encode_delegreturn_maxsz + \ |
| 498 | encode_getattr_maxsz) | 616 | encode_getattr_maxsz) |
| 499 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ | 617 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ |
| 618 | decode_sequence_maxsz + \ | ||
| 500 | decode_delegreturn_maxsz + \ | 619 | decode_delegreturn_maxsz + \ |
| 501 | decode_getattr_maxsz) | 620 | decode_getattr_maxsz) |
| 502 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ | 621 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ |
| 622 | encode_sequence_maxsz + \ | ||
| 503 | encode_putfh_maxsz + \ | 623 | encode_putfh_maxsz + \ |
| 504 | encode_getacl_maxsz) | 624 | encode_getacl_maxsz) |
| 505 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ | 625 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ |
| 626 | decode_sequence_maxsz + \ | ||
| 506 | decode_putfh_maxsz + \ | 627 | decode_putfh_maxsz + \ |
| 507 | decode_getacl_maxsz) | 628 | decode_getacl_maxsz) |
| 508 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ | 629 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ |
| 630 | encode_sequence_maxsz + \ | ||
| 509 | encode_putfh_maxsz + \ | 631 | encode_putfh_maxsz + \ |
| 510 | encode_setacl_maxsz) | 632 | encode_setacl_maxsz) |
| 511 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ | 633 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ |
| 634 | decode_sequence_maxsz + \ | ||
| 512 | decode_putfh_maxsz + \ | 635 | decode_putfh_maxsz + \ |
| 513 | decode_setacl_maxsz) | 636 | decode_setacl_maxsz) |
| 514 | #define NFS4_enc_fs_locations_sz \ | 637 | #define NFS4_enc_fs_locations_sz \ |
| 515 | (compound_encode_hdr_maxsz + \ | 638 | (compound_encode_hdr_maxsz + \ |
| 639 | encode_sequence_maxsz + \ | ||
| 516 | encode_putfh_maxsz + \ | 640 | encode_putfh_maxsz + \ |
| 517 | encode_lookup_maxsz + \ | 641 | encode_lookup_maxsz + \ |
| 518 | encode_fs_locations_maxsz) | 642 | encode_fs_locations_maxsz) |
| 519 | #define NFS4_dec_fs_locations_sz \ | 643 | #define NFS4_dec_fs_locations_sz \ |
| 520 | (compound_decode_hdr_maxsz + \ | 644 | (compound_decode_hdr_maxsz + \ |
| 645 | decode_sequence_maxsz + \ | ||
| 521 | decode_putfh_maxsz + \ | 646 | decode_putfh_maxsz + \ |
| 522 | decode_lookup_maxsz + \ | 647 | decode_lookup_maxsz + \ |
| 523 | decode_fs_locations_maxsz) | 648 | decode_fs_locations_maxsz) |
| 649 | #if defined(CONFIG_NFS_V4_1) | ||
| 650 | #define NFS4_enc_exchange_id_sz \ | ||
| 651 | (compound_encode_hdr_maxsz + \ | ||
| 652 | encode_exchange_id_maxsz) | ||
| 653 | #define NFS4_dec_exchange_id_sz \ | ||
| 654 | (compound_decode_hdr_maxsz + \ | ||
| 655 | decode_exchange_id_maxsz) | ||
| 656 | #define NFS4_enc_create_session_sz \ | ||
| 657 | (compound_encode_hdr_maxsz + \ | ||
| 658 | encode_create_session_maxsz) | ||
| 659 | #define NFS4_dec_create_session_sz \ | ||
| 660 | (compound_decode_hdr_maxsz + \ | ||
| 661 | decode_create_session_maxsz) | ||
| 662 | #define NFS4_enc_destroy_session_sz (compound_encode_hdr_maxsz + \ | ||
| 663 | encode_destroy_session_maxsz) | ||
| 664 | #define NFS4_dec_destroy_session_sz (compound_decode_hdr_maxsz + \ | ||
| 665 | decode_destroy_session_maxsz) | ||
| 666 | #define NFS4_enc_sequence_sz \ | ||
| 667 | (compound_decode_hdr_maxsz + \ | ||
| 668 | encode_sequence_maxsz) | ||
| 669 | #define NFS4_dec_sequence_sz \ | ||
| 670 | (compound_decode_hdr_maxsz + \ | ||
| 671 | decode_sequence_maxsz) | ||
| 672 | #define NFS4_enc_get_lease_time_sz (compound_encode_hdr_maxsz + \ | ||
| 673 | encode_sequence_maxsz + \ | ||
| 674 | encode_putrootfh_maxsz + \ | ||
| 675 | encode_fsinfo_maxsz) | ||
| 676 | #define NFS4_dec_get_lease_time_sz (compound_decode_hdr_maxsz + \ | ||
| 677 | decode_sequence_maxsz + \ | ||
| 678 | decode_putrootfh_maxsz + \ | ||
| 679 | decode_fsinfo_maxsz) | ||
| 680 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 524 | 681 | ||
| 525 | static const umode_t nfs_type2fmt[] = { | 682 | static const umode_t nfs_type2fmt[] = { |
| 526 | [NF4BAD] = 0, | 683 | [NF4BAD] = 0, |
| @@ -541,6 +698,8 @@ struct compound_hdr { | |||
| 541 | __be32 * nops_p; | 698 | __be32 * nops_p; |
| 542 | uint32_t taglen; | 699 | uint32_t taglen; |
| 543 | char * tag; | 700 | char * tag; |
| 701 | uint32_t replen; /* expected reply words */ | ||
| 702 | u32 minorversion; | ||
| 544 | }; | 703 | }; |
| 545 | 704 | ||
| 546 | /* | 705 | /* |
| @@ -576,22 +735,31 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char * | |||
| 576 | xdr_encode_opaque(p, str, len); | 735 | xdr_encode_opaque(p, str, len); |
| 577 | } | 736 | } |
| 578 | 737 | ||
| 579 | static void encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) | 738 | static void encode_compound_hdr(struct xdr_stream *xdr, |
| 739 | struct rpc_rqst *req, | ||
| 740 | struct compound_hdr *hdr) | ||
| 580 | { | 741 | { |
| 581 | __be32 *p; | 742 | __be32 *p; |
| 743 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
| 744 | |||
| 745 | /* initialize running count of expected bytes in reply. | ||
| 746 | * NOTE: the replied tag SHOULD be the same is the one sent, | ||
| 747 | * but this is not required as a MUST for the server to do so. */ | ||
| 748 | hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen; | ||
| 582 | 749 | ||
| 583 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); | 750 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); |
| 584 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); | 751 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); |
| 585 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); | 752 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); |
| 586 | WRITE32(hdr->taglen); | 753 | WRITE32(hdr->taglen); |
| 587 | WRITEMEM(hdr->tag, hdr->taglen); | 754 | WRITEMEM(hdr->tag, hdr->taglen); |
| 588 | WRITE32(NFS4_MINOR_VERSION); | 755 | WRITE32(hdr->minorversion); |
| 589 | hdr->nops_p = p; | 756 | hdr->nops_p = p; |
| 590 | WRITE32(hdr->nops); | 757 | WRITE32(hdr->nops); |
| 591 | } | 758 | } |
| 592 | 759 | ||
| 593 | static void encode_nops(struct compound_hdr *hdr) | 760 | static void encode_nops(struct compound_hdr *hdr) |
| 594 | { | 761 | { |
| 762 | BUG_ON(hdr->nops > NFS4_MAX_OPS); | ||
| 595 | *hdr->nops_p = htonl(hdr->nops); | 763 | *hdr->nops_p = htonl(hdr->nops); |
| 596 | } | 764 | } |
| 597 | 765 | ||
| @@ -736,6 +904,7 @@ static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hd | |||
| 736 | WRITE32(OP_ACCESS); | 904 | WRITE32(OP_ACCESS); |
| 737 | WRITE32(access); | 905 | WRITE32(access); |
| 738 | hdr->nops++; | 906 | hdr->nops++; |
| 907 | hdr->replen += decode_access_maxsz; | ||
| 739 | } | 908 | } |
| 740 | 909 | ||
| 741 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 910 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
| @@ -747,6 +916,7 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg | |||
| 747 | WRITE32(arg->seqid->sequence->counter); | 916 | WRITE32(arg->seqid->sequence->counter); |
| 748 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 917 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
| 749 | hdr->nops++; | 918 | hdr->nops++; |
| 919 | hdr->replen += decode_close_maxsz; | ||
| 750 | } | 920 | } |
| 751 | 921 | ||
| 752 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 922 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
| @@ -758,6 +928,7 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar | |||
| 758 | WRITE64(args->offset); | 928 | WRITE64(args->offset); |
| 759 | WRITE32(args->count); | 929 | WRITE32(args->count); |
| 760 | hdr->nops++; | 930 | hdr->nops++; |
| 931 | hdr->replen += decode_commit_maxsz; | ||
| 761 | } | 932 | } |
| 762 | 933 | ||
| 763 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) | 934 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) |
| @@ -789,6 +960,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * | |||
| 789 | WRITE32(create->name->len); | 960 | WRITE32(create->name->len); |
| 790 | WRITEMEM(create->name->name, create->name->len); | 961 | WRITEMEM(create->name->name, create->name->len); |
| 791 | hdr->nops++; | 962 | hdr->nops++; |
| 963 | hdr->replen += decode_create_maxsz; | ||
| 792 | 964 | ||
| 793 | encode_attrs(xdr, create->attrs, create->server); | 965 | encode_attrs(xdr, create->attrs, create->server); |
| 794 | } | 966 | } |
| @@ -802,6 +974,7 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c | |||
| 802 | WRITE32(1); | 974 | WRITE32(1); |
| 803 | WRITE32(bitmap); | 975 | WRITE32(bitmap); |
| 804 | hdr->nops++; | 976 | hdr->nops++; |
| 977 | hdr->replen += decode_getattr_maxsz; | ||
| 805 | } | 978 | } |
| 806 | 979 | ||
| 807 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) | 980 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) |
| @@ -814,6 +987,7 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm | |||
| 814 | WRITE32(bm0); | 987 | WRITE32(bm0); |
| 815 | WRITE32(bm1); | 988 | WRITE32(bm1); |
| 816 | hdr->nops++; | 989 | hdr->nops++; |
| 990 | hdr->replen += decode_getattr_maxsz; | ||
| 817 | } | 991 | } |
| 818 | 992 | ||
| 819 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) | 993 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
| @@ -841,6 +1015,7 @@ static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 841 | RESERVE_SPACE(4); | 1015 | RESERVE_SPACE(4); |
| 842 | WRITE32(OP_GETFH); | 1016 | WRITE32(OP_GETFH); |
| 843 | hdr->nops++; | 1017 | hdr->nops++; |
| 1018 | hdr->replen += decode_getfh_maxsz; | ||
| 844 | } | 1019 | } |
| 845 | 1020 | ||
| 846 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1021 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| @@ -852,6 +1027,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct | |||
| 852 | WRITE32(name->len); | 1027 | WRITE32(name->len); |
| 853 | WRITEMEM(name->name, name->len); | 1028 | WRITEMEM(name->name, name->len); |
| 854 | hdr->nops++; | 1029 | hdr->nops++; |
| 1030 | hdr->replen += decode_link_maxsz; | ||
| 855 | } | 1031 | } |
| 856 | 1032 | ||
| 857 | static inline int nfs4_lock_type(struct file_lock *fl, int block) | 1033 | static inline int nfs4_lock_type(struct file_lock *fl, int block) |
| @@ -899,6 +1075,7 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args | |||
| 899 | WRITE32(args->lock_seqid->sequence->counter); | 1075 | WRITE32(args->lock_seqid->sequence->counter); |
| 900 | } | 1076 | } |
| 901 | hdr->nops++; | 1077 | hdr->nops++; |
| 1078 | hdr->replen += decode_lock_maxsz; | ||
| 902 | } | 1079 | } |
| 903 | 1080 | ||
| 904 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) | 1081 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) |
| @@ -915,6 +1092,7 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar | |||
| 915 | WRITEMEM("lock id:", 8); | 1092 | WRITEMEM("lock id:", 8); |
| 916 | WRITE64(args->lock_owner.id); | 1093 | WRITE64(args->lock_owner.id); |
| 917 | hdr->nops++; | 1094 | hdr->nops++; |
| 1095 | hdr->replen += decode_lockt_maxsz; | ||
| 918 | } | 1096 | } |
| 919 | 1097 | ||
| 920 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) | 1098 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) |
| @@ -929,6 +1107,7 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar | |||
| 929 | WRITE64(args->fl->fl_start); | 1107 | WRITE64(args->fl->fl_start); |
| 930 | WRITE64(nfs4_lock_length(args->fl)); | 1108 | WRITE64(nfs4_lock_length(args->fl)); |
| 931 | hdr->nops++; | 1109 | hdr->nops++; |
| 1110 | hdr->replen += decode_locku_maxsz; | ||
| 932 | } | 1111 | } |
| 933 | 1112 | ||
| 934 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1113 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| @@ -941,6 +1120,7 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc | |||
| 941 | WRITE32(len); | 1120 | WRITE32(len); |
| 942 | WRITEMEM(name->name, len); | 1121 | WRITEMEM(name->name, len); |
| 943 | hdr->nops++; | 1122 | hdr->nops++; |
| 1123 | hdr->replen += decode_lookup_maxsz; | ||
| 944 | } | 1124 | } |
| 945 | 1125 | ||
| 946 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) | 1126 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) |
| @@ -1080,6 +1260,7 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, | |||
| 1080 | BUG(); | 1260 | BUG(); |
| 1081 | } | 1261 | } |
| 1082 | hdr->nops++; | 1262 | hdr->nops++; |
| 1263 | hdr->replen += decode_open_maxsz; | ||
| 1083 | } | 1264 | } |
| 1084 | 1265 | ||
| 1085 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) | 1266 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) |
| @@ -1091,6 +1272,7 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co | |||
| 1091 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 1272 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
| 1092 | WRITE32(arg->seqid->sequence->counter); | 1273 | WRITE32(arg->seqid->sequence->counter); |
| 1093 | hdr->nops++; | 1274 | hdr->nops++; |
| 1275 | hdr->replen += decode_open_confirm_maxsz; | ||
| 1094 | } | 1276 | } |
| 1095 | 1277 | ||
| 1096 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 1278 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
| @@ -1103,6 +1285,7 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close | |||
| 1103 | WRITE32(arg->seqid->sequence->counter); | 1285 | WRITE32(arg->seqid->sequence->counter); |
| 1104 | encode_share_access(xdr, arg->fmode); | 1286 | encode_share_access(xdr, arg->fmode); |
| 1105 | hdr->nops++; | 1287 | hdr->nops++; |
| 1288 | hdr->replen += decode_open_downgrade_maxsz; | ||
| 1106 | } | 1289 | } |
| 1107 | 1290 | ||
| 1108 | static void | 1291 | static void |
| @@ -1116,6 +1299,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd | |||
| 1116 | WRITE32(len); | 1299 | WRITE32(len); |
| 1117 | WRITEMEM(fh->data, len); | 1300 | WRITEMEM(fh->data, len); |
| 1118 | hdr->nops++; | 1301 | hdr->nops++; |
| 1302 | hdr->replen += decode_putfh_maxsz; | ||
| 1119 | } | 1303 | } |
| 1120 | 1304 | ||
| 1121 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | 1305 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
| @@ -1125,6 +1309,7 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 1125 | RESERVE_SPACE(4); | 1309 | RESERVE_SPACE(4); |
| 1126 | WRITE32(OP_PUTROOTFH); | 1310 | WRITE32(OP_PUTROOTFH); |
| 1127 | hdr->nops++; | 1311 | hdr->nops++; |
| 1312 | hdr->replen += decode_putrootfh_maxsz; | ||
| 1128 | } | 1313 | } |
| 1129 | 1314 | ||
| 1130 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 1315 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) |
| @@ -1153,6 +1338,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
| 1153 | WRITE64(args->offset); | 1338 | WRITE64(args->offset); |
| 1154 | WRITE32(args->count); | 1339 | WRITE32(args->count); |
| 1155 | hdr->nops++; | 1340 | hdr->nops++; |
| 1341 | hdr->replen += decode_read_maxsz; | ||
| 1156 | } | 1342 | } |
| 1157 | 1343 | ||
| 1158 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) | 1344 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
| @@ -1178,6 +1364,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
| 1178 | WRITE32(attrs[0] & readdir->bitmask[0]); | 1364 | WRITE32(attrs[0] & readdir->bitmask[0]); |
| 1179 | WRITE32(attrs[1] & readdir->bitmask[1]); | 1365 | WRITE32(attrs[1] & readdir->bitmask[1]); |
| 1180 | hdr->nops++; | 1366 | hdr->nops++; |
| 1367 | hdr->replen += decode_readdir_maxsz; | ||
| 1181 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", | 1368 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
| 1182 | __func__, | 1369 | __func__, |
| 1183 | (unsigned long long)readdir->cookie, | 1370 | (unsigned long long)readdir->cookie, |
| @@ -1194,6 +1381,7 @@ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink * | |||
| 1194 | RESERVE_SPACE(4); | 1381 | RESERVE_SPACE(4); |
| 1195 | WRITE32(OP_READLINK); | 1382 | WRITE32(OP_READLINK); |
| 1196 | hdr->nops++; | 1383 | hdr->nops++; |
| 1384 | hdr->replen += decode_readlink_maxsz; | ||
| 1197 | } | 1385 | } |
| 1198 | 1386 | ||
| 1199 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1387 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| @@ -1205,6 +1393,7 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc | |||
| 1205 | WRITE32(name->len); | 1393 | WRITE32(name->len); |
| 1206 | WRITEMEM(name->name, name->len); | 1394 | WRITEMEM(name->name, name->len); |
| 1207 | hdr->nops++; | 1395 | hdr->nops++; |
| 1396 | hdr->replen += decode_remove_maxsz; | ||
| 1208 | } | 1397 | } |
| 1209 | 1398 | ||
| 1210 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) | 1399 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) |
| @@ -1220,6 +1409,7 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co | |||
| 1220 | WRITE32(newname->len); | 1409 | WRITE32(newname->len); |
| 1221 | WRITEMEM(newname->name, newname->len); | 1410 | WRITEMEM(newname->name, newname->len); |
| 1222 | hdr->nops++; | 1411 | hdr->nops++; |
| 1412 | hdr->replen += decode_rename_maxsz; | ||
| 1223 | } | 1413 | } |
| 1224 | 1414 | ||
| 1225 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) | 1415 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) |
| @@ -1230,6 +1420,7 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client | |||
| 1230 | WRITE32(OP_RENEW); | 1420 | WRITE32(OP_RENEW); |
| 1231 | WRITE64(client_stateid->cl_clientid); | 1421 | WRITE64(client_stateid->cl_clientid); |
| 1232 | hdr->nops++; | 1422 | hdr->nops++; |
| 1423 | hdr->replen += decode_renew_maxsz; | ||
| 1233 | } | 1424 | } |
| 1234 | 1425 | ||
| 1235 | static void | 1426 | static void |
| @@ -1240,6 +1431,7 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 1240 | RESERVE_SPACE(4); | 1431 | RESERVE_SPACE(4); |
| 1241 | WRITE32(OP_RESTOREFH); | 1432 | WRITE32(OP_RESTOREFH); |
| 1242 | hdr->nops++; | 1433 | hdr->nops++; |
| 1434 | hdr->replen += decode_restorefh_maxsz; | ||
| 1243 | } | 1435 | } |
| 1244 | 1436 | ||
| 1245 | static int | 1437 | static int |
| @@ -1259,6 +1451,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun | |||
| 1259 | WRITE32(arg->acl_len); | 1451 | WRITE32(arg->acl_len); |
| 1260 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | 1452 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); |
| 1261 | hdr->nops++; | 1453 | hdr->nops++; |
| 1454 | hdr->replen += decode_setacl_maxsz; | ||
| 1262 | return 0; | 1455 | return 0; |
| 1263 | } | 1456 | } |
| 1264 | 1457 | ||
| @@ -1270,6 +1463,7 @@ encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 1270 | RESERVE_SPACE(4); | 1463 | RESERVE_SPACE(4); |
| 1271 | WRITE32(OP_SAVEFH); | 1464 | WRITE32(OP_SAVEFH); |
| 1272 | hdr->nops++; | 1465 | hdr->nops++; |
| 1466 | hdr->replen += decode_savefh_maxsz; | ||
| 1273 | } | 1467 | } |
| 1274 | 1468 | ||
| 1275 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) | 1469 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) |
| @@ -1280,6 +1474,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs | |||
| 1280 | WRITE32(OP_SETATTR); | 1474 | WRITE32(OP_SETATTR); |
| 1281 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); | 1475 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); |
| 1282 | hdr->nops++; | 1476 | hdr->nops++; |
| 1477 | hdr->replen += decode_setattr_maxsz; | ||
| 1283 | encode_attrs(xdr, arg->iap, server); | 1478 | encode_attrs(xdr, arg->iap, server); |
| 1284 | } | 1479 | } |
| 1285 | 1480 | ||
| @@ -1299,6 +1494,7 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
| 1299 | RESERVE_SPACE(4); | 1494 | RESERVE_SPACE(4); |
| 1300 | WRITE32(setclientid->sc_cb_ident); | 1495 | WRITE32(setclientid->sc_cb_ident); |
| 1301 | hdr->nops++; | 1496 | hdr->nops++; |
| 1497 | hdr->replen += decode_setclientid_maxsz; | ||
| 1302 | } | 1498 | } |
| 1303 | 1499 | ||
| 1304 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) | 1500 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) |
| @@ -1310,6 +1506,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ | |||
| 1310 | WRITE64(client_state->cl_clientid); | 1506 | WRITE64(client_state->cl_clientid); |
| 1311 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | 1507 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); |
| 1312 | hdr->nops++; | 1508 | hdr->nops++; |
| 1509 | hdr->replen += decode_setclientid_confirm_maxsz; | ||
| 1313 | } | 1510 | } |
| 1314 | 1511 | ||
| 1315 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 1512 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
| @@ -1328,6 +1525,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg | |||
| 1328 | 1525 | ||
| 1329 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); | 1526 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); |
| 1330 | hdr->nops++; | 1527 | hdr->nops++; |
| 1528 | hdr->replen += decode_write_maxsz; | ||
| 1331 | } | 1529 | } |
| 1332 | 1530 | ||
| 1333 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) | 1531 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) |
| @@ -1339,11 +1537,163 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state | |||
| 1339 | WRITE32(OP_DELEGRETURN); | 1537 | WRITE32(OP_DELEGRETURN); |
| 1340 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); | 1538 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); |
| 1341 | hdr->nops++; | 1539 | hdr->nops++; |
| 1540 | hdr->replen += decode_delegreturn_maxsz; | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | #if defined(CONFIG_NFS_V4_1) | ||
| 1544 | /* NFSv4.1 operations */ | ||
| 1545 | static void encode_exchange_id(struct xdr_stream *xdr, | ||
| 1546 | struct nfs41_exchange_id_args *args, | ||
| 1547 | struct compound_hdr *hdr) | ||
| 1548 | { | ||
| 1549 | __be32 *p; | ||
| 1550 | |||
| 1551 | RESERVE_SPACE(4 + sizeof(args->verifier->data)); | ||
| 1552 | WRITE32(OP_EXCHANGE_ID); | ||
| 1553 | WRITEMEM(args->verifier->data, sizeof(args->verifier->data)); | ||
| 1554 | |||
| 1555 | encode_string(xdr, args->id_len, args->id); | ||
| 1556 | |||
| 1557 | RESERVE_SPACE(12); | ||
| 1558 | WRITE32(args->flags); | ||
| 1559 | WRITE32(0); /* zero length state_protect4_a */ | ||
| 1560 | WRITE32(0); /* zero length implementation id array */ | ||
| 1561 | hdr->nops++; | ||
| 1562 | hdr->replen += decode_exchange_id_maxsz; | ||
| 1563 | } | ||
| 1564 | |||
| 1565 | static void encode_create_session(struct xdr_stream *xdr, | ||
| 1566 | struct nfs41_create_session_args *args, | ||
| 1567 | struct compound_hdr *hdr) | ||
| 1568 | { | ||
| 1569 | __be32 *p; | ||
| 1570 | char machine_name[NFS4_MAX_MACHINE_NAME_LEN]; | ||
| 1571 | uint32_t len; | ||
| 1572 | struct nfs_client *clp = args->client; | ||
| 1573 | |||
| 1574 | RESERVE_SPACE(4); | ||
| 1575 | WRITE32(OP_CREATE_SESSION); | ||
| 1576 | |||
| 1577 | RESERVE_SPACE(8); | ||
| 1578 | WRITE64(clp->cl_ex_clid); | ||
| 1579 | |||
| 1580 | RESERVE_SPACE(8); | ||
| 1581 | WRITE32(clp->cl_seqid); /*Sequence id */ | ||
| 1582 | WRITE32(args->flags); /*flags */ | ||
| 1583 | |||
| 1584 | RESERVE_SPACE(2*28); /* 2 channel_attrs */ | ||
| 1585 | /* Fore Channel */ | ||
| 1586 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | ||
| 1587 | WRITE32(args->fc_attrs.max_rqst_sz); /* max req size */ | ||
| 1588 | WRITE32(args->fc_attrs.max_resp_sz); /* max resp size */ | ||
| 1589 | WRITE32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | ||
| 1590 | WRITE32(args->fc_attrs.max_ops); /* max operations */ | ||
| 1591 | WRITE32(args->fc_attrs.max_reqs); /* max requests */ | ||
| 1592 | WRITE32(0); /* rdmachannel_attrs */ | ||
| 1593 | |||
| 1594 | /* Back Channel */ | ||
| 1595 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | ||
| 1596 | WRITE32(args->bc_attrs.max_rqst_sz); /* max req size */ | ||
| 1597 | WRITE32(args->bc_attrs.max_resp_sz); /* max resp size */ | ||
| 1598 | WRITE32(args->bc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | ||
| 1599 | WRITE32(args->bc_attrs.max_ops); /* max operations */ | ||
| 1600 | WRITE32(args->bc_attrs.max_reqs); /* max requests */ | ||
| 1601 | WRITE32(0); /* rdmachannel_attrs */ | ||
| 1602 | |||
| 1603 | RESERVE_SPACE(4); | ||
| 1604 | WRITE32(args->cb_program); /* cb_program */ | ||
| 1605 | |||
| 1606 | RESERVE_SPACE(4); /* # of security flavors */ | ||
| 1607 | WRITE32(1); | ||
| 1608 | |||
| 1609 | RESERVE_SPACE(4); | ||
| 1610 | WRITE32(RPC_AUTH_UNIX); /* auth_sys */ | ||
| 1611 | |||
| 1612 | /* authsys_parms rfc1831 */ | ||
| 1613 | RESERVE_SPACE(4); | ||
| 1614 | WRITE32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ | ||
| 1615 | len = scnprintf(machine_name, sizeof(machine_name), "%s", | ||
| 1616 | clp->cl_ipaddr); | ||
| 1617 | RESERVE_SPACE(16 + len); | ||
| 1618 | WRITE32(len); | ||
| 1619 | WRITEMEM(machine_name, len); | ||
| 1620 | WRITE32(0); /* UID */ | ||
| 1621 | WRITE32(0); /* GID */ | ||
| 1622 | WRITE32(0); /* No more gids */ | ||
| 1623 | hdr->nops++; | ||
| 1624 | hdr->replen += decode_create_session_maxsz; | ||
| 1625 | } | ||
| 1626 | |||
| 1627 | static void encode_destroy_session(struct xdr_stream *xdr, | ||
| 1628 | struct nfs4_session *session, | ||
| 1629 | struct compound_hdr *hdr) | ||
| 1630 | { | ||
| 1631 | __be32 *p; | ||
| 1632 | RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN); | ||
| 1633 | WRITE32(OP_DESTROY_SESSION); | ||
| 1634 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
| 1635 | hdr->nops++; | ||
| 1636 | hdr->replen += decode_destroy_session_maxsz; | ||
| 1342 | } | 1637 | } |
| 1638 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1639 | |||
| 1640 | static void encode_sequence(struct xdr_stream *xdr, | ||
| 1641 | const struct nfs4_sequence_args *args, | ||
| 1642 | struct compound_hdr *hdr) | ||
| 1643 | { | ||
| 1644 | #if defined(CONFIG_NFS_V4_1) | ||
| 1645 | struct nfs4_session *session = args->sa_session; | ||
| 1646 | struct nfs4_slot_table *tp; | ||
| 1647 | struct nfs4_slot *slot; | ||
| 1648 | __be32 *p; | ||
| 1649 | |||
| 1650 | if (!session) | ||
| 1651 | return; | ||
| 1652 | |||
| 1653 | tp = &session->fc_slot_table; | ||
| 1654 | |||
| 1655 | WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); | ||
| 1656 | slot = tp->slots + args->sa_slotid; | ||
| 1657 | |||
| 1658 | RESERVE_SPACE(4); | ||
| 1659 | WRITE32(OP_SEQUENCE); | ||
| 1660 | |||
| 1661 | /* | ||
| 1662 | * Sessionid + seqid + slotid + max slotid + cache_this | ||
| 1663 | */ | ||
| 1664 | dprintk("%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d " | ||
| 1665 | "max_slotid=%d cache_this=%d\n", | ||
| 1666 | __func__, | ||
| 1667 | ((u32 *)session->sess_id.data)[0], | ||
| 1668 | ((u32 *)session->sess_id.data)[1], | ||
| 1669 | ((u32 *)session->sess_id.data)[2], | ||
| 1670 | ((u32 *)session->sess_id.data)[3], | ||
| 1671 | slot->seq_nr, args->sa_slotid, | ||
| 1672 | tp->highest_used_slotid, args->sa_cache_this); | ||
| 1673 | RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 16); | ||
| 1674 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
| 1675 | WRITE32(slot->seq_nr); | ||
| 1676 | WRITE32(args->sa_slotid); | ||
| 1677 | WRITE32(tp->highest_used_slotid); | ||
| 1678 | WRITE32(args->sa_cache_this); | ||
| 1679 | hdr->nops++; | ||
| 1680 | hdr->replen += decode_sequence_maxsz; | ||
| 1681 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1682 | } | ||
| 1683 | |||
| 1343 | /* | 1684 | /* |
| 1344 | * END OF "GENERIC" ENCODE ROUTINES. | 1685 | * END OF "GENERIC" ENCODE ROUTINES. |
| 1345 | */ | 1686 | */ |
| 1346 | 1687 | ||
| 1688 | static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args) | ||
| 1689 | { | ||
| 1690 | #if defined(CONFIG_NFS_V4_1) | ||
| 1691 | if (args->sa_session) | ||
| 1692 | return args->sa_session->clp->cl_minorversion; | ||
| 1693 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1694 | return 0; | ||
| 1695 | } | ||
| 1696 | |||
| 1347 | /* | 1697 | /* |
| 1348 | * Encode an ACCESS request | 1698 | * Encode an ACCESS request |
| 1349 | */ | 1699 | */ |
| @@ -1351,11 +1701,12 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1351 | { | 1701 | { |
| 1352 | struct xdr_stream xdr; | 1702 | struct xdr_stream xdr; |
| 1353 | struct compound_hdr hdr = { | 1703 | struct compound_hdr hdr = { |
| 1354 | .nops = 0, | 1704 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1355 | }; | 1705 | }; |
| 1356 | 1706 | ||
| 1357 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1707 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1358 | encode_compound_hdr(&xdr, &hdr); | 1708 | encode_compound_hdr(&xdr, req, &hdr); |
| 1709 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1359 | encode_putfh(&xdr, args->fh, &hdr); | 1710 | encode_putfh(&xdr, args->fh, &hdr); |
| 1360 | encode_access(&xdr, args->access, &hdr); | 1711 | encode_access(&xdr, args->access, &hdr); |
| 1361 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1712 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| @@ -1370,11 +1721,12 @@ static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1370 | { | 1721 | { |
| 1371 | struct xdr_stream xdr; | 1722 | struct xdr_stream xdr; |
| 1372 | struct compound_hdr hdr = { | 1723 | struct compound_hdr hdr = { |
| 1373 | .nops = 0, | 1724 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1374 | }; | 1725 | }; |
| 1375 | 1726 | ||
| 1376 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1727 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1377 | encode_compound_hdr(&xdr, &hdr); | 1728 | encode_compound_hdr(&xdr, req, &hdr); |
| 1729 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1378 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1730 | encode_putfh(&xdr, args->dir_fh, &hdr); |
| 1379 | encode_lookup(&xdr, args->name, &hdr); | 1731 | encode_lookup(&xdr, args->name, &hdr); |
| 1380 | encode_getfh(&xdr, &hdr); | 1732 | encode_getfh(&xdr, &hdr); |
| @@ -1390,11 +1742,12 @@ static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struc | |||
| 1390 | { | 1742 | { |
| 1391 | struct xdr_stream xdr; | 1743 | struct xdr_stream xdr; |
| 1392 | struct compound_hdr hdr = { | 1744 | struct compound_hdr hdr = { |
| 1393 | .nops = 0, | 1745 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1394 | }; | 1746 | }; |
| 1395 | 1747 | ||
| 1396 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1748 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1397 | encode_compound_hdr(&xdr, &hdr); | 1749 | encode_compound_hdr(&xdr, req, &hdr); |
| 1750 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1398 | encode_putrootfh(&xdr, &hdr); | 1751 | encode_putrootfh(&xdr, &hdr); |
| 1399 | encode_getfh(&xdr, &hdr); | 1752 | encode_getfh(&xdr, &hdr); |
| 1400 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1753 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| @@ -1409,11 +1762,12 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1409 | { | 1762 | { |
| 1410 | struct xdr_stream xdr; | 1763 | struct xdr_stream xdr; |
| 1411 | struct compound_hdr hdr = { | 1764 | struct compound_hdr hdr = { |
| 1412 | .nops = 0, | 1765 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1413 | }; | 1766 | }; |
| 1414 | 1767 | ||
| 1415 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1768 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1416 | encode_compound_hdr(&xdr, &hdr); | 1769 | encode_compound_hdr(&xdr, req, &hdr); |
| 1770 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1417 | encode_putfh(&xdr, args->fh, &hdr); | 1771 | encode_putfh(&xdr, args->fh, &hdr); |
| 1418 | encode_remove(&xdr, &args->name, &hdr); | 1772 | encode_remove(&xdr, &args->name, &hdr); |
| 1419 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1773 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| @@ -1428,11 +1782,12 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1428 | { | 1782 | { |
| 1429 | struct xdr_stream xdr; | 1783 | struct xdr_stream xdr; |
| 1430 | struct compound_hdr hdr = { | 1784 | struct compound_hdr hdr = { |
| 1431 | .nops = 0, | 1785 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1432 | }; | 1786 | }; |
| 1433 | 1787 | ||
| 1434 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1788 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1435 | encode_compound_hdr(&xdr, &hdr); | 1789 | encode_compound_hdr(&xdr, req, &hdr); |
| 1790 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1436 | encode_putfh(&xdr, args->old_dir, &hdr); | 1791 | encode_putfh(&xdr, args->old_dir, &hdr); |
| 1437 | encode_savefh(&xdr, &hdr); | 1792 | encode_savefh(&xdr, &hdr); |
| 1438 | encode_putfh(&xdr, args->new_dir, &hdr); | 1793 | encode_putfh(&xdr, args->new_dir, &hdr); |
| @@ -1451,11 +1806,12 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_ | |||
| 1451 | { | 1806 | { |
| 1452 | struct xdr_stream xdr; | 1807 | struct xdr_stream xdr; |
| 1453 | struct compound_hdr hdr = { | 1808 | struct compound_hdr hdr = { |
| 1454 | .nops = 0, | 1809 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1455 | }; | 1810 | }; |
| 1456 | 1811 | ||
| 1457 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1812 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1458 | encode_compound_hdr(&xdr, &hdr); | 1813 | encode_compound_hdr(&xdr, req, &hdr); |
| 1814 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1459 | encode_putfh(&xdr, args->fh, &hdr); | 1815 | encode_putfh(&xdr, args->fh, &hdr); |
| 1460 | encode_savefh(&xdr, &hdr); | 1816 | encode_savefh(&xdr, &hdr); |
| 1461 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1817 | encode_putfh(&xdr, args->dir_fh, &hdr); |
| @@ -1474,11 +1830,12 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1474 | { | 1830 | { |
| 1475 | struct xdr_stream xdr; | 1831 | struct xdr_stream xdr; |
| 1476 | struct compound_hdr hdr = { | 1832 | struct compound_hdr hdr = { |
| 1477 | .nops = 0, | 1833 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1478 | }; | 1834 | }; |
| 1479 | 1835 | ||
| 1480 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1836 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1481 | encode_compound_hdr(&xdr, &hdr); | 1837 | encode_compound_hdr(&xdr, req, &hdr); |
| 1838 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1482 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1839 | encode_putfh(&xdr, args->dir_fh, &hdr); |
| 1483 | encode_savefh(&xdr, &hdr); | 1840 | encode_savefh(&xdr, &hdr); |
| 1484 | encode_create(&xdr, args, &hdr); | 1841 | encode_create(&xdr, args, &hdr); |
| @@ -1505,11 +1862,12 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf | |||
| 1505 | { | 1862 | { |
| 1506 | struct xdr_stream xdr; | 1863 | struct xdr_stream xdr; |
| 1507 | struct compound_hdr hdr = { | 1864 | struct compound_hdr hdr = { |
| 1508 | .nops = 0, | 1865 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1509 | }; | 1866 | }; |
| 1510 | 1867 | ||
| 1511 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1868 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1512 | encode_compound_hdr(&xdr, &hdr); | 1869 | encode_compound_hdr(&xdr, req, &hdr); |
| 1870 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1513 | encode_putfh(&xdr, args->fh, &hdr); | 1871 | encode_putfh(&xdr, args->fh, &hdr); |
| 1514 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1872 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| 1515 | encode_nops(&hdr); | 1873 | encode_nops(&hdr); |
| @@ -1523,11 +1881,12 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closea | |||
| 1523 | { | 1881 | { |
| 1524 | struct xdr_stream xdr; | 1882 | struct xdr_stream xdr; |
| 1525 | struct compound_hdr hdr = { | 1883 | struct compound_hdr hdr = { |
| 1526 | .nops = 0, | 1884 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1527 | }; | 1885 | }; |
| 1528 | 1886 | ||
| 1529 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1887 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1530 | encode_compound_hdr(&xdr, &hdr); | 1888 | encode_compound_hdr(&xdr, req, &hdr); |
| 1889 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1531 | encode_putfh(&xdr, args->fh, &hdr); | 1890 | encode_putfh(&xdr, args->fh, &hdr); |
| 1532 | encode_close(&xdr, args, &hdr); | 1891 | encode_close(&xdr, args, &hdr); |
| 1533 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1892 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| @@ -1542,11 +1901,12 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openarg | |||
| 1542 | { | 1901 | { |
| 1543 | struct xdr_stream xdr; | 1902 | struct xdr_stream xdr; |
| 1544 | struct compound_hdr hdr = { | 1903 | struct compound_hdr hdr = { |
| 1545 | .nops = 0, | 1904 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1546 | }; | 1905 | }; |
| 1547 | 1906 | ||
| 1548 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1907 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1549 | encode_compound_hdr(&xdr, &hdr); | 1908 | encode_compound_hdr(&xdr, req, &hdr); |
| 1909 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1550 | encode_putfh(&xdr, args->fh, &hdr); | 1910 | encode_putfh(&xdr, args->fh, &hdr); |
| 1551 | encode_savefh(&xdr, &hdr); | 1911 | encode_savefh(&xdr, &hdr); |
| 1552 | encode_open(&xdr, args, &hdr); | 1912 | encode_open(&xdr, args, &hdr); |
| @@ -1569,7 +1929,7 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs | |||
| 1569 | }; | 1929 | }; |
| 1570 | 1930 | ||
| 1571 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1931 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1572 | encode_compound_hdr(&xdr, &hdr); | 1932 | encode_compound_hdr(&xdr, req, &hdr); |
| 1573 | encode_putfh(&xdr, args->fh, &hdr); | 1933 | encode_putfh(&xdr, args->fh, &hdr); |
| 1574 | encode_open_confirm(&xdr, args, &hdr); | 1934 | encode_open_confirm(&xdr, args, &hdr); |
| 1575 | encode_nops(&hdr); | 1935 | encode_nops(&hdr); |
| @@ -1583,11 +1943,12 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_ | |||
| 1583 | { | 1943 | { |
| 1584 | struct xdr_stream xdr; | 1944 | struct xdr_stream xdr; |
| 1585 | struct compound_hdr hdr = { | 1945 | struct compound_hdr hdr = { |
| 1586 | .nops = 0, | 1946 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1587 | }; | 1947 | }; |
| 1588 | 1948 | ||
| 1589 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1949 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1590 | encode_compound_hdr(&xdr, &hdr); | 1950 | encode_compound_hdr(&xdr, req, &hdr); |
| 1951 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1591 | encode_putfh(&xdr, args->fh, &hdr); | 1952 | encode_putfh(&xdr, args->fh, &hdr); |
| 1592 | encode_open(&xdr, args, &hdr); | 1953 | encode_open(&xdr, args, &hdr); |
| 1593 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1954 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| @@ -1602,11 +1963,12 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct n | |||
| 1602 | { | 1963 | { |
| 1603 | struct xdr_stream xdr; | 1964 | struct xdr_stream xdr; |
| 1604 | struct compound_hdr hdr = { | 1965 | struct compound_hdr hdr = { |
| 1605 | .nops = 0, | 1966 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1606 | }; | 1967 | }; |
| 1607 | 1968 | ||
| 1608 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1969 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1609 | encode_compound_hdr(&xdr, &hdr); | 1970 | encode_compound_hdr(&xdr, req, &hdr); |
| 1971 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1610 | encode_putfh(&xdr, args->fh, &hdr); | 1972 | encode_putfh(&xdr, args->fh, &hdr); |
| 1611 | encode_open_downgrade(&xdr, args, &hdr); | 1973 | encode_open_downgrade(&xdr, args, &hdr); |
| 1612 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1974 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| @@ -1621,11 +1983,12 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_ar | |||
| 1621 | { | 1983 | { |
| 1622 | struct xdr_stream xdr; | 1984 | struct xdr_stream xdr; |
| 1623 | struct compound_hdr hdr = { | 1985 | struct compound_hdr hdr = { |
| 1624 | .nops = 0, | 1986 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1625 | }; | 1987 | }; |
| 1626 | 1988 | ||
| 1627 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1989 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1628 | encode_compound_hdr(&xdr, &hdr); | 1990 | encode_compound_hdr(&xdr, req, &hdr); |
| 1991 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1629 | encode_putfh(&xdr, args->fh, &hdr); | 1992 | encode_putfh(&xdr, args->fh, &hdr); |
| 1630 | encode_lock(&xdr, args, &hdr); | 1993 | encode_lock(&xdr, args, &hdr); |
| 1631 | encode_nops(&hdr); | 1994 | encode_nops(&hdr); |
| @@ -1639,11 +2002,12 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_ | |||
| 1639 | { | 2002 | { |
| 1640 | struct xdr_stream xdr; | 2003 | struct xdr_stream xdr; |
| 1641 | struct compound_hdr hdr = { | 2004 | struct compound_hdr hdr = { |
| 1642 | .nops = 0, | 2005 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1643 | }; | 2006 | }; |
| 1644 | 2007 | ||
| 1645 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2008 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1646 | encode_compound_hdr(&xdr, &hdr); | 2009 | encode_compound_hdr(&xdr, req, &hdr); |
| 2010 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1647 | encode_putfh(&xdr, args->fh, &hdr); | 2011 | encode_putfh(&xdr, args->fh, &hdr); |
| 1648 | encode_lockt(&xdr, args, &hdr); | 2012 | encode_lockt(&xdr, args, &hdr); |
| 1649 | encode_nops(&hdr); | 2013 | encode_nops(&hdr); |
| @@ -1657,11 +2021,12 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_ | |||
| 1657 | { | 2021 | { |
| 1658 | struct xdr_stream xdr; | 2022 | struct xdr_stream xdr; |
| 1659 | struct compound_hdr hdr = { | 2023 | struct compound_hdr hdr = { |
| 1660 | .nops = 0, | 2024 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1661 | }; | 2025 | }; |
| 1662 | 2026 | ||
| 1663 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2027 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1664 | encode_compound_hdr(&xdr, &hdr); | 2028 | encode_compound_hdr(&xdr, req, &hdr); |
| 2029 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1665 | encode_putfh(&xdr, args->fh, &hdr); | 2030 | encode_putfh(&xdr, args->fh, &hdr); |
| 1666 | encode_locku(&xdr, args, &hdr); | 2031 | encode_locku(&xdr, args, &hdr); |
| 1667 | encode_nops(&hdr); | 2032 | encode_nops(&hdr); |
| @@ -1675,22 +2040,16 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n | |||
| 1675 | { | 2040 | { |
| 1676 | struct xdr_stream xdr; | 2041 | struct xdr_stream xdr; |
| 1677 | struct compound_hdr hdr = { | 2042 | struct compound_hdr hdr = { |
| 1678 | .nops = 0, | 2043 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1679 | }; | 2044 | }; |
| 1680 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
| 1681 | unsigned int replen; | ||
| 1682 | 2045 | ||
| 1683 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2046 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1684 | encode_compound_hdr(&xdr, &hdr); | 2047 | encode_compound_hdr(&xdr, req, &hdr); |
| 2048 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1685 | encode_putfh(&xdr, args->fh, &hdr); | 2049 | encode_putfh(&xdr, args->fh, &hdr); |
| 1686 | encode_readlink(&xdr, args, req, &hdr); | 2050 | encode_readlink(&xdr, args, req, &hdr); |
| 1687 | 2051 | ||
| 1688 | /* set up reply kvec | 2052 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, |
| 1689 | * toplevel_status + taglen + rescount + OP_PUTFH + status | ||
| 1690 | * + OP_READLINK + status + string length = 8 | ||
| 1691 | */ | ||
| 1692 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2; | ||
| 1693 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | ||
| 1694 | args->pgbase, args->pglen); | 2053 | args->pgbase, args->pglen); |
| 1695 | encode_nops(&hdr); | 2054 | encode_nops(&hdr); |
| 1696 | return 0; | 2055 | return 0; |
| @@ -1703,25 +2062,19 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
| 1703 | { | 2062 | { |
| 1704 | struct xdr_stream xdr; | 2063 | struct xdr_stream xdr; |
| 1705 | struct compound_hdr hdr = { | 2064 | struct compound_hdr hdr = { |
| 1706 | .nops = 0, | 2065 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1707 | }; | 2066 | }; |
| 1708 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
| 1709 | int replen; | ||
| 1710 | 2067 | ||
| 1711 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2068 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1712 | encode_compound_hdr(&xdr, &hdr); | 2069 | encode_compound_hdr(&xdr, req, &hdr); |
| 2070 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1713 | encode_putfh(&xdr, args->fh, &hdr); | 2071 | encode_putfh(&xdr, args->fh, &hdr); |
| 1714 | encode_readdir(&xdr, args, req, &hdr); | 2072 | encode_readdir(&xdr, args, req, &hdr); |
| 1715 | 2073 | ||
| 1716 | /* set up reply kvec | 2074 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, |
| 1717 | * toplevel_status + taglen + rescount + OP_PUTFH + status | ||
| 1718 | * + OP_READDIR + status + verifer(2) = 9 | ||
| 1719 | */ | ||
| 1720 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readdir_sz) << 2; | ||
| 1721 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | ||
| 1722 | args->pgbase, args->count); | 2075 | args->pgbase, args->count); |
| 1723 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", | 2076 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", |
| 1724 | __func__, replen, args->pages, | 2077 | __func__, hdr.replen << 2, args->pages, |
| 1725 | args->pgbase, args->count); | 2078 | args->pgbase, args->count); |
| 1726 | encode_nops(&hdr); | 2079 | encode_nops(&hdr); |
| 1727 | return 0; | 2080 | return 0; |
| @@ -1732,24 +2085,18 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
| 1732 | */ | 2085 | */ |
| 1733 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | 2086 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) |
| 1734 | { | 2087 | { |
| 1735 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
| 1736 | struct xdr_stream xdr; | 2088 | struct xdr_stream xdr; |
| 1737 | struct compound_hdr hdr = { | 2089 | struct compound_hdr hdr = { |
| 1738 | .nops = 0, | 2090 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1739 | }; | 2091 | }; |
| 1740 | int replen; | ||
| 1741 | 2092 | ||
| 1742 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2093 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1743 | encode_compound_hdr(&xdr, &hdr); | 2094 | encode_compound_hdr(&xdr, req, &hdr); |
| 2095 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1744 | encode_putfh(&xdr, args->fh, &hdr); | 2096 | encode_putfh(&xdr, args->fh, &hdr); |
| 1745 | encode_read(&xdr, args, &hdr); | 2097 | encode_read(&xdr, args, &hdr); |
| 1746 | 2098 | ||
| 1747 | /* set up reply kvec | 2099 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, |
| 1748 | * toplevel status + taglen=0 + rescount + OP_PUTFH + status | ||
| 1749 | * + OP_READ + status + eof + datalen = 9 | ||
| 1750 | */ | ||
| 1751 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2; | ||
| 1752 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
| 1753 | args->pages, args->pgbase, args->count); | 2100 | args->pages, args->pgbase, args->count); |
| 1754 | req->rq_rcv_buf.flags |= XDRBUF_READ; | 2101 | req->rq_rcv_buf.flags |= XDRBUF_READ; |
| 1755 | encode_nops(&hdr); | 2102 | encode_nops(&hdr); |
| @@ -1763,11 +2110,12 @@ static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_seta | |||
| 1763 | { | 2110 | { |
| 1764 | struct xdr_stream xdr; | 2111 | struct xdr_stream xdr; |
| 1765 | struct compound_hdr hdr = { | 2112 | struct compound_hdr hdr = { |
| 1766 | .nops = 0, | 2113 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1767 | }; | 2114 | }; |
| 1768 | 2115 | ||
| 1769 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2116 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1770 | encode_compound_hdr(&xdr, &hdr); | 2117 | encode_compound_hdr(&xdr, req, &hdr); |
| 2118 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1771 | encode_putfh(&xdr, args->fh, &hdr); | 2119 | encode_putfh(&xdr, args->fh, &hdr); |
| 1772 | encode_setattr(&xdr, args, args->server, &hdr); | 2120 | encode_setattr(&xdr, args, args->server, &hdr); |
| 1773 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2121 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| @@ -1783,20 +2131,19 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p, | |||
| 1783 | struct nfs_getaclargs *args) | 2131 | struct nfs_getaclargs *args) |
| 1784 | { | 2132 | { |
| 1785 | struct xdr_stream xdr; | 2133 | struct xdr_stream xdr; |
| 1786 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
| 1787 | struct compound_hdr hdr = { | 2134 | struct compound_hdr hdr = { |
| 1788 | .nops = 0, | 2135 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1789 | }; | 2136 | }; |
| 1790 | int replen; | 2137 | uint32_t replen; |
| 1791 | 2138 | ||
| 1792 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2139 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1793 | encode_compound_hdr(&xdr, &hdr); | 2140 | encode_compound_hdr(&xdr, req, &hdr); |
| 2141 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1794 | encode_putfh(&xdr, args->fh, &hdr); | 2142 | encode_putfh(&xdr, args->fh, &hdr); |
| 2143 | replen = hdr.replen + nfs4_fattr_bitmap_maxsz + 1; | ||
| 1795 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); | 2144 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); |
| 1796 | 2145 | ||
| 1797 | /* set up reply buffer: */ | 2146 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, |
| 1798 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; | ||
| 1799 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
| 1800 | args->acl_pages, args->acl_pgbase, args->acl_len); | 2147 | args->acl_pages, args->acl_pgbase, args->acl_len); |
| 1801 | encode_nops(&hdr); | 2148 | encode_nops(&hdr); |
| 1802 | return 0; | 2149 | return 0; |
| @@ -1809,11 +2156,12 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea | |||
| 1809 | { | 2156 | { |
| 1810 | struct xdr_stream xdr; | 2157 | struct xdr_stream xdr; |
| 1811 | struct compound_hdr hdr = { | 2158 | struct compound_hdr hdr = { |
| 1812 | .nops = 0, | 2159 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1813 | }; | 2160 | }; |
| 1814 | 2161 | ||
| 1815 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2162 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1816 | encode_compound_hdr(&xdr, &hdr); | 2163 | encode_compound_hdr(&xdr, req, &hdr); |
| 2164 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1817 | encode_putfh(&xdr, args->fh, &hdr); | 2165 | encode_putfh(&xdr, args->fh, &hdr); |
| 1818 | encode_write(&xdr, args, &hdr); | 2166 | encode_write(&xdr, args, &hdr); |
| 1819 | req->rq_snd_buf.flags |= XDRBUF_WRITE; | 2167 | req->rq_snd_buf.flags |= XDRBUF_WRITE; |
| @@ -1829,11 +2177,12 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_write | |||
| 1829 | { | 2177 | { |
| 1830 | struct xdr_stream xdr; | 2178 | struct xdr_stream xdr; |
| 1831 | struct compound_hdr hdr = { | 2179 | struct compound_hdr hdr = { |
| 1832 | .nops = 0, | 2180 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1833 | }; | 2181 | }; |
| 1834 | 2182 | ||
| 1835 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2183 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1836 | encode_compound_hdr(&xdr, &hdr); | 2184 | encode_compound_hdr(&xdr, req, &hdr); |
| 2185 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1837 | encode_putfh(&xdr, args->fh, &hdr); | 2186 | encode_putfh(&xdr, args->fh, &hdr); |
| 1838 | encode_commit(&xdr, args, &hdr); | 2187 | encode_commit(&xdr, args, &hdr); |
| 1839 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2188 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| @@ -1848,11 +2197,12 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsin | |||
| 1848 | { | 2197 | { |
| 1849 | struct xdr_stream xdr; | 2198 | struct xdr_stream xdr; |
| 1850 | struct compound_hdr hdr = { | 2199 | struct compound_hdr hdr = { |
| 1851 | .nops = 0, | 2200 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1852 | }; | 2201 | }; |
| 1853 | 2202 | ||
| 1854 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2203 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1855 | encode_compound_hdr(&xdr, &hdr); | 2204 | encode_compound_hdr(&xdr, req, &hdr); |
| 2205 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1856 | encode_putfh(&xdr, args->fh, &hdr); | 2206 | encode_putfh(&xdr, args->fh, &hdr); |
| 1857 | encode_fsinfo(&xdr, args->bitmask, &hdr); | 2207 | encode_fsinfo(&xdr, args->bitmask, &hdr); |
| 1858 | encode_nops(&hdr); | 2208 | encode_nops(&hdr); |
| @@ -1866,11 +2216,12 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct n | |||
| 1866 | { | 2216 | { |
| 1867 | struct xdr_stream xdr; | 2217 | struct xdr_stream xdr; |
| 1868 | struct compound_hdr hdr = { | 2218 | struct compound_hdr hdr = { |
| 1869 | .nops = 0, | 2219 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1870 | }; | 2220 | }; |
| 1871 | 2221 | ||
| 1872 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2222 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1873 | encode_compound_hdr(&xdr, &hdr); | 2223 | encode_compound_hdr(&xdr, req, &hdr); |
| 2224 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1874 | encode_putfh(&xdr, args->fh, &hdr); | 2225 | encode_putfh(&xdr, args->fh, &hdr); |
| 1875 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], | 2226 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], |
| 1876 | &hdr); | 2227 | &hdr); |
| @@ -1885,11 +2236,12 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1885 | { | 2236 | { |
| 1886 | struct xdr_stream xdr; | 2237 | struct xdr_stream xdr; |
| 1887 | struct compound_hdr hdr = { | 2238 | struct compound_hdr hdr = { |
| 1888 | .nops = 0, | 2239 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1889 | }; | 2240 | }; |
| 1890 | 2241 | ||
| 1891 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2242 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1892 | encode_compound_hdr(&xdr, &hdr); | 2243 | encode_compound_hdr(&xdr, req, &hdr); |
| 2244 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1893 | encode_putfh(&xdr, args->fh, &hdr); | 2245 | encode_putfh(&xdr, args->fh, &hdr); |
| 1894 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], | 2246 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], |
| 1895 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); | 2247 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); |
| @@ -1900,16 +2252,18 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
| 1900 | /* | 2252 | /* |
| 1901 | * GETATTR_BITMAP request | 2253 | * GETATTR_BITMAP request |
| 1902 | */ | 2254 | */ |
| 1903 | static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle) | 2255 | static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, |
| 2256 | struct nfs4_server_caps_arg *args) | ||
| 1904 | { | 2257 | { |
| 1905 | struct xdr_stream xdr; | 2258 | struct xdr_stream xdr; |
| 1906 | struct compound_hdr hdr = { | 2259 | struct compound_hdr hdr = { |
| 1907 | .nops = 0, | 2260 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1908 | }; | 2261 | }; |
| 1909 | 2262 | ||
| 1910 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2263 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1911 | encode_compound_hdr(&xdr, &hdr); | 2264 | encode_compound_hdr(&xdr, req, &hdr); |
| 1912 | encode_putfh(&xdr, fhandle, &hdr); | 2265 | encode_sequence(&xdr, &args->seq_args, &hdr); |
| 2266 | encode_putfh(&xdr, args->fhandle, &hdr); | ||
| 1913 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| | 2267 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| |
| 1914 | FATTR4_WORD0_LINK_SUPPORT| | 2268 | FATTR4_WORD0_LINK_SUPPORT| |
| 1915 | FATTR4_WORD0_SYMLINK_SUPPORT| | 2269 | FATTR4_WORD0_SYMLINK_SUPPORT| |
| @@ -1929,7 +2283,7 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client | |||
| 1929 | }; | 2283 | }; |
| 1930 | 2284 | ||
| 1931 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2285 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1932 | encode_compound_hdr(&xdr, &hdr); | 2286 | encode_compound_hdr(&xdr, req, &hdr); |
| 1933 | encode_renew(&xdr, clp, &hdr); | 2287 | encode_renew(&xdr, clp, &hdr); |
| 1934 | encode_nops(&hdr); | 2288 | encode_nops(&hdr); |
| 1935 | return 0; | 2289 | return 0; |
| @@ -1946,7 +2300,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
| 1946 | }; | 2300 | }; |
| 1947 | 2301 | ||
| 1948 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2302 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1949 | encode_compound_hdr(&xdr, &hdr); | 2303 | encode_compound_hdr(&xdr, req, &hdr); |
| 1950 | encode_setclientid(&xdr, sc, &hdr); | 2304 | encode_setclientid(&xdr, sc, &hdr); |
| 1951 | encode_nops(&hdr); | 2305 | encode_nops(&hdr); |
| 1952 | return 0; | 2306 | return 0; |
| @@ -1964,7 +2318,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
| 1964 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | 2318 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; |
| 1965 | 2319 | ||
| 1966 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2320 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1967 | encode_compound_hdr(&xdr, &hdr); | 2321 | encode_compound_hdr(&xdr, req, &hdr); |
| 1968 | encode_setclientid_confirm(&xdr, clp, &hdr); | 2322 | encode_setclientid_confirm(&xdr, clp, &hdr); |
| 1969 | encode_putrootfh(&xdr, &hdr); | 2323 | encode_putrootfh(&xdr, &hdr); |
| 1970 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | 2324 | encode_fsinfo(&xdr, lease_bitmap, &hdr); |
| @@ -1979,11 +2333,12 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struc | |||
| 1979 | { | 2333 | { |
| 1980 | struct xdr_stream xdr; | 2334 | struct xdr_stream xdr; |
| 1981 | struct compound_hdr hdr = { | 2335 | struct compound_hdr hdr = { |
| 1982 | .nops = 0, | 2336 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 1983 | }; | 2337 | }; |
| 1984 | 2338 | ||
| 1985 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2339 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 1986 | encode_compound_hdr(&xdr, &hdr); | 2340 | encode_compound_hdr(&xdr, req, &hdr); |
| 2341 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 1987 | encode_putfh(&xdr, args->fhandle, &hdr); | 2342 | encode_putfh(&xdr, args->fhandle, &hdr); |
| 1988 | encode_delegreturn(&xdr, args->stateid, &hdr); | 2343 | encode_delegreturn(&xdr, args->stateid, &hdr); |
| 1989 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2344 | encode_getfattr(&xdr, args->bitmask, &hdr); |
| @@ -1998,28 +2353,119 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
| 1998 | { | 2353 | { |
| 1999 | struct xdr_stream xdr; | 2354 | struct xdr_stream xdr; |
| 2000 | struct compound_hdr hdr = { | 2355 | struct compound_hdr hdr = { |
| 2001 | .nops = 0, | 2356 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 2002 | }; | 2357 | }; |
| 2003 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 2358 | uint32_t replen; |
| 2004 | int replen; | ||
| 2005 | 2359 | ||
| 2006 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2360 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2007 | encode_compound_hdr(&xdr, &hdr); | 2361 | encode_compound_hdr(&xdr, req, &hdr); |
| 2362 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 2008 | encode_putfh(&xdr, args->dir_fh, &hdr); | 2363 | encode_putfh(&xdr, args->dir_fh, &hdr); |
| 2009 | encode_lookup(&xdr, args->name, &hdr); | 2364 | encode_lookup(&xdr, args->name, &hdr); |
| 2365 | replen = hdr.replen; /* get the attribute into args->page */ | ||
| 2010 | encode_fs_locations(&xdr, args->bitmask, &hdr); | 2366 | encode_fs_locations(&xdr, args->bitmask, &hdr); |
| 2011 | 2367 | ||
| 2012 | /* set up reply | 2368 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page, |
| 2013 | * toplevel_status + OP_PUTFH + status | ||
| 2014 | * + OP_LOOKUP + status + OP_GETATTR + status = 7 | ||
| 2015 | */ | ||
| 2016 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; | ||
| 2017 | xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page, | ||
| 2018 | 0, PAGE_SIZE); | 2369 | 0, PAGE_SIZE); |
| 2019 | encode_nops(&hdr); | 2370 | encode_nops(&hdr); |
| 2020 | return 0; | 2371 | return 0; |
| 2021 | } | 2372 | } |
| 2022 | 2373 | ||
| 2374 | #if defined(CONFIG_NFS_V4_1) | ||
| 2375 | /* | ||
| 2376 | * EXCHANGE_ID request | ||
| 2377 | */ | ||
| 2378 | static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p, | ||
| 2379 | struct nfs41_exchange_id_args *args) | ||
| 2380 | { | ||
| 2381 | struct xdr_stream xdr; | ||
| 2382 | struct compound_hdr hdr = { | ||
| 2383 | .minorversion = args->client->cl_minorversion, | ||
| 2384 | }; | ||
| 2385 | |||
| 2386 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
| 2387 | encode_compound_hdr(&xdr, req, &hdr); | ||
| 2388 | encode_exchange_id(&xdr, args, &hdr); | ||
| 2389 | encode_nops(&hdr); | ||
| 2390 | return 0; | ||
| 2391 | } | ||
| 2392 | |||
| 2393 | /* | ||
| 2394 | * a CREATE_SESSION request | ||
| 2395 | */ | ||
| 2396 | static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p, | ||
| 2397 | struct nfs41_create_session_args *args) | ||
| 2398 | { | ||
| 2399 | struct xdr_stream xdr; | ||
| 2400 | struct compound_hdr hdr = { | ||
| 2401 | .minorversion = args->client->cl_minorversion, | ||
| 2402 | }; | ||
| 2403 | |||
| 2404 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
| 2405 | encode_compound_hdr(&xdr, req, &hdr); | ||
| 2406 | encode_create_session(&xdr, args, &hdr); | ||
| 2407 | encode_nops(&hdr); | ||
| 2408 | return 0; | ||
| 2409 | } | ||
| 2410 | |||
| 2411 | /* | ||
| 2412 | * a DESTROY_SESSION request | ||
| 2413 | */ | ||
| 2414 | static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p, | ||
| 2415 | struct nfs4_session *session) | ||
| 2416 | { | ||
| 2417 | struct xdr_stream xdr; | ||
| 2418 | struct compound_hdr hdr = { | ||
| 2419 | .minorversion = session->clp->cl_minorversion, | ||
| 2420 | }; | ||
| 2421 | |||
| 2422 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
| 2423 | encode_compound_hdr(&xdr, req, &hdr); | ||
| 2424 | encode_destroy_session(&xdr, session, &hdr); | ||
| 2425 | encode_nops(&hdr); | ||
| 2426 | return 0; | ||
| 2427 | } | ||
| 2428 | |||
| 2429 | /* | ||
| 2430 | * a SEQUENCE request | ||
| 2431 | */ | ||
| 2432 | static int nfs4_xdr_enc_sequence(struct rpc_rqst *req, uint32_t *p, | ||
| 2433 | struct nfs4_sequence_args *args) | ||
| 2434 | { | ||
| 2435 | struct xdr_stream xdr; | ||
| 2436 | struct compound_hdr hdr = { | ||
| 2437 | .minorversion = nfs4_xdr_minorversion(args), | ||
| 2438 | }; | ||
| 2439 | |||
| 2440 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
| 2441 | encode_compound_hdr(&xdr, req, &hdr); | ||
| 2442 | encode_sequence(&xdr, args, &hdr); | ||
| 2443 | encode_nops(&hdr); | ||
| 2444 | return 0; | ||
| 2445 | } | ||
| 2446 | |||
| 2447 | /* | ||
| 2448 | * a GET_LEASE_TIME request | ||
| 2449 | */ | ||
| 2450 | static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, | ||
| 2451 | struct nfs4_get_lease_time_args *args) | ||
| 2452 | { | ||
| 2453 | struct xdr_stream xdr; | ||
| 2454 | struct compound_hdr hdr = { | ||
| 2455 | .minorversion = nfs4_xdr_minorversion(&args->la_seq_args), | ||
| 2456 | }; | ||
| 2457 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | ||
| 2458 | |||
| 2459 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
| 2460 | encode_compound_hdr(&xdr, req, &hdr); | ||
| 2461 | encode_sequence(&xdr, &args->la_seq_args, &hdr); | ||
| 2462 | encode_putrootfh(&xdr, &hdr); | ||
| 2463 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | ||
| 2464 | encode_nops(&hdr); | ||
| 2465 | return 0; | ||
| 2466 | } | ||
| 2467 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 2468 | |||
| 2023 | /* | 2469 | /* |
| 2024 | * START OF "GENERIC" DECODE ROUTINES. | 2470 | * START OF "GENERIC" DECODE ROUTINES. |
| 2025 | * These may look a little ugly since they are imported from a "generic" | 2471 | * These may look a little ugly since they are imported from a "generic" |
| @@ -3657,7 +4103,7 @@ decode_savefh(struct xdr_stream *xdr) | |||
| 3657 | return decode_op_hdr(xdr, OP_SAVEFH); | 4103 | return decode_op_hdr(xdr, OP_SAVEFH); |
| 3658 | } | 4104 | } |
| 3659 | 4105 | ||
| 3660 | static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) | 4106 | static int decode_setattr(struct xdr_stream *xdr) |
| 3661 | { | 4107 | { |
| 3662 | __be32 *p; | 4108 | __be32 *p; |
| 3663 | uint32_t bmlen; | 4109 | uint32_t bmlen; |
| @@ -3735,6 +4181,169 @@ static int decode_delegreturn(struct xdr_stream *xdr) | |||
| 3735 | return decode_op_hdr(xdr, OP_DELEGRETURN); | 4181 | return decode_op_hdr(xdr, OP_DELEGRETURN); |
| 3736 | } | 4182 | } |
| 3737 | 4183 | ||
| 4184 | #if defined(CONFIG_NFS_V4_1) | ||
| 4185 | static int decode_exchange_id(struct xdr_stream *xdr, | ||
| 4186 | struct nfs41_exchange_id_res *res) | ||
| 4187 | { | ||
| 4188 | __be32 *p; | ||
| 4189 | uint32_t dummy; | ||
| 4190 | int status; | ||
| 4191 | struct nfs_client *clp = res->client; | ||
| 4192 | |||
| 4193 | status = decode_op_hdr(xdr, OP_EXCHANGE_ID); | ||
| 4194 | if (status) | ||
| 4195 | return status; | ||
| 4196 | |||
| 4197 | READ_BUF(8); | ||
| 4198 | READ64(clp->cl_ex_clid); | ||
| 4199 | READ_BUF(12); | ||
| 4200 | READ32(clp->cl_seqid); | ||
| 4201 | READ32(clp->cl_exchange_flags); | ||
| 4202 | |||
| 4203 | /* We ask for SP4_NONE */ | ||
| 4204 | READ32(dummy); | ||
| 4205 | if (dummy != SP4_NONE) | ||
| 4206 | return -EIO; | ||
| 4207 | |||
| 4208 | /* Throw away minor_id */ | ||
| 4209 | READ_BUF(8); | ||
| 4210 | |||
| 4211 | /* Throw away Major id */ | ||
| 4212 | READ_BUF(4); | ||
| 4213 | READ32(dummy); | ||
| 4214 | READ_BUF(dummy); | ||
| 4215 | |||
| 4216 | /* Throw away server_scope */ | ||
| 4217 | READ_BUF(4); | ||
| 4218 | READ32(dummy); | ||
| 4219 | READ_BUF(dummy); | ||
| 4220 | |||
| 4221 | /* Throw away Implementation id array */ | ||
| 4222 | READ_BUF(4); | ||
| 4223 | READ32(dummy); | ||
| 4224 | READ_BUF(dummy); | ||
| 4225 | |||
| 4226 | return 0; | ||
| 4227 | } | ||
| 4228 | |||
| 4229 | static int decode_chan_attrs(struct xdr_stream *xdr, | ||
| 4230 | struct nfs4_channel_attrs *attrs) | ||
| 4231 | { | ||
| 4232 | __be32 *p; | ||
| 4233 | u32 nr_attrs; | ||
| 4234 | |||
| 4235 | READ_BUF(28); | ||
| 4236 | READ32(attrs->headerpadsz); | ||
| 4237 | READ32(attrs->max_rqst_sz); | ||
| 4238 | READ32(attrs->max_resp_sz); | ||
| 4239 | READ32(attrs->max_resp_sz_cached); | ||
| 4240 | READ32(attrs->max_ops); | ||
| 4241 | READ32(attrs->max_reqs); | ||
| 4242 | READ32(nr_attrs); | ||
| 4243 | if (unlikely(nr_attrs > 1)) { | ||
| 4244 | printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n", | ||
| 4245 | __func__, nr_attrs); | ||
| 4246 | return -EINVAL; | ||
| 4247 | } | ||
| 4248 | if (nr_attrs == 1) | ||
| 4249 | READ_BUF(4); /* skip rdma_attrs */ | ||
| 4250 | return 0; | ||
| 4251 | } | ||
| 4252 | |||
| 4253 | static int decode_create_session(struct xdr_stream *xdr, | ||
| 4254 | struct nfs41_create_session_res *res) | ||
| 4255 | { | ||
| 4256 | __be32 *p; | ||
| 4257 | int status; | ||
| 4258 | struct nfs_client *clp = res->client; | ||
| 4259 | struct nfs4_session *session = clp->cl_session; | ||
| 4260 | |||
| 4261 | status = decode_op_hdr(xdr, OP_CREATE_SESSION); | ||
| 4262 | |||
| 4263 | if (status) | ||
| 4264 | return status; | ||
| 4265 | |||
| 4266 | /* sessionid */ | ||
| 4267 | READ_BUF(NFS4_MAX_SESSIONID_LEN); | ||
| 4268 | COPYMEM(&session->sess_id, NFS4_MAX_SESSIONID_LEN); | ||
| 4269 | |||
| 4270 | /* seqid, flags */ | ||
| 4271 | READ_BUF(8); | ||
| 4272 | READ32(clp->cl_seqid); | ||
| 4273 | READ32(session->flags); | ||
| 4274 | |||
| 4275 | /* Channel attributes */ | ||
| 4276 | status = decode_chan_attrs(xdr, &session->fc_attrs); | ||
| 4277 | if (!status) | ||
| 4278 | status = decode_chan_attrs(xdr, &session->bc_attrs); | ||
| 4279 | return status; | ||
| 4280 | } | ||
| 4281 | |||
| 4282 | static int decode_destroy_session(struct xdr_stream *xdr, void *dummy) | ||
| 4283 | { | ||
| 4284 | return decode_op_hdr(xdr, OP_DESTROY_SESSION); | ||
| 4285 | } | ||
| 4286 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 4287 | |||
| 4288 | static int decode_sequence(struct xdr_stream *xdr, | ||
| 4289 | struct nfs4_sequence_res *res, | ||
| 4290 | struct rpc_rqst *rqstp) | ||
| 4291 | { | ||
| 4292 | #if defined(CONFIG_NFS_V4_1) | ||
| 4293 | struct nfs4_slot *slot; | ||
| 4294 | struct nfs4_sessionid id; | ||
| 4295 | u32 dummy; | ||
| 4296 | int status; | ||
| 4297 | __be32 *p; | ||
| 4298 | |||
| 4299 | if (!res->sr_session) | ||
| 4300 | return 0; | ||
| 4301 | |||
| 4302 | status = decode_op_hdr(xdr, OP_SEQUENCE); | ||
| 4303 | if (status) | ||
| 4304 | goto out_err; | ||
| 4305 | |||
| 4306 | /* | ||
| 4307 | * If the server returns different values for sessionID, slotID or | ||
| 4308 | * sequence number, the server is looney tunes. | ||
| 4309 | */ | ||
| 4310 | status = -ESERVERFAULT; | ||
| 4311 | |||
| 4312 | slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; | ||
| 4313 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 20); | ||
| 4314 | COPYMEM(id.data, NFS4_MAX_SESSIONID_LEN); | ||
| 4315 | if (memcmp(id.data, res->sr_session->sess_id.data, | ||
| 4316 | NFS4_MAX_SESSIONID_LEN)) { | ||
| 4317 | dprintk("%s Invalid session id\n", __func__); | ||
| 4318 | goto out_err; | ||
| 4319 | } | ||
| 4320 | /* seqid */ | ||
| 4321 | READ32(dummy); | ||
| 4322 | if (dummy != slot->seq_nr) { | ||
| 4323 | dprintk("%s Invalid sequence number\n", __func__); | ||
| 4324 | goto out_err; | ||
| 4325 | } | ||
| 4326 | /* slot id */ | ||
| 4327 | READ32(dummy); | ||
| 4328 | if (dummy != res->sr_slotid) { | ||
| 4329 | dprintk("%s Invalid slot id\n", __func__); | ||
| 4330 | goto out_err; | ||
| 4331 | } | ||
| 4332 | /* highest slot id - currently not processed */ | ||
| 4333 | READ32(dummy); | ||
| 4334 | /* target highest slot id - currently not processed */ | ||
| 4335 | READ32(dummy); | ||
| 4336 | /* result flags - currently not processed */ | ||
| 4337 | READ32(dummy); | ||
| 4338 | status = 0; | ||
| 4339 | out_err: | ||
| 4340 | res->sr_status = status; | ||
| 4341 | return status; | ||
| 4342 | #else /* CONFIG_NFS_V4_1 */ | ||
| 4343 | return 0; | ||
| 4344 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 4345 | } | ||
| 4346 | |||
| 3738 | /* | 4347 | /* |
| 3739 | * END OF "GENERIC" DECODE ROUTINES. | 4348 | * END OF "GENERIC" DECODE ROUTINES. |
| 3740 | */ | 4349 | */ |
| @@ -3752,6 +4361,9 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct | |||
| 3752 | status = decode_compound_hdr(&xdr, &hdr); | 4361 | status = decode_compound_hdr(&xdr, &hdr); |
| 3753 | if (status) | 4362 | if (status) |
| 3754 | goto out; | 4363 | goto out; |
| 4364 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4365 | if (status) | ||
| 4366 | goto out; | ||
| 3755 | status = decode_putfh(&xdr); | 4367 | status = decode_putfh(&xdr); |
| 3756 | if (status) | 4368 | if (status) |
| 3757 | goto out; | 4369 | goto out; |
| @@ -3773,7 +4385,11 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac | |||
| 3773 | int status; | 4385 | int status; |
| 3774 | 4386 | ||
| 3775 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4387 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3776 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4388 | status = decode_compound_hdr(&xdr, &hdr); |
| 4389 | if (status) | ||
| 4390 | goto out; | ||
| 4391 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4392 | if (status) | ||
| 3777 | goto out; | 4393 | goto out; |
| 3778 | status = decode_putfh(&xdr); | 4394 | status = decode_putfh(&xdr); |
| 3779 | if (status != 0) | 4395 | if (status != 0) |
| @@ -3796,7 +4412,11 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo | |||
| 3796 | int status; | 4412 | int status; |
| 3797 | 4413 | ||
| 3798 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4414 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3799 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4415 | status = decode_compound_hdr(&xdr, &hdr); |
| 4416 | if (status) | ||
| 4417 | goto out; | ||
| 4418 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4419 | if (status) | ||
| 3800 | goto out; | 4420 | goto out; |
| 3801 | if ((status = decode_putfh(&xdr)) != 0) | 4421 | if ((status = decode_putfh(&xdr)) != 0) |
| 3802 | goto out; | 4422 | goto out; |
| @@ -3819,7 +4439,11 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
| 3819 | int status; | 4439 | int status; |
| 3820 | 4440 | ||
| 3821 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4441 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3822 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4442 | status = decode_compound_hdr(&xdr, &hdr); |
| 4443 | if (status) | ||
| 4444 | goto out; | ||
| 4445 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4446 | if (status) | ||
| 3823 | goto out; | 4447 | goto out; |
| 3824 | if ((status = decode_putrootfh(&xdr)) != 0) | 4448 | if ((status = decode_putrootfh(&xdr)) != 0) |
| 3825 | goto out; | 4449 | goto out; |
| @@ -3839,7 +4463,11 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
| 3839 | int status; | 4463 | int status; |
| 3840 | 4464 | ||
| 3841 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4465 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3842 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4466 | status = decode_compound_hdr(&xdr, &hdr); |
| 4467 | if (status) | ||
| 4468 | goto out; | ||
| 4469 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4470 | if (status) | ||
| 3843 | goto out; | 4471 | goto out; |
| 3844 | if ((status = decode_putfh(&xdr)) != 0) | 4472 | if ((status = decode_putfh(&xdr)) != 0) |
| 3845 | goto out; | 4473 | goto out; |
| @@ -3860,7 +4488,11 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re | |||
| 3860 | int status; | 4488 | int status; |
| 3861 | 4489 | ||
| 3862 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4490 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3863 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4491 | status = decode_compound_hdr(&xdr, &hdr); |
| 4492 | if (status) | ||
| 4493 | goto out; | ||
| 4494 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4495 | if (status) | ||
| 3864 | goto out; | 4496 | goto out; |
| 3865 | if ((status = decode_putfh(&xdr)) != 0) | 4497 | if ((status = decode_putfh(&xdr)) != 0) |
| 3866 | goto out; | 4498 | goto out; |
| @@ -3890,7 +4522,11 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link | |||
| 3890 | int status; | 4522 | int status; |
| 3891 | 4523 | ||
| 3892 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4524 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3893 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4525 | status = decode_compound_hdr(&xdr, &hdr); |
| 4526 | if (status) | ||
| 4527 | goto out; | ||
| 4528 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4529 | if (status) | ||
| 3894 | goto out; | 4530 | goto out; |
| 3895 | if ((status = decode_putfh(&xdr)) != 0) | 4531 | if ((status = decode_putfh(&xdr)) != 0) |
| 3896 | goto out; | 4532 | goto out; |
| @@ -3923,7 +4559,11 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr | |||
| 3923 | int status; | 4559 | int status; |
| 3924 | 4560 | ||
| 3925 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4561 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 3926 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4562 | status = decode_compound_hdr(&xdr, &hdr); |
| 4563 | if (status) | ||
| 4564 | goto out; | ||
| 4565 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4566 | if (status) | ||
| 3927 | goto out; | 4567 | goto out; |
| 3928 | if ((status = decode_putfh(&xdr)) != 0) | 4568 | if ((status = decode_putfh(&xdr)) != 0) |
| 3929 | goto out; | 4569 | goto out; |
| @@ -3963,6 +4603,9 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g | |||
| 3963 | status = decode_compound_hdr(&xdr, &hdr); | 4603 | status = decode_compound_hdr(&xdr, &hdr); |
| 3964 | if (status) | 4604 | if (status) |
| 3965 | goto out; | 4605 | goto out; |
| 4606 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4607 | if (status) | ||
| 4608 | goto out; | ||
| 3966 | status = decode_putfh(&xdr); | 4609 | status = decode_putfh(&xdr); |
| 3967 | if (status) | 4610 | if (status) |
| 3968 | goto out; | 4611 | goto out; |
| @@ -3979,12 +4622,13 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args | |||
| 3979 | { | 4622 | { |
| 3980 | struct xdr_stream xdr; | 4623 | struct xdr_stream xdr; |
| 3981 | struct compound_hdr hdr = { | 4624 | struct compound_hdr hdr = { |
| 3982 | .nops = 0, | 4625 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 3983 | }; | 4626 | }; |
| 3984 | int status; | 4627 | int status; |
| 3985 | 4628 | ||
| 3986 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 4629 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 3987 | encode_compound_hdr(&xdr, &hdr); | 4630 | encode_compound_hdr(&xdr, req, &hdr); |
| 4631 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
| 3988 | encode_putfh(&xdr, args->fh, &hdr); | 4632 | encode_putfh(&xdr, args->fh, &hdr); |
| 3989 | status = encode_setacl(&xdr, args, &hdr); | 4633 | status = encode_setacl(&xdr, args, &hdr); |
| 3990 | encode_nops(&hdr); | 4634 | encode_nops(&hdr); |
| @@ -3995,7 +4639,8 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args | |||
| 3995 | * Decode SETACL response | 4639 | * Decode SETACL response |
| 3996 | */ | 4640 | */ |
| 3997 | static int | 4641 | static int |
| 3998 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) | 4642 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, |
| 4643 | struct nfs_setaclres *res) | ||
| 3999 | { | 4644 | { |
| 4000 | struct xdr_stream xdr; | 4645 | struct xdr_stream xdr; |
| 4001 | struct compound_hdr hdr; | 4646 | struct compound_hdr hdr; |
| @@ -4005,10 +4650,13 @@ nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) | |||
| 4005 | status = decode_compound_hdr(&xdr, &hdr); | 4650 | status = decode_compound_hdr(&xdr, &hdr); |
| 4006 | if (status) | 4651 | if (status) |
| 4007 | goto out; | 4652 | goto out; |
| 4653 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4654 | if (status) | ||
| 4655 | goto out; | ||
| 4008 | status = decode_putfh(&xdr); | 4656 | status = decode_putfh(&xdr); |
| 4009 | if (status) | 4657 | if (status) |
| 4010 | goto out; | 4658 | goto out; |
| 4011 | status = decode_setattr(&xdr, res); | 4659 | status = decode_setattr(&xdr); |
| 4012 | out: | 4660 | out: |
| 4013 | return status; | 4661 | return status; |
| 4014 | } | 4662 | } |
| @@ -4017,7 +4665,8 @@ out: | |||
| 4017 | * Decode GETACL response | 4665 | * Decode GETACL response |
| 4018 | */ | 4666 | */ |
| 4019 | static int | 4667 | static int |
| 4020 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) | 4668 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, |
| 4669 | struct nfs_getaclres *res) | ||
| 4021 | { | 4670 | { |
| 4022 | struct xdr_stream xdr; | 4671 | struct xdr_stream xdr; |
| 4023 | struct compound_hdr hdr; | 4672 | struct compound_hdr hdr; |
| @@ -4027,10 +4676,13 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) | |||
| 4027 | status = decode_compound_hdr(&xdr, &hdr); | 4676 | status = decode_compound_hdr(&xdr, &hdr); |
| 4028 | if (status) | 4677 | if (status) |
| 4029 | goto out; | 4678 | goto out; |
| 4679 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4680 | if (status) | ||
| 4681 | goto out; | ||
| 4030 | status = decode_putfh(&xdr); | 4682 | status = decode_putfh(&xdr); |
| 4031 | if (status) | 4683 | if (status) |
| 4032 | goto out; | 4684 | goto out; |
| 4033 | status = decode_getacl(&xdr, rqstp, acl_len); | 4685 | status = decode_getacl(&xdr, rqstp, &res->acl_len); |
| 4034 | 4686 | ||
| 4035 | out: | 4687 | out: |
| 4036 | return status; | 4688 | return status; |
| @@ -4049,6 +4701,9 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos | |||
| 4049 | status = decode_compound_hdr(&xdr, &hdr); | 4701 | status = decode_compound_hdr(&xdr, &hdr); |
| 4050 | if (status) | 4702 | if (status) |
| 4051 | goto out; | 4703 | goto out; |
| 4704 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4705 | if (status) | ||
| 4706 | goto out; | ||
| 4052 | status = decode_putfh(&xdr); | 4707 | status = decode_putfh(&xdr); |
| 4053 | if (status) | 4708 | if (status) |
| 4054 | goto out; | 4709 | goto out; |
| @@ -4079,6 +4734,9 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr | |||
| 4079 | status = decode_compound_hdr(&xdr, &hdr); | 4734 | status = decode_compound_hdr(&xdr, &hdr); |
| 4080 | if (status) | 4735 | if (status) |
| 4081 | goto out; | 4736 | goto out; |
| 4737 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4738 | if (status) | ||
| 4739 | goto out; | ||
| 4082 | status = decode_putfh(&xdr); | 4740 | status = decode_putfh(&xdr); |
| 4083 | if (status) | 4741 | if (status) |
| 4084 | goto out; | 4742 | goto out; |
| @@ -4133,6 +4791,9 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
| 4133 | status = decode_compound_hdr(&xdr, &hdr); | 4791 | status = decode_compound_hdr(&xdr, &hdr); |
| 4134 | if (status) | 4792 | if (status) |
| 4135 | goto out; | 4793 | goto out; |
| 4794 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4795 | if (status) | ||
| 4796 | goto out; | ||
| 4136 | status = decode_putfh(&xdr); | 4797 | status = decode_putfh(&xdr); |
| 4137 | if (status) | 4798 | if (status) |
| 4138 | goto out; | 4799 | goto out; |
| @@ -4157,10 +4818,13 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se | |||
| 4157 | status = decode_compound_hdr(&xdr, &hdr); | 4818 | status = decode_compound_hdr(&xdr, &hdr); |
| 4158 | if (status) | 4819 | if (status) |
| 4159 | goto out; | 4820 | goto out; |
| 4821 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4822 | if (status) | ||
| 4823 | goto out; | ||
| 4160 | status = decode_putfh(&xdr); | 4824 | status = decode_putfh(&xdr); |
| 4161 | if (status) | 4825 | if (status) |
| 4162 | goto out; | 4826 | goto out; |
| 4163 | status = decode_setattr(&xdr, res); | 4827 | status = decode_setattr(&xdr); |
| 4164 | if (status) | 4828 | if (status) |
| 4165 | goto out; | 4829 | goto out; |
| 4166 | decode_getfattr(&xdr, res->fattr, res->server); | 4830 | decode_getfattr(&xdr, res->fattr, res->server); |
| @@ -4181,6 +4845,9 @@ static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_ | |||
| 4181 | status = decode_compound_hdr(&xdr, &hdr); | 4845 | status = decode_compound_hdr(&xdr, &hdr); |
| 4182 | if (status) | 4846 | if (status) |
| 4183 | goto out; | 4847 | goto out; |
| 4848 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4849 | if (status) | ||
| 4850 | goto out; | ||
| 4184 | status = decode_putfh(&xdr); | 4851 | status = decode_putfh(&xdr); |
| 4185 | if (status) | 4852 | if (status) |
| 4186 | goto out; | 4853 | goto out; |
| @@ -4202,6 +4869,9 @@ static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock | |||
| 4202 | status = decode_compound_hdr(&xdr, &hdr); | 4869 | status = decode_compound_hdr(&xdr, &hdr); |
| 4203 | if (status) | 4870 | if (status) |
| 4204 | goto out; | 4871 | goto out; |
| 4872 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4873 | if (status) | ||
| 4874 | goto out; | ||
| 4205 | status = decode_putfh(&xdr); | 4875 | status = decode_putfh(&xdr); |
| 4206 | if (status) | 4876 | if (status) |
| 4207 | goto out; | 4877 | goto out; |
| @@ -4223,6 +4893,9 @@ static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock | |||
| 4223 | status = decode_compound_hdr(&xdr, &hdr); | 4893 | status = decode_compound_hdr(&xdr, &hdr); |
| 4224 | if (status) | 4894 | if (status) |
| 4225 | goto out; | 4895 | goto out; |
| 4896 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4897 | if (status) | ||
| 4898 | goto out; | ||
| 4226 | status = decode_putfh(&xdr); | 4899 | status = decode_putfh(&xdr); |
| 4227 | if (status) | 4900 | if (status) |
| 4228 | goto out; | 4901 | goto out; |
| @@ -4234,7 +4907,8 @@ out: | |||
| 4234 | /* | 4907 | /* |
| 4235 | * Decode READLINK response | 4908 | * Decode READLINK response |
| 4236 | */ | 4909 | */ |
| 4237 | static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) | 4910 | static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, |
| 4911 | struct nfs4_readlink_res *res) | ||
| 4238 | { | 4912 | { |
| 4239 | struct xdr_stream xdr; | 4913 | struct xdr_stream xdr; |
| 4240 | struct compound_hdr hdr; | 4914 | struct compound_hdr hdr; |
| @@ -4244,6 +4918,9 @@ static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) | |||
| 4244 | status = decode_compound_hdr(&xdr, &hdr); | 4918 | status = decode_compound_hdr(&xdr, &hdr); |
| 4245 | if (status) | 4919 | if (status) |
| 4246 | goto out; | 4920 | goto out; |
| 4921 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4922 | if (status) | ||
| 4923 | goto out; | ||
| 4247 | status = decode_putfh(&xdr); | 4924 | status = decode_putfh(&xdr); |
| 4248 | if (status) | 4925 | if (status) |
| 4249 | goto out; | 4926 | goto out; |
| @@ -4265,6 +4942,9 @@ static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_r | |||
| 4265 | status = decode_compound_hdr(&xdr, &hdr); | 4942 | status = decode_compound_hdr(&xdr, &hdr); |
| 4266 | if (status) | 4943 | if (status) |
| 4267 | goto out; | 4944 | goto out; |
| 4945 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4946 | if (status) | ||
| 4947 | goto out; | ||
| 4268 | status = decode_putfh(&xdr); | 4948 | status = decode_putfh(&xdr); |
| 4269 | if (status) | 4949 | if (status) |
| 4270 | goto out; | 4950 | goto out; |
| @@ -4286,6 +4966,9 @@ static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readr | |||
| 4286 | status = decode_compound_hdr(&xdr, &hdr); | 4966 | status = decode_compound_hdr(&xdr, &hdr); |
| 4287 | if (status) | 4967 | if (status) |
| 4288 | goto out; | 4968 | goto out; |
| 4969 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4970 | if (status) | ||
| 4971 | goto out; | ||
| 4289 | status = decode_putfh(&xdr); | 4972 | status = decode_putfh(&xdr); |
| 4290 | if (status) | 4973 | if (status) |
| 4291 | goto out; | 4974 | goto out; |
| @@ -4309,6 +4992,9 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ | |||
| 4309 | status = decode_compound_hdr(&xdr, &hdr); | 4992 | status = decode_compound_hdr(&xdr, &hdr); |
| 4310 | if (status) | 4993 | if (status) |
| 4311 | goto out; | 4994 | goto out; |
| 4995 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 4996 | if (status) | ||
| 4997 | goto out; | ||
| 4312 | status = decode_putfh(&xdr); | 4998 | status = decode_putfh(&xdr); |
| 4313 | if (status) | 4999 | if (status) |
| 4314 | goto out; | 5000 | goto out; |
| @@ -4335,6 +5021,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri | |||
| 4335 | status = decode_compound_hdr(&xdr, &hdr); | 5021 | status = decode_compound_hdr(&xdr, &hdr); |
| 4336 | if (status) | 5022 | if (status) |
| 4337 | goto out; | 5023 | goto out; |
| 5024 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 5025 | if (status) | ||
| 5026 | goto out; | ||
| 4338 | status = decode_putfh(&xdr); | 5027 | status = decode_putfh(&xdr); |
| 4339 | if (status) | 5028 | if (status) |
| 4340 | goto out; | 5029 | goto out; |
| @@ -4349,7 +5038,8 @@ out: | |||
| 4349 | /* | 5038 | /* |
| 4350 | * FSINFO request | 5039 | * FSINFO request |
| 4351 | */ | 5040 | */ |
| 4352 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo) | 5041 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, |
| 5042 | struct nfs4_fsinfo_res *res) | ||
| 4353 | { | 5043 | { |
| 4354 | struct xdr_stream xdr; | 5044 | struct xdr_stream xdr; |
| 4355 | struct compound_hdr hdr; | 5045 | struct compound_hdr hdr; |
| @@ -4358,16 +5048,19 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf | |||
| 4358 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5048 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
| 4359 | status = decode_compound_hdr(&xdr, &hdr); | 5049 | status = decode_compound_hdr(&xdr, &hdr); |
| 4360 | if (!status) | 5050 | if (!status) |
| 5051 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
| 5052 | if (!status) | ||
| 4361 | status = decode_putfh(&xdr); | 5053 | status = decode_putfh(&xdr); |
| 4362 | if (!status) | 5054 | if (!status) |
| 4363 | status = decode_fsinfo(&xdr, fsinfo); | 5055 | status = decode_fsinfo(&xdr, res->fsinfo); |
| 4364 | return status; | 5056 | return status; |
| 4365 | } | 5057 | } |
| 4366 | 5058 | ||
| 4367 | /* | 5059 | /* |
| 4368 | * PATHCONF request | 5060 | * PATHCONF request |
| 4369 | */ | 5061 | */ |
| 4370 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf) | 5062 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, |
| 5063 | struct nfs4_pathconf_res *res) | ||
| 4371 | { | 5064 | { |
| 4372 | struct xdr_stream xdr; | 5065 | struct xdr_stream xdr; |
| 4373 | struct compound_hdr hdr; | 5066 | struct compound_hdr hdr; |
| @@ -4376,16 +5069,19 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pat | |||
| 4376 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5069 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
| 4377 | status = decode_compound_hdr(&xdr, &hdr); | 5070 | status = decode_compound_hdr(&xdr, &hdr); |
| 4378 | if (!status) | 5071 | if (!status) |
| 5072 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
| 5073 | if (!status) | ||
| 4379 | status = decode_putfh(&xdr); | 5074 | status = decode_putfh(&xdr); |
| 4380 | if (!status) | 5075 | if (!status) |
| 4381 | status = decode_pathconf(&xdr, pathconf); | 5076 | status = decode_pathconf(&xdr, res->pathconf); |
| 4382 | return status; | 5077 | return status; |
| 4383 | } | 5078 | } |
| 4384 | 5079 | ||
| 4385 | /* | 5080 | /* |
| 4386 | * STATFS request | 5081 | * STATFS request |
| 4387 | */ | 5082 | */ |
| 4388 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat) | 5083 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, |
| 5084 | struct nfs4_statfs_res *res) | ||
| 4389 | { | 5085 | { |
| 4390 | struct xdr_stream xdr; | 5086 | struct xdr_stream xdr; |
| 4391 | struct compound_hdr hdr; | 5087 | struct compound_hdr hdr; |
| @@ -4394,9 +5090,11 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fssta | |||
| 4394 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5090 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
| 4395 | status = decode_compound_hdr(&xdr, &hdr); | 5091 | status = decode_compound_hdr(&xdr, &hdr); |
| 4396 | if (!status) | 5092 | if (!status) |
| 5093 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
| 5094 | if (!status) | ||
| 4397 | status = decode_putfh(&xdr); | 5095 | status = decode_putfh(&xdr); |
| 4398 | if (!status) | 5096 | if (!status) |
| 4399 | status = decode_statfs(&xdr, fsstat); | 5097 | status = decode_statfs(&xdr, res->fsstat); |
| 4400 | return status; | 5098 | return status; |
| 4401 | } | 5099 | } |
| 4402 | 5100 | ||
| @@ -4410,7 +5108,11 @@ static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
| 4410 | int status; | 5108 | int status; |
| 4411 | 5109 | ||
| 4412 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5110 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
| 4413 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 5111 | status = decode_compound_hdr(&xdr, &hdr); |
| 5112 | if (status) | ||
| 5113 | goto out; | ||
| 5114 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
| 5115 | if (status) | ||
| 4414 | goto out; | 5116 | goto out; |
| 4415 | if ((status = decode_putfh(&xdr)) != 0) | 5117 | if ((status = decode_putfh(&xdr)) != 0) |
| 4416 | goto out; | 5118 | goto out; |
| @@ -4483,7 +5185,10 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
| 4483 | 5185 | ||
| 4484 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 5186 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
| 4485 | status = decode_compound_hdr(&xdr, &hdr); | 5187 | status = decode_compound_hdr(&xdr, &hdr); |
| 4486 | if (status != 0) | 5188 | if (status) |
| 5189 | goto out; | ||
| 5190 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
| 5191 | if (status) | ||
| 4487 | goto out; | 5192 | goto out; |
| 4488 | status = decode_putfh(&xdr); | 5193 | status = decode_putfh(&xdr); |
| 4489 | if (status != 0) | 5194 | if (status != 0) |
| @@ -4497,7 +5202,8 @@ out: | |||
| 4497 | /* | 5202 | /* |
| 4498 | * FS_LOCATIONS request | 5203 | * FS_LOCATIONS request |
| 4499 | */ | 5204 | */ |
| 4500 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res) | 5205 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, |
| 5206 | struct nfs4_fs_locations_res *res) | ||
| 4501 | { | 5207 | { |
| 4502 | struct xdr_stream xdr; | 5208 | struct xdr_stream xdr; |
| 4503 | struct compound_hdr hdr; | 5209 | struct compound_hdr hdr; |
| @@ -4505,18 +5211,113 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
| 4505 | 5211 | ||
| 4506 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5212 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
| 4507 | status = decode_compound_hdr(&xdr, &hdr); | 5213 | status = decode_compound_hdr(&xdr, &hdr); |
| 4508 | if (status != 0) | 5214 | if (status) |
| 5215 | goto out; | ||
| 5216 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
| 5217 | if (status) | ||
| 4509 | goto out; | 5218 | goto out; |
| 4510 | if ((status = decode_putfh(&xdr)) != 0) | 5219 | if ((status = decode_putfh(&xdr)) != 0) |
| 4511 | goto out; | 5220 | goto out; |
| 4512 | if ((status = decode_lookup(&xdr)) != 0) | 5221 | if ((status = decode_lookup(&xdr)) != 0) |
| 4513 | goto out; | 5222 | goto out; |
| 4514 | xdr_enter_page(&xdr, PAGE_SIZE); | 5223 | xdr_enter_page(&xdr, PAGE_SIZE); |
| 4515 | status = decode_getfattr(&xdr, &res->fattr, res->server); | 5224 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, |
| 5225 | res->fs_locations->server); | ||
| 4516 | out: | 5226 | out: |
| 4517 | return status; | 5227 | return status; |
| 4518 | } | 5228 | } |
| 4519 | 5229 | ||
| 5230 | #if defined(CONFIG_NFS_V4_1) | ||
| 5231 | /* | ||
| 5232 | * EXCHANGE_ID request | ||
| 5233 | */ | ||
| 5234 | static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p, | ||
| 5235 | void *res) | ||
| 5236 | { | ||
| 5237 | struct xdr_stream xdr; | ||
| 5238 | struct compound_hdr hdr; | ||
| 5239 | int status; | ||
| 5240 | |||
| 5241 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
| 5242 | status = decode_compound_hdr(&xdr, &hdr); | ||
| 5243 | if (!status) | ||
| 5244 | status = decode_exchange_id(&xdr, res); | ||
| 5245 | return status; | ||
| 5246 | } | ||
| 5247 | |||
| 5248 | /* | ||
| 5249 | * a CREATE_SESSION request | ||
| 5250 | */ | ||
| 5251 | static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p, | ||
| 5252 | struct nfs41_create_session_res *res) | ||
| 5253 | { | ||
| 5254 | struct xdr_stream xdr; | ||
| 5255 | struct compound_hdr hdr; | ||
| 5256 | int status; | ||
| 5257 | |||
| 5258 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
| 5259 | status = decode_compound_hdr(&xdr, &hdr); | ||
| 5260 | if (!status) | ||
| 5261 | status = decode_create_session(&xdr, res); | ||
| 5262 | return status; | ||
| 5263 | } | ||
| 5264 | |||
| 5265 | /* | ||
| 5266 | * a DESTROY_SESSION request | ||
| 5267 | */ | ||
| 5268 | static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p, | ||
| 5269 | void *dummy) | ||
| 5270 | { | ||
| 5271 | struct xdr_stream xdr; | ||
| 5272 | struct compound_hdr hdr; | ||
| 5273 | int status; | ||
| 5274 | |||
| 5275 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
| 5276 | status = decode_compound_hdr(&xdr, &hdr); | ||
| 5277 | if (!status) | ||
| 5278 | status = decode_destroy_session(&xdr, dummy); | ||
| 5279 | return status; | ||
| 5280 | } | ||
| 5281 | |||
| 5282 | /* | ||
| 5283 | * a SEQUENCE request | ||
| 5284 | */ | ||
| 5285 | static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p, | ||
| 5286 | struct nfs4_sequence_res *res) | ||
| 5287 | { | ||
| 5288 | struct xdr_stream xdr; | ||
| 5289 | struct compound_hdr hdr; | ||
| 5290 | int status; | ||
| 5291 | |||
| 5292 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
| 5293 | status = decode_compound_hdr(&xdr, &hdr); | ||
| 5294 | if (!status) | ||
| 5295 | status = decode_sequence(&xdr, res, rqstp); | ||
| 5296 | return status; | ||
| 5297 | } | ||
| 5298 | |||
| 5299 | /* | ||
| 5300 | * a GET_LEASE_TIME request | ||
| 5301 | */ | ||
| 5302 | static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p, | ||
| 5303 | struct nfs4_get_lease_time_res *res) | ||
| 5304 | { | ||
| 5305 | struct xdr_stream xdr; | ||
| 5306 | struct compound_hdr hdr; | ||
| 5307 | int status; | ||
| 5308 | |||
| 5309 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
| 5310 | status = decode_compound_hdr(&xdr, &hdr); | ||
| 5311 | if (!status) | ||
| 5312 | status = decode_sequence(&xdr, &res->lr_seq_res, rqstp); | ||
| 5313 | if (!status) | ||
| 5314 | status = decode_putrootfh(&xdr); | ||
| 5315 | if (!status) | ||
| 5316 | status = decode_fsinfo(&xdr, res->lr_fsinfo); | ||
| 5317 | return status; | ||
| 5318 | } | ||
| 5319 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 5320 | |||
| 4520 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | 5321 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) |
| 4521 | { | 5322 | { |
| 4522 | uint32_t bitmap[2] = {0}; | 5323 | uint32_t bitmap[2] = {0}; |
| @@ -4686,6 +5487,13 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
| 4686 | PROC(GETACL, enc_getacl, dec_getacl), | 5487 | PROC(GETACL, enc_getacl, dec_getacl), |
| 4687 | PROC(SETACL, enc_setacl, dec_setacl), | 5488 | PROC(SETACL, enc_setacl, dec_setacl), |
| 4688 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 5489 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
| 5490 | #if defined(CONFIG_NFS_V4_1) | ||
| 5491 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | ||
| 5492 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | ||
| 5493 | PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session), | ||
| 5494 | PROC(SEQUENCE, enc_sequence, dec_sequence), | ||
| 5495 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), | ||
| 5496 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 4689 | }; | 5497 | }; |
| 4690 | 5498 | ||
| 4691 | struct rpc_version nfs_version4 = { | 5499 | struct rpc_version nfs_version4 = { |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 4ace3c50a8eb..96c4ebfa46f4 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | 22 | ||
| 23 | #include <asm/system.h> | 23 | #include <asm/system.h> |
| 24 | 24 | ||
| 25 | #include "nfs4_fs.h" | ||
| 25 | #include "internal.h" | 26 | #include "internal.h" |
| 26 | #include "iostat.h" | 27 | #include "iostat.h" |
| 27 | #include "fscache.h" | 28 | #include "fscache.h" |
| @@ -46,6 +47,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
| 46 | memset(p, 0, sizeof(*p)); | 47 | memset(p, 0, sizeof(*p)); |
| 47 | INIT_LIST_HEAD(&p->pages); | 48 | INIT_LIST_HEAD(&p->pages); |
| 48 | p->npages = pagecount; | 49 | p->npages = pagecount; |
| 50 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 49 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 51 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
| 50 | p->pagevec = p->page_array; | 52 | p->pagevec = p->page_array; |
| 51 | else { | 53 | else { |
| @@ -357,19 +359,25 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data | |||
| 357 | struct nfs_readres *resp = &data->res; | 359 | struct nfs_readres *resp = &data->res; |
| 358 | 360 | ||
| 359 | if (resp->eof || resp->count == argp->count) | 361 | if (resp->eof || resp->count == argp->count) |
| 360 | return; | 362 | goto out; |
| 361 | 363 | ||
| 362 | /* This is a short read! */ | 364 | /* This is a short read! */ |
| 363 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 365 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
| 364 | /* Has the server at least made some progress? */ | 366 | /* Has the server at least made some progress? */ |
| 365 | if (resp->count == 0) | 367 | if (resp->count == 0) |
| 366 | return; | 368 | goto out; |
| 367 | 369 | ||
| 368 | /* Yes, so retry the read at the end of the data */ | 370 | /* Yes, so retry the read at the end of the data */ |
| 369 | argp->offset += resp->count; | 371 | argp->offset += resp->count; |
| 370 | argp->pgbase += resp->count; | 372 | argp->pgbase += resp->count; |
| 371 | argp->count -= resp->count; | 373 | argp->count -= resp->count; |
| 372 | rpc_restart_call(task); | 374 | nfs4_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client); |
| 375 | return; | ||
| 376 | out: | ||
| 377 | nfs4_sequence_free_slot(NFS_SERVER(data->inode)->nfs_client, | ||
| 378 | &data->res.seq_res); | ||
| 379 | return; | ||
| 380 | |||
| 373 | } | 381 | } |
| 374 | 382 | ||
| 375 | /* | 383 | /* |
| @@ -406,7 +414,23 @@ static void nfs_readpage_release_partial(void *calldata) | |||
| 406 | nfs_readdata_release(calldata); | 414 | nfs_readdata_release(calldata); |
| 407 | } | 415 | } |
| 408 | 416 | ||
| 417 | #if defined(CONFIG_NFS_V4_1) | ||
| 418 | void nfs_read_prepare(struct rpc_task *task, void *calldata) | ||
| 419 | { | ||
| 420 | struct nfs_read_data *data = calldata; | ||
| 421 | |||
| 422 | if (nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client, | ||
| 423 | &data->args.seq_args, &data->res.seq_res, | ||
| 424 | 0, task)) | ||
| 425 | return; | ||
| 426 | rpc_call_start(task); | ||
| 427 | } | ||
| 428 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 429 | |||
| 409 | static const struct rpc_call_ops nfs_read_partial_ops = { | 430 | static const struct rpc_call_ops nfs_read_partial_ops = { |
| 431 | #if defined(CONFIG_NFS_V4_1) | ||
| 432 | .rpc_call_prepare = nfs_read_prepare, | ||
| 433 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 410 | .rpc_call_done = nfs_readpage_result_partial, | 434 | .rpc_call_done = nfs_readpage_result_partial, |
| 411 | .rpc_release = nfs_readpage_release_partial, | 435 | .rpc_release = nfs_readpage_release_partial, |
| 412 | }; | 436 | }; |
| @@ -470,6 +494,9 @@ static void nfs_readpage_release_full(void *calldata) | |||
| 470 | } | 494 | } |
| 471 | 495 | ||
| 472 | static const struct rpc_call_ops nfs_read_full_ops = { | 496 | static const struct rpc_call_ops nfs_read_full_ops = { |
| 497 | #if defined(CONFIG_NFS_V4_1) | ||
| 498 | .rpc_call_prepare = nfs_read_prepare, | ||
| 499 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 473 | .rpc_call_done = nfs_readpage_result_full, | 500 | .rpc_call_done = nfs_readpage_result_full, |
| 474 | .rpc_release = nfs_readpage_release_full, | 501 | .rpc_release = nfs_readpage_release_full, |
| 475 | }; | 502 | }; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 26127b69a275..6063054455f8 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -90,6 +90,7 @@ enum { | |||
| 90 | Opt_mountport, | 90 | Opt_mountport, |
| 91 | Opt_mountvers, | 91 | Opt_mountvers, |
| 92 | Opt_nfsvers, | 92 | Opt_nfsvers, |
| 93 | Opt_minorversion, | ||
| 93 | 94 | ||
| 94 | /* Mount options that take string arguments */ | 95 | /* Mount options that take string arguments */ |
| 95 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, | 96 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
| @@ -155,6 +156,7 @@ static const match_table_t nfs_mount_option_tokens = { | |||
| 155 | { Opt_mountvers, "mountvers=%u" }, | 156 | { Opt_mountvers, "mountvers=%u" }, |
| 156 | { Opt_nfsvers, "nfsvers=%u" }, | 157 | { Opt_nfsvers, "nfsvers=%u" }, |
| 157 | { Opt_nfsvers, "vers=%u" }, | 158 | { Opt_nfsvers, "vers=%u" }, |
| 159 | { Opt_minorversion, "minorversion=%u" }, | ||
| 158 | 160 | ||
| 159 | { Opt_sec, "sec=%s" }, | 161 | { Opt_sec, "sec=%s" }, |
| 160 | { Opt_proto, "proto=%s" }, | 162 | { Opt_proto, "proto=%s" }, |
| @@ -1211,6 +1213,13 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1211 | nfs_parse_invalid_value("nfsvers"); | 1213 | nfs_parse_invalid_value("nfsvers"); |
| 1212 | } | 1214 | } |
| 1213 | break; | 1215 | break; |
| 1216 | case Opt_minorversion: | ||
| 1217 | if (match_int(args, &option)) | ||
| 1218 | return 0; | ||
| 1219 | if (option < 0 || option > NFS4_MAX_MINOR_VERSION) | ||
| 1220 | return 0; | ||
| 1221 | mnt->minorversion = option; | ||
| 1222 | break; | ||
| 1214 | 1223 | ||
| 1215 | /* | 1224 | /* |
| 1216 | * options that take text values | 1225 | * options that take text values |
| @@ -2263,6 +2272,7 @@ static int nfs4_validate_mount_data(void *options, | |||
| 2263 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | 2272 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ |
| 2264 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2273 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
| 2265 | args->auth_flavor_len = 0; | 2274 | args->auth_flavor_len = 0; |
| 2275 | args->minorversion = 0; | ||
| 2266 | 2276 | ||
| 2267 | switch (data->version) { | 2277 | switch (data->version) { |
| 2268 | case 1: | 2278 | case 1: |
| @@ -2477,12 +2487,13 @@ static void nfs4_kill_super(struct super_block *sb) | |||
| 2477 | { | 2487 | { |
| 2478 | struct nfs_server *server = NFS_SB(sb); | 2488 | struct nfs_server *server = NFS_SB(sb); |
| 2479 | 2489 | ||
| 2490 | dprintk("--> %s\n", __func__); | ||
| 2480 | nfs_super_return_all_delegations(sb); | 2491 | nfs_super_return_all_delegations(sb); |
| 2481 | kill_anon_super(sb); | 2492 | kill_anon_super(sb); |
| 2482 | |||
| 2483 | nfs4_renewd_prepare_shutdown(server); | 2493 | nfs4_renewd_prepare_shutdown(server); |
| 2484 | nfs_fscache_release_super_cookie(sb); | 2494 | nfs_fscache_release_super_cookie(sb); |
| 2485 | nfs_free_server(server); | 2495 | nfs_free_server(server); |
| 2496 | dprintk("<-- %s\n", __func__); | ||
| 2486 | } | 2497 | } |
| 2487 | 2498 | ||
| 2488 | /* | 2499 | /* |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index ecc295347775..1064c91ae810 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/wait.h> | 15 | #include <linux/wait.h> |
| 16 | 16 | ||
| 17 | #include "internal.h" | 17 | #include "internal.h" |
| 18 | #include "nfs4_fs.h" | ||
| 18 | 19 | ||
| 19 | struct nfs_unlinkdata { | 20 | struct nfs_unlinkdata { |
| 20 | struct hlist_node list; | 21 | struct hlist_node list; |
| @@ -82,7 +83,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) | |||
| 82 | struct inode *dir = data->dir; | 83 | struct inode *dir = data->dir; |
| 83 | 84 | ||
| 84 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) | 85 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) |
| 85 | rpc_restart_call(task); | 86 | nfs4_restart_rpc(task, NFS_SERVER(dir)->nfs_client); |
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | /** | 89 | /** |
| @@ -102,9 +103,25 @@ static void nfs_async_unlink_release(void *calldata) | |||
| 102 | nfs_sb_deactive(sb); | 103 | nfs_sb_deactive(sb); |
| 103 | } | 104 | } |
| 104 | 105 | ||
| 106 | #if defined(CONFIG_NFS_V4_1) | ||
| 107 | void nfs_unlink_prepare(struct rpc_task *task, void *calldata) | ||
| 108 | { | ||
| 109 | struct nfs_unlinkdata *data = calldata; | ||
| 110 | struct nfs_server *server = NFS_SERVER(data->dir); | ||
| 111 | |||
| 112 | if (nfs4_setup_sequence(server->nfs_client, &data->args.seq_args, | ||
| 113 | &data->res.seq_res, 1, task)) | ||
| 114 | return; | ||
| 115 | rpc_call_start(task); | ||
| 116 | } | ||
| 117 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 118 | |||
| 105 | static const struct rpc_call_ops nfs_unlink_ops = { | 119 | static const struct rpc_call_ops nfs_unlink_ops = { |
| 106 | .rpc_call_done = nfs_async_unlink_done, | 120 | .rpc_call_done = nfs_async_unlink_done, |
| 107 | .rpc_release = nfs_async_unlink_release, | 121 | .rpc_release = nfs_async_unlink_release, |
| 122 | #if defined(CONFIG_NFS_V4_1) | ||
| 123 | .rpc_call_prepare = nfs_unlink_prepare, | ||
| 124 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 108 | }; | 125 | }; |
| 109 | 126 | ||
| 110 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) | 127 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) |
| @@ -241,6 +258,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
| 241 | status = PTR_ERR(data->cred); | 258 | status = PTR_ERR(data->cred); |
| 242 | goto out_free; | 259 | goto out_free; |
| 243 | } | 260 | } |
| 261 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 244 | 262 | ||
| 245 | status = -EBUSY; | 263 | status = -EBUSY; |
| 246 | spin_lock(&dentry->d_lock); | 264 | spin_lock(&dentry->d_lock); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e560a78995a3..ce728829f79a 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include "delegation.h" | 25 | #include "delegation.h" |
| 26 | #include "internal.h" | 26 | #include "internal.h" |
| 27 | #include "iostat.h" | 27 | #include "iostat.h" |
| 28 | #include "nfs4_fs.h" | ||
| 28 | 29 | ||
| 29 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 30 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
| 30 | 31 | ||
| @@ -52,6 +53,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void) | |||
| 52 | if (p) { | 53 | if (p) { |
| 53 | memset(p, 0, sizeof(*p)); | 54 | memset(p, 0, sizeof(*p)); |
| 54 | INIT_LIST_HEAD(&p->pages); | 55 | INIT_LIST_HEAD(&p->pages); |
| 56 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 55 | } | 57 | } |
| 56 | return p; | 58 | return p; |
| 57 | } | 59 | } |
| @@ -71,6 +73,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
| 71 | memset(p, 0, sizeof(*p)); | 73 | memset(p, 0, sizeof(*p)); |
| 72 | INIT_LIST_HEAD(&p->pages); | 74 | INIT_LIST_HEAD(&p->pages); |
| 73 | p->npages = pagecount; | 75 | p->npages = pagecount; |
| 76 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
| 74 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 77 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
| 75 | p->pagevec = p->page_array; | 78 | p->pagevec = p->page_array; |
| 76 | else { | 79 | else { |
| @@ -1048,7 +1051,23 @@ out: | |||
| 1048 | nfs_writedata_release(calldata); | 1051 | nfs_writedata_release(calldata); |
| 1049 | } | 1052 | } |
| 1050 | 1053 | ||
| 1054 | #if defined(CONFIG_NFS_V4_1) | ||
| 1055 | void nfs_write_prepare(struct rpc_task *task, void *calldata) | ||
| 1056 | { | ||
| 1057 | struct nfs_write_data *data = calldata; | ||
| 1058 | struct nfs_client *clp = (NFS_SERVER(data->inode))->nfs_client; | ||
| 1059 | |||
| 1060 | if (nfs4_setup_sequence(clp, &data->args.seq_args, | ||
| 1061 | &data->res.seq_res, 1, task)) | ||
| 1062 | return; | ||
| 1063 | rpc_call_start(task); | ||
| 1064 | } | ||
| 1065 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1066 | |||
| 1051 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1067 | static const struct rpc_call_ops nfs_write_partial_ops = { |
| 1068 | #if defined(CONFIG_NFS_V4_1) | ||
| 1069 | .rpc_call_prepare = nfs_write_prepare, | ||
| 1070 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1052 | .rpc_call_done = nfs_writeback_done_partial, | 1071 | .rpc_call_done = nfs_writeback_done_partial, |
| 1053 | .rpc_release = nfs_writeback_release_partial, | 1072 | .rpc_release = nfs_writeback_release_partial, |
| 1054 | }; | 1073 | }; |
| @@ -1111,6 +1130,9 @@ remove_request: | |||
| 1111 | } | 1130 | } |
| 1112 | 1131 | ||
| 1113 | static const struct rpc_call_ops nfs_write_full_ops = { | 1132 | static const struct rpc_call_ops nfs_write_full_ops = { |
| 1133 | #if defined(CONFIG_NFS_V4_1) | ||
| 1134 | .rpc_call_prepare = nfs_write_prepare, | ||
| 1135 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1114 | .rpc_call_done = nfs_writeback_done_full, | 1136 | .rpc_call_done = nfs_writeback_done_full, |
| 1115 | .rpc_release = nfs_writeback_release_full, | 1137 | .rpc_release = nfs_writeback_release_full, |
| 1116 | }; | 1138 | }; |
| @@ -1123,6 +1145,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 1123 | { | 1145 | { |
| 1124 | struct nfs_writeargs *argp = &data->args; | 1146 | struct nfs_writeargs *argp = &data->args; |
| 1125 | struct nfs_writeres *resp = &data->res; | 1147 | struct nfs_writeres *resp = &data->res; |
| 1148 | struct nfs_server *server = NFS_SERVER(data->inode); | ||
| 1126 | int status; | 1149 | int status; |
| 1127 | 1150 | ||
| 1128 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", | 1151 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", |
| @@ -1155,7 +1178,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 1155 | if (time_before(complain, jiffies)) { | 1178 | if (time_before(complain, jiffies)) { |
| 1156 | dprintk("NFS: faulty NFS server %s:" | 1179 | dprintk("NFS: faulty NFS server %s:" |
| 1157 | " (committed = %d) != (stable = %d)\n", | 1180 | " (committed = %d) != (stable = %d)\n", |
| 1158 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, | 1181 | server->nfs_client->cl_hostname, |
| 1159 | resp->verf->committed, argp->stable); | 1182 | resp->verf->committed, argp->stable); |
| 1160 | complain = jiffies + 300 * HZ; | 1183 | complain = jiffies + 300 * HZ; |
| 1161 | } | 1184 | } |
| @@ -1181,7 +1204,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 1181 | */ | 1204 | */ |
| 1182 | argp->stable = NFS_FILE_SYNC; | 1205 | argp->stable = NFS_FILE_SYNC; |
| 1183 | } | 1206 | } |
| 1184 | rpc_restart_call(task); | 1207 | nfs4_restart_rpc(task, server->nfs_client); |
| 1185 | return -EAGAIN; | 1208 | return -EAGAIN; |
| 1186 | } | 1209 | } |
| 1187 | if (time_before(complain, jiffies)) { | 1210 | if (time_before(complain, jiffies)) { |
| @@ -1193,6 +1216,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 1193 | /* Can't do anything about it except throw an error. */ | 1216 | /* Can't do anything about it except throw an error. */ |
| 1194 | task->tk_status = -EIO; | 1217 | task->tk_status = -EIO; |
| 1195 | } | 1218 | } |
| 1219 | nfs4_sequence_free_slot(server->nfs_client, &data->res.seq_res); | ||
| 1196 | return 0; | 1220 | return 0; |
| 1197 | } | 1221 | } |
| 1198 | 1222 | ||
| @@ -1349,6 +1373,9 @@ static void nfs_commit_release(void *calldata) | |||
| 1349 | } | 1373 | } |
| 1350 | 1374 | ||
| 1351 | static const struct rpc_call_ops nfs_commit_ops = { | 1375 | static const struct rpc_call_ops nfs_commit_ops = { |
| 1376 | #if defined(CONFIG_NFS_V4_1) | ||
| 1377 | .rpc_call_prepare = nfs_write_prepare, | ||
| 1378 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1352 | .rpc_call_done = nfs_commit_done, | 1379 | .rpc_call_done = nfs_commit_done, |
| 1353 | .rpc_release = nfs_commit_release, | 1380 | .rpc_release = nfs_commit_release, |
| 1354 | }; | 1381 | }; |
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index e3f0cbcbd0db..bd2eba530667 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #define NFS4_FHSIZE 128 | 21 | #define NFS4_FHSIZE 128 |
| 22 | #define NFS4_MAXPATHLEN PATH_MAX | 22 | #define NFS4_MAXPATHLEN PATH_MAX |
| 23 | #define NFS4_MAXNAMLEN NAME_MAX | 23 | #define NFS4_MAXNAMLEN NAME_MAX |
| 24 | #define NFS4_OPAQUE_LIMIT 1024 | ||
| 24 | #define NFS4_MAX_SESSIONID_LEN 16 | 25 | #define NFS4_MAX_SESSIONID_LEN 16 |
| 25 | 26 | ||
| 26 | #define NFS4_ACCESS_READ 0x0001 | 27 | #define NFS4_ACCESS_READ 0x0001 |
| @@ -130,6 +131,16 @@ | |||
| 130 | 131 | ||
| 131 | #define NFS4_MAX_UINT64 (~(u64)0) | 132 | #define NFS4_MAX_UINT64 (~(u64)0) |
| 132 | 133 | ||
| 134 | /* An NFS4 sessions server must support at least NFS4_MAX_OPS operations. | ||
| 135 | * If a compound requires more operations, adjust NFS4_MAX_OPS accordingly. | ||
| 136 | */ | ||
| 137 | #define NFS4_MAX_OPS 8 | ||
| 138 | |||
| 139 | /* Our NFS4 client back channel server only wants the cb_sequene and the | ||
| 140 | * actual operation per compound | ||
| 141 | */ | ||
| 142 | #define NFS4_MAX_BACK_CHANNEL_OPS 2 | ||
| 143 | |||
| 133 | enum nfs4_acl_whotype { | 144 | enum nfs4_acl_whotype { |
| 134 | NFS4_ACL_WHO_NAMED = 0, | 145 | NFS4_ACL_WHO_NAMED = 0, |
| 135 | NFS4_ACL_WHO_OWNER, | 146 | NFS4_ACL_WHO_OWNER, |
| @@ -462,6 +473,13 @@ enum lock_type4 { | |||
| 462 | #define NFSPROC4_NULL 0 | 473 | #define NFSPROC4_NULL 0 |
| 463 | #define NFSPROC4_COMPOUND 1 | 474 | #define NFSPROC4_COMPOUND 1 |
| 464 | #define NFS4_MINOR_VERSION 0 | 475 | #define NFS4_MINOR_VERSION 0 |
| 476 | |||
| 477 | #if defined(CONFIG_NFS_V4_1) | ||
| 478 | #define NFS4_MAX_MINOR_VERSION 1 | ||
| 479 | #else | ||
| 480 | #define NFS4_MAX_MINOR_VERSION 0 | ||
| 481 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 482 | |||
| 465 | #define NFS4_DEBUG 1 | 483 | #define NFS4_DEBUG 1 |
| 466 | 484 | ||
| 467 | /* Index of predefined Linux client operations */ | 485 | /* Index of predefined Linux client operations */ |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 6ad75948cbf7..19fe15d12042 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
| @@ -4,11 +4,17 @@ | |||
| 4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
| 5 | #include <linux/backing-dev.h> | 5 | #include <linux/backing-dev.h> |
| 6 | #include <linux/wait.h> | 6 | #include <linux/wait.h> |
| 7 | #include <linux/nfs_xdr.h> | ||
| 8 | #include <linux/sunrpc/xprt.h> | ||
| 7 | 9 | ||
| 8 | #include <asm/atomic.h> | 10 | #include <asm/atomic.h> |
| 9 | 11 | ||
| 12 | struct nfs4_session; | ||
| 10 | struct nfs_iostats; | 13 | struct nfs_iostats; |
| 11 | struct nlm_host; | 14 | struct nlm_host; |
| 15 | struct nfs4_sequence_args; | ||
| 16 | struct nfs4_sequence_res; | ||
| 17 | struct nfs_server; | ||
| 12 | 18 | ||
| 13 | /* | 19 | /* |
| 14 | * The nfs_client identifies our client state to the server. | 20 | * The nfs_client identifies our client state to the server. |
| @@ -18,6 +24,7 @@ struct nfs_client { | |||
| 18 | int cl_cons_state; /* current construction state (-ve: init error) */ | 24 | int cl_cons_state; /* current construction state (-ve: init error) */ |
| 19 | #define NFS_CS_READY 0 /* ready to be used */ | 25 | #define NFS_CS_READY 0 /* ready to be used */ |
| 20 | #define NFS_CS_INITING 1 /* busy initialising */ | 26 | #define NFS_CS_INITING 1 /* busy initialising */ |
| 27 | #define NFS_CS_SESSION_INITING 2 /* busy initialising session */ | ||
| 21 | unsigned long cl_res_state; /* NFS resources state */ | 28 | unsigned long cl_res_state; /* NFS resources state */ |
| 22 | #define NFS_CS_CALLBACK 1 /* - callback started */ | 29 | #define NFS_CS_CALLBACK 1 /* - callback started */ |
| 23 | #define NFS_CS_IDMAP 2 /* - idmap started */ | 30 | #define NFS_CS_IDMAP 2 /* - idmap started */ |
| @@ -32,6 +39,7 @@ struct nfs_client { | |||
| 32 | const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */ | 39 | const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */ |
| 33 | int cl_proto; /* Network transport protocol */ | 40 | int cl_proto; /* Network transport protocol */ |
| 34 | 41 | ||
| 42 | u32 cl_minorversion;/* NFSv4 minorversion */ | ||
| 35 | struct rpc_cred *cl_machine_cred; | 43 | struct rpc_cred *cl_machine_cred; |
| 36 | 44 | ||
| 37 | #ifdef CONFIG_NFS_V4 | 45 | #ifdef CONFIG_NFS_V4 |
| @@ -63,7 +71,22 @@ struct nfs_client { | |||
| 63 | */ | 71 | */ |
| 64 | char cl_ipaddr[48]; | 72 | char cl_ipaddr[48]; |
| 65 | unsigned char cl_id_uniquifier; | 73 | unsigned char cl_id_uniquifier; |
| 66 | #endif | 74 | int (* cl_call_sync)(struct nfs_server *server, |
| 75 | struct rpc_message *msg, | ||
| 76 | struct nfs4_sequence_args *args, | ||
| 77 | struct nfs4_sequence_res *res, | ||
| 78 | int cache_reply); | ||
| 79 | #endif /* CONFIG_NFS_V4 */ | ||
| 80 | |||
| 81 | #ifdef CONFIG_NFS_V4_1 | ||
| 82 | /* clientid returned from EXCHANGE_ID, used by session operations */ | ||
| 83 | u64 cl_ex_clid; | ||
| 84 | /* The sequence id to use for the next CREATE_SESSION */ | ||
| 85 | u32 cl_seqid; | ||
| 86 | /* The flags used for obtaining the clientid during EXCHANGE_ID */ | ||
| 87 | u32 cl_exchange_flags; | ||
| 88 | struct nfs4_session *cl_session; /* sharred session */ | ||
| 89 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 67 | 90 | ||
| 68 | #ifdef CONFIG_NFS_FSCACHE | 91 | #ifdef CONFIG_NFS_FSCACHE |
| 69 | struct fscache_cookie *fscache; /* client index cache cookie */ | 92 | struct fscache_cookie *fscache; /* client index cache cookie */ |
| @@ -145,4 +168,46 @@ struct nfs_server { | |||
| 145 | #define NFS_CAP_ACLS (1U << 3) | 168 | #define NFS_CAP_ACLS (1U << 3) |
| 146 | #define NFS_CAP_ATOMIC_OPEN (1U << 4) | 169 | #define NFS_CAP_ATOMIC_OPEN (1U << 4) |
| 147 | 170 | ||
| 171 | |||
| 172 | /* maximum number of slots to use */ | ||
| 173 | #define NFS4_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE | ||
| 174 | |||
| 175 | #if defined(CONFIG_NFS_V4_1) | ||
| 176 | |||
| 177 | /* Sessions */ | ||
| 178 | #define SLOT_TABLE_SZ (NFS4_MAX_SLOT_TABLE/(8*sizeof(long))) | ||
| 179 | struct nfs4_slot_table { | ||
| 180 | struct nfs4_slot *slots; /* seqid per slot */ | ||
| 181 | unsigned long used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */ | ||
| 182 | spinlock_t slot_tbl_lock; | ||
| 183 | struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */ | ||
| 184 | int max_slots; /* # slots in table */ | ||
| 185 | int highest_used_slotid; /* sent to server on each SEQ. | ||
| 186 | * op for dynamic resizing */ | ||
| 187 | }; | ||
| 188 | |||
| 189 | static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp) | ||
| 190 | { | ||
| 191 | return sp - tbl->slots; | ||
| 192 | } | ||
| 193 | |||
| 194 | /* | ||
| 195 | * Session related parameters | ||
| 196 | */ | ||
| 197 | struct nfs4_session { | ||
| 198 | struct nfs4_sessionid sess_id; | ||
| 199 | u32 flags; | ||
| 200 | unsigned long session_state; | ||
| 201 | u32 hash_alg; | ||
| 202 | u32 ssv_len; | ||
| 203 | |||
| 204 | /* The fore and back channel */ | ||
| 205 | struct nfs4_channel_attrs fc_attrs; | ||
| 206 | struct nfs4_slot_table fc_slot_table; | ||
| 207 | struct nfs4_channel_attrs bc_attrs; | ||
| 208 | struct nfs4_slot_table bc_slot_table; | ||
| 209 | struct nfs_client *clp; | ||
| 210 | }; | ||
| 211 | |||
| 212 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 148 | #endif | 213 | #endif |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index b89c34e40bc2..62f63fb0c4c8 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -145,6 +145,44 @@ struct nfs4_change_info { | |||
| 145 | }; | 145 | }; |
| 146 | 146 | ||
| 147 | struct nfs_seqid; | 147 | struct nfs_seqid; |
| 148 | |||
| 149 | /* nfs41 sessions channel attributes */ | ||
| 150 | struct nfs4_channel_attrs { | ||
| 151 | u32 headerpadsz; | ||
| 152 | u32 max_rqst_sz; | ||
| 153 | u32 max_resp_sz; | ||
| 154 | u32 max_resp_sz_cached; | ||
| 155 | u32 max_ops; | ||
| 156 | u32 max_reqs; | ||
| 157 | }; | ||
| 158 | |||
| 159 | /* nfs41 sessions slot seqid */ | ||
| 160 | struct nfs4_slot { | ||
| 161 | u32 seq_nr; | ||
| 162 | }; | ||
| 163 | |||
| 164 | struct nfs4_sequence_args { | ||
| 165 | struct nfs4_session *sa_session; | ||
| 166 | u8 sa_slotid; | ||
| 167 | u8 sa_cache_this; | ||
| 168 | }; | ||
| 169 | |||
| 170 | struct nfs4_sequence_res { | ||
| 171 | struct nfs4_session *sr_session; | ||
| 172 | u8 sr_slotid; /* slot used to send request */ | ||
| 173 | unsigned long sr_renewal_time; | ||
| 174 | int sr_status; /* sequence operation status */ | ||
| 175 | }; | ||
| 176 | |||
| 177 | struct nfs4_get_lease_time_args { | ||
| 178 | struct nfs4_sequence_args la_seq_args; | ||
| 179 | }; | ||
| 180 | |||
| 181 | struct nfs4_get_lease_time_res { | ||
| 182 | struct nfs_fsinfo *lr_fsinfo; | ||
| 183 | struct nfs4_sequence_res lr_seq_res; | ||
| 184 | }; | ||
| 185 | |||
| 148 | /* | 186 | /* |
| 149 | * Arguments to the open call. | 187 | * Arguments to the open call. |
| 150 | */ | 188 | */ |
| @@ -165,6 +203,7 @@ struct nfs_openargs { | |||
| 165 | const struct nfs_server *server; /* Needed for ID mapping */ | 203 | const struct nfs_server *server; /* Needed for ID mapping */ |
| 166 | const u32 * bitmask; | 204 | const u32 * bitmask; |
| 167 | __u32 claim; | 205 | __u32 claim; |
| 206 | struct nfs4_sequence_args seq_args; | ||
| 168 | }; | 207 | }; |
| 169 | 208 | ||
| 170 | struct nfs_openres { | 209 | struct nfs_openres { |
| @@ -181,6 +220,7 @@ struct nfs_openres { | |||
| 181 | __u32 do_recall; | 220 | __u32 do_recall; |
| 182 | __u64 maxsize; | 221 | __u64 maxsize; |
| 183 | __u32 attrset[NFS4_BITMAP_SIZE]; | 222 | __u32 attrset[NFS4_BITMAP_SIZE]; |
| 223 | struct nfs4_sequence_res seq_res; | ||
| 184 | }; | 224 | }; |
| 185 | 225 | ||
| 186 | /* | 226 | /* |
| @@ -206,6 +246,7 @@ struct nfs_closeargs { | |||
| 206 | struct nfs_seqid * seqid; | 246 | struct nfs_seqid * seqid; |
| 207 | fmode_t fmode; | 247 | fmode_t fmode; |
| 208 | const u32 * bitmask; | 248 | const u32 * bitmask; |
| 249 | struct nfs4_sequence_args seq_args; | ||
| 209 | }; | 250 | }; |
| 210 | 251 | ||
| 211 | struct nfs_closeres { | 252 | struct nfs_closeres { |
| @@ -213,6 +254,7 @@ struct nfs_closeres { | |||
| 213 | struct nfs_fattr * fattr; | 254 | struct nfs_fattr * fattr; |
| 214 | struct nfs_seqid * seqid; | 255 | struct nfs_seqid * seqid; |
| 215 | const struct nfs_server *server; | 256 | const struct nfs_server *server; |
| 257 | struct nfs4_sequence_res seq_res; | ||
| 216 | }; | 258 | }; |
| 217 | /* | 259 | /* |
| 218 | * * Arguments to the lock,lockt, and locku call. | 260 | * * Arguments to the lock,lockt, and locku call. |
| @@ -233,12 +275,14 @@ struct nfs_lock_args { | |||
| 233 | unsigned char block : 1; | 275 | unsigned char block : 1; |
| 234 | unsigned char reclaim : 1; | 276 | unsigned char reclaim : 1; |
| 235 | unsigned char new_lock_owner : 1; | 277 | unsigned char new_lock_owner : 1; |
| 278 | struct nfs4_sequence_args seq_args; | ||
| 236 | }; | 279 | }; |
| 237 | 280 | ||
| 238 | struct nfs_lock_res { | 281 | struct nfs_lock_res { |
| 239 | nfs4_stateid stateid; | 282 | nfs4_stateid stateid; |
| 240 | struct nfs_seqid * lock_seqid; | 283 | struct nfs_seqid * lock_seqid; |
| 241 | struct nfs_seqid * open_seqid; | 284 | struct nfs_seqid * open_seqid; |
| 285 | struct nfs4_sequence_res seq_res; | ||
| 242 | }; | 286 | }; |
| 243 | 287 | ||
| 244 | struct nfs_locku_args { | 288 | struct nfs_locku_args { |
| @@ -246,32 +290,38 @@ struct nfs_locku_args { | |||
| 246 | struct file_lock * fl; | 290 | struct file_lock * fl; |
| 247 | struct nfs_seqid * seqid; | 291 | struct nfs_seqid * seqid; |
| 248 | nfs4_stateid * stateid; | 292 | nfs4_stateid * stateid; |
| 293 | struct nfs4_sequence_args seq_args; | ||
| 249 | }; | 294 | }; |
| 250 | 295 | ||
| 251 | struct nfs_locku_res { | 296 | struct nfs_locku_res { |
| 252 | nfs4_stateid stateid; | 297 | nfs4_stateid stateid; |
| 253 | struct nfs_seqid * seqid; | 298 | struct nfs_seqid * seqid; |
| 299 | struct nfs4_sequence_res seq_res; | ||
| 254 | }; | 300 | }; |
| 255 | 301 | ||
| 256 | struct nfs_lockt_args { | 302 | struct nfs_lockt_args { |
| 257 | struct nfs_fh * fh; | 303 | struct nfs_fh * fh; |
| 258 | struct file_lock * fl; | 304 | struct file_lock * fl; |
| 259 | struct nfs_lowner lock_owner; | 305 | struct nfs_lowner lock_owner; |
| 306 | struct nfs4_sequence_args seq_args; | ||
| 260 | }; | 307 | }; |
| 261 | 308 | ||
| 262 | struct nfs_lockt_res { | 309 | struct nfs_lockt_res { |
| 263 | struct file_lock * denied; /* LOCK, LOCKT failed */ | 310 | struct file_lock * denied; /* LOCK, LOCKT failed */ |
| 311 | struct nfs4_sequence_res seq_res; | ||
| 264 | }; | 312 | }; |
| 265 | 313 | ||
| 266 | struct nfs4_delegreturnargs { | 314 | struct nfs4_delegreturnargs { |
| 267 | const struct nfs_fh *fhandle; | 315 | const struct nfs_fh *fhandle; |
| 268 | const nfs4_stateid *stateid; | 316 | const nfs4_stateid *stateid; |
| 269 | const u32 * bitmask; | 317 | const u32 * bitmask; |
| 318 | struct nfs4_sequence_args seq_args; | ||
| 270 | }; | 319 | }; |
| 271 | 320 | ||
| 272 | struct nfs4_delegreturnres { | 321 | struct nfs4_delegreturnres { |
| 273 | struct nfs_fattr * fattr; | 322 | struct nfs_fattr * fattr; |
| 274 | const struct nfs_server *server; | 323 | const struct nfs_server *server; |
| 324 | struct nfs4_sequence_res seq_res; | ||
| 275 | }; | 325 | }; |
| 276 | 326 | ||
| 277 | /* | 327 | /* |
| @@ -284,12 +334,14 @@ struct nfs_readargs { | |||
| 284 | __u32 count; | 334 | __u32 count; |
| 285 | unsigned int pgbase; | 335 | unsigned int pgbase; |
| 286 | struct page ** pages; | 336 | struct page ** pages; |
| 337 | struct nfs4_sequence_args seq_args; | ||
| 287 | }; | 338 | }; |
| 288 | 339 | ||
| 289 | struct nfs_readres { | 340 | struct nfs_readres { |
| 290 | struct nfs_fattr * fattr; | 341 | struct nfs_fattr * fattr; |
| 291 | __u32 count; | 342 | __u32 count; |
| 292 | int eof; | 343 | int eof; |
| 344 | struct nfs4_sequence_res seq_res; | ||
| 293 | }; | 345 | }; |
| 294 | 346 | ||
| 295 | /* | 347 | /* |
| @@ -304,6 +356,7 @@ struct nfs_writeargs { | |||
| 304 | unsigned int pgbase; | 356 | unsigned int pgbase; |
| 305 | struct page ** pages; | 357 | struct page ** pages; |
| 306 | const u32 * bitmask; | 358 | const u32 * bitmask; |
| 359 | struct nfs4_sequence_args seq_args; | ||
| 307 | }; | 360 | }; |
| 308 | 361 | ||
| 309 | struct nfs_writeverf { | 362 | struct nfs_writeverf { |
| @@ -316,6 +369,7 @@ struct nfs_writeres { | |||
| 316 | struct nfs_writeverf * verf; | 369 | struct nfs_writeverf * verf; |
| 317 | __u32 count; | 370 | __u32 count; |
| 318 | const struct nfs_server *server; | 371 | const struct nfs_server *server; |
| 372 | struct nfs4_sequence_res seq_res; | ||
| 319 | }; | 373 | }; |
| 320 | 374 | ||
| 321 | /* | 375 | /* |
| @@ -325,12 +379,14 @@ struct nfs_removeargs { | |||
| 325 | const struct nfs_fh *fh; | 379 | const struct nfs_fh *fh; |
| 326 | struct qstr name; | 380 | struct qstr name; |
| 327 | const u32 * bitmask; | 381 | const u32 * bitmask; |
| 382 | struct nfs4_sequence_args seq_args; | ||
| 328 | }; | 383 | }; |
| 329 | 384 | ||
| 330 | struct nfs_removeres { | 385 | struct nfs_removeres { |
| 331 | const struct nfs_server *server; | 386 | const struct nfs_server *server; |
| 332 | struct nfs4_change_info cinfo; | 387 | struct nfs4_change_info cinfo; |
| 333 | struct nfs_fattr dir_attr; | 388 | struct nfs_fattr dir_attr; |
| 389 | struct nfs4_sequence_res seq_res; | ||
| 334 | }; | 390 | }; |
| 335 | 391 | ||
| 336 | /* | 392 | /* |
| @@ -383,6 +439,7 @@ struct nfs_setattrargs { | |||
| 383 | struct iattr * iap; | 439 | struct iattr * iap; |
| 384 | const struct nfs_server * server; /* Needed for name mapping */ | 440 | const struct nfs_server * server; /* Needed for name mapping */ |
| 385 | const u32 * bitmask; | 441 | const u32 * bitmask; |
| 442 | struct nfs4_sequence_args seq_args; | ||
| 386 | }; | 443 | }; |
| 387 | 444 | ||
| 388 | struct nfs_setaclargs { | 445 | struct nfs_setaclargs { |
| @@ -390,6 +447,11 @@ struct nfs_setaclargs { | |||
| 390 | size_t acl_len; | 447 | size_t acl_len; |
| 391 | unsigned int acl_pgbase; | 448 | unsigned int acl_pgbase; |
| 392 | struct page ** acl_pages; | 449 | struct page ** acl_pages; |
| 450 | struct nfs4_sequence_args seq_args; | ||
| 451 | }; | ||
| 452 | |||
| 453 | struct nfs_setaclres { | ||
| 454 | struct nfs4_sequence_res seq_res; | ||
| 393 | }; | 455 | }; |
| 394 | 456 | ||
| 395 | struct nfs_getaclargs { | 457 | struct nfs_getaclargs { |
| @@ -397,11 +459,18 @@ struct nfs_getaclargs { | |||
| 397 | size_t acl_len; | 459 | size_t acl_len; |
| 398 | unsigned int acl_pgbase; | 460 | unsigned int acl_pgbase; |
| 399 | struct page ** acl_pages; | 461 | struct page ** acl_pages; |
| 462 | struct nfs4_sequence_args seq_args; | ||
| 463 | }; | ||
| 464 | |||
| 465 | struct nfs_getaclres { | ||
| 466 | size_t acl_len; | ||
| 467 | struct nfs4_sequence_res seq_res; | ||
| 400 | }; | 468 | }; |
| 401 | 469 | ||
| 402 | struct nfs_setattrres { | 470 | struct nfs_setattrres { |
| 403 | struct nfs_fattr * fattr; | 471 | struct nfs_fattr * fattr; |
| 404 | const struct nfs_server * server; | 472 | const struct nfs_server * server; |
| 473 | struct nfs4_sequence_res seq_res; | ||
| 405 | }; | 474 | }; |
| 406 | 475 | ||
| 407 | struct nfs_linkargs { | 476 | struct nfs_linkargs { |
| @@ -583,6 +652,7 @@ struct nfs4_accessargs { | |||
| 583 | const struct nfs_fh * fh; | 652 | const struct nfs_fh * fh; |
| 584 | const u32 * bitmask; | 653 | const u32 * bitmask; |
| 585 | u32 access; | 654 | u32 access; |
| 655 | struct nfs4_sequence_args seq_args; | ||
| 586 | }; | 656 | }; |
| 587 | 657 | ||
| 588 | struct nfs4_accessres { | 658 | struct nfs4_accessres { |
| @@ -590,6 +660,7 @@ struct nfs4_accessres { | |||
| 590 | struct nfs_fattr * fattr; | 660 | struct nfs_fattr * fattr; |
| 591 | u32 supported; | 661 | u32 supported; |
| 592 | u32 access; | 662 | u32 access; |
| 663 | struct nfs4_sequence_res seq_res; | ||
| 593 | }; | 664 | }; |
| 594 | 665 | ||
| 595 | struct nfs4_create_arg { | 666 | struct nfs4_create_arg { |
| @@ -609,6 +680,7 @@ struct nfs4_create_arg { | |||
| 609 | const struct iattr * attrs; | 680 | const struct iattr * attrs; |
| 610 | const struct nfs_fh * dir_fh; | 681 | const struct nfs_fh * dir_fh; |
| 611 | const u32 * bitmask; | 682 | const u32 * bitmask; |
| 683 | struct nfs4_sequence_args seq_args; | ||
| 612 | }; | 684 | }; |
| 613 | 685 | ||
| 614 | struct nfs4_create_res { | 686 | struct nfs4_create_res { |
| @@ -617,21 +689,30 @@ struct nfs4_create_res { | |||
| 617 | struct nfs_fattr * fattr; | 689 | struct nfs_fattr * fattr; |
| 618 | struct nfs4_change_info dir_cinfo; | 690 | struct nfs4_change_info dir_cinfo; |
| 619 | struct nfs_fattr * dir_fattr; | 691 | struct nfs_fattr * dir_fattr; |
| 692 | struct nfs4_sequence_res seq_res; | ||
| 620 | }; | 693 | }; |
| 621 | 694 | ||
| 622 | struct nfs4_fsinfo_arg { | 695 | struct nfs4_fsinfo_arg { |
| 623 | const struct nfs_fh * fh; | 696 | const struct nfs_fh * fh; |
| 624 | const u32 * bitmask; | 697 | const u32 * bitmask; |
| 698 | struct nfs4_sequence_args seq_args; | ||
| 699 | }; | ||
| 700 | |||
| 701 | struct nfs4_fsinfo_res { | ||
| 702 | struct nfs_fsinfo *fsinfo; | ||
| 703 | struct nfs4_sequence_res seq_res; | ||
| 625 | }; | 704 | }; |
| 626 | 705 | ||
| 627 | struct nfs4_getattr_arg { | 706 | struct nfs4_getattr_arg { |
| 628 | const struct nfs_fh * fh; | 707 | const struct nfs_fh * fh; |
| 629 | const u32 * bitmask; | 708 | const u32 * bitmask; |
| 709 | struct nfs4_sequence_args seq_args; | ||
| 630 | }; | 710 | }; |
| 631 | 711 | ||
| 632 | struct nfs4_getattr_res { | 712 | struct nfs4_getattr_res { |
| 633 | const struct nfs_server * server; | 713 | const struct nfs_server * server; |
| 634 | struct nfs_fattr * fattr; | 714 | struct nfs_fattr * fattr; |
| 715 | struct nfs4_sequence_res seq_res; | ||
| 635 | }; | 716 | }; |
| 636 | 717 | ||
| 637 | struct nfs4_link_arg { | 718 | struct nfs4_link_arg { |
| @@ -639,6 +720,7 @@ struct nfs4_link_arg { | |||
| 639 | const struct nfs_fh * dir_fh; | 720 | const struct nfs_fh * dir_fh; |
| 640 | const struct qstr * name; | 721 | const struct qstr * name; |
| 641 | const u32 * bitmask; | 722 | const u32 * bitmask; |
| 723 | struct nfs4_sequence_args seq_args; | ||
| 642 | }; | 724 | }; |
| 643 | 725 | ||
| 644 | struct nfs4_link_res { | 726 | struct nfs4_link_res { |
| @@ -646,6 +728,7 @@ struct nfs4_link_res { | |||
| 646 | struct nfs_fattr * fattr; | 728 | struct nfs_fattr * fattr; |
| 647 | struct nfs4_change_info cinfo; | 729 | struct nfs4_change_info cinfo; |
| 648 | struct nfs_fattr * dir_attr; | 730 | struct nfs_fattr * dir_attr; |
| 731 | struct nfs4_sequence_res seq_res; | ||
| 649 | }; | 732 | }; |
| 650 | 733 | ||
| 651 | 734 | ||
| @@ -653,21 +736,30 @@ struct nfs4_lookup_arg { | |||
| 653 | const struct nfs_fh * dir_fh; | 736 | const struct nfs_fh * dir_fh; |
| 654 | const struct qstr * name; | 737 | const struct qstr * name; |
| 655 | const u32 * bitmask; | 738 | const u32 * bitmask; |
| 739 | struct nfs4_sequence_args seq_args; | ||
| 656 | }; | 740 | }; |
| 657 | 741 | ||
| 658 | struct nfs4_lookup_res { | 742 | struct nfs4_lookup_res { |
| 659 | const struct nfs_server * server; | 743 | const struct nfs_server * server; |
| 660 | struct nfs_fattr * fattr; | 744 | struct nfs_fattr * fattr; |
| 661 | struct nfs_fh * fh; | 745 | struct nfs_fh * fh; |
| 746 | struct nfs4_sequence_res seq_res; | ||
| 662 | }; | 747 | }; |
| 663 | 748 | ||
| 664 | struct nfs4_lookup_root_arg { | 749 | struct nfs4_lookup_root_arg { |
| 665 | const u32 * bitmask; | 750 | const u32 * bitmask; |
| 751 | struct nfs4_sequence_args seq_args; | ||
| 666 | }; | 752 | }; |
| 667 | 753 | ||
| 668 | struct nfs4_pathconf_arg { | 754 | struct nfs4_pathconf_arg { |
| 669 | const struct nfs_fh * fh; | 755 | const struct nfs_fh * fh; |
| 670 | const u32 * bitmask; | 756 | const u32 * bitmask; |
| 757 | struct nfs4_sequence_args seq_args; | ||
| 758 | }; | ||
| 759 | |||
| 760 | struct nfs4_pathconf_res { | ||
| 761 | struct nfs_pathconf *pathconf; | ||
| 762 | struct nfs4_sequence_res seq_res; | ||
| 671 | }; | 763 | }; |
| 672 | 764 | ||
| 673 | struct nfs4_readdir_arg { | 765 | struct nfs4_readdir_arg { |
| @@ -678,11 +770,13 @@ struct nfs4_readdir_arg { | |||
| 678 | struct page ** pages; /* zero-copy data */ | 770 | struct page ** pages; /* zero-copy data */ |
| 679 | unsigned int pgbase; /* zero-copy data */ | 771 | unsigned int pgbase; /* zero-copy data */ |
| 680 | const u32 * bitmask; | 772 | const u32 * bitmask; |
| 773 | struct nfs4_sequence_args seq_args; | ||
| 681 | }; | 774 | }; |
| 682 | 775 | ||
| 683 | struct nfs4_readdir_res { | 776 | struct nfs4_readdir_res { |
| 684 | nfs4_verifier verifier; | 777 | nfs4_verifier verifier; |
| 685 | unsigned int pgbase; | 778 | unsigned int pgbase; |
| 779 | struct nfs4_sequence_res seq_res; | ||
| 686 | }; | 780 | }; |
| 687 | 781 | ||
| 688 | struct nfs4_readlink { | 782 | struct nfs4_readlink { |
| @@ -690,6 +784,11 @@ struct nfs4_readlink { | |||
| 690 | unsigned int pgbase; | 784 | unsigned int pgbase; |
| 691 | unsigned int pglen; /* zero-copy data */ | 785 | unsigned int pglen; /* zero-copy data */ |
| 692 | struct page ** pages; /* zero-copy data */ | 786 | struct page ** pages; /* zero-copy data */ |
| 787 | struct nfs4_sequence_args seq_args; | ||
| 788 | }; | ||
| 789 | |||
| 790 | struct nfs4_readlink_res { | ||
| 791 | struct nfs4_sequence_res seq_res; | ||
| 693 | }; | 792 | }; |
| 694 | 793 | ||
| 695 | struct nfs4_rename_arg { | 794 | struct nfs4_rename_arg { |
| @@ -698,6 +797,7 @@ struct nfs4_rename_arg { | |||
| 698 | const struct qstr * old_name; | 797 | const struct qstr * old_name; |
| 699 | const struct qstr * new_name; | 798 | const struct qstr * new_name; |
| 700 | const u32 * bitmask; | 799 | const u32 * bitmask; |
| 800 | struct nfs4_sequence_args seq_args; | ||
| 701 | }; | 801 | }; |
| 702 | 802 | ||
| 703 | struct nfs4_rename_res { | 803 | struct nfs4_rename_res { |
| @@ -706,6 +806,7 @@ struct nfs4_rename_res { | |||
| 706 | struct nfs_fattr * old_fattr; | 806 | struct nfs_fattr * old_fattr; |
| 707 | struct nfs4_change_info new_cinfo; | 807 | struct nfs4_change_info new_cinfo; |
| 708 | struct nfs_fattr * new_fattr; | 808 | struct nfs_fattr * new_fattr; |
| 809 | struct nfs4_sequence_res seq_res; | ||
| 709 | }; | 810 | }; |
| 710 | 811 | ||
| 711 | #define NFS4_SETCLIENTID_NAMELEN (127) | 812 | #define NFS4_SETCLIENTID_NAMELEN (127) |
| @@ -724,6 +825,17 @@ struct nfs4_setclientid { | |||
| 724 | struct nfs4_statfs_arg { | 825 | struct nfs4_statfs_arg { |
| 725 | const struct nfs_fh * fh; | 826 | const struct nfs_fh * fh; |
| 726 | const u32 * bitmask; | 827 | const u32 * bitmask; |
| 828 | struct nfs4_sequence_args seq_args; | ||
| 829 | }; | ||
| 830 | |||
| 831 | struct nfs4_statfs_res { | ||
| 832 | struct nfs_fsstat *fsstat; | ||
| 833 | struct nfs4_sequence_res seq_res; | ||
| 834 | }; | ||
| 835 | |||
| 836 | struct nfs4_server_caps_arg { | ||
| 837 | struct nfs_fh *fhandle; | ||
| 838 | struct nfs4_sequence_args seq_args; | ||
| 727 | }; | 839 | }; |
| 728 | 840 | ||
| 729 | struct nfs4_server_caps_res { | 841 | struct nfs4_server_caps_res { |
| @@ -731,6 +843,7 @@ struct nfs4_server_caps_res { | |||
| 731 | u32 acl_bitmask; | 843 | u32 acl_bitmask; |
| 732 | u32 has_links; | 844 | u32 has_links; |
| 733 | u32 has_symlinks; | 845 | u32 has_symlinks; |
| 846 | struct nfs4_sequence_res seq_res; | ||
| 734 | }; | 847 | }; |
| 735 | 848 | ||
| 736 | struct nfs4_string { | 849 | struct nfs4_string { |
| @@ -765,10 +878,68 @@ struct nfs4_fs_locations_arg { | |||
| 765 | const struct qstr *name; | 878 | const struct qstr *name; |
| 766 | struct page *page; | 879 | struct page *page; |
| 767 | const u32 *bitmask; | 880 | const u32 *bitmask; |
| 881 | struct nfs4_sequence_args seq_args; | ||
| 882 | }; | ||
| 883 | |||
| 884 | struct nfs4_fs_locations_res { | ||
| 885 | struct nfs4_fs_locations *fs_locations; | ||
| 886 | struct nfs4_sequence_res seq_res; | ||
| 768 | }; | 887 | }; |
| 769 | 888 | ||
| 770 | #endif /* CONFIG_NFS_V4 */ | 889 | #endif /* CONFIG_NFS_V4 */ |
| 771 | 890 | ||
| 891 | struct nfstime4 { | ||
| 892 | u64 seconds; | ||
| 893 | u32 nseconds; | ||
| 894 | }; | ||
| 895 | |||
| 896 | #ifdef CONFIG_NFS_V4_1 | ||
| 897 | struct nfs_impl_id4 { | ||
| 898 | u32 domain_len; | ||
| 899 | char *domain; | ||
| 900 | u32 name_len; | ||
| 901 | char *name; | ||
| 902 | struct nfstime4 date; | ||
| 903 | }; | ||
| 904 | |||
| 905 | #define NFS4_EXCHANGE_ID_LEN (48) | ||
| 906 | struct nfs41_exchange_id_args { | ||
| 907 | struct nfs_client *client; | ||
| 908 | nfs4_verifier *verifier; | ||
| 909 | unsigned int id_len; | ||
| 910 | char id[NFS4_EXCHANGE_ID_LEN]; | ||
| 911 | u32 flags; | ||
| 912 | }; | ||
| 913 | |||
| 914 | struct server_owner { | ||
| 915 | uint64_t minor_id; | ||
| 916 | uint32_t major_id_sz; | ||
| 917 | char major_id[NFS4_OPAQUE_LIMIT]; | ||
| 918 | }; | ||
| 919 | |||
| 920 | struct server_scope { | ||
| 921 | uint32_t server_scope_sz; | ||
| 922 | char server_scope[NFS4_OPAQUE_LIMIT]; | ||
| 923 | }; | ||
| 924 | |||
| 925 | struct nfs41_exchange_id_res { | ||
| 926 | struct nfs_client *client; | ||
| 927 | u32 flags; | ||
| 928 | }; | ||
| 929 | |||
| 930 | struct nfs41_create_session_args { | ||
| 931 | struct nfs_client *client; | ||
| 932 | uint32_t flags; | ||
| 933 | uint32_t cb_program; | ||
| 934 | struct nfs4_channel_attrs fc_attrs; /* Fore Channel */ | ||
| 935 | struct nfs4_channel_attrs bc_attrs; /* Back Channel */ | ||
| 936 | }; | ||
| 937 | |||
| 938 | struct nfs41_create_session_res { | ||
| 939 | struct nfs_client *client; | ||
| 940 | }; | ||
| 941 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 942 | |||
| 772 | struct nfs_page; | 943 | struct nfs_page; |
| 773 | 944 | ||
| 774 | #define NFS_PAGEVEC_SIZE (8U) | 945 | #define NFS_PAGEVEC_SIZE (8U) |
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 4d61c873feed..7ef4b7ad1214 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h | |||
| @@ -41,7 +41,6 @@ | |||
| 41 | #include <linux/kref.h> | 41 | #include <linux/kref.h> |
| 42 | #include <linux/sunrpc/clnt.h> | 42 | #include <linux/sunrpc/clnt.h> |
| 43 | 43 | ||
| 44 | #define NFS4_OPAQUE_LIMIT 1024 | ||
| 45 | typedef struct { | 44 | typedef struct { |
| 46 | u32 cl_boot; | 45 | u32 cl_boot; |
| 47 | u32 cl_id; | 46 | u32 cl_id; |
diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h new file mode 100644 index 000000000000..6508f0dc0eff --- /dev/null +++ b/include/linux/sunrpc/bc_xprt.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | |||
| 3 | (c) 2008 NetApp. All Rights Reserved. | ||
| 4 | |||
| 5 | NetApp provides this source code under the GPL v2 License. | ||
| 6 | The GPL v2 license is available at | ||
| 7 | http://opensource.org/licenses/gpl-license.php. | ||
| 8 | |||
| 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 10 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 11 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 12 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
| 13 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| 14 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| 15 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
| 16 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 17 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 18 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| 19 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 20 | |||
| 21 | ******************************************************************************/ | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Functions to create and manage the backchannel | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef _LINUX_SUNRPC_BC_XPRT_H | ||
| 28 | #define _LINUX_SUNRPC_BC_XPRT_H | ||
| 29 | |||
| 30 | #include <linux/sunrpc/svcsock.h> | ||
| 31 | #include <linux/sunrpc/xprt.h> | ||
| 32 | #include <linux/sunrpc/sched.h> | ||
| 33 | |||
| 34 | #ifdef CONFIG_NFS_V4_1 | ||
| 35 | struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt); | ||
| 36 | void xprt_free_bc_request(struct rpc_rqst *req); | ||
| 37 | int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); | ||
| 38 | void xprt_destroy_backchannel(struct rpc_xprt *, int max_reqs); | ||
| 39 | void bc_release_request(struct rpc_task *); | ||
| 40 | int bc_send(struct rpc_rqst *req); | ||
| 41 | #else /* CONFIG_NFS_V4_1 */ | ||
| 42 | static inline int xprt_setup_backchannel(struct rpc_xprt *xprt, | ||
| 43 | unsigned int min_reqs) | ||
| 44 | { | ||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 48 | #endif /* _LINUX_SUNRPC_BC_XPRT_H */ | ||
| 49 | |||
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index c39a21040dcb..37881f1a0bd7 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
| @@ -143,6 +143,7 @@ int rpc_call_sync(struct rpc_clnt *clnt, | |||
| 143 | const struct rpc_message *msg, int flags); | 143 | const struct rpc_message *msg, int flags); |
| 144 | struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, | 144 | struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, |
| 145 | int flags); | 145 | int flags); |
| 146 | void rpc_restart_call_prepare(struct rpc_task *); | ||
| 146 | void rpc_restart_call(struct rpc_task *); | 147 | void rpc_restart_call(struct rpc_task *); |
| 147 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); | 148 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); |
| 148 | size_t rpc_max_payload(struct rpc_clnt *); | 149 | size_t rpc_max_payload(struct rpc_clnt *); |
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 64981a2f1cae..401097781fc0 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
| @@ -210,6 +210,8 @@ struct rpc_wait_queue { | |||
| 210 | */ | 210 | */ |
| 211 | struct rpc_task *rpc_new_task(const struct rpc_task_setup *); | 211 | struct rpc_task *rpc_new_task(const struct rpc_task_setup *); |
| 212 | struct rpc_task *rpc_run_task(const struct rpc_task_setup *); | 212 | struct rpc_task *rpc_run_task(const struct rpc_task_setup *); |
| 213 | struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, | ||
| 214 | const struct rpc_call_ops *ops); | ||
| 213 | void rpc_put_task(struct rpc_task *); | 215 | void rpc_put_task(struct rpc_task *); |
| 214 | void rpc_exit_task(struct rpc_task *); | 216 | void rpc_exit_task(struct rpc_task *); |
| 215 | void rpc_release_calldata(const struct rpc_call_ops *, void *); | 217 | void rpc_release_calldata(const struct rpc_call_ops *, void *); |
| @@ -237,6 +239,7 @@ void rpc_show_tasks(void); | |||
| 237 | int rpc_init_mempool(void); | 239 | int rpc_init_mempool(void); |
| 238 | void rpc_destroy_mempool(void); | 240 | void rpc_destroy_mempool(void); |
| 239 | extern struct workqueue_struct *rpciod_workqueue; | 241 | extern struct workqueue_struct *rpciod_workqueue; |
| 242 | void rpc_prepare_task(struct rpc_task *task); | ||
| 240 | 243 | ||
| 241 | static inline void rpc_exit(struct rpc_task *task, int status) | 244 | static inline void rpc_exit(struct rpc_task *task, int status) |
| 242 | { | 245 | { |
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 2a30775959e9..ea8009695c69 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
| @@ -96,6 +96,15 @@ struct svc_serv { | |||
| 96 | svc_thread_fn sv_function; /* main function for threads */ | 96 | svc_thread_fn sv_function; /* main function for threads */ |
| 97 | unsigned int sv_drc_max_pages; /* Total pages for DRC */ | 97 | unsigned int sv_drc_max_pages; /* Total pages for DRC */ |
| 98 | unsigned int sv_drc_pages_used;/* DRC pages used */ | 98 | unsigned int sv_drc_pages_used;/* DRC pages used */ |
| 99 | #if defined(CONFIG_NFS_V4_1) | ||
| 100 | struct list_head sv_cb_list; /* queue for callback requests | ||
| 101 | * that arrive over the same | ||
| 102 | * connection */ | ||
| 103 | spinlock_t sv_cb_lock; /* protects the svc_cb_list */ | ||
| 104 | wait_queue_head_t sv_cb_waitq; /* sleep here if there are no | ||
| 105 | * entries in the svc_cb_list */ | ||
| 106 | struct svc_xprt *bc_xprt; | ||
| 107 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 99 | }; | 108 | }; |
| 100 | 109 | ||
| 101 | /* | 110 | /* |
| @@ -411,6 +420,8 @@ int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); | |||
| 411 | int svc_pool_stats_open(struct svc_serv *serv, struct file *file); | 420 | int svc_pool_stats_open(struct svc_serv *serv, struct file *file); |
| 412 | void svc_destroy(struct svc_serv *); | 421 | void svc_destroy(struct svc_serv *); |
| 413 | int svc_process(struct svc_rqst *); | 422 | int svc_process(struct svc_rqst *); |
| 423 | int bc_svc_process(struct svc_serv *, struct rpc_rqst *, | ||
| 424 | struct svc_rqst *); | ||
| 414 | int svc_register(const struct svc_serv *, const int, | 425 | int svc_register(const struct svc_serv *, const int, |
| 415 | const unsigned short, const unsigned short); | 426 | const unsigned short, const unsigned short); |
| 416 | 427 | ||
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 483e10380aae..6bb1ec4ae310 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h | |||
| @@ -42,6 +42,8 @@ int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose); | |||
| 42 | int svc_addsock(struct svc_serv *serv, int fd, char *name_return); | 42 | int svc_addsock(struct svc_serv *serv, int fd, char *name_return); |
| 43 | void svc_init_xprt_sock(void); | 43 | void svc_init_xprt_sock(void); |
| 44 | void svc_cleanup_xprt_sock(void); | 44 | void svc_cleanup_xprt_sock(void); |
| 45 | struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot); | ||
| 46 | void svc_sock_destroy(struct svc_xprt *); | ||
| 45 | 47 | ||
| 46 | /* | 48 | /* |
| 47 | * svc_makesock socket characteristics | 49 | * svc_makesock socket characteristics |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 08afe43118f4..1175d58efc2e 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -67,7 +67,8 @@ struct rpc_rqst { | |||
| 67 | struct rpc_task * rq_task; /* RPC task data */ | 67 | struct rpc_task * rq_task; /* RPC task data */ |
| 68 | __be32 rq_xid; /* request XID */ | 68 | __be32 rq_xid; /* request XID */ |
| 69 | int rq_cong; /* has incremented xprt->cong */ | 69 | int rq_cong; /* has incremented xprt->cong */ |
| 70 | int rq_received; /* receive completed */ | 70 | int rq_reply_bytes_recvd; /* number of reply */ |
| 71 | /* bytes received */ | ||
| 71 | u32 rq_seqno; /* gss seq no. used on req. */ | 72 | u32 rq_seqno; /* gss seq no. used on req. */ |
| 72 | int rq_enc_pages_num; | 73 | int rq_enc_pages_num; |
| 73 | struct page **rq_enc_pages; /* scratch pages for use by | 74 | struct page **rq_enc_pages; /* scratch pages for use by |
| @@ -97,6 +98,12 @@ struct rpc_rqst { | |||
| 97 | 98 | ||
| 98 | unsigned long rq_xtime; /* when transmitted */ | 99 | unsigned long rq_xtime; /* when transmitted */ |
| 99 | int rq_ntrans; | 100 | int rq_ntrans; |
| 101 | |||
| 102 | #if defined(CONFIG_NFS_V4_1) | ||
| 103 | struct list_head rq_bc_list; /* Callback service list */ | ||
| 104 | unsigned long rq_bc_pa_state; /* Backchannel prealloc state */ | ||
| 105 | struct list_head rq_bc_pa_list; /* Backchannel prealloc list */ | ||
| 106 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 100 | }; | 107 | }; |
| 101 | #define rq_svec rq_snd_buf.head | 108 | #define rq_svec rq_snd_buf.head |
| 102 | #define rq_slen rq_snd_buf.len | 109 | #define rq_slen rq_snd_buf.len |
| @@ -174,6 +181,15 @@ struct rpc_xprt { | |||
| 174 | spinlock_t reserve_lock; /* lock slot table */ | 181 | spinlock_t reserve_lock; /* lock slot table */ |
| 175 | u32 xid; /* Next XID value to use */ | 182 | u32 xid; /* Next XID value to use */ |
| 176 | struct rpc_task * snd_task; /* Task blocked in send */ | 183 | struct rpc_task * snd_task; /* Task blocked in send */ |
| 184 | #if defined(CONFIG_NFS_V4_1) | ||
| 185 | struct svc_serv *bc_serv; /* The RPC service which will */ | ||
| 186 | /* process the callback */ | ||
| 187 | unsigned int bc_alloc_count; /* Total number of preallocs */ | ||
| 188 | spinlock_t bc_pa_lock; /* Protects the preallocated | ||
| 189 | * items */ | ||
| 190 | struct list_head bc_pa_list; /* List of preallocated | ||
| 191 | * backchannel rpc_rqst's */ | ||
| 192 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 177 | struct list_head recv; | 193 | struct list_head recv; |
| 178 | 194 | ||
| 179 | struct { | 195 | struct { |
| @@ -192,6 +208,26 @@ struct rpc_xprt { | |||
| 192 | const char *address_strings[RPC_DISPLAY_MAX]; | 208 | const char *address_strings[RPC_DISPLAY_MAX]; |
| 193 | }; | 209 | }; |
| 194 | 210 | ||
| 211 | #if defined(CONFIG_NFS_V4_1) | ||
| 212 | /* | ||
| 213 | * Backchannel flags | ||
| 214 | */ | ||
| 215 | #define RPC_BC_PA_IN_USE 0x0001 /* Preallocated backchannel */ | ||
| 216 | /* buffer in use */ | ||
| 217 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 218 | |||
| 219 | #if defined(CONFIG_NFS_V4_1) | ||
| 220 | static inline int bc_prealloc(struct rpc_rqst *req) | ||
| 221 | { | ||
| 222 | return test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); | ||
| 223 | } | ||
| 224 | #else | ||
| 225 | static inline int bc_prealloc(struct rpc_rqst *req) | ||
| 226 | { | ||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 230 | |||
| 195 | struct xprt_create { | 231 | struct xprt_create { |
| 196 | int ident; /* XPRT_TRANSPORT identifier */ | 232 | int ident; /* XPRT_TRANSPORT identifier */ |
| 197 | struct sockaddr * srcaddr; /* optional local address */ | 233 | struct sockaddr * srcaddr; /* optional local address */ |
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile index 5369aa369b35..db73fd2a3f0e 100644 --- a/net/sunrpc/Makefile +++ b/net/sunrpc/Makefile | |||
| @@ -13,5 +13,6 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ | |||
| 13 | rpcb_clnt.o timer.o xdr.o \ | 13 | rpcb_clnt.o timer.o xdr.o \ |
| 14 | sunrpc_syms.o cache.o rpc_pipe.o \ | 14 | sunrpc_syms.o cache.o rpc_pipe.o \ |
| 15 | svc_xprt.o | 15 | svc_xprt.o |
| 16 | sunrpc-$(CONFIG_NFS_V4_1) += backchannel_rqst.o bc_svc.o | ||
| 16 | sunrpc-$(CONFIG_PROC_FS) += stats.o | 17 | sunrpc-$(CONFIG_PROC_FS) += stats.o |
| 17 | sunrpc-$(CONFIG_SYSCTL) += sysctl.o | 18 | sunrpc-$(CONFIG_SYSCTL) += sysctl.o |
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c new file mode 100644 index 000000000000..5a7d342e3087 --- /dev/null +++ b/net/sunrpc/backchannel_rqst.c | |||
| @@ -0,0 +1,278 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | |||
| 3 | (c) 2007 Network Appliance, Inc. All Rights Reserved. | ||
| 4 | (c) 2009 NetApp. All Rights Reserved. | ||
| 5 | |||
| 6 | NetApp provides this source code under the GPL v2 License. | ||
| 7 | The GPL v2 license is available at | ||
| 8 | http://opensource.org/licenses/gpl-license.php. | ||
| 9 | |||
| 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 11 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 12 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 13 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
| 14 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| 15 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| 16 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
| 17 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 18 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 19 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| 20 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 21 | |||
| 22 | ******************************************************************************/ | ||
| 23 | |||
| 24 | #include <linux/tcp.h> | ||
| 25 | #include <linux/sunrpc/xprt.h> | ||
| 26 | |||
| 27 | #ifdef RPC_DEBUG | ||
| 28 | #define RPCDBG_FACILITY RPCDBG_TRANS | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #if defined(CONFIG_NFS_V4_1) | ||
| 32 | |||
| 33 | /* | ||
| 34 | * Helper routines that track the number of preallocation elements | ||
| 35 | * on the transport. | ||
| 36 | */ | ||
| 37 | static inline int xprt_need_to_requeue(struct rpc_xprt *xprt) | ||
| 38 | { | ||
| 39 | return xprt->bc_alloc_count > 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | static inline void xprt_inc_alloc_count(struct rpc_xprt *xprt, unsigned int n) | ||
| 43 | { | ||
| 44 | xprt->bc_alloc_count += n; | ||
| 45 | } | ||
| 46 | |||
| 47 | static inline int xprt_dec_alloc_count(struct rpc_xprt *xprt, unsigned int n) | ||
| 48 | { | ||
| 49 | return xprt->bc_alloc_count -= n; | ||
| 50 | } | ||
| 51 | |||
| 52 | /* | ||
| 53 | * Free the preallocated rpc_rqst structure and the memory | ||
| 54 | * buffers hanging off of it. | ||
| 55 | */ | ||
| 56 | static void xprt_free_allocation(struct rpc_rqst *req) | ||
| 57 | { | ||
| 58 | struct xdr_buf *xbufp; | ||
| 59 | |||
| 60 | dprintk("RPC: free allocations for req= %p\n", req); | ||
| 61 | BUG_ON(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); | ||
| 62 | xbufp = &req->rq_private_buf; | ||
| 63 | free_page((unsigned long)xbufp->head[0].iov_base); | ||
| 64 | xbufp = &req->rq_snd_buf; | ||
| 65 | free_page((unsigned long)xbufp->head[0].iov_base); | ||
| 66 | list_del(&req->rq_bc_pa_list); | ||
| 67 | kfree(req); | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Preallocate up to min_reqs structures and related buffers for use | ||
| 72 | * by the backchannel. This function can be called multiple times | ||
| 73 | * when creating new sessions that use the same rpc_xprt. The | ||
| 74 | * preallocated buffers are added to the pool of resources used by | ||
| 75 | * the rpc_xprt. Anyone of these resources may be used used by an | ||
| 76 | * incoming callback request. It's up to the higher levels in the | ||
| 77 | * stack to enforce that the maximum number of session slots is not | ||
| 78 | * being exceeded. | ||
| 79 | * | ||
| 80 | * Some callback arguments can be large. For example, a pNFS server | ||
| 81 | * using multiple deviceids. The list can be unbound, but the client | ||
| 82 | * has the ability to tell the server the maximum size of the callback | ||
| 83 | * requests. Each deviceID is 16 bytes, so allocate one page | ||
| 84 | * for the arguments to have enough room to receive a number of these | ||
| 85 | * deviceIDs. The NFS client indicates to the pNFS server that its | ||
| 86 | * callback requests can be up to 4096 bytes in size. | ||
| 87 | */ | ||
| 88 | int xprt_setup_backchannel(struct rpc_xprt *xprt, unsigned int min_reqs) | ||
| 89 | { | ||
| 90 | struct page *page_rcv = NULL, *page_snd = NULL; | ||
| 91 | struct xdr_buf *xbufp = NULL; | ||
| 92 | struct rpc_rqst *req, *tmp; | ||
| 93 | struct list_head tmp_list; | ||
| 94 | int i; | ||
| 95 | |||
| 96 | dprintk("RPC: setup backchannel transport\n"); | ||
| 97 | |||
| 98 | /* | ||
| 99 | * We use a temporary list to keep track of the preallocated | ||
| 100 | * buffers. Once we're done building the list we splice it | ||
| 101 | * into the backchannel preallocation list off of the rpc_xprt | ||
| 102 | * struct. This helps minimize the amount of time the list | ||
| 103 | * lock is held on the rpc_xprt struct. It also makes cleanup | ||
| 104 | * easier in case of memory allocation errors. | ||
| 105 | */ | ||
| 106 | INIT_LIST_HEAD(&tmp_list); | ||
| 107 | for (i = 0; i < min_reqs; i++) { | ||
| 108 | /* Pre-allocate one backchannel rpc_rqst */ | ||
| 109 | req = kzalloc(sizeof(struct rpc_rqst), GFP_KERNEL); | ||
| 110 | if (req == NULL) { | ||
| 111 | printk(KERN_ERR "Failed to create bc rpc_rqst\n"); | ||
| 112 | goto out_free; | ||
| 113 | } | ||
| 114 | |||
| 115 | /* Add the allocated buffer to the tmp list */ | ||
| 116 | dprintk("RPC: adding req= %p\n", req); | ||
| 117 | list_add(&req->rq_bc_pa_list, &tmp_list); | ||
| 118 | |||
| 119 | req->rq_xprt = xprt; | ||
| 120 | INIT_LIST_HEAD(&req->rq_list); | ||
| 121 | INIT_LIST_HEAD(&req->rq_bc_list); | ||
| 122 | |||
| 123 | /* Preallocate one XDR receive buffer */ | ||
| 124 | page_rcv = alloc_page(GFP_KERNEL); | ||
| 125 | if (page_rcv == NULL) { | ||
| 126 | printk(KERN_ERR "Failed to create bc receive xbuf\n"); | ||
| 127 | goto out_free; | ||
| 128 | } | ||
| 129 | xbufp = &req->rq_rcv_buf; | ||
| 130 | xbufp->head[0].iov_base = page_address(page_rcv); | ||
| 131 | xbufp->head[0].iov_len = PAGE_SIZE; | ||
| 132 | xbufp->tail[0].iov_base = NULL; | ||
| 133 | xbufp->tail[0].iov_len = 0; | ||
| 134 | xbufp->page_len = 0; | ||
| 135 | xbufp->len = PAGE_SIZE; | ||
| 136 | xbufp->buflen = PAGE_SIZE; | ||
| 137 | |||
| 138 | /* Preallocate one XDR send buffer */ | ||
| 139 | page_snd = alloc_page(GFP_KERNEL); | ||
| 140 | if (page_snd == NULL) { | ||
| 141 | printk(KERN_ERR "Failed to create bc snd xbuf\n"); | ||
| 142 | goto out_free; | ||
| 143 | } | ||
| 144 | |||
| 145 | xbufp = &req->rq_snd_buf; | ||
| 146 | xbufp->head[0].iov_base = page_address(page_snd); | ||
| 147 | xbufp->head[0].iov_len = 0; | ||
| 148 | xbufp->tail[0].iov_base = NULL; | ||
| 149 | xbufp->tail[0].iov_len = 0; | ||
| 150 | xbufp->page_len = 0; | ||
| 151 | xbufp->len = 0; | ||
| 152 | xbufp->buflen = PAGE_SIZE; | ||
| 153 | } | ||
| 154 | |||
| 155 | /* | ||
| 156 | * Add the temporary list to the backchannel preallocation list | ||
| 157 | */ | ||
| 158 | spin_lock_bh(&xprt->bc_pa_lock); | ||
| 159 | list_splice(&tmp_list, &xprt->bc_pa_list); | ||
| 160 | xprt_inc_alloc_count(xprt, min_reqs); | ||
| 161 | spin_unlock_bh(&xprt->bc_pa_lock); | ||
| 162 | |||
| 163 | dprintk("RPC: setup backchannel transport done\n"); | ||
| 164 | return 0; | ||
| 165 | |||
| 166 | out_free: | ||
| 167 | /* | ||
| 168 | * Memory allocation failed, free the temporary list | ||
| 169 | */ | ||
| 170 | list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) | ||
| 171 | xprt_free_allocation(req); | ||
| 172 | |||
| 173 | dprintk("RPC: setup backchannel transport failed\n"); | ||
| 174 | return -1; | ||
| 175 | } | ||
| 176 | EXPORT_SYMBOL(xprt_setup_backchannel); | ||
| 177 | |||
| 178 | /* | ||
| 179 | * Destroys the backchannel preallocated structures. | ||
| 180 | * Since these structures may have been allocated by multiple calls | ||
| 181 | * to xprt_setup_backchannel, we only destroy up to the maximum number | ||
| 182 | * of reqs specified by the caller. | ||
| 183 | * @xprt: the transport holding the preallocated strucures | ||
| 184 | * @max_reqs the maximum number of preallocated structures to destroy | ||
| 185 | */ | ||
| 186 | void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs) | ||
| 187 | { | ||
| 188 | struct rpc_rqst *req = NULL, *tmp = NULL; | ||
| 189 | |||
| 190 | dprintk("RPC: destroy backchannel transport\n"); | ||
| 191 | |||
| 192 | BUG_ON(max_reqs == 0); | ||
| 193 | spin_lock_bh(&xprt->bc_pa_lock); | ||
| 194 | xprt_dec_alloc_count(xprt, max_reqs); | ||
| 195 | list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) { | ||
| 196 | dprintk("RPC: req=%p\n", req); | ||
| 197 | xprt_free_allocation(req); | ||
| 198 | if (--max_reqs == 0) | ||
| 199 | break; | ||
| 200 | } | ||
| 201 | spin_unlock_bh(&xprt->bc_pa_lock); | ||
| 202 | |||
| 203 | dprintk("RPC: backchannel list empty= %s\n", | ||
| 204 | list_empty(&xprt->bc_pa_list) ? "true" : "false"); | ||
| 205 | } | ||
| 206 | EXPORT_SYMBOL(xprt_destroy_backchannel); | ||
| 207 | |||
| 208 | /* | ||
| 209 | * One or more rpc_rqst structure have been preallocated during the | ||
| 210 | * backchannel setup. Buffer space for the send and private XDR buffers | ||
| 211 | * has been preallocated as well. Use xprt_alloc_bc_request to allocate | ||
| 212 | * to this request. Use xprt_free_bc_request to return it. | ||
| 213 | * | ||
| 214 | * Return an available rpc_rqst, otherwise NULL if non are available. | ||
| 215 | */ | ||
| 216 | struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt) | ||
| 217 | { | ||
| 218 | struct rpc_rqst *req; | ||
| 219 | |||
| 220 | dprintk("RPC: allocate a backchannel request\n"); | ||
| 221 | spin_lock_bh(&xprt->bc_pa_lock); | ||
| 222 | if (!list_empty(&xprt->bc_pa_list)) { | ||
| 223 | req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst, | ||
| 224 | rq_bc_pa_list); | ||
| 225 | list_del(&req->rq_bc_pa_list); | ||
| 226 | } else { | ||
| 227 | req = NULL; | ||
| 228 | } | ||
| 229 | spin_unlock_bh(&xprt->bc_pa_lock); | ||
| 230 | |||
| 231 | if (req != NULL) { | ||
| 232 | set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); | ||
| 233 | req->rq_reply_bytes_recvd = 0; | ||
| 234 | req->rq_bytes_sent = 0; | ||
| 235 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, | ||
| 236 | sizeof(req->rq_private_buf)); | ||
| 237 | } | ||
| 238 | dprintk("RPC: backchannel req=%p\n", req); | ||
| 239 | return req; | ||
| 240 | } | ||
| 241 | |||
| 242 | /* | ||
| 243 | * Return the preallocated rpc_rqst structure and XDR buffers | ||
| 244 | * associated with this rpc_task. | ||
| 245 | */ | ||
| 246 | void xprt_free_bc_request(struct rpc_rqst *req) | ||
| 247 | { | ||
| 248 | struct rpc_xprt *xprt = req->rq_xprt; | ||
| 249 | |||
| 250 | dprintk("RPC: free backchannel req=%p\n", req); | ||
| 251 | |||
| 252 | smp_mb__before_clear_bit(); | ||
| 253 | BUG_ON(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); | ||
| 254 | clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); | ||
| 255 | smp_mb__after_clear_bit(); | ||
| 256 | |||
| 257 | if (!xprt_need_to_requeue(xprt)) { | ||
| 258 | /* | ||
| 259 | * The last remaining session was destroyed while this | ||
| 260 | * entry was in use. Free the entry and don't attempt | ||
| 261 | * to add back to the list because there is no need to | ||
| 262 | * have anymore preallocated entries. | ||
| 263 | */ | ||
| 264 | dprintk("RPC: Last session removed req=%p\n", req); | ||
| 265 | xprt_free_allocation(req); | ||
| 266 | return; | ||
| 267 | } | ||
| 268 | |||
| 269 | /* | ||
| 270 | * Return it to the list of preallocations so that it | ||
| 271 | * may be reused by a new callback request. | ||
| 272 | */ | ||
| 273 | spin_lock_bh(&xprt->bc_pa_lock); | ||
| 274 | list_add(&req->rq_bc_pa_list, &xprt->bc_pa_list); | ||
| 275 | spin_unlock_bh(&xprt->bc_pa_lock); | ||
| 276 | } | ||
| 277 | |||
| 278 | #endif /* CONFIG_NFS_V4_1 */ | ||
diff --git a/net/sunrpc/bc_svc.c b/net/sunrpc/bc_svc.c new file mode 100644 index 000000000000..13f214f53120 --- /dev/null +++ b/net/sunrpc/bc_svc.c | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | |||
| 3 | (c) 2007 Network Appliance, Inc. All Rights Reserved. | ||
| 4 | (c) 2009 NetApp. All Rights Reserved. | ||
| 5 | |||
| 6 | NetApp provides this source code under the GPL v2 License. | ||
| 7 | The GPL v2 license is available at | ||
| 8 | http://opensource.org/licenses/gpl-license.php. | ||
| 9 | |||
| 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 11 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 12 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 13 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
| 14 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| 15 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| 16 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
| 17 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 18 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 19 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| 20 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 21 | |||
| 22 | ******************************************************************************/ | ||
| 23 | |||
| 24 | /* | ||
| 25 | * The NFSv4.1 callback service helper routines. | ||
| 26 | * They implement the transport level processing required to send the | ||
| 27 | * reply over an existing open connection previously established by the client. | ||
| 28 | */ | ||
| 29 | |||
| 30 | #if defined(CONFIG_NFS_V4_1) | ||
| 31 | |||
| 32 | #include <linux/module.h> | ||
| 33 | |||
| 34 | #include <linux/sunrpc/xprt.h> | ||
| 35 | #include <linux/sunrpc/sched.h> | ||
| 36 | #include <linux/sunrpc/bc_xprt.h> | ||
| 37 | |||
| 38 | #define RPCDBG_FACILITY RPCDBG_SVCDSP | ||
| 39 | |||
| 40 | void bc_release_request(struct rpc_task *task) | ||
| 41 | { | ||
| 42 | struct rpc_rqst *req = task->tk_rqstp; | ||
| 43 | |||
| 44 | dprintk("RPC: bc_release_request: task= %p\n", task); | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Release this request only if it's a backchannel | ||
| 48 | * preallocated request | ||
| 49 | */ | ||
| 50 | if (!bc_prealloc(req)) | ||
| 51 | return; | ||
| 52 | xprt_free_bc_request(req); | ||
| 53 | } | ||
| 54 | |||
| 55 | /* Empty callback ops */ | ||
| 56 | static const struct rpc_call_ops nfs41_callback_ops = { | ||
| 57 | }; | ||
| 58 | |||
| 59 | |||
| 60 | /* | ||
| 61 | * Send the callback reply | ||
| 62 | */ | ||
| 63 | int bc_send(struct rpc_rqst *req) | ||
| 64 | { | ||
| 65 | struct rpc_task *task; | ||
| 66 | int ret; | ||
| 67 | |||
| 68 | dprintk("RPC: bc_send req= %p\n", req); | ||
| 69 | task = rpc_run_bc_task(req, &nfs41_callback_ops); | ||
| 70 | if (IS_ERR(task)) | ||
| 71 | ret = PTR_ERR(task); | ||
| 72 | else { | ||
| 73 | BUG_ON(atomic_read(&task->tk_count) != 1); | ||
| 74 | ret = task->tk_status; | ||
| 75 | rpc_put_task(task); | ||
| 76 | } | ||
| 77 | return ret; | ||
| 78 | dprintk("RPC: bc_send ret= %d \n", ret); | ||
| 79 | } | ||
| 80 | |||
| 81 | #endif /* CONFIG_NFS_V4_1 */ | ||
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 5abab094441f..5bc2f45bddf0 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -36,7 +36,9 @@ | |||
| 36 | #include <linux/sunrpc/clnt.h> | 36 | #include <linux/sunrpc/clnt.h> |
| 37 | #include <linux/sunrpc/rpc_pipe_fs.h> | 37 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 38 | #include <linux/sunrpc/metrics.h> | 38 | #include <linux/sunrpc/metrics.h> |
| 39 | #include <linux/sunrpc/bc_xprt.h> | ||
| 39 | 40 | ||
| 41 | #include "sunrpc.h" | ||
| 40 | 42 | ||
| 41 | #ifdef RPC_DEBUG | 43 | #ifdef RPC_DEBUG |
| 42 | # define RPCDBG_FACILITY RPCDBG_CALL | 44 | # define RPCDBG_FACILITY RPCDBG_CALL |
| @@ -63,6 +65,9 @@ static void call_decode(struct rpc_task *task); | |||
| 63 | static void call_bind(struct rpc_task *task); | 65 | static void call_bind(struct rpc_task *task); |
| 64 | static void call_bind_status(struct rpc_task *task); | 66 | static void call_bind_status(struct rpc_task *task); |
| 65 | static void call_transmit(struct rpc_task *task); | 67 | static void call_transmit(struct rpc_task *task); |
| 68 | #if defined(CONFIG_NFS_V4_1) | ||
| 69 | static void call_bc_transmit(struct rpc_task *task); | ||
| 70 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 66 | static void call_status(struct rpc_task *task); | 71 | static void call_status(struct rpc_task *task); |
| 67 | static void call_transmit_status(struct rpc_task *task); | 72 | static void call_transmit_status(struct rpc_task *task); |
| 68 | static void call_refresh(struct rpc_task *task); | 73 | static void call_refresh(struct rpc_task *task); |
| @@ -613,6 +618,50 @@ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags, | |||
| 613 | } | 618 | } |
| 614 | EXPORT_SYMBOL_GPL(rpc_call_async); | 619 | EXPORT_SYMBOL_GPL(rpc_call_async); |
| 615 | 620 | ||
| 621 | #if defined(CONFIG_NFS_V4_1) | ||
| 622 | /** | ||
| 623 | * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run | ||
| 624 | * rpc_execute against it | ||
| 625 | * @ops: RPC call ops | ||
| 626 | */ | ||
| 627 | struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, | ||
| 628 | const struct rpc_call_ops *tk_ops) | ||
| 629 | { | ||
| 630 | struct rpc_task *task; | ||
| 631 | struct xdr_buf *xbufp = &req->rq_snd_buf; | ||
| 632 | struct rpc_task_setup task_setup_data = { | ||
| 633 | .callback_ops = tk_ops, | ||
| 634 | }; | ||
| 635 | |||
| 636 | dprintk("RPC: rpc_run_bc_task req= %p\n", req); | ||
| 637 | /* | ||
| 638 | * Create an rpc_task to send the data | ||
| 639 | */ | ||
| 640 | task = rpc_new_task(&task_setup_data); | ||
| 641 | if (!task) { | ||
| 642 | xprt_free_bc_request(req); | ||
| 643 | goto out; | ||
| 644 | } | ||
| 645 | task->tk_rqstp = req; | ||
| 646 | |||
| 647 | /* | ||
| 648 | * Set up the xdr_buf length. | ||
| 649 | * This also indicates that the buffer is XDR encoded already. | ||
| 650 | */ | ||
| 651 | xbufp->len = xbufp->head[0].iov_len + xbufp->page_len + | ||
| 652 | xbufp->tail[0].iov_len; | ||
| 653 | |||
| 654 | task->tk_action = call_bc_transmit; | ||
| 655 | atomic_inc(&task->tk_count); | ||
| 656 | BUG_ON(atomic_read(&task->tk_count) != 2); | ||
| 657 | rpc_execute(task); | ||
| 658 | |||
| 659 | out: | ||
| 660 | dprintk("RPC: rpc_run_bc_task: task= %p\n", task); | ||
| 661 | return task; | ||
| 662 | } | ||
| 663 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 664 | |||
| 616 | void | 665 | void |
| 617 | rpc_call_start(struct rpc_task *task) | 666 | rpc_call_start(struct rpc_task *task) |
| 618 | { | 667 | { |
| @@ -695,6 +744,19 @@ void rpc_force_rebind(struct rpc_clnt *clnt) | |||
| 695 | EXPORT_SYMBOL_GPL(rpc_force_rebind); | 744 | EXPORT_SYMBOL_GPL(rpc_force_rebind); |
| 696 | 745 | ||
| 697 | /* | 746 | /* |
| 747 | * Restart an (async) RPC call from the call_prepare state. | ||
| 748 | * Usually called from within the exit handler. | ||
| 749 | */ | ||
| 750 | void | ||
| 751 | rpc_restart_call_prepare(struct rpc_task *task) | ||
| 752 | { | ||
| 753 | if (RPC_ASSASSINATED(task)) | ||
| 754 | return; | ||
| 755 | task->tk_action = rpc_prepare_task; | ||
| 756 | } | ||
| 757 | EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); | ||
| 758 | |||
| 759 | /* | ||
| 698 | * Restart an (async) RPC call. Usually called from within the | 760 | * Restart an (async) RPC call. Usually called from within the |
| 699 | * exit handler. | 761 | * exit handler. |
| 700 | */ | 762 | */ |
| @@ -1085,7 +1147,7 @@ call_transmit(struct rpc_task *task) | |||
| 1085 | * in order to allow access to the socket to other RPC requests. | 1147 | * in order to allow access to the socket to other RPC requests. |
| 1086 | */ | 1148 | */ |
| 1087 | call_transmit_status(task); | 1149 | call_transmit_status(task); |
| 1088 | if (task->tk_msg.rpc_proc->p_decode != NULL) | 1150 | if (rpc_reply_expected(task)) |
| 1089 | return; | 1151 | return; |
| 1090 | task->tk_action = rpc_exit_task; | 1152 | task->tk_action = rpc_exit_task; |
| 1091 | rpc_wake_up_queued_task(&task->tk_xprt->pending, task); | 1153 | rpc_wake_up_queued_task(&task->tk_xprt->pending, task); |
| @@ -1120,6 +1182,72 @@ call_transmit_status(struct rpc_task *task) | |||
| 1120 | } | 1182 | } |
| 1121 | } | 1183 | } |
| 1122 | 1184 | ||
| 1185 | #if defined(CONFIG_NFS_V4_1) | ||
| 1186 | /* | ||
| 1187 | * 5b. Send the backchannel RPC reply. On error, drop the reply. In | ||
| 1188 | * addition, disconnect on connectivity errors. | ||
| 1189 | */ | ||
| 1190 | static void | ||
| 1191 | call_bc_transmit(struct rpc_task *task) | ||
| 1192 | { | ||
| 1193 | struct rpc_rqst *req = task->tk_rqstp; | ||
| 1194 | |||
| 1195 | BUG_ON(task->tk_status != 0); | ||
| 1196 | task->tk_status = xprt_prepare_transmit(task); | ||
| 1197 | if (task->tk_status == -EAGAIN) { | ||
| 1198 | /* | ||
| 1199 | * Could not reserve the transport. Try again after the | ||
| 1200 | * transport is released. | ||
| 1201 | */ | ||
| 1202 | task->tk_status = 0; | ||
| 1203 | task->tk_action = call_bc_transmit; | ||
| 1204 | return; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | task->tk_action = rpc_exit_task; | ||
| 1208 | if (task->tk_status < 0) { | ||
| 1209 | printk(KERN_NOTICE "RPC: Could not send backchannel reply " | ||
| 1210 | "error: %d\n", task->tk_status); | ||
| 1211 | return; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | xprt_transmit(task); | ||
| 1215 | xprt_end_transmit(task); | ||
| 1216 | dprint_status(task); | ||
| 1217 | switch (task->tk_status) { | ||
| 1218 | case 0: | ||
| 1219 | /* Success */ | ||
| 1220 | break; | ||
| 1221 | case -EHOSTDOWN: | ||
| 1222 | case -EHOSTUNREACH: | ||
| 1223 | case -ENETUNREACH: | ||
| 1224 | case -ETIMEDOUT: | ||
| 1225 | /* | ||
| 1226 | * Problem reaching the server. Disconnect and let the | ||
| 1227 | * forechannel reestablish the connection. The server will | ||
| 1228 | * have to retransmit the backchannel request and we'll | ||
| 1229 | * reprocess it. Since these ops are idempotent, there's no | ||
| 1230 | * need to cache our reply at this time. | ||
| 1231 | */ | ||
| 1232 | printk(KERN_NOTICE "RPC: Could not send backchannel reply " | ||
| 1233 | "error: %d\n", task->tk_status); | ||
| 1234 | xprt_conditional_disconnect(task->tk_xprt, | ||
| 1235 | req->rq_connect_cookie); | ||
| 1236 | break; | ||
| 1237 | default: | ||
| 1238 | /* | ||
| 1239 | * We were unable to reply and will have to drop the | ||
| 1240 | * request. The server should reconnect and retransmit. | ||
| 1241 | */ | ||
| 1242 | BUG_ON(task->tk_status == -EAGAIN); | ||
| 1243 | printk(KERN_NOTICE "RPC: Could not send backchannel reply " | ||
| 1244 | "error: %d\n", task->tk_status); | ||
| 1245 | break; | ||
| 1246 | } | ||
| 1247 | rpc_wake_up_queued_task(&req->rq_xprt->pending, task); | ||
| 1248 | } | ||
| 1249 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1250 | |||
| 1123 | /* | 1251 | /* |
| 1124 | * 6. Sort out the RPC call status | 1252 | * 6. Sort out the RPC call status |
| 1125 | */ | 1253 | */ |
| @@ -1130,8 +1258,8 @@ call_status(struct rpc_task *task) | |||
| 1130 | struct rpc_rqst *req = task->tk_rqstp; | 1258 | struct rpc_rqst *req = task->tk_rqstp; |
| 1131 | int status; | 1259 | int status; |
| 1132 | 1260 | ||
| 1133 | if (req->rq_received > 0 && !req->rq_bytes_sent) | 1261 | if (req->rq_reply_bytes_recvd > 0 && !req->rq_bytes_sent) |
| 1134 | task->tk_status = req->rq_received; | 1262 | task->tk_status = req->rq_reply_bytes_recvd; |
| 1135 | 1263 | ||
| 1136 | dprint_status(task); | 1264 | dprint_status(task); |
| 1137 | 1265 | ||
| @@ -1248,7 +1376,7 @@ call_decode(struct rpc_task *task) | |||
| 1248 | 1376 | ||
| 1249 | /* | 1377 | /* |
| 1250 | * Ensure that we see all writes made by xprt_complete_rqst() | 1378 | * Ensure that we see all writes made by xprt_complete_rqst() |
| 1251 | * before it changed req->rq_received. | 1379 | * before it changed req->rq_reply_bytes_recvd. |
| 1252 | */ | 1380 | */ |
| 1253 | smp_rmb(); | 1381 | smp_rmb(); |
| 1254 | req->rq_rcv_buf.len = req->rq_private_buf.len; | 1382 | req->rq_rcv_buf.len = req->rq_private_buf.len; |
| @@ -1289,7 +1417,7 @@ out_retry: | |||
| 1289 | task->tk_status = 0; | 1417 | task->tk_status = 0; |
| 1290 | /* Note: rpc_verify_header() may have freed the RPC slot */ | 1418 | /* Note: rpc_verify_header() may have freed the RPC slot */ |
| 1291 | if (task->tk_rqstp == req) { | 1419 | if (task->tk_rqstp == req) { |
| 1292 | req->rq_received = req->rq_rcv_buf.len = 0; | 1420 | req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0; |
| 1293 | if (task->tk_client->cl_discrtry) | 1421 | if (task->tk_client->cl_discrtry) |
| 1294 | xprt_conditional_disconnect(task->tk_xprt, | 1422 | xprt_conditional_disconnect(task->tk_xprt, |
| 1295 | req->rq_connect_cookie); | 1423 | req->rq_connect_cookie); |
| @@ -1377,13 +1505,14 @@ rpc_verify_header(struct rpc_task *task) | |||
| 1377 | } | 1505 | } |
| 1378 | if ((len -= 3) < 0) | 1506 | if ((len -= 3) < 0) |
| 1379 | goto out_overflow; | 1507 | goto out_overflow; |
| 1380 | p += 1; /* skip XID */ | ||
| 1381 | 1508 | ||
| 1509 | p += 1; /* skip XID */ | ||
| 1382 | if ((n = ntohl(*p++)) != RPC_REPLY) { | 1510 | if ((n = ntohl(*p++)) != RPC_REPLY) { |
| 1383 | dprintk("RPC: %5u %s: not an RPC reply: %x\n", | 1511 | dprintk("RPC: %5u %s: not an RPC reply: %x\n", |
| 1384 | task->tk_pid, __func__, n); | 1512 | task->tk_pid, __func__, n); |
| 1385 | goto out_garbage; | 1513 | goto out_garbage; |
| 1386 | } | 1514 | } |
| 1515 | |||
| 1387 | if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { | 1516 | if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { |
| 1388 | if (--len < 0) | 1517 | if (--len < 0) |
| 1389 | goto out_overflow; | 1518 | goto out_overflow; |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index ff50a0546865..1102ce1251f7 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
| @@ -569,7 +569,7 @@ EXPORT_SYMBOL_GPL(rpc_delay); | |||
| 569 | /* | 569 | /* |
| 570 | * Helper to call task->tk_ops->rpc_call_prepare | 570 | * Helper to call task->tk_ops->rpc_call_prepare |
| 571 | */ | 571 | */ |
| 572 | static void rpc_prepare_task(struct rpc_task *task) | 572 | void rpc_prepare_task(struct rpc_task *task) |
| 573 | { | 573 | { |
| 574 | task->tk_ops->rpc_call_prepare(task, task->tk_calldata); | 574 | task->tk_ops->rpc_call_prepare(task, task->tk_calldata); |
| 575 | } | 575 | } |
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 1ef6e46d9da2..1b4e6791ecf3 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c | |||
| @@ -141,12 +141,14 @@ EXPORT_SYMBOL_GPL(rpc_free_iostats); | |||
| 141 | void rpc_count_iostats(struct rpc_task *task) | 141 | void rpc_count_iostats(struct rpc_task *task) |
| 142 | { | 142 | { |
| 143 | struct rpc_rqst *req = task->tk_rqstp; | 143 | struct rpc_rqst *req = task->tk_rqstp; |
| 144 | struct rpc_iostats *stats = task->tk_client->cl_metrics; | 144 | struct rpc_iostats *stats; |
| 145 | struct rpc_iostats *op_metrics; | 145 | struct rpc_iostats *op_metrics; |
| 146 | long rtt, execute, queue; | 146 | long rtt, execute, queue; |
| 147 | 147 | ||
| 148 | if (!stats || !req) | 148 | if (!task->tk_client || !task->tk_client->cl_metrics || !req) |
| 149 | return; | 149 | return; |
| 150 | |||
| 151 | stats = task->tk_client->cl_metrics; | ||
| 150 | op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx]; | 152 | op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx]; |
| 151 | 153 | ||
| 152 | op_metrics->om_ops++; | 154 | op_metrics->om_ops++; |
| @@ -154,7 +156,7 @@ void rpc_count_iostats(struct rpc_task *task) | |||
| 154 | op_metrics->om_timeouts += task->tk_timeouts; | 156 | op_metrics->om_timeouts += task->tk_timeouts; |
| 155 | 157 | ||
| 156 | op_metrics->om_bytes_sent += task->tk_bytes_sent; | 158 | op_metrics->om_bytes_sent += task->tk_bytes_sent; |
| 157 | op_metrics->om_bytes_recv += req->rq_received; | 159 | op_metrics->om_bytes_recv += req->rq_reply_bytes_recvd; |
| 158 | 160 | ||
| 159 | queue = (long)req->rq_xtime - task->tk_start; | 161 | queue = (long)req->rq_xtime - task->tk_start; |
| 160 | if (queue < 0) | 162 | if (queue < 0) |
diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h new file mode 100644 index 000000000000..5d9dd742264b --- /dev/null +++ b/net/sunrpc/sunrpc.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | |||
| 3 | (c) 2008 NetApp. All Rights Reserved. | ||
| 4 | |||
| 5 | NetApp provides this source code under the GPL v2 License. | ||
| 6 | The GPL v2 license is available at | ||
| 7 | http://opensource.org/licenses/gpl-license.php. | ||
| 8 | |||
| 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 10 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 11 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 12 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
| 13 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| 14 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| 15 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
| 16 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 17 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 18 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| 19 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 20 | |||
| 21 | ******************************************************************************/ | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Functions and macros used internally by RPC | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef _NET_SUNRPC_SUNRPC_H | ||
| 28 | #define _NET_SUNRPC_SUNRPC_H | ||
| 29 | |||
| 30 | static inline int rpc_reply_expected(struct rpc_task *task) | ||
| 31 | { | ||
| 32 | return (task->tk_msg.rpc_proc != NULL) && | ||
| 33 | (task->tk_msg.rpc_proc->p_decode != NULL); | ||
| 34 | } | ||
| 35 | |||
| 36 | #endif /* _NET_SUNRPC_SUNRPC_H */ | ||
| 37 | |||
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 5ed8931dfe98..952f206ff307 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/sunrpc/stats.h> | 25 | #include <linux/sunrpc/stats.h> |
| 26 | #include <linux/sunrpc/svcsock.h> | 26 | #include <linux/sunrpc/svcsock.h> |
| 27 | #include <linux/sunrpc/clnt.h> | 27 | #include <linux/sunrpc/clnt.h> |
| 28 | #include <linux/sunrpc/bc_xprt.h> | ||
| 28 | 29 | ||
| 29 | #define RPCDBG_FACILITY RPCDBG_SVCDSP | 30 | #define RPCDBG_FACILITY RPCDBG_SVCDSP |
| 30 | 31 | ||
| @@ -486,6 +487,10 @@ svc_destroy(struct svc_serv *serv) | |||
| 486 | if (svc_serv_is_pooled(serv)) | 487 | if (svc_serv_is_pooled(serv)) |
| 487 | svc_pool_map_put(); | 488 | svc_pool_map_put(); |
| 488 | 489 | ||
| 490 | #if defined(CONFIG_NFS_V4_1) | ||
| 491 | svc_sock_destroy(serv->bc_xprt); | ||
| 492 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 493 | |||
| 489 | svc_unregister(serv); | 494 | svc_unregister(serv); |
| 490 | kfree(serv->sv_pools); | 495 | kfree(serv->sv_pools); |
| 491 | kfree(serv); | 496 | kfree(serv); |
| @@ -970,20 +975,18 @@ svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) | |||
| 970 | } | 975 | } |
| 971 | 976 | ||
| 972 | /* | 977 | /* |
| 973 | * Process the RPC request. | 978 | * Common routine for processing the RPC request. |
| 974 | */ | 979 | */ |
| 975 | int | 980 | static int |
| 976 | svc_process(struct svc_rqst *rqstp) | 981 | svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) |
| 977 | { | 982 | { |
| 978 | struct svc_program *progp; | 983 | struct svc_program *progp; |
| 979 | struct svc_version *versp = NULL; /* compiler food */ | 984 | struct svc_version *versp = NULL; /* compiler food */ |
| 980 | struct svc_procedure *procp = NULL; | 985 | struct svc_procedure *procp = NULL; |
| 981 | struct kvec * argv = &rqstp->rq_arg.head[0]; | ||
| 982 | struct kvec * resv = &rqstp->rq_res.head[0]; | ||
| 983 | struct svc_serv *serv = rqstp->rq_server; | 986 | struct svc_serv *serv = rqstp->rq_server; |
| 984 | kxdrproc_t xdr; | 987 | kxdrproc_t xdr; |
| 985 | __be32 *statp; | 988 | __be32 *statp; |
| 986 | u32 dir, prog, vers, proc; | 989 | u32 prog, vers, proc; |
| 987 | __be32 auth_stat, rpc_stat; | 990 | __be32 auth_stat, rpc_stat; |
| 988 | int auth_res; | 991 | int auth_res; |
| 989 | __be32 *reply_statp; | 992 | __be32 *reply_statp; |
| @@ -993,19 +996,6 @@ svc_process(struct svc_rqst *rqstp) | |||
| 993 | if (argv->iov_len < 6*4) | 996 | if (argv->iov_len < 6*4) |
| 994 | goto err_short_len; | 997 | goto err_short_len; |
| 995 | 998 | ||
| 996 | /* setup response xdr_buf. | ||
| 997 | * Initially it has just one page | ||
| 998 | */ | ||
| 999 | rqstp->rq_resused = 1; | ||
| 1000 | resv->iov_base = page_address(rqstp->rq_respages[0]); | ||
| 1001 | resv->iov_len = 0; | ||
| 1002 | rqstp->rq_res.pages = rqstp->rq_respages + 1; | ||
| 1003 | rqstp->rq_res.len = 0; | ||
| 1004 | rqstp->rq_res.page_base = 0; | ||
| 1005 | rqstp->rq_res.page_len = 0; | ||
| 1006 | rqstp->rq_res.buflen = PAGE_SIZE; | ||
| 1007 | rqstp->rq_res.tail[0].iov_base = NULL; | ||
| 1008 | rqstp->rq_res.tail[0].iov_len = 0; | ||
| 1009 | /* Will be turned off only in gss privacy case: */ | 999 | /* Will be turned off only in gss privacy case: */ |
| 1010 | rqstp->rq_splice_ok = 1; | 1000 | rqstp->rq_splice_ok = 1; |
| 1011 | /* Will be turned off only when NFSv4 Sessions are used */ | 1001 | /* Will be turned off only when NFSv4 Sessions are used */ |
| @@ -1014,17 +1004,13 @@ svc_process(struct svc_rqst *rqstp) | |||
| 1014 | /* Setup reply header */ | 1004 | /* Setup reply header */ |
| 1015 | rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); | 1005 | rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); |
| 1016 | 1006 | ||
| 1017 | rqstp->rq_xid = svc_getu32(argv); | ||
| 1018 | svc_putu32(resv, rqstp->rq_xid); | 1007 | svc_putu32(resv, rqstp->rq_xid); |
| 1019 | 1008 | ||
| 1020 | dir = svc_getnl(argv); | ||
| 1021 | vers = svc_getnl(argv); | 1009 | vers = svc_getnl(argv); |
| 1022 | 1010 | ||
| 1023 | /* First words of reply: */ | 1011 | /* First words of reply: */ |
| 1024 | svc_putnl(resv, 1); /* REPLY */ | 1012 | svc_putnl(resv, 1); /* REPLY */ |
| 1025 | 1013 | ||
| 1026 | if (dir != 0) /* direction != CALL */ | ||
| 1027 | goto err_bad_dir; | ||
| 1028 | if (vers != 2) /* RPC version number */ | 1014 | if (vers != 2) /* RPC version number */ |
| 1029 | goto err_bad_rpc; | 1015 | goto err_bad_rpc; |
| 1030 | 1016 | ||
| @@ -1147,7 +1133,7 @@ svc_process(struct svc_rqst *rqstp) | |||
| 1147 | sendit: | 1133 | sendit: |
| 1148 | if (svc_authorise(rqstp)) | 1134 | if (svc_authorise(rqstp)) |
| 1149 | goto dropit; | 1135 | goto dropit; |
| 1150 | return svc_send(rqstp); | 1136 | return 1; /* Caller can now send it */ |
| 1151 | 1137 | ||
| 1152 | dropit: | 1138 | dropit: |
| 1153 | svc_authorise(rqstp); /* doesn't hurt to call this twice */ | 1139 | svc_authorise(rqstp); /* doesn't hurt to call this twice */ |
| @@ -1161,12 +1147,6 @@ err_short_len: | |||
| 1161 | 1147 | ||
| 1162 | goto dropit; /* drop request */ | 1148 | goto dropit; /* drop request */ |
| 1163 | 1149 | ||
| 1164 | err_bad_dir: | ||
| 1165 | svc_printk(rqstp, "bad direction %d, dropping request\n", dir); | ||
| 1166 | |||
| 1167 | serv->sv_stats->rpcbadfmt++; | ||
| 1168 | goto dropit; /* drop request */ | ||
| 1169 | |||
| 1170 | err_bad_rpc: | 1150 | err_bad_rpc: |
| 1171 | serv->sv_stats->rpcbadfmt++; | 1151 | serv->sv_stats->rpcbadfmt++; |
| 1172 | svc_putnl(resv, 1); /* REJECT */ | 1152 | svc_putnl(resv, 1); /* REJECT */ |
| @@ -1220,6 +1200,100 @@ err_bad: | |||
| 1220 | EXPORT_SYMBOL_GPL(svc_process); | 1200 | EXPORT_SYMBOL_GPL(svc_process); |
| 1221 | 1201 | ||
| 1222 | /* | 1202 | /* |
| 1203 | * Process the RPC request. | ||
| 1204 | */ | ||
| 1205 | int | ||
| 1206 | svc_process(struct svc_rqst *rqstp) | ||
| 1207 | { | ||
| 1208 | struct kvec *argv = &rqstp->rq_arg.head[0]; | ||
| 1209 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
| 1210 | struct svc_serv *serv = rqstp->rq_server; | ||
| 1211 | u32 dir; | ||
| 1212 | int error; | ||
| 1213 | |||
| 1214 | /* | ||
| 1215 | * Setup response xdr_buf. | ||
| 1216 | * Initially it has just one page | ||
| 1217 | */ | ||
| 1218 | rqstp->rq_resused = 1; | ||
| 1219 | resv->iov_base = page_address(rqstp->rq_respages[0]); | ||
| 1220 | resv->iov_len = 0; | ||
| 1221 | rqstp->rq_res.pages = rqstp->rq_respages + 1; | ||
| 1222 | rqstp->rq_res.len = 0; | ||
| 1223 | rqstp->rq_res.page_base = 0; | ||
| 1224 | rqstp->rq_res.page_len = 0; | ||
| 1225 | rqstp->rq_res.buflen = PAGE_SIZE; | ||
| 1226 | rqstp->rq_res.tail[0].iov_base = NULL; | ||
| 1227 | rqstp->rq_res.tail[0].iov_len = 0; | ||
| 1228 | |||
| 1229 | rqstp->rq_xid = svc_getu32(argv); | ||
| 1230 | |||
| 1231 | dir = svc_getnl(argv); | ||
| 1232 | if (dir != 0) { | ||
| 1233 | /* direction != CALL */ | ||
| 1234 | svc_printk(rqstp, "bad direction %d, dropping request\n", dir); | ||
| 1235 | serv->sv_stats->rpcbadfmt++; | ||
| 1236 | svc_drop(rqstp); | ||
| 1237 | return 0; | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | error = svc_process_common(rqstp, argv, resv); | ||
| 1241 | if (error <= 0) | ||
| 1242 | return error; | ||
| 1243 | |||
| 1244 | return svc_send(rqstp); | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | #if defined(CONFIG_NFS_V4_1) | ||
| 1248 | /* | ||
| 1249 | * Process a backchannel RPC request that arrived over an existing | ||
| 1250 | * outbound connection | ||
| 1251 | */ | ||
| 1252 | int | ||
| 1253 | bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, | ||
| 1254 | struct svc_rqst *rqstp) | ||
| 1255 | { | ||
| 1256 | struct kvec *argv = &rqstp->rq_arg.head[0]; | ||
| 1257 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
| 1258 | int error; | ||
| 1259 | |||
| 1260 | /* Build the svc_rqst used by the common processing routine */ | ||
| 1261 | rqstp->rq_xprt = serv->bc_xprt; | ||
| 1262 | rqstp->rq_xid = req->rq_xid; | ||
| 1263 | rqstp->rq_prot = req->rq_xprt->prot; | ||
| 1264 | rqstp->rq_server = serv; | ||
| 1265 | |||
| 1266 | rqstp->rq_addrlen = sizeof(req->rq_xprt->addr); | ||
| 1267 | memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); | ||
| 1268 | memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg)); | ||
| 1269 | memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res)); | ||
| 1270 | |||
| 1271 | /* reset result send buffer "put" position */ | ||
| 1272 | resv->iov_len = 0; | ||
| 1273 | |||
| 1274 | if (rqstp->rq_prot != IPPROTO_TCP) { | ||
| 1275 | printk(KERN_ERR "No support for Non-TCP transports!\n"); | ||
| 1276 | BUG(); | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | /* | ||
| 1280 | * Skip the next two words because they've already been | ||
| 1281 | * processed in the trasport | ||
| 1282 | */ | ||
| 1283 | svc_getu32(argv); /* XID */ | ||
| 1284 | svc_getnl(argv); /* CALLDIR */ | ||
| 1285 | |||
| 1286 | error = svc_process_common(rqstp, argv, resv); | ||
| 1287 | if (error <= 0) | ||
| 1288 | return error; | ||
| 1289 | |||
| 1290 | memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); | ||
| 1291 | return bc_send(req); | ||
| 1292 | } | ||
| 1293 | EXPORT_SYMBOL(bc_svc_process); | ||
| 1294 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1295 | |||
| 1296 | /* | ||
| 1223 | * Return (transport-specific) limit on the rpc payload. | 1297 | * Return (transport-specific) limit on the rpc payload. |
| 1224 | */ | 1298 | */ |
| 1225 | u32 svc_max_payload(const struct svc_rqst *rqstp) | 1299 | u32 svc_max_payload(const struct svc_rqst *rqstp) |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 9d504234af4a..a2a03e500533 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -1327,3 +1327,42 @@ static void svc_sock_free(struct svc_xprt *xprt) | |||
| 1327 | sock_release(svsk->sk_sock); | 1327 | sock_release(svsk->sk_sock); |
| 1328 | kfree(svsk); | 1328 | kfree(svsk); |
| 1329 | } | 1329 | } |
| 1330 | |||
| 1331 | /* | ||
| 1332 | * Create a svc_xprt. | ||
| 1333 | * | ||
| 1334 | * For internal use only (e.g. nfsv4.1 backchannel). | ||
| 1335 | * Callers should typically use the xpo_create() method. | ||
| 1336 | */ | ||
| 1337 | struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot) | ||
| 1338 | { | ||
| 1339 | struct svc_sock *svsk; | ||
| 1340 | struct svc_xprt *xprt = NULL; | ||
| 1341 | |||
| 1342 | dprintk("svc: %s\n", __func__); | ||
| 1343 | svsk = kzalloc(sizeof(*svsk), GFP_KERNEL); | ||
| 1344 | if (!svsk) | ||
| 1345 | goto out; | ||
| 1346 | |||
| 1347 | xprt = &svsk->sk_xprt; | ||
| 1348 | if (prot == IPPROTO_TCP) | ||
| 1349 | svc_xprt_init(&svc_tcp_class, xprt, serv); | ||
| 1350 | else if (prot == IPPROTO_UDP) | ||
| 1351 | svc_xprt_init(&svc_udp_class, xprt, serv); | ||
| 1352 | else | ||
| 1353 | BUG(); | ||
| 1354 | out: | ||
| 1355 | dprintk("svc: %s return %p\n", __func__, xprt); | ||
| 1356 | return xprt; | ||
| 1357 | } | ||
| 1358 | EXPORT_SYMBOL_GPL(svc_sock_create); | ||
| 1359 | |||
| 1360 | /* | ||
| 1361 | * Destroy a svc_sock. | ||
| 1362 | */ | ||
| 1363 | void svc_sock_destroy(struct svc_xprt *xprt) | ||
| 1364 | { | ||
| 1365 | if (xprt) | ||
| 1366 | kfree(container_of(xprt, struct svc_sock, sk_xprt)); | ||
| 1367 | } | ||
| 1368 | EXPORT_SYMBOL_GPL(svc_sock_destroy); | ||
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 06ca058572f2..f412a852bc73 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -12,8 +12,9 @@ | |||
| 12 | * - Next, the caller puts together the RPC message, stuffs it into | 12 | * - Next, the caller puts together the RPC message, stuffs it into |
| 13 | * the request struct, and calls xprt_transmit(). | 13 | * the request struct, and calls xprt_transmit(). |
| 14 | * - xprt_transmit sends the message and installs the caller on the | 14 | * - xprt_transmit sends the message and installs the caller on the |
| 15 | * transport's wait list. At the same time, it installs a timer that | 15 | * transport's wait list. At the same time, if a reply is expected, |
| 16 | * is run after the packet's timeout has expired. | 16 | * it installs a timer that is run after the packet's timeout has |
| 17 | * expired. | ||
| 17 | * - When a packet arrives, the data_ready handler walks the list of | 18 | * - When a packet arrives, the data_ready handler walks the list of |
| 18 | * pending requests for that transport. If a matching XID is found, the | 19 | * pending requests for that transport. If a matching XID is found, the |
| 19 | * caller is woken up, and the timer removed. | 20 | * caller is woken up, and the timer removed. |
| @@ -46,6 +47,8 @@ | |||
| 46 | #include <linux/sunrpc/clnt.h> | 47 | #include <linux/sunrpc/clnt.h> |
| 47 | #include <linux/sunrpc/metrics.h> | 48 | #include <linux/sunrpc/metrics.h> |
| 48 | 49 | ||
| 50 | #include "sunrpc.h" | ||
| 51 | |||
| 49 | /* | 52 | /* |
| 50 | * Local variables | 53 | * Local variables |
| 51 | */ | 54 | */ |
| @@ -192,8 +195,8 @@ EXPORT_SYMBOL_GPL(xprt_load_transport); | |||
| 192 | */ | 195 | */ |
| 193 | int xprt_reserve_xprt(struct rpc_task *task) | 196 | int xprt_reserve_xprt(struct rpc_task *task) |
| 194 | { | 197 | { |
| 195 | struct rpc_xprt *xprt = task->tk_xprt; | ||
| 196 | struct rpc_rqst *req = task->tk_rqstp; | 198 | struct rpc_rqst *req = task->tk_rqstp; |
| 199 | struct rpc_xprt *xprt = req->rq_xprt; | ||
| 197 | 200 | ||
| 198 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { | 201 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { |
| 199 | if (task == xprt->snd_task) | 202 | if (task == xprt->snd_task) |
| @@ -803,9 +806,10 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) | |||
| 803 | 806 | ||
| 804 | list_del_init(&req->rq_list); | 807 | list_del_init(&req->rq_list); |
| 805 | req->rq_private_buf.len = copied; | 808 | req->rq_private_buf.len = copied; |
| 806 | /* Ensure all writes are done before we update req->rq_received */ | 809 | /* Ensure all writes are done before we update */ |
| 810 | /* req->rq_reply_bytes_recvd */ | ||
| 807 | smp_wmb(); | 811 | smp_wmb(); |
| 808 | req->rq_received = copied; | 812 | req->rq_reply_bytes_recvd = copied; |
| 809 | rpc_wake_up_queued_task(&xprt->pending, task); | 813 | rpc_wake_up_queued_task(&xprt->pending, task); |
| 810 | } | 814 | } |
| 811 | EXPORT_SYMBOL_GPL(xprt_complete_rqst); | 815 | EXPORT_SYMBOL_GPL(xprt_complete_rqst); |
| @@ -820,7 +824,7 @@ static void xprt_timer(struct rpc_task *task) | |||
| 820 | dprintk("RPC: %5u xprt_timer\n", task->tk_pid); | 824 | dprintk("RPC: %5u xprt_timer\n", task->tk_pid); |
| 821 | 825 | ||
| 822 | spin_lock_bh(&xprt->transport_lock); | 826 | spin_lock_bh(&xprt->transport_lock); |
| 823 | if (!req->rq_received) { | 827 | if (!req->rq_reply_bytes_recvd) { |
| 824 | if (xprt->ops->timer) | 828 | if (xprt->ops->timer) |
| 825 | xprt->ops->timer(task); | 829 | xprt->ops->timer(task); |
| 826 | } else | 830 | } else |
| @@ -842,8 +846,8 @@ int xprt_prepare_transmit(struct rpc_task *task) | |||
| 842 | dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); | 846 | dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); |
| 843 | 847 | ||
| 844 | spin_lock_bh(&xprt->transport_lock); | 848 | spin_lock_bh(&xprt->transport_lock); |
| 845 | if (req->rq_received && !req->rq_bytes_sent) { | 849 | if (req->rq_reply_bytes_recvd && !req->rq_bytes_sent) { |
| 846 | err = req->rq_received; | 850 | err = req->rq_reply_bytes_recvd; |
| 847 | goto out_unlock; | 851 | goto out_unlock; |
| 848 | } | 852 | } |
| 849 | if (!xprt->ops->reserve_xprt(task)) | 853 | if (!xprt->ops->reserve_xprt(task)) |
| @@ -855,7 +859,7 @@ out_unlock: | |||
| 855 | 859 | ||
| 856 | void xprt_end_transmit(struct rpc_task *task) | 860 | void xprt_end_transmit(struct rpc_task *task) |
| 857 | { | 861 | { |
| 858 | xprt_release_write(task->tk_xprt, task); | 862 | xprt_release_write(task->tk_rqstp->rq_xprt, task); |
| 859 | } | 863 | } |
| 860 | 864 | ||
| 861 | /** | 865 | /** |
| @@ -872,8 +876,11 @@ void xprt_transmit(struct rpc_task *task) | |||
| 872 | 876 | ||
| 873 | dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); | 877 | dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); |
| 874 | 878 | ||
| 875 | if (!req->rq_received) { | 879 | if (!req->rq_reply_bytes_recvd) { |
| 876 | if (list_empty(&req->rq_list)) { | 880 | if (list_empty(&req->rq_list) && rpc_reply_expected(task)) { |
| 881 | /* | ||
| 882 | * Add to the list only if we're expecting a reply | ||
| 883 | */ | ||
| 877 | spin_lock_bh(&xprt->transport_lock); | 884 | spin_lock_bh(&xprt->transport_lock); |
| 878 | /* Update the softirq receive buffer */ | 885 | /* Update the softirq receive buffer */ |
| 879 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, | 886 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, |
| @@ -908,8 +915,13 @@ void xprt_transmit(struct rpc_task *task) | |||
| 908 | /* Don't race with disconnect */ | 915 | /* Don't race with disconnect */ |
| 909 | if (!xprt_connected(xprt)) | 916 | if (!xprt_connected(xprt)) |
| 910 | task->tk_status = -ENOTCONN; | 917 | task->tk_status = -ENOTCONN; |
| 911 | else if (!req->rq_received) | 918 | else if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task)) { |
| 919 | /* | ||
| 920 | * Sleep on the pending queue since | ||
| 921 | * we're expecting a reply. | ||
| 922 | */ | ||
| 912 | rpc_sleep_on(&xprt->pending, task, xprt_timer); | 923 | rpc_sleep_on(&xprt->pending, task, xprt_timer); |
| 924 | } | ||
| 913 | spin_unlock_bh(&xprt->transport_lock); | 925 | spin_unlock_bh(&xprt->transport_lock); |
| 914 | } | 926 | } |
| 915 | 927 | ||
| @@ -982,11 +994,17 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) | |||
| 982 | */ | 994 | */ |
| 983 | void xprt_release(struct rpc_task *task) | 995 | void xprt_release(struct rpc_task *task) |
| 984 | { | 996 | { |
| 985 | struct rpc_xprt *xprt = task->tk_xprt; | 997 | struct rpc_xprt *xprt; |
| 986 | struct rpc_rqst *req; | 998 | struct rpc_rqst *req; |
| 999 | int is_bc_request; | ||
| 987 | 1000 | ||
| 988 | if (!(req = task->tk_rqstp)) | 1001 | if (!(req = task->tk_rqstp)) |
| 989 | return; | 1002 | return; |
| 1003 | |||
| 1004 | /* Preallocated backchannel request? */ | ||
| 1005 | is_bc_request = bc_prealloc(req); | ||
| 1006 | |||
| 1007 | xprt = req->rq_xprt; | ||
| 990 | rpc_count_iostats(task); | 1008 | rpc_count_iostats(task); |
| 991 | spin_lock_bh(&xprt->transport_lock); | 1009 | spin_lock_bh(&xprt->transport_lock); |
| 992 | xprt->ops->release_xprt(xprt, task); | 1010 | xprt->ops->release_xprt(xprt, task); |
| @@ -999,10 +1017,19 @@ void xprt_release(struct rpc_task *task) | |||
| 999 | mod_timer(&xprt->timer, | 1017 | mod_timer(&xprt->timer, |
| 1000 | xprt->last_used + xprt->idle_timeout); | 1018 | xprt->last_used + xprt->idle_timeout); |
| 1001 | spin_unlock_bh(&xprt->transport_lock); | 1019 | spin_unlock_bh(&xprt->transport_lock); |
| 1002 | xprt->ops->buf_free(req->rq_buffer); | 1020 | if (!bc_prealloc(req)) |
| 1021 | xprt->ops->buf_free(req->rq_buffer); | ||
| 1003 | task->tk_rqstp = NULL; | 1022 | task->tk_rqstp = NULL; |
| 1004 | if (req->rq_release_snd_buf) | 1023 | if (req->rq_release_snd_buf) |
| 1005 | req->rq_release_snd_buf(req); | 1024 | req->rq_release_snd_buf(req); |
| 1025 | |||
| 1026 | /* | ||
| 1027 | * Early exit if this is a backchannel preallocated request. | ||
| 1028 | * There is no need to have it added to the RPC slot list. | ||
| 1029 | */ | ||
| 1030 | if (is_bc_request) | ||
| 1031 | return; | ||
| 1032 | |||
| 1006 | memset(req, 0, sizeof(*req)); /* mark unused */ | 1033 | memset(req, 0, sizeof(*req)); /* mark unused */ |
| 1007 | 1034 | ||
| 1008 | dprintk("RPC: %5u release request %p\n", task->tk_pid, req); | 1035 | dprintk("RPC: %5u release request %p\n", task->tk_pid, req); |
| @@ -1049,6 +1076,11 @@ found: | |||
| 1049 | 1076 | ||
| 1050 | INIT_LIST_HEAD(&xprt->free); | 1077 | INIT_LIST_HEAD(&xprt->free); |
| 1051 | INIT_LIST_HEAD(&xprt->recv); | 1078 | INIT_LIST_HEAD(&xprt->recv); |
| 1079 | #if defined(CONFIG_NFS_V4_1) | ||
| 1080 | spin_lock_init(&xprt->bc_pa_lock); | ||
| 1081 | INIT_LIST_HEAD(&xprt->bc_pa_list); | ||
| 1082 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1083 | |||
| 1052 | INIT_WORK(&xprt->task_cleanup, xprt_autoclose); | 1084 | INIT_WORK(&xprt->task_cleanup, xprt_autoclose); |
| 1053 | setup_timer(&xprt->timer, xprt_init_autodisconnect, | 1085 | setup_timer(&xprt->timer, xprt_init_autodisconnect, |
| 1054 | (unsigned long)xprt); | 1086 | (unsigned long)xprt); |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 6c2d61586551..9111d11c09fd 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -34,6 +34,9 @@ | |||
| 34 | #include <linux/sunrpc/sched.h> | 34 | #include <linux/sunrpc/sched.h> |
| 35 | #include <linux/sunrpc/xprtsock.h> | 35 | #include <linux/sunrpc/xprtsock.h> |
| 36 | #include <linux/file.h> | 36 | #include <linux/file.h> |
| 37 | #ifdef CONFIG_NFS_V4_1 | ||
| 38 | #include <linux/sunrpc/bc_xprt.h> | ||
| 39 | #endif | ||
| 37 | 40 | ||
| 38 | #include <net/sock.h> | 41 | #include <net/sock.h> |
| 39 | #include <net/checksum.h> | 42 | #include <net/checksum.h> |
| @@ -270,6 +273,13 @@ struct sock_xprt { | |||
| 270 | #define TCP_RCV_COPY_FRAGHDR (1UL << 1) | 273 | #define TCP_RCV_COPY_FRAGHDR (1UL << 1) |
| 271 | #define TCP_RCV_COPY_XID (1UL << 2) | 274 | #define TCP_RCV_COPY_XID (1UL << 2) |
| 272 | #define TCP_RCV_COPY_DATA (1UL << 3) | 275 | #define TCP_RCV_COPY_DATA (1UL << 3) |
| 276 | #define TCP_RCV_READ_CALLDIR (1UL << 4) | ||
| 277 | #define TCP_RCV_COPY_CALLDIR (1UL << 5) | ||
| 278 | |||
| 279 | /* | ||
| 280 | * TCP RPC flags | ||
| 281 | */ | ||
| 282 | #define TCP_RPC_REPLY (1UL << 6) | ||
| 273 | 283 | ||
| 274 | static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) | 284 | static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) |
| 275 | { | 285 | { |
| @@ -956,7 +966,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea | |||
| 956 | transport->tcp_offset = 0; | 966 | transport->tcp_offset = 0; |
| 957 | 967 | ||
| 958 | /* Sanity check of the record length */ | 968 | /* Sanity check of the record length */ |
| 959 | if (unlikely(transport->tcp_reclen < 4)) { | 969 | if (unlikely(transport->tcp_reclen < 8)) { |
| 960 | dprintk("RPC: invalid TCP record fragment length\n"); | 970 | dprintk("RPC: invalid TCP record fragment length\n"); |
| 961 | xprt_force_disconnect(xprt); | 971 | xprt_force_disconnect(xprt); |
| 962 | return; | 972 | return; |
| @@ -991,33 +1001,77 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, struct xdr_skb_r | |||
| 991 | if (used != len) | 1001 | if (used != len) |
| 992 | return; | 1002 | return; |
| 993 | transport->tcp_flags &= ~TCP_RCV_COPY_XID; | 1003 | transport->tcp_flags &= ~TCP_RCV_COPY_XID; |
| 994 | transport->tcp_flags |= TCP_RCV_COPY_DATA; | 1004 | transport->tcp_flags |= TCP_RCV_READ_CALLDIR; |
| 995 | transport->tcp_copied = 4; | 1005 | transport->tcp_copied = 4; |
| 996 | dprintk("RPC: reading reply for XID %08x\n", | 1006 | dprintk("RPC: reading %s XID %08x\n", |
| 1007 | (transport->tcp_flags & TCP_RPC_REPLY) ? "reply for" | ||
| 1008 | : "request with", | ||
| 997 | ntohl(transport->tcp_xid)); | 1009 | ntohl(transport->tcp_xid)); |
| 998 | xs_tcp_check_fraghdr(transport); | 1010 | xs_tcp_check_fraghdr(transport); |
| 999 | } | 1011 | } |
| 1000 | 1012 | ||
| 1001 | static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) | 1013 | static inline void xs_tcp_read_calldir(struct sock_xprt *transport, |
| 1014 | struct xdr_skb_reader *desc) | ||
| 1002 | { | 1015 | { |
| 1003 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 1016 | size_t len, used; |
| 1004 | struct rpc_rqst *req; | 1017 | u32 offset; |
| 1018 | __be32 calldir; | ||
| 1019 | |||
| 1020 | /* | ||
| 1021 | * We want transport->tcp_offset to be 8 at the end of this routine | ||
| 1022 | * (4 bytes for the xid and 4 bytes for the call/reply flag). | ||
| 1023 | * When this function is called for the first time, | ||
| 1024 | * transport->tcp_offset is 4 (after having already read the xid). | ||
| 1025 | */ | ||
| 1026 | offset = transport->tcp_offset - sizeof(transport->tcp_xid); | ||
| 1027 | len = sizeof(calldir) - offset; | ||
| 1028 | dprintk("RPC: reading CALL/REPLY flag (%Zu bytes)\n", len); | ||
| 1029 | used = xdr_skb_read_bits(desc, &calldir, len); | ||
| 1030 | transport->tcp_offset += used; | ||
| 1031 | if (used != len) | ||
| 1032 | return; | ||
| 1033 | transport->tcp_flags &= ~TCP_RCV_READ_CALLDIR; | ||
| 1034 | transport->tcp_flags |= TCP_RCV_COPY_CALLDIR; | ||
| 1035 | transport->tcp_flags |= TCP_RCV_COPY_DATA; | ||
| 1036 | /* | ||
| 1037 | * We don't yet have the XDR buffer, so we will write the calldir | ||
| 1038 | * out after we get the buffer from the 'struct rpc_rqst' | ||
| 1039 | */ | ||
| 1040 | if (ntohl(calldir) == RPC_REPLY) | ||
| 1041 | transport->tcp_flags |= TCP_RPC_REPLY; | ||
| 1042 | else | ||
| 1043 | transport->tcp_flags &= ~TCP_RPC_REPLY; | ||
| 1044 | dprintk("RPC: reading %s CALL/REPLY flag %08x\n", | ||
| 1045 | (transport->tcp_flags & TCP_RPC_REPLY) ? | ||
| 1046 | "reply for" : "request with", calldir); | ||
| 1047 | xs_tcp_check_fraghdr(transport); | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | static inline void xs_tcp_read_common(struct rpc_xprt *xprt, | ||
| 1051 | struct xdr_skb_reader *desc, | ||
| 1052 | struct rpc_rqst *req) | ||
| 1053 | { | ||
| 1054 | struct sock_xprt *transport = | ||
| 1055 | container_of(xprt, struct sock_xprt, xprt); | ||
| 1005 | struct xdr_buf *rcvbuf; | 1056 | struct xdr_buf *rcvbuf; |
| 1006 | size_t len; | 1057 | size_t len; |
| 1007 | ssize_t r; | 1058 | ssize_t r; |
| 1008 | 1059 | ||
| 1009 | /* Find and lock the request corresponding to this xid */ | 1060 | rcvbuf = &req->rq_private_buf; |
| 1010 | spin_lock(&xprt->transport_lock); | 1061 | |
| 1011 | req = xprt_lookup_rqst(xprt, transport->tcp_xid); | 1062 | if (transport->tcp_flags & TCP_RCV_COPY_CALLDIR) { |
| 1012 | if (!req) { | 1063 | /* |
| 1013 | transport->tcp_flags &= ~TCP_RCV_COPY_DATA; | 1064 | * Save the RPC direction in the XDR buffer |
| 1014 | dprintk("RPC: XID %08x request not found!\n", | 1065 | */ |
| 1015 | ntohl(transport->tcp_xid)); | 1066 | __be32 calldir = transport->tcp_flags & TCP_RPC_REPLY ? |
| 1016 | spin_unlock(&xprt->transport_lock); | 1067 | htonl(RPC_REPLY) : 0; |
| 1017 | return; | 1068 | |
| 1069 | memcpy(rcvbuf->head[0].iov_base + transport->tcp_copied, | ||
| 1070 | &calldir, sizeof(calldir)); | ||
| 1071 | transport->tcp_copied += sizeof(calldir); | ||
| 1072 | transport->tcp_flags &= ~TCP_RCV_COPY_CALLDIR; | ||
| 1018 | } | 1073 | } |
| 1019 | 1074 | ||
| 1020 | rcvbuf = &req->rq_private_buf; | ||
| 1021 | len = desc->count; | 1075 | len = desc->count; |
| 1022 | if (len > transport->tcp_reclen - transport->tcp_offset) { | 1076 | if (len > transport->tcp_reclen - transport->tcp_offset) { |
| 1023 | struct xdr_skb_reader my_desc; | 1077 | struct xdr_skb_reader my_desc; |
| @@ -1054,7 +1108,7 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea | |||
| 1054 | "tcp_offset = %u, tcp_reclen = %u\n", | 1108 | "tcp_offset = %u, tcp_reclen = %u\n", |
| 1055 | xprt, transport->tcp_copied, | 1109 | xprt, transport->tcp_copied, |
| 1056 | transport->tcp_offset, transport->tcp_reclen); | 1110 | transport->tcp_offset, transport->tcp_reclen); |
| 1057 | goto out; | 1111 | return; |
| 1058 | } | 1112 | } |
| 1059 | 1113 | ||
| 1060 | dprintk("RPC: XID %08x read %Zd bytes\n", | 1114 | dprintk("RPC: XID %08x read %Zd bytes\n", |
| @@ -1070,11 +1124,125 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea | |||
| 1070 | transport->tcp_flags &= ~TCP_RCV_COPY_DATA; | 1124 | transport->tcp_flags &= ~TCP_RCV_COPY_DATA; |
| 1071 | } | 1125 | } |
| 1072 | 1126 | ||
| 1073 | out: | 1127 | return; |
| 1128 | } | ||
| 1129 | |||
| 1130 | /* | ||
| 1131 | * Finds the request corresponding to the RPC xid and invokes the common | ||
| 1132 | * tcp read code to read the data. | ||
| 1133 | */ | ||
| 1134 | static inline int xs_tcp_read_reply(struct rpc_xprt *xprt, | ||
| 1135 | struct xdr_skb_reader *desc) | ||
| 1136 | { | ||
| 1137 | struct sock_xprt *transport = | ||
| 1138 | container_of(xprt, struct sock_xprt, xprt); | ||
| 1139 | struct rpc_rqst *req; | ||
| 1140 | |||
| 1141 | dprintk("RPC: read reply XID %08x\n", ntohl(transport->tcp_xid)); | ||
| 1142 | |||
| 1143 | /* Find and lock the request corresponding to this xid */ | ||
| 1144 | spin_lock(&xprt->transport_lock); | ||
| 1145 | req = xprt_lookup_rqst(xprt, transport->tcp_xid); | ||
| 1146 | if (!req) { | ||
| 1147 | dprintk("RPC: XID %08x request not found!\n", | ||
| 1148 | ntohl(transport->tcp_xid)); | ||
| 1149 | spin_unlock(&xprt->transport_lock); | ||
| 1150 | return -1; | ||
| 1151 | } | ||
| 1152 | |||
| 1153 | xs_tcp_read_common(xprt, desc, req); | ||
| 1154 | |||
| 1074 | if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) | 1155 | if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) |
| 1075 | xprt_complete_rqst(req->rq_task, transport->tcp_copied); | 1156 | xprt_complete_rqst(req->rq_task, transport->tcp_copied); |
| 1157 | |||
| 1076 | spin_unlock(&xprt->transport_lock); | 1158 | spin_unlock(&xprt->transport_lock); |
| 1077 | xs_tcp_check_fraghdr(transport); | 1159 | return 0; |
| 1160 | } | ||
| 1161 | |||
| 1162 | #if defined(CONFIG_NFS_V4_1) | ||
| 1163 | /* | ||
| 1164 | * Obtains an rpc_rqst previously allocated and invokes the common | ||
| 1165 | * tcp read code to read the data. The result is placed in the callback | ||
| 1166 | * queue. | ||
| 1167 | * If we're unable to obtain the rpc_rqst we schedule the closing of the | ||
| 1168 | * connection and return -1. | ||
| 1169 | */ | ||
| 1170 | static inline int xs_tcp_read_callback(struct rpc_xprt *xprt, | ||
| 1171 | struct xdr_skb_reader *desc) | ||
| 1172 | { | ||
| 1173 | struct sock_xprt *transport = | ||
| 1174 | container_of(xprt, struct sock_xprt, xprt); | ||
| 1175 | struct rpc_rqst *req; | ||
| 1176 | |||
| 1177 | req = xprt_alloc_bc_request(xprt); | ||
| 1178 | if (req == NULL) { | ||
| 1179 | printk(KERN_WARNING "Callback slot table overflowed\n"); | ||
| 1180 | xprt_force_disconnect(xprt); | ||
| 1181 | return -1; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | req->rq_xid = transport->tcp_xid; | ||
| 1185 | dprintk("RPC: read callback XID %08x\n", ntohl(req->rq_xid)); | ||
| 1186 | xs_tcp_read_common(xprt, desc, req); | ||
| 1187 | |||
| 1188 | if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) { | ||
| 1189 | struct svc_serv *bc_serv = xprt->bc_serv; | ||
| 1190 | |||
| 1191 | /* | ||
| 1192 | * Add callback request to callback list. The callback | ||
| 1193 | * service sleeps on the sv_cb_waitq waiting for new | ||
| 1194 | * requests. Wake it up after adding enqueing the | ||
| 1195 | * request. | ||
| 1196 | */ | ||
| 1197 | dprintk("RPC: add callback request to list\n"); | ||
| 1198 | spin_lock(&bc_serv->sv_cb_lock); | ||
| 1199 | list_add(&req->rq_bc_list, &bc_serv->sv_cb_list); | ||
| 1200 | spin_unlock(&bc_serv->sv_cb_lock); | ||
| 1201 | wake_up(&bc_serv->sv_cb_waitq); | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | req->rq_private_buf.len = transport->tcp_copied; | ||
| 1205 | |||
| 1206 | return 0; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | static inline int _xs_tcp_read_data(struct rpc_xprt *xprt, | ||
| 1210 | struct xdr_skb_reader *desc) | ||
| 1211 | { | ||
| 1212 | struct sock_xprt *transport = | ||
| 1213 | container_of(xprt, struct sock_xprt, xprt); | ||
| 1214 | |||
| 1215 | return (transport->tcp_flags & TCP_RPC_REPLY) ? | ||
| 1216 | xs_tcp_read_reply(xprt, desc) : | ||
| 1217 | xs_tcp_read_callback(xprt, desc); | ||
| 1218 | } | ||
| 1219 | #else | ||
| 1220 | static inline int _xs_tcp_read_data(struct rpc_xprt *xprt, | ||
| 1221 | struct xdr_skb_reader *desc) | ||
| 1222 | { | ||
| 1223 | return xs_tcp_read_reply(xprt, desc); | ||
| 1224 | } | ||
| 1225 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1226 | |||
| 1227 | /* | ||
| 1228 | * Read data off the transport. This can be either an RPC_CALL or an | ||
| 1229 | * RPC_REPLY. Relay the processing to helper functions. | ||
| 1230 | */ | ||
| 1231 | static void xs_tcp_read_data(struct rpc_xprt *xprt, | ||
| 1232 | struct xdr_skb_reader *desc) | ||
| 1233 | { | ||
| 1234 | struct sock_xprt *transport = | ||
| 1235 | container_of(xprt, struct sock_xprt, xprt); | ||
| 1236 | |||
| 1237 | if (_xs_tcp_read_data(xprt, desc) == 0) | ||
| 1238 | xs_tcp_check_fraghdr(transport); | ||
| 1239 | else { | ||
| 1240 | /* | ||
| 1241 | * The transport_lock protects the request handling. | ||
| 1242 | * There's no need to hold it to update the tcp_flags. | ||
| 1243 | */ | ||
| 1244 | transport->tcp_flags &= ~TCP_RCV_COPY_DATA; | ||
| 1245 | } | ||
| 1078 | } | 1246 | } |
| 1079 | 1247 | ||
| 1080 | static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_skb_reader *desc) | 1248 | static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_skb_reader *desc) |
| @@ -1114,9 +1282,14 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns | |||
| 1114 | xs_tcp_read_xid(transport, &desc); | 1282 | xs_tcp_read_xid(transport, &desc); |
| 1115 | continue; | 1283 | continue; |
| 1116 | } | 1284 | } |
| 1285 | /* Read in the call/reply flag */ | ||
| 1286 | if (transport->tcp_flags & TCP_RCV_READ_CALLDIR) { | ||
| 1287 | xs_tcp_read_calldir(transport, &desc); | ||
| 1288 | continue; | ||
| 1289 | } | ||
| 1117 | /* Read in the request data */ | 1290 | /* Read in the request data */ |
| 1118 | if (transport->tcp_flags & TCP_RCV_COPY_DATA) { | 1291 | if (transport->tcp_flags & TCP_RCV_COPY_DATA) { |
| 1119 | xs_tcp_read_request(xprt, &desc); | 1292 | xs_tcp_read_data(xprt, &desc); |
| 1120 | continue; | 1293 | continue; |
| 1121 | } | 1294 | } |
| 1122 | /* Skip over any trailing bytes on short reads */ | 1295 | /* Skip over any trailing bytes on short reads */ |
| @@ -2010,6 +2183,9 @@ static struct rpc_xprt_ops xs_tcp_ops = { | |||
| 2010 | .buf_free = rpc_free, | 2183 | .buf_free = rpc_free, |
| 2011 | .send_request = xs_tcp_send_request, | 2184 | .send_request = xs_tcp_send_request, |
| 2012 | .set_retrans_timeout = xprt_set_retrans_timeout_def, | 2185 | .set_retrans_timeout = xprt_set_retrans_timeout_def, |
| 2186 | #if defined(CONFIG_NFS_V4_1) | ||
| 2187 | .release_request = bc_release_request, | ||
| 2188 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 2013 | .close = xs_tcp_close, | 2189 | .close = xs_tcp_close, |
| 2014 | .destroy = xs_destroy, | 2190 | .destroy = xs_destroy, |
| 2015 | .print_stats = xs_tcp_print_stats, | 2191 | .print_stats = xs_tcp_print_stats, |
