diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 876 |
1 files changed, 499 insertions, 377 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 648e0ac0f90e..6ca2795ccd9c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -65,6 +65,9 @@ static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *) | |||
65 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | 65 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); |
66 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | 66 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); |
67 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); | 67 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); |
68 | static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags); | ||
69 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | ||
70 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | ||
68 | 71 | ||
69 | /* Prevent leaks of NFSv4 errors into userland */ | 72 | /* Prevent leaks of NFSv4 errors into userland */ |
70 | int nfs4_map_errors(int err) | 73 | int nfs4_map_errors(int err) |
@@ -214,27 +217,39 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | |||
214 | } | 217 | } |
215 | 218 | ||
216 | struct nfs4_opendata { | 219 | struct nfs4_opendata { |
217 | atomic_t count; | 220 | struct kref kref; |
218 | struct nfs_openargs o_arg; | 221 | struct nfs_openargs o_arg; |
219 | struct nfs_openres o_res; | 222 | struct nfs_openres o_res; |
220 | struct nfs_open_confirmargs c_arg; | 223 | struct nfs_open_confirmargs c_arg; |
221 | struct nfs_open_confirmres c_res; | 224 | struct nfs_open_confirmres c_res; |
222 | struct nfs_fattr f_attr; | 225 | struct nfs_fattr f_attr; |
223 | struct nfs_fattr dir_attr; | 226 | struct nfs_fattr dir_attr; |
224 | struct dentry *dentry; | 227 | struct path path; |
225 | struct dentry *dir; | 228 | struct dentry *dir; |
226 | struct nfs4_state_owner *owner; | 229 | struct nfs4_state_owner *owner; |
230 | struct nfs4_state *state; | ||
227 | struct iattr attrs; | 231 | struct iattr attrs; |
228 | unsigned long timestamp; | 232 | unsigned long timestamp; |
233 | unsigned int rpc_done : 1; | ||
229 | int rpc_status; | 234 | int rpc_status; |
230 | int cancelled; | 235 | int cancelled; |
231 | }; | 236 | }; |
232 | 237 | ||
233 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | 238 | |
239 | static void nfs4_init_opendata_res(struct nfs4_opendata *p) | ||
240 | { | ||
241 | p->o_res.f_attr = &p->f_attr; | ||
242 | p->o_res.dir_attr = &p->dir_attr; | ||
243 | p->o_res.server = p->o_arg.server; | ||
244 | nfs_fattr_init(&p->f_attr); | ||
245 | nfs_fattr_init(&p->dir_attr); | ||
246 | } | ||
247 | |||
248 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | ||
234 | struct nfs4_state_owner *sp, int flags, | 249 | struct nfs4_state_owner *sp, int flags, |
235 | const struct iattr *attrs) | 250 | const struct iattr *attrs) |
236 | { | 251 | { |
237 | struct dentry *parent = dget_parent(dentry); | 252 | struct dentry *parent = dget_parent(path->dentry); |
238 | struct inode *dir = parent->d_inode; | 253 | struct inode *dir = parent->d_inode; |
239 | struct nfs_server *server = NFS_SERVER(dir); | 254 | struct nfs_server *server = NFS_SERVER(dir); |
240 | struct nfs4_opendata *p; | 255 | struct nfs4_opendata *p; |
@@ -245,24 +260,19 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
245 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 260 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); |
246 | if (p->o_arg.seqid == NULL) | 261 | if (p->o_arg.seqid == NULL) |
247 | goto err_free; | 262 | goto err_free; |
248 | atomic_set(&p->count, 1); | 263 | p->path.mnt = mntget(path->mnt); |
249 | p->dentry = dget(dentry); | 264 | p->path.dentry = dget(path->dentry); |
250 | p->dir = parent; | 265 | p->dir = parent; |
251 | p->owner = sp; | 266 | p->owner = sp; |
252 | atomic_inc(&sp->so_count); | 267 | atomic_inc(&sp->so_count); |
253 | p->o_arg.fh = NFS_FH(dir); | 268 | p->o_arg.fh = NFS_FH(dir); |
254 | p->o_arg.open_flags = flags, | 269 | p->o_arg.open_flags = flags, |
255 | p->o_arg.clientid = server->nfs_client->cl_clientid; | 270 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
256 | p->o_arg.id = sp->so_id; | 271 | p->o_arg.id = sp->so_owner_id.id; |
257 | p->o_arg.name = &dentry->d_name; | 272 | p->o_arg.name = &p->path.dentry->d_name; |
258 | p->o_arg.server = server; | 273 | p->o_arg.server = server; |
259 | p->o_arg.bitmask = server->attr_bitmask; | 274 | p->o_arg.bitmask = server->attr_bitmask; |
260 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 275 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
261 | p->o_res.f_attr = &p->f_attr; | ||
262 | p->o_res.dir_attr = &p->dir_attr; | ||
263 | p->o_res.server = server; | ||
264 | nfs_fattr_init(&p->f_attr); | ||
265 | nfs_fattr_init(&p->dir_attr); | ||
266 | if (flags & O_EXCL) { | 276 | if (flags & O_EXCL) { |
267 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | 277 | u32 *s = (u32 *) p->o_arg.u.verifier.data; |
268 | s[0] = jiffies; | 278 | s[0] = jiffies; |
@@ -274,6 +284,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
274 | p->c_arg.fh = &p->o_res.fh; | 284 | p->c_arg.fh = &p->o_res.fh; |
275 | p->c_arg.stateid = &p->o_res.stateid; | 285 | p->c_arg.stateid = &p->o_res.stateid; |
276 | p->c_arg.seqid = p->o_arg.seqid; | 286 | p->c_arg.seqid = p->o_arg.seqid; |
287 | nfs4_init_opendata_res(p); | ||
288 | kref_init(&p->kref); | ||
277 | return p; | 289 | return p; |
278 | err_free: | 290 | err_free: |
279 | kfree(p); | 291 | kfree(p); |
@@ -282,27 +294,25 @@ err: | |||
282 | return NULL; | 294 | return NULL; |
283 | } | 295 | } |
284 | 296 | ||
285 | static void nfs4_opendata_free(struct nfs4_opendata *p) | 297 | static void nfs4_opendata_free(struct kref *kref) |
286 | { | 298 | { |
287 | if (p != NULL && atomic_dec_and_test(&p->count)) { | 299 | struct nfs4_opendata *p = container_of(kref, |
288 | nfs_free_seqid(p->o_arg.seqid); | 300 | struct nfs4_opendata, kref); |
289 | nfs4_put_state_owner(p->owner); | 301 | |
290 | dput(p->dir); | 302 | nfs_free_seqid(p->o_arg.seqid); |
291 | dput(p->dentry); | 303 | if (p->state != NULL) |
292 | kfree(p); | 304 | nfs4_put_open_state(p->state); |
293 | } | 305 | nfs4_put_state_owner(p->owner); |
306 | dput(p->dir); | ||
307 | dput(p->path.dentry); | ||
308 | mntput(p->path.mnt); | ||
309 | kfree(p); | ||
294 | } | 310 | } |
295 | 311 | ||
296 | /* Helper for asynchronous RPC calls */ | 312 | static void nfs4_opendata_put(struct nfs4_opendata *p) |
297 | static int nfs4_call_async(struct rpc_clnt *clnt, | ||
298 | const struct rpc_call_ops *tk_ops, void *calldata) | ||
299 | { | 313 | { |
300 | struct rpc_task *task; | 314 | if (p != NULL) |
301 | 315 | kref_put(&p->kref, nfs4_opendata_free); | |
302 | if (!(task = rpc_new_task(clnt, RPC_TASK_ASYNC, tk_ops, calldata))) | ||
303 | return -ENOMEM; | ||
304 | rpc_execute(task); | ||
305 | return 0; | ||
306 | } | 316 | } |
307 | 317 | ||
308 | static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | 318 | static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) |
@@ -316,7 +326,34 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | |||
316 | return ret; | 326 | return ret; |
317 | } | 327 | } |
318 | 328 | ||
319 | static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | 329 | static int can_open_cached(struct nfs4_state *state, int mode) |
330 | { | ||
331 | int ret = 0; | ||
332 | switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) { | ||
333 | case FMODE_READ: | ||
334 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; | ||
335 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | ||
336 | break; | ||
337 | case FMODE_WRITE: | ||
338 | ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; | ||
339 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | ||
340 | break; | ||
341 | case FMODE_READ|FMODE_WRITE: | ||
342 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | ||
343 | } | ||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags) | ||
348 | { | ||
349 | if ((delegation->type & open_flags) != open_flags) | ||
350 | return 0; | ||
351 | if (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) | ||
352 | return 0; | ||
353 | return 1; | ||
354 | } | ||
355 | |||
356 | static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | ||
320 | { | 357 | { |
321 | switch (open_flags) { | 358 | switch (open_flags) { |
322 | case FMODE_WRITE: | 359 | case FMODE_WRITE: |
@@ -328,41 +365,176 @@ static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_ | |||
328 | case FMODE_READ|FMODE_WRITE: | 365 | case FMODE_READ|FMODE_WRITE: |
329 | state->n_rdwr++; | 366 | state->n_rdwr++; |
330 | } | 367 | } |
368 | nfs4_state_set_mode_locked(state, state->state | open_flags); | ||
331 | } | 369 | } |
332 | 370 | ||
333 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 371 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) |
334 | { | 372 | { |
335 | struct inode *inode = state->inode; | 373 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
374 | memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); | ||
375 | memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); | ||
376 | switch (open_flags) { | ||
377 | case FMODE_READ: | ||
378 | set_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
379 | break; | ||
380 | case FMODE_WRITE: | ||
381 | set_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
382 | break; | ||
383 | case FMODE_READ|FMODE_WRITE: | ||
384 | set_bit(NFS_O_RDWR_STATE, &state->flags); | ||
385 | } | ||
386 | } | ||
387 | |||
388 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | ||
389 | { | ||
390 | write_seqlock(&state->seqlock); | ||
391 | nfs_set_open_stateid_locked(state, stateid, open_flags); | ||
392 | write_sequnlock(&state->seqlock); | ||
393 | } | ||
336 | 394 | ||
395 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags) | ||
396 | { | ||
337 | open_flags &= (FMODE_READ|FMODE_WRITE); | 397 | open_flags &= (FMODE_READ|FMODE_WRITE); |
338 | /* Protect against nfs4_find_state_byowner() */ | 398 | /* |
399 | * Protect the call to nfs4_state_set_mode_locked and | ||
400 | * serialise the stateid update | ||
401 | */ | ||
402 | write_seqlock(&state->seqlock); | ||
403 | if (deleg_stateid != NULL) { | ||
404 | memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data)); | ||
405 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
406 | } | ||
407 | if (open_stateid != NULL) | ||
408 | nfs_set_open_stateid_locked(state, open_stateid, open_flags); | ||
409 | write_sequnlock(&state->seqlock); | ||
339 | spin_lock(&state->owner->so_lock); | 410 | spin_lock(&state->owner->so_lock); |
340 | spin_lock(&inode->i_lock); | ||
341 | memcpy(&state->stateid, stateid, sizeof(state->stateid)); | ||
342 | update_open_stateflags(state, open_flags); | 411 | update_open_stateflags(state, open_flags); |
343 | nfs4_state_set_mode_locked(state, state->state | open_flags); | ||
344 | spin_unlock(&inode->i_lock); | ||
345 | spin_unlock(&state->owner->so_lock); | 412 | spin_unlock(&state->owner->so_lock); |
346 | } | 413 | } |
347 | 414 | ||
415 | static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open_flags) | ||
416 | { | ||
417 | struct nfs_delegation *delegation; | ||
418 | |||
419 | rcu_read_lock(); | ||
420 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
421 | if (delegation == NULL || (delegation->type & open_flags) == open_flags) { | ||
422 | rcu_read_unlock(); | ||
423 | return; | ||
424 | } | ||
425 | rcu_read_unlock(); | ||
426 | nfs_inode_return_delegation(inode); | ||
427 | } | ||
428 | |||
429 | static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | ||
430 | { | ||
431 | struct nfs4_state *state = opendata->state; | ||
432 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
433 | struct nfs_delegation *delegation; | ||
434 | int open_mode = opendata->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL); | ||
435 | nfs4_stateid stateid; | ||
436 | int ret = -EAGAIN; | ||
437 | |||
438 | rcu_read_lock(); | ||
439 | delegation = rcu_dereference(nfsi->delegation); | ||
440 | for (;;) { | ||
441 | if (can_open_cached(state, open_mode)) { | ||
442 | spin_lock(&state->owner->so_lock); | ||
443 | if (can_open_cached(state, open_mode)) { | ||
444 | update_open_stateflags(state, open_mode); | ||
445 | spin_unlock(&state->owner->so_lock); | ||
446 | rcu_read_unlock(); | ||
447 | goto out_return_state; | ||
448 | } | ||
449 | spin_unlock(&state->owner->so_lock); | ||
450 | } | ||
451 | if (delegation == NULL) | ||
452 | break; | ||
453 | if (!can_open_delegated(delegation, open_mode)) | ||
454 | break; | ||
455 | /* Save the delegation */ | ||
456 | memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); | ||
457 | rcu_read_unlock(); | ||
458 | lock_kernel(); | ||
459 | ret = _nfs4_do_access(state->inode, state->owner->so_cred, open_mode); | ||
460 | unlock_kernel(); | ||
461 | if (ret != 0) | ||
462 | goto out; | ||
463 | ret = -EAGAIN; | ||
464 | rcu_read_lock(); | ||
465 | delegation = rcu_dereference(nfsi->delegation); | ||
466 | /* If no delegation, try a cached open */ | ||
467 | if (delegation == NULL) | ||
468 | continue; | ||
469 | /* Is the delegation still valid? */ | ||
470 | if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0) | ||
471 | continue; | ||
472 | rcu_read_unlock(); | ||
473 | update_open_stateid(state, NULL, &stateid, open_mode); | ||
474 | goto out_return_state; | ||
475 | } | ||
476 | rcu_read_unlock(); | ||
477 | out: | ||
478 | return ERR_PTR(ret); | ||
479 | out_return_state: | ||
480 | atomic_inc(&state->count); | ||
481 | return state; | ||
482 | } | ||
483 | |||
348 | static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) | 484 | static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) |
349 | { | 485 | { |
350 | struct inode *inode; | 486 | struct inode *inode; |
351 | struct nfs4_state *state = NULL; | 487 | struct nfs4_state *state = NULL; |
488 | struct nfs_delegation *delegation; | ||
489 | nfs4_stateid *deleg_stateid = NULL; | ||
490 | int ret; | ||
352 | 491 | ||
353 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | 492 | if (!data->rpc_done) { |
493 | state = nfs4_try_open_cached(data); | ||
354 | goto out; | 494 | goto out; |
495 | } | ||
496 | |||
497 | ret = -EAGAIN; | ||
498 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | ||
499 | goto err; | ||
355 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); | 500 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); |
501 | ret = PTR_ERR(inode); | ||
356 | if (IS_ERR(inode)) | 502 | if (IS_ERR(inode)) |
357 | goto out; | 503 | goto err; |
504 | ret = -ENOMEM; | ||
358 | state = nfs4_get_open_state(inode, data->owner); | 505 | state = nfs4_get_open_state(inode, data->owner); |
359 | if (state == NULL) | 506 | if (state == NULL) |
360 | goto put_inode; | 507 | goto err_put_inode; |
361 | update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags); | 508 | if (data->o_res.delegation_type != 0) { |
362 | put_inode: | 509 | int delegation_flags = 0; |
510 | |||
511 | rcu_read_lock(); | ||
512 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
513 | if (delegation) | ||
514 | delegation_flags = delegation->flags; | ||
515 | rcu_read_unlock(); | ||
516 | if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) | ||
517 | nfs_inode_set_delegation(state->inode, | ||
518 | data->owner->so_cred, | ||
519 | &data->o_res); | ||
520 | else | ||
521 | nfs_inode_reclaim_delegation(state->inode, | ||
522 | data->owner->so_cred, | ||
523 | &data->o_res); | ||
524 | } | ||
525 | rcu_read_lock(); | ||
526 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
527 | if (delegation != NULL) | ||
528 | deleg_stateid = &delegation->stateid; | ||
529 | update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags); | ||
530 | rcu_read_unlock(); | ||
363 | iput(inode); | 531 | iput(inode); |
364 | out: | 532 | out: |
365 | return state; | 533 | return state; |
534 | err_put_inode: | ||
535 | iput(inode); | ||
536 | err: | ||
537 | return ERR_PTR(ret); | ||
366 | } | 538 | } |
367 | 539 | ||
368 | static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) | 540 | static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) |
@@ -382,79 +554,78 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state * | |||
382 | return ERR_PTR(-ENOENT); | 554 | return ERR_PTR(-ENOENT); |
383 | } | 555 | } |
384 | 556 | ||
385 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid) | 557 | static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state) |
386 | { | 558 | { |
559 | struct nfs4_opendata *opendata; | ||
560 | |||
561 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); | ||
562 | if (opendata == NULL) | ||
563 | return ERR_PTR(-ENOMEM); | ||
564 | opendata->state = state; | ||
565 | atomic_inc(&state->count); | ||
566 | return opendata; | ||
567 | } | ||
568 | |||
569 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res) | ||
570 | { | ||
571 | struct nfs4_state *newstate; | ||
387 | int ret; | 572 | int ret; |
388 | 573 | ||
389 | opendata->o_arg.open_flags = openflags; | 574 | opendata->o_arg.open_flags = openflags; |
575 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | ||
576 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | ||
577 | nfs4_init_opendata_res(opendata); | ||
390 | ret = _nfs4_proc_open(opendata); | 578 | ret = _nfs4_proc_open(opendata); |
391 | if (ret != 0) | 579 | if (ret != 0) |
392 | return ret; | 580 | return ret; |
393 | memcpy(stateid->data, opendata->o_res.stateid.data, | 581 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
394 | sizeof(stateid->data)); | 582 | if (IS_ERR(newstate)) |
583 | return PTR_ERR(newstate); | ||
584 | nfs4_close_state(&opendata->path, newstate, openflags); | ||
585 | *res = newstate; | ||
395 | return 0; | 586 | return 0; |
396 | } | 587 | } |
397 | 588 | ||
398 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) | 589 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) |
399 | { | 590 | { |
400 | nfs4_stateid stateid; | ||
401 | struct nfs4_state *newstate; | 591 | struct nfs4_state *newstate; |
402 | int mode = 0; | ||
403 | int delegation = 0; | ||
404 | int ret; | 592 | int ret; |
405 | 593 | ||
406 | /* memory barrier prior to reading state->n_* */ | 594 | /* memory barrier prior to reading state->n_* */ |
595 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
407 | smp_rmb(); | 596 | smp_rmb(); |
408 | if (state->n_rdwr != 0) { | 597 | if (state->n_rdwr != 0) { |
409 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid); | 598 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); |
410 | if (ret != 0) | 599 | if (ret != 0) |
411 | return ret; | 600 | return ret; |
412 | mode |= FMODE_READ|FMODE_WRITE; | 601 | if (newstate != state) |
413 | if (opendata->o_res.delegation_type != 0) | 602 | return -ESTALE; |
414 | delegation = opendata->o_res.delegation_type; | ||
415 | smp_rmb(); | ||
416 | } | 603 | } |
417 | if (state->n_wronly != 0) { | 604 | if (state->n_wronly != 0) { |
418 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid); | 605 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); |
419 | if (ret != 0) | 606 | if (ret != 0) |
420 | return ret; | 607 | return ret; |
421 | mode |= FMODE_WRITE; | 608 | if (newstate != state) |
422 | if (opendata->o_res.delegation_type != 0) | 609 | return -ESTALE; |
423 | delegation = opendata->o_res.delegation_type; | ||
424 | smp_rmb(); | ||
425 | } | 610 | } |
426 | if (state->n_rdonly != 0) { | 611 | if (state->n_rdonly != 0) { |
427 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid); | 612 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); |
428 | if (ret != 0) | 613 | if (ret != 0) |
429 | return ret; | 614 | return ret; |
430 | mode |= FMODE_READ; | 615 | if (newstate != state) |
616 | return -ESTALE; | ||
431 | } | 617 | } |
432 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 618 | /* |
433 | if (mode == 0) | 619 | * We may have performed cached opens for all three recoveries. |
434 | return 0; | 620 | * Check if we need to update the current stateid. |
435 | if (opendata->o_res.delegation_type == 0) | 621 | */ |
436 | opendata->o_res.delegation_type = delegation; | 622 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && |
437 | opendata->o_arg.open_flags |= mode; | 623 | memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) { |
438 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 624 | write_seqlock(&state->seqlock); |
439 | if (newstate != NULL) { | 625 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
440 | if (opendata->o_res.delegation_type != 0) { | 626 | memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)); |
441 | struct nfs_inode *nfsi = NFS_I(newstate->inode); | 627 | write_sequnlock(&state->seqlock); |
442 | int delegation_flags = 0; | ||
443 | if (nfsi->delegation) | ||
444 | delegation_flags = nfsi->delegation->flags; | ||
445 | if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) | ||
446 | nfs_inode_set_delegation(newstate->inode, | ||
447 | opendata->owner->so_cred, | ||
448 | &opendata->o_res); | ||
449 | else | ||
450 | nfs_inode_reclaim_delegation(newstate->inode, | ||
451 | opendata->owner->so_cred, | ||
452 | &opendata->o_res); | ||
453 | } | ||
454 | nfs4_close_state(newstate, opendata->o_arg.open_flags); | ||
455 | } | 628 | } |
456 | if (newstate != state) | ||
457 | return -ESTALE; | ||
458 | return 0; | 629 | return 0; |
459 | } | 630 | } |
460 | 631 | ||
@@ -462,41 +633,36 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
462 | * OPEN_RECLAIM: | 633 | * OPEN_RECLAIM: |
463 | * reclaim state on the server after a reboot. | 634 | * reclaim state on the server after a reboot. |
464 | */ | 635 | */ |
465 | static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 636 | static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state) |
466 | { | 637 | { |
467 | struct nfs_delegation *delegation = NFS_I(state->inode)->delegation; | 638 | struct nfs_delegation *delegation; |
468 | struct nfs4_opendata *opendata; | 639 | struct nfs4_opendata *opendata; |
469 | int delegation_type = 0; | 640 | int delegation_type = 0; |
470 | int status; | 641 | int status; |
471 | 642 | ||
472 | if (delegation != NULL) { | 643 | opendata = nfs4_open_recoverdata_alloc(ctx, state); |
473 | if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { | 644 | if (IS_ERR(opendata)) |
474 | memcpy(&state->stateid, &delegation->stateid, | 645 | return PTR_ERR(opendata); |
475 | sizeof(state->stateid)); | ||
476 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
477 | return 0; | ||
478 | } | ||
479 | delegation_type = delegation->type; | ||
480 | } | ||
481 | opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); | ||
482 | if (opendata == NULL) | ||
483 | return -ENOMEM; | ||
484 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; | 646 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; |
485 | opendata->o_arg.fh = NFS_FH(state->inode); | 647 | opendata->o_arg.fh = NFS_FH(state->inode); |
486 | nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh); | 648 | rcu_read_lock(); |
649 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); | ||
650 | if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0) | ||
651 | delegation_type = delegation->flags; | ||
652 | rcu_read_unlock(); | ||
487 | opendata->o_arg.u.delegation_type = delegation_type; | 653 | opendata->o_arg.u.delegation_type = delegation_type; |
488 | status = nfs4_open_recover(opendata, state); | 654 | status = nfs4_open_recover(opendata, state); |
489 | nfs4_opendata_free(opendata); | 655 | nfs4_opendata_put(opendata); |
490 | return status; | 656 | return status; |
491 | } | 657 | } |
492 | 658 | ||
493 | static int nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 659 | static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state) |
494 | { | 660 | { |
495 | struct nfs_server *server = NFS_SERVER(state->inode); | 661 | struct nfs_server *server = NFS_SERVER(state->inode); |
496 | struct nfs4_exception exception = { }; | 662 | struct nfs4_exception exception = { }; |
497 | int err; | 663 | int err; |
498 | do { | 664 | do { |
499 | err = _nfs4_do_open_reclaim(sp, state, dentry); | 665 | err = _nfs4_do_open_reclaim(ctx, state); |
500 | if (err != -NFS4ERR_DELAY) | 666 | if (err != -NFS4ERR_DELAY) |
501 | break; | 667 | break; |
502 | nfs4_handle_exception(server, err, &exception); | 668 | nfs4_handle_exception(server, err, &exception); |
@@ -512,37 +678,34 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
512 | ctx = nfs4_state_find_open_context(state); | 678 | ctx = nfs4_state_find_open_context(state); |
513 | if (IS_ERR(ctx)) | 679 | if (IS_ERR(ctx)) |
514 | return PTR_ERR(ctx); | 680 | return PTR_ERR(ctx); |
515 | ret = nfs4_do_open_reclaim(sp, state, ctx->dentry); | 681 | ret = nfs4_do_open_reclaim(ctx, state); |
516 | put_nfs_open_context(ctx); | 682 | put_nfs_open_context(ctx); |
517 | return ret; | 683 | return ret; |
518 | } | 684 | } |
519 | 685 | ||
520 | static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | 686 | static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) |
521 | { | 687 | { |
522 | struct nfs4_state_owner *sp = state->owner; | ||
523 | struct nfs4_opendata *opendata; | 688 | struct nfs4_opendata *opendata; |
524 | int ret; | 689 | int ret; |
525 | 690 | ||
526 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 691 | opendata = nfs4_open_recoverdata_alloc(ctx, state); |
527 | return 0; | 692 | if (IS_ERR(opendata)) |
528 | opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); | 693 | return PTR_ERR(opendata); |
529 | if (opendata == NULL) | ||
530 | return -ENOMEM; | ||
531 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; | 694 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; |
532 | memcpy(opendata->o_arg.u.delegation.data, state->stateid.data, | 695 | memcpy(opendata->o_arg.u.delegation.data, stateid->data, |
533 | sizeof(opendata->o_arg.u.delegation.data)); | 696 | sizeof(opendata->o_arg.u.delegation.data)); |
534 | ret = nfs4_open_recover(opendata, state); | 697 | ret = nfs4_open_recover(opendata, state); |
535 | nfs4_opendata_free(opendata); | 698 | nfs4_opendata_put(opendata); |
536 | return ret; | 699 | return ret; |
537 | } | 700 | } |
538 | 701 | ||
539 | int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | 702 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) |
540 | { | 703 | { |
541 | struct nfs4_exception exception = { }; | 704 | struct nfs4_exception exception = { }; |
542 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | 705 | struct nfs_server *server = NFS_SERVER(state->inode); |
543 | int err; | 706 | int err; |
544 | do { | 707 | do { |
545 | err = _nfs4_open_delegation_recall(dentry, state); | 708 | err = _nfs4_open_delegation_recall(ctx, state, stateid); |
546 | switch (err) { | 709 | switch (err) { |
547 | case 0: | 710 | case 0: |
548 | return err; | 711 | return err; |
@@ -582,9 +745,10 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | |||
582 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, | 745 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, |
583 | sizeof(data->o_res.stateid.data)); | 746 | sizeof(data->o_res.stateid.data)); |
584 | renew_lease(data->o_res.server, data->timestamp); | 747 | renew_lease(data->o_res.server, data->timestamp); |
748 | data->rpc_done = 1; | ||
585 | } | 749 | } |
586 | nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | ||
587 | nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status); | 750 | nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status); |
751 | nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | ||
588 | } | 752 | } |
589 | 753 | ||
590 | static void nfs4_open_confirm_release(void *calldata) | 754 | static void nfs4_open_confirm_release(void *calldata) |
@@ -596,14 +760,14 @@ static void nfs4_open_confirm_release(void *calldata) | |||
596 | if (data->cancelled == 0) | 760 | if (data->cancelled == 0) |
597 | goto out_free; | 761 | goto out_free; |
598 | /* In case of error, no cleanup! */ | 762 | /* In case of error, no cleanup! */ |
599 | if (data->rpc_status != 0) | 763 | if (!data->rpc_done) |
600 | goto out_free; | 764 | goto out_free; |
601 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 765 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
602 | state = nfs4_opendata_to_nfs4_state(data); | 766 | state = nfs4_opendata_to_nfs4_state(data); |
603 | if (state != NULL) | 767 | if (!IS_ERR(state)) |
604 | nfs4_close_state(state, data->o_arg.open_flags); | 768 | nfs4_close_state(&data->path, state, data->o_arg.open_flags); |
605 | out_free: | 769 | out_free: |
606 | nfs4_opendata_free(data); | 770 | nfs4_opendata_put(data); |
607 | } | 771 | } |
608 | 772 | ||
609 | static const struct rpc_call_ops nfs4_open_confirm_ops = { | 773 | static const struct rpc_call_ops nfs4_open_confirm_ops = { |
@@ -621,12 +785,9 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |||
621 | struct rpc_task *task; | 785 | struct rpc_task *task; |
622 | int status; | 786 | int status; |
623 | 787 | ||
624 | atomic_inc(&data->count); | 788 | kref_get(&data->kref); |
625 | /* | 789 | data->rpc_done = 0; |
626 | * If rpc_run_task() ends up calling ->rpc_release(), we | 790 | data->rpc_status = 0; |
627 | * want to ensure that it takes the 'error' code path. | ||
628 | */ | ||
629 | data->rpc_status = -ENOMEM; | ||
630 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); | 791 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); |
631 | if (IS_ERR(task)) | 792 | if (IS_ERR(task)) |
632 | return PTR_ERR(task); | 793 | return PTR_ERR(task); |
@@ -653,13 +814,37 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
653 | 814 | ||
654 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) | 815 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) |
655 | return; | 816 | return; |
817 | /* | ||
818 | * Check if we still need to send an OPEN call, or if we can use | ||
819 | * a delegation instead. | ||
820 | */ | ||
821 | if (data->state != NULL) { | ||
822 | struct nfs_delegation *delegation; | ||
823 | |||
824 | if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL))) | ||
825 | goto out_no_action; | ||
826 | rcu_read_lock(); | ||
827 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); | ||
828 | if (delegation != NULL && | ||
829 | (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) { | ||
830 | rcu_read_unlock(); | ||
831 | goto out_no_action; | ||
832 | } | ||
833 | rcu_read_unlock(); | ||
834 | } | ||
656 | /* Update sequence id. */ | 835 | /* Update sequence id. */ |
657 | data->o_arg.id = sp->so_id; | 836 | data->o_arg.id = sp->so_owner_id.id; |
658 | data->o_arg.clientid = sp->so_client->cl_clientid; | 837 | data->o_arg.clientid = sp->so_client->cl_clientid; |
659 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) | 838 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { |
660 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | 839 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; |
840 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | ||
841 | } | ||
661 | data->timestamp = jiffies; | 842 | data->timestamp = jiffies; |
662 | rpc_call_setup(task, &msg, 0); | 843 | rpc_call_setup(task, &msg, 0); |
844 | return; | ||
845 | out_no_action: | ||
846 | task->tk_action = NULL; | ||
847 | |||
663 | } | 848 | } |
664 | 849 | ||
665 | static void nfs4_open_done(struct rpc_task *task, void *calldata) | 850 | static void nfs4_open_done(struct rpc_task *task, void *calldata) |
@@ -683,8 +868,11 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
683 | data->rpc_status = -ENOTDIR; | 868 | data->rpc_status = -ENOTDIR; |
684 | } | 869 | } |
685 | renew_lease(data->o_res.server, data->timestamp); | 870 | renew_lease(data->o_res.server, data->timestamp); |
871 | if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) | ||
872 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | ||
686 | } | 873 | } |
687 | nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); | 874 | nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); |
875 | data->rpc_done = 1; | ||
688 | } | 876 | } |
689 | 877 | ||
690 | static void nfs4_open_release(void *calldata) | 878 | static void nfs4_open_release(void *calldata) |
@@ -696,17 +884,17 @@ static void nfs4_open_release(void *calldata) | |||
696 | if (data->cancelled == 0) | 884 | if (data->cancelled == 0) |
697 | goto out_free; | 885 | goto out_free; |
698 | /* In case of error, no cleanup! */ | 886 | /* In case of error, no cleanup! */ |
699 | if (data->rpc_status != 0) | 887 | if (data->rpc_status != 0 || !data->rpc_done) |
700 | goto out_free; | 888 | goto out_free; |
701 | /* In case we need an open_confirm, no cleanup! */ | 889 | /* In case we need an open_confirm, no cleanup! */ |
702 | if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) | 890 | if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) |
703 | goto out_free; | 891 | goto out_free; |
704 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 892 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
705 | state = nfs4_opendata_to_nfs4_state(data); | 893 | state = nfs4_opendata_to_nfs4_state(data); |
706 | if (state != NULL) | 894 | if (!IS_ERR(state)) |
707 | nfs4_close_state(state, data->o_arg.open_flags); | 895 | nfs4_close_state(&data->path, state, data->o_arg.open_flags); |
708 | out_free: | 896 | out_free: |
709 | nfs4_opendata_free(data); | 897 | nfs4_opendata_put(data); |
710 | } | 898 | } |
711 | 899 | ||
712 | static const struct rpc_call_ops nfs4_open_ops = { | 900 | static const struct rpc_call_ops nfs4_open_ops = { |
@@ -727,12 +915,10 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
727 | struct rpc_task *task; | 915 | struct rpc_task *task; |
728 | int status; | 916 | int status; |
729 | 917 | ||
730 | atomic_inc(&data->count); | 918 | kref_get(&data->kref); |
731 | /* | 919 | data->rpc_done = 0; |
732 | * If rpc_run_task() ends up calling ->rpc_release(), we | 920 | data->rpc_status = 0; |
733 | * want to ensure that it takes the 'error' code path. | 921 | data->cancelled = 0; |
734 | */ | ||
735 | data->rpc_status = -ENOMEM; | ||
736 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); | 922 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); |
737 | if (IS_ERR(task)) | 923 | if (IS_ERR(task)) |
738 | return PTR_ERR(task); | 924 | return PTR_ERR(task); |
@@ -743,9 +929,12 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
743 | } else | 929 | } else |
744 | status = data->rpc_status; | 930 | status = data->rpc_status; |
745 | rpc_put_task(task); | 931 | rpc_put_task(task); |
746 | if (status != 0) | 932 | if (status != 0 || !data->rpc_done) |
747 | return status; | 933 | return status; |
748 | 934 | ||
935 | if (o_res->fh.size == 0) | ||
936 | _nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr); | ||
937 | |||
749 | if (o_arg->open_flags & O_CREAT) { | 938 | if (o_arg->open_flags & O_CREAT) { |
750 | update_changeattr(dir, &o_res->cinfo); | 939 | update_changeattr(dir, &o_res->cinfo); |
751 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 940 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
@@ -756,9 +945,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
756 | if (status != 0) | 945 | if (status != 0) |
757 | return status; | 946 | return status; |
758 | } | 947 | } |
759 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | ||
760 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) | 948 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) |
761 | return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); | 949 | _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr); |
762 | return 0; | 950 | return 0; |
763 | } | 951 | } |
764 | 952 | ||
@@ -772,6 +960,8 @@ static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openf | |||
772 | mask |= MAY_READ; | 960 | mask |= MAY_READ; |
773 | if (openflags & FMODE_WRITE) | 961 | if (openflags & FMODE_WRITE) |
774 | mask |= MAY_WRITE; | 962 | mask |= MAY_WRITE; |
963 | if (openflags & FMODE_EXEC) | ||
964 | mask |= MAY_EXEC; | ||
775 | status = nfs_access_get_cached(inode, cred, &cache); | 965 | status = nfs_access_get_cached(inode, cred, &cache); |
776 | if (status == 0) | 966 | if (status == 0) |
777 | goto out; | 967 | goto out; |
@@ -811,43 +1001,32 @@ static int nfs4_recover_expired_lease(struct nfs_server *server) | |||
811 | * reclaim state on the server after a network partition. | 1001 | * reclaim state on the server after a network partition. |
812 | * Assumes caller holds the appropriate lock | 1002 | * Assumes caller holds the appropriate lock |
813 | */ | 1003 | */ |
814 | static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 1004 | static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) |
815 | { | 1005 | { |
816 | struct inode *inode = state->inode; | ||
817 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | ||
818 | struct nfs4_opendata *opendata; | 1006 | struct nfs4_opendata *opendata; |
819 | int openflags = state->state & (FMODE_READ|FMODE_WRITE); | ||
820 | int ret; | 1007 | int ret; |
821 | 1008 | ||
822 | if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { | 1009 | opendata = nfs4_open_recoverdata_alloc(ctx, state); |
823 | ret = _nfs4_do_access(inode, sp->so_cred, openflags); | 1010 | if (IS_ERR(opendata)) |
824 | if (ret < 0) | 1011 | return PTR_ERR(opendata); |
825 | return ret; | ||
826 | memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); | ||
827 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
828 | return 0; | ||
829 | } | ||
830 | opendata = nfs4_opendata_alloc(dentry, sp, openflags, NULL); | ||
831 | if (opendata == NULL) | ||
832 | return -ENOMEM; | ||
833 | ret = nfs4_open_recover(opendata, state); | 1012 | ret = nfs4_open_recover(opendata, state); |
834 | if (ret == -ESTALE) { | 1013 | if (ret == -ESTALE) { |
835 | /* Invalidate the state owner so we don't ever use it again */ | 1014 | /* Invalidate the state owner so we don't ever use it again */ |
836 | nfs4_drop_state_owner(sp); | 1015 | nfs4_drop_state_owner(state->owner); |
837 | d_drop(dentry); | 1016 | d_drop(ctx->path.dentry); |
838 | } | 1017 | } |
839 | nfs4_opendata_free(opendata); | 1018 | nfs4_opendata_put(opendata); |
840 | return ret; | 1019 | return ret; |
841 | } | 1020 | } |
842 | 1021 | ||
843 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 1022 | static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) |
844 | { | 1023 | { |
845 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | 1024 | struct nfs_server *server = NFS_SERVER(state->inode); |
846 | struct nfs4_exception exception = { }; | 1025 | struct nfs4_exception exception = { }; |
847 | int err; | 1026 | int err; |
848 | 1027 | ||
849 | do { | 1028 | do { |
850 | err = _nfs4_open_expired(sp, state, dentry); | 1029 | err = _nfs4_open_expired(ctx, state); |
851 | if (err == -NFS4ERR_DELAY) | 1030 | if (err == -NFS4ERR_DELAY) |
852 | nfs4_handle_exception(server, err, &exception); | 1031 | nfs4_handle_exception(server, err, &exception); |
853 | } while (exception.retry); | 1032 | } while (exception.retry); |
@@ -862,107 +1041,38 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
862 | ctx = nfs4_state_find_open_context(state); | 1041 | ctx = nfs4_state_find_open_context(state); |
863 | if (IS_ERR(ctx)) | 1042 | if (IS_ERR(ctx)) |
864 | return PTR_ERR(ctx); | 1043 | return PTR_ERR(ctx); |
865 | ret = nfs4_do_open_expired(sp, state, ctx->dentry); | 1044 | ret = nfs4_do_open_expired(ctx, state); |
866 | put_nfs_open_context(ctx); | 1045 | put_nfs_open_context(ctx); |
867 | return ret; | 1046 | return ret; |
868 | } | 1047 | } |
869 | 1048 | ||
870 | /* | 1049 | /* |
871 | * Returns a referenced nfs4_state if there is an open delegation on the file | 1050 | * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-* |
1051 | * fields corresponding to attributes that were used to store the verifier. | ||
1052 | * Make sure we clobber those fields in the later setattr call | ||
872 | */ | 1053 | */ |
873 | static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) | 1054 | static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr) |
874 | { | 1055 | { |
875 | struct nfs_delegation *delegation; | 1056 | if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) && |
876 | struct nfs_server *server = NFS_SERVER(inode); | 1057 | !(sattr->ia_valid & ATTR_ATIME_SET)) |
877 | struct nfs_client *clp = server->nfs_client; | 1058 | sattr->ia_valid |= ATTR_ATIME; |
878 | struct nfs_inode *nfsi = NFS_I(inode); | ||
879 | struct nfs4_state_owner *sp = NULL; | ||
880 | struct nfs4_state *state = NULL; | ||
881 | int open_flags = flags & (FMODE_READ|FMODE_WRITE); | ||
882 | int err; | ||
883 | 1059 | ||
884 | err = -ENOMEM; | 1060 | if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) && |
885 | if (!(sp = nfs4_get_state_owner(server, cred))) { | 1061 | !(sattr->ia_valid & ATTR_MTIME_SET)) |
886 | dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); | 1062 | sattr->ia_valid |= ATTR_MTIME; |
887 | return err; | ||
888 | } | ||
889 | err = nfs4_recover_expired_lease(server); | ||
890 | if (err != 0) | ||
891 | goto out_put_state_owner; | ||
892 | /* Protect against reboot recovery - NOTE ORDER! */ | ||
893 | down_read(&clp->cl_sem); | ||
894 | /* Protect against delegation recall */ | ||
895 | down_read(&nfsi->rwsem); | ||
896 | delegation = NFS_I(inode)->delegation; | ||
897 | err = -ENOENT; | ||
898 | if (delegation == NULL || (delegation->type & open_flags) != open_flags) | ||
899 | goto out_err; | ||
900 | err = -ENOMEM; | ||
901 | state = nfs4_get_open_state(inode, sp); | ||
902 | if (state == NULL) | ||
903 | goto out_err; | ||
904 | |||
905 | err = -ENOENT; | ||
906 | if ((state->state & open_flags) == open_flags) { | ||
907 | spin_lock(&inode->i_lock); | ||
908 | update_open_stateflags(state, open_flags); | ||
909 | spin_unlock(&inode->i_lock); | ||
910 | goto out_ok; | ||
911 | } else if (state->state != 0) | ||
912 | goto out_put_open_state; | ||
913 | |||
914 | lock_kernel(); | ||
915 | err = _nfs4_do_access(inode, cred, open_flags); | ||
916 | unlock_kernel(); | ||
917 | if (err != 0) | ||
918 | goto out_put_open_state; | ||
919 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
920 | update_open_stateid(state, &delegation->stateid, open_flags); | ||
921 | out_ok: | ||
922 | nfs4_put_state_owner(sp); | ||
923 | up_read(&nfsi->rwsem); | ||
924 | up_read(&clp->cl_sem); | ||
925 | *res = state; | ||
926 | return 0; | ||
927 | out_put_open_state: | ||
928 | nfs4_put_open_state(state); | ||
929 | out_err: | ||
930 | up_read(&nfsi->rwsem); | ||
931 | up_read(&clp->cl_sem); | ||
932 | if (err != -EACCES) | ||
933 | nfs_inode_return_delegation(inode); | ||
934 | out_put_state_owner: | ||
935 | nfs4_put_state_owner(sp); | ||
936 | return err; | ||
937 | } | ||
938 | |||
939 | static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred) | ||
940 | { | ||
941 | struct nfs4_exception exception = { }; | ||
942 | struct nfs4_state *res = ERR_PTR(-EIO); | ||
943 | int err; | ||
944 | |||
945 | do { | ||
946 | err = _nfs4_open_delegated(inode, flags, cred, &res); | ||
947 | if (err == 0) | ||
948 | break; | ||
949 | res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(inode), | ||
950 | err, &exception)); | ||
951 | } while (exception.retry); | ||
952 | return res; | ||
953 | } | 1063 | } |
954 | 1064 | ||
955 | /* | 1065 | /* |
956 | * Returns a referenced nfs4_state | 1066 | * Returns a referenced nfs4_state |
957 | */ | 1067 | */ |
958 | static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | 1068 | static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) |
959 | { | 1069 | { |
960 | struct nfs4_state_owner *sp; | 1070 | struct nfs4_state_owner *sp; |
961 | struct nfs4_state *state = NULL; | 1071 | struct nfs4_state *state = NULL; |
962 | struct nfs_server *server = NFS_SERVER(dir); | 1072 | struct nfs_server *server = NFS_SERVER(dir); |
963 | struct nfs_client *clp = server->nfs_client; | 1073 | struct nfs_client *clp = server->nfs_client; |
964 | struct nfs4_opendata *opendata; | 1074 | struct nfs4_opendata *opendata; |
965 | int status; | 1075 | int status; |
966 | 1076 | ||
967 | /* Protect against reboot recovery conflicts */ | 1077 | /* Protect against reboot recovery conflicts */ |
968 | status = -ENOMEM; | 1078 | status = -ENOMEM; |
@@ -973,29 +1083,35 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
973 | status = nfs4_recover_expired_lease(server); | 1083 | status = nfs4_recover_expired_lease(server); |
974 | if (status != 0) | 1084 | if (status != 0) |
975 | goto err_put_state_owner; | 1085 | goto err_put_state_owner; |
1086 | if (path->dentry->d_inode != NULL) | ||
1087 | nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE)); | ||
976 | down_read(&clp->cl_sem); | 1088 | down_read(&clp->cl_sem); |
977 | status = -ENOMEM; | 1089 | status = -ENOMEM; |
978 | opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); | 1090 | opendata = nfs4_opendata_alloc(path, sp, flags, sattr); |
979 | if (opendata == NULL) | 1091 | if (opendata == NULL) |
980 | goto err_release_rwsem; | 1092 | goto err_release_rwsem; |
981 | 1093 | ||
1094 | if (path->dentry->d_inode != NULL) | ||
1095 | opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); | ||
1096 | |||
982 | status = _nfs4_proc_open(opendata); | 1097 | status = _nfs4_proc_open(opendata); |
983 | if (status != 0) | 1098 | if (status != 0) |
984 | goto err_opendata_free; | 1099 | goto err_opendata_put; |
1100 | |||
1101 | if (opendata->o_arg.open_flags & O_EXCL) | ||
1102 | nfs4_exclusive_attrset(opendata, sattr); | ||
985 | 1103 | ||
986 | status = -ENOMEM; | ||
987 | state = nfs4_opendata_to_nfs4_state(opendata); | 1104 | state = nfs4_opendata_to_nfs4_state(opendata); |
988 | if (state == NULL) | 1105 | status = PTR_ERR(state); |
989 | goto err_opendata_free; | 1106 | if (IS_ERR(state)) |
990 | if (opendata->o_res.delegation_type != 0) | 1107 | goto err_opendata_put; |
991 | nfs_inode_set_delegation(state->inode, cred, &opendata->o_res); | 1108 | nfs4_opendata_put(opendata); |
992 | nfs4_opendata_free(opendata); | ||
993 | nfs4_put_state_owner(sp); | 1109 | nfs4_put_state_owner(sp); |
994 | up_read(&clp->cl_sem); | 1110 | up_read(&clp->cl_sem); |
995 | *res = state; | 1111 | *res = state; |
996 | return 0; | 1112 | return 0; |
997 | err_opendata_free: | 1113 | err_opendata_put: |
998 | nfs4_opendata_free(opendata); | 1114 | nfs4_opendata_put(opendata); |
999 | err_release_rwsem: | 1115 | err_release_rwsem: |
1000 | up_read(&clp->cl_sem); | 1116 | up_read(&clp->cl_sem); |
1001 | err_put_state_owner: | 1117 | err_put_state_owner: |
@@ -1006,14 +1122,14 @@ out_err: | |||
1006 | } | 1122 | } |
1007 | 1123 | ||
1008 | 1124 | ||
1009 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred) | 1125 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred) |
1010 | { | 1126 | { |
1011 | struct nfs4_exception exception = { }; | 1127 | struct nfs4_exception exception = { }; |
1012 | struct nfs4_state *res; | 1128 | struct nfs4_state *res; |
1013 | int status; | 1129 | int status; |
1014 | 1130 | ||
1015 | do { | 1131 | do { |
1016 | status = _nfs4_do_open(dir, dentry, flags, sattr, cred, &res); | 1132 | status = _nfs4_do_open(dir, path, flags, sattr, cred, &res); |
1017 | if (status == 0) | 1133 | if (status == 0) |
1018 | break; | 1134 | break; |
1019 | /* NOTE: BAD_SEQID means the server and client disagree about the | 1135 | /* NOTE: BAD_SEQID means the server and client disagree about the |
@@ -1028,7 +1144,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, | |||
1028 | * the user though... | 1144 | * the user though... |
1029 | */ | 1145 | */ |
1030 | if (status == -NFS4ERR_BAD_SEQID) { | 1146 | if (status == -NFS4ERR_BAD_SEQID) { |
1031 | printk(KERN_WARNING "NFS: v4 server returned a bad sequence-id error!\n"); | 1147 | printk(KERN_WARNING "NFS: v4 server %s " |
1148 | " returned a bad sequence-id error!\n", | ||
1149 | NFS_SERVER(dir)->nfs_client->cl_hostname); | ||
1032 | exception.retry = 1; | 1150 | exception.retry = 1; |
1033 | continue; | 1151 | continue; |
1034 | } | 1152 | } |
@@ -1042,6 +1160,11 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, | |||
1042 | exception.retry = 1; | 1160 | exception.retry = 1; |
1043 | continue; | 1161 | continue; |
1044 | } | 1162 | } |
1163 | if (status == -EAGAIN) { | ||
1164 | /* We must have found a delegation */ | ||
1165 | exception.retry = 1; | ||
1166 | continue; | ||
1167 | } | ||
1045 | res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), | 1168 | res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), |
1046 | status, &exception)); | 1169 | status, &exception)); |
1047 | } while (exception.retry); | 1170 | } while (exception.retry); |
@@ -1101,6 +1224,7 @@ static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, | |||
1101 | } | 1224 | } |
1102 | 1225 | ||
1103 | struct nfs4_closedata { | 1226 | struct nfs4_closedata { |
1227 | struct path path; | ||
1104 | struct inode *inode; | 1228 | struct inode *inode; |
1105 | struct nfs4_state *state; | 1229 | struct nfs4_state *state; |
1106 | struct nfs_closeargs arg; | 1230 | struct nfs_closeargs arg; |
@@ -1117,6 +1241,8 @@ static void nfs4_free_closedata(void *data) | |||
1117 | nfs4_put_open_state(calldata->state); | 1241 | nfs4_put_open_state(calldata->state); |
1118 | nfs_free_seqid(calldata->arg.seqid); | 1242 | nfs_free_seqid(calldata->arg.seqid); |
1119 | nfs4_put_state_owner(sp); | 1243 | nfs4_put_state_owner(sp); |
1244 | dput(calldata->path.dentry); | ||
1245 | mntput(calldata->path.mnt); | ||
1120 | kfree(calldata); | 1246 | kfree(calldata); |
1121 | } | 1247 | } |
1122 | 1248 | ||
@@ -1134,8 +1260,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1134 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); | 1260 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); |
1135 | switch (task->tk_status) { | 1261 | switch (task->tk_status) { |
1136 | case 0: | 1262 | case 0: |
1137 | memcpy(&state->stateid, &calldata->res.stateid, | 1263 | nfs_set_open_stateid(state, &calldata->res.stateid, calldata->arg.open_flags); |
1138 | sizeof(state->stateid)); | ||
1139 | renew_lease(server, calldata->timestamp); | 1264 | renew_lease(server, calldata->timestamp); |
1140 | break; | 1265 | break; |
1141 | case -NFS4ERR_STALE_STATEID: | 1266 | case -NFS4ERR_STALE_STATEID: |
@@ -1160,26 +1285,30 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1160 | .rpc_resp = &calldata->res, | 1285 | .rpc_resp = &calldata->res, |
1161 | .rpc_cred = state->owner->so_cred, | 1286 | .rpc_cred = state->owner->so_cred, |
1162 | }; | 1287 | }; |
1163 | int mode = 0, old_mode; | 1288 | int clear_rd, clear_wr, clear_rdwr; |
1289 | int mode; | ||
1164 | 1290 | ||
1165 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 1291 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
1166 | return; | 1292 | return; |
1167 | /* Recalculate the new open mode in case someone reopened the file | 1293 | |
1168 | * while we were waiting in line to be scheduled. | 1294 | mode = FMODE_READ|FMODE_WRITE; |
1169 | */ | 1295 | clear_rd = clear_wr = clear_rdwr = 0; |
1170 | spin_lock(&state->owner->so_lock); | 1296 | spin_lock(&state->owner->so_lock); |
1171 | spin_lock(&calldata->inode->i_lock); | 1297 | /* Calculate the change in open mode */ |
1172 | mode = old_mode = state->state; | ||
1173 | if (state->n_rdwr == 0) { | 1298 | if (state->n_rdwr == 0) { |
1174 | if (state->n_rdonly == 0) | 1299 | if (state->n_rdonly == 0) { |
1175 | mode &= ~FMODE_READ; | 1300 | mode &= ~FMODE_READ; |
1176 | if (state->n_wronly == 0) | 1301 | clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); |
1302 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1303 | } | ||
1304 | if (state->n_wronly == 0) { | ||
1177 | mode &= ~FMODE_WRITE; | 1305 | mode &= ~FMODE_WRITE; |
1306 | clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1307 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1308 | } | ||
1178 | } | 1309 | } |
1179 | nfs4_state_set_mode_locked(state, mode); | ||
1180 | spin_unlock(&calldata->inode->i_lock); | ||
1181 | spin_unlock(&state->owner->so_lock); | 1310 | spin_unlock(&state->owner->so_lock); |
1182 | if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 1311 | if (!clear_rd && !clear_wr && !clear_rdwr) { |
1183 | /* Note: exit _without_ calling nfs4_close_done */ | 1312 | /* Note: exit _without_ calling nfs4_close_done */ |
1184 | task->tk_action = NULL; | 1313 | task->tk_action = NULL; |
1185 | return; | 1314 | return; |
@@ -1209,19 +1338,21 @@ static const struct rpc_call_ops nfs4_close_ops = { | |||
1209 | * | 1338 | * |
1210 | * NOTE: Caller must be holding the sp->so_owner semaphore! | 1339 | * NOTE: Caller must be holding the sp->so_owner semaphore! |
1211 | */ | 1340 | */ |
1212 | int nfs4_do_close(struct inode *inode, struct nfs4_state *state) | 1341 | int nfs4_do_close(struct path *path, struct nfs4_state *state) |
1213 | { | 1342 | { |
1214 | struct nfs_server *server = NFS_SERVER(inode); | 1343 | struct nfs_server *server = NFS_SERVER(state->inode); |
1215 | struct nfs4_closedata *calldata; | 1344 | struct nfs4_closedata *calldata; |
1345 | struct nfs4_state_owner *sp = state->owner; | ||
1346 | struct rpc_task *task; | ||
1216 | int status = -ENOMEM; | 1347 | int status = -ENOMEM; |
1217 | 1348 | ||
1218 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 1349 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); |
1219 | if (calldata == NULL) | 1350 | if (calldata == NULL) |
1220 | goto out; | 1351 | goto out; |
1221 | calldata->inode = inode; | 1352 | calldata->inode = state->inode; |
1222 | calldata->state = state; | 1353 | calldata->state = state; |
1223 | calldata->arg.fh = NFS_FH(inode); | 1354 | calldata->arg.fh = NFS_FH(state->inode); |
1224 | calldata->arg.stateid = &state->stateid; | 1355 | calldata->arg.stateid = &state->open_stateid; |
1225 | /* Serialization for the sequence id */ | 1356 | /* Serialization for the sequence id */ |
1226 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1357 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1227 | if (calldata->arg.seqid == NULL) | 1358 | if (calldata->arg.seqid == NULL) |
@@ -1229,36 +1360,55 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state) | |||
1229 | calldata->arg.bitmask = server->attr_bitmask; | 1360 | calldata->arg.bitmask = server->attr_bitmask; |
1230 | calldata->res.fattr = &calldata->fattr; | 1361 | calldata->res.fattr = &calldata->fattr; |
1231 | calldata->res.server = server; | 1362 | calldata->res.server = server; |
1363 | calldata->path.mnt = mntget(path->mnt); | ||
1364 | calldata->path.dentry = dget(path->dentry); | ||
1232 | 1365 | ||
1233 | status = nfs4_call_async(server->client, &nfs4_close_ops, calldata); | 1366 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata); |
1234 | if (status == 0) | 1367 | if (IS_ERR(task)) |
1235 | goto out; | 1368 | return PTR_ERR(task); |
1236 | 1369 | rpc_put_task(task); | |
1237 | nfs_free_seqid(calldata->arg.seqid); | 1370 | return 0; |
1238 | out_free_calldata: | 1371 | out_free_calldata: |
1239 | kfree(calldata); | 1372 | kfree(calldata); |
1240 | out: | 1373 | out: |
1374 | nfs4_put_open_state(state); | ||
1375 | nfs4_put_state_owner(sp); | ||
1241 | return status; | 1376 | return status; |
1242 | } | 1377 | } |
1243 | 1378 | ||
1244 | static int nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state) | 1379 | static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state) |
1245 | { | 1380 | { |
1246 | struct file *filp; | 1381 | struct file *filp; |
1382 | int ret; | ||
1247 | 1383 | ||
1248 | filp = lookup_instantiate_filp(nd, dentry, NULL); | 1384 | /* If the open_intent is for execute, we have an extra check to make */ |
1385 | if (nd->intent.open.flags & FMODE_EXEC) { | ||
1386 | ret = _nfs4_do_access(state->inode, | ||
1387 | state->owner->so_cred, | ||
1388 | nd->intent.open.flags); | ||
1389 | if (ret < 0) | ||
1390 | goto out_close; | ||
1391 | } | ||
1392 | filp = lookup_instantiate_filp(nd, path->dentry, NULL); | ||
1249 | if (!IS_ERR(filp)) { | 1393 | if (!IS_ERR(filp)) { |
1250 | struct nfs_open_context *ctx; | 1394 | struct nfs_open_context *ctx; |
1251 | ctx = (struct nfs_open_context *)filp->private_data; | 1395 | ctx = (struct nfs_open_context *)filp->private_data; |
1252 | ctx->state = state; | 1396 | ctx->state = state; |
1253 | return 0; | 1397 | return 0; |
1254 | } | 1398 | } |
1255 | nfs4_close_state(state, nd->intent.open.flags); | 1399 | ret = PTR_ERR(filp); |
1256 | return PTR_ERR(filp); | 1400 | out_close: |
1401 | nfs4_close_state(path, state, nd->intent.open.flags); | ||
1402 | return ret; | ||
1257 | } | 1403 | } |
1258 | 1404 | ||
1259 | struct dentry * | 1405 | struct dentry * |
1260 | nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 1406 | nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
1261 | { | 1407 | { |
1408 | struct path path = { | ||
1409 | .mnt = nd->mnt, | ||
1410 | .dentry = dentry, | ||
1411 | }; | ||
1262 | struct iattr attr; | 1412 | struct iattr attr; |
1263 | struct rpc_cred *cred; | 1413 | struct rpc_cred *cred; |
1264 | struct nfs4_state *state; | 1414 | struct nfs4_state *state; |
@@ -1277,7 +1427,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1277 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1427 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
1278 | if (IS_ERR(cred)) | 1428 | if (IS_ERR(cred)) |
1279 | return (struct dentry *)cred; | 1429 | return (struct dentry *)cred; |
1280 | state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); | 1430 | state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); |
1281 | put_rpccred(cred); | 1431 | put_rpccred(cred); |
1282 | if (IS_ERR(state)) { | 1432 | if (IS_ERR(state)) { |
1283 | if (PTR_ERR(state) == -ENOENT) | 1433 | if (PTR_ERR(state) == -ENOENT) |
@@ -1287,22 +1437,24 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1287 | res = d_add_unique(dentry, igrab(state->inode)); | 1437 | res = d_add_unique(dentry, igrab(state->inode)); |
1288 | if (res != NULL) | 1438 | if (res != NULL) |
1289 | dentry = res; | 1439 | dentry = res; |
1290 | nfs4_intent_set_file(nd, dentry, state); | 1440 | nfs4_intent_set_file(nd, &path, state); |
1291 | return res; | 1441 | return res; |
1292 | } | 1442 | } |
1293 | 1443 | ||
1294 | int | 1444 | int |
1295 | nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) | 1445 | nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) |
1296 | { | 1446 | { |
1447 | struct path path = { | ||
1448 | .mnt = nd->mnt, | ||
1449 | .dentry = dentry, | ||
1450 | }; | ||
1297 | struct rpc_cred *cred; | 1451 | struct rpc_cred *cred; |
1298 | struct nfs4_state *state; | 1452 | struct nfs4_state *state; |
1299 | 1453 | ||
1300 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1454 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
1301 | if (IS_ERR(cred)) | 1455 | if (IS_ERR(cred)) |
1302 | return PTR_ERR(cred); | 1456 | return PTR_ERR(cred); |
1303 | state = nfs4_open_delegated(dentry->d_inode, openflags, cred); | 1457 | state = nfs4_do_open(dir, &path, openflags, NULL, cred); |
1304 | if (IS_ERR(state)) | ||
1305 | state = nfs4_do_open(dir, dentry, openflags, NULL, cred); | ||
1306 | put_rpccred(cred); | 1458 | put_rpccred(cred); |
1307 | if (IS_ERR(state)) { | 1459 | if (IS_ERR(state)) { |
1308 | switch (PTR_ERR(state)) { | 1460 | switch (PTR_ERR(state)) { |
@@ -1318,10 +1470,10 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1318 | } | 1470 | } |
1319 | } | 1471 | } |
1320 | if (state->inode == dentry->d_inode) { | 1472 | if (state->inode == dentry->d_inode) { |
1321 | nfs4_intent_set_file(nd, dentry, state); | 1473 | nfs4_intent_set_file(nd, &path, state); |
1322 | return 1; | 1474 | return 1; |
1323 | } | 1475 | } |
1324 | nfs4_close_state(state, openflags); | 1476 | nfs4_close_state(&path, state, openflags); |
1325 | out_drop: | 1477 | out_drop: |
1326 | d_drop(dentry); | 1478 | d_drop(dentry); |
1327 | return 0; | 1479 | return 0; |
@@ -1418,7 +1570,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1418 | * Note that we'll actually follow the referral later when | 1570 | * Note that we'll actually follow the referral later when |
1419 | * we detect fsid mismatch in inode revalidation | 1571 | * we detect fsid mismatch in inode revalidation |
1420 | */ | 1572 | */ |
1421 | static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle) | 1573 | static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle) |
1422 | { | 1574 | { |
1423 | int status = -ENOMEM; | 1575 | int status = -ENOMEM; |
1424 | struct page *page = NULL; | 1576 | struct page *page = NULL; |
@@ -1533,8 +1685,8 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1533 | return status; | 1685 | return status; |
1534 | } | 1686 | } |
1535 | 1687 | ||
1536 | static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | 1688 | static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *dirfh, |
1537 | struct qstr *name, struct nfs_fh *fhandle, | 1689 | const struct qstr *name, struct nfs_fh *fhandle, |
1538 | struct nfs_fattr *fattr) | 1690 | struct nfs_fattr *fattr) |
1539 | { | 1691 | { |
1540 | int status; | 1692 | int status; |
@@ -1559,8 +1711,6 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |||
1559 | dprintk("NFS call lookupfh %s\n", name->name); | 1711 | dprintk("NFS call lookupfh %s\n", name->name); |
1560 | status = rpc_call_sync(server->client, &msg, 0); | 1712 | status = rpc_call_sync(server->client, &msg, 0); |
1561 | dprintk("NFS reply lookupfh: %d\n", status); | 1713 | dprintk("NFS reply lookupfh: %d\n", status); |
1562 | if (status == -NFS4ERR_MOVED) | ||
1563 | status = -EREMOTE; | ||
1564 | return status; | 1714 | return status; |
1565 | } | 1715 | } |
1566 | 1716 | ||
@@ -1571,39 +1721,24 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |||
1571 | struct nfs4_exception exception = { }; | 1721 | struct nfs4_exception exception = { }; |
1572 | int err; | 1722 | int err; |
1573 | do { | 1723 | do { |
1574 | err = nfs4_handle_exception(server, | 1724 | err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr); |
1575 | _nfs4_proc_lookupfh(server, dirfh, name, | 1725 | /* FIXME: !!!! */ |
1576 | fhandle, fattr), | 1726 | if (err == -NFS4ERR_MOVED) { |
1577 | &exception); | 1727 | err = -EREMOTE; |
1728 | break; | ||
1729 | } | ||
1730 | err = nfs4_handle_exception(server, err, &exception); | ||
1578 | } while (exception.retry); | 1731 | } while (exception.retry); |
1579 | return err; | 1732 | return err; |
1580 | } | 1733 | } |
1581 | 1734 | ||
1582 | static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, | 1735 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, |
1583 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 1736 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
1584 | { | 1737 | { |
1585 | int status; | 1738 | int status; |
1586 | struct nfs_server *server = NFS_SERVER(dir); | ||
1587 | struct nfs4_lookup_arg args = { | ||
1588 | .bitmask = server->attr_bitmask, | ||
1589 | .dir_fh = NFS_FH(dir), | ||
1590 | .name = name, | ||
1591 | }; | ||
1592 | struct nfs4_lookup_res res = { | ||
1593 | .server = server, | ||
1594 | .fattr = fattr, | ||
1595 | .fh = fhandle, | ||
1596 | }; | ||
1597 | struct rpc_message msg = { | ||
1598 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], | ||
1599 | .rpc_argp = &args, | ||
1600 | .rpc_resp = &res, | ||
1601 | }; | ||
1602 | |||
1603 | nfs_fattr_init(fattr); | ||
1604 | 1739 | ||
1605 | dprintk("NFS call lookup %s\n", name->name); | 1740 | dprintk("NFS call lookup %s\n", name->name); |
1606 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 1741 | status = _nfs4_proc_lookupfh(NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr); |
1607 | if (status == -NFS4ERR_MOVED) | 1742 | if (status == -NFS4ERR_MOVED) |
1608 | status = nfs4_get_referral(dir, name, fattr, fhandle); | 1743 | status = nfs4_get_referral(dir, name, fattr, fhandle); |
1609 | dprintk("NFS reply lookup: %d\n", status); | 1744 | dprintk("NFS reply lookup: %d\n", status); |
@@ -1752,6 +1887,10 @@ static int | |||
1752 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 1887 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
1753 | int flags, struct nameidata *nd) | 1888 | int flags, struct nameidata *nd) |
1754 | { | 1889 | { |
1890 | struct path path = { | ||
1891 | .mnt = nd->mnt, | ||
1892 | .dentry = dentry, | ||
1893 | }; | ||
1755 | struct nfs4_state *state; | 1894 | struct nfs4_state *state; |
1756 | struct rpc_cred *cred; | 1895 | struct rpc_cred *cred; |
1757 | int status = 0; | 1896 | int status = 0; |
@@ -1761,7 +1900,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1761 | status = PTR_ERR(cred); | 1900 | status = PTR_ERR(cred); |
1762 | goto out; | 1901 | goto out; |
1763 | } | 1902 | } |
1764 | state = nfs4_do_open(dir, dentry, flags, sattr, cred); | 1903 | state = nfs4_do_open(dir, &path, flags, sattr, cred); |
1765 | put_rpccred(cred); | 1904 | put_rpccred(cred); |
1766 | if (IS_ERR(state)) { | 1905 | if (IS_ERR(state)) { |
1767 | status = PTR_ERR(state); | 1906 | status = PTR_ERR(state); |
@@ -1773,11 +1912,12 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1773 | status = nfs4_do_setattr(state->inode, &fattr, sattr, state); | 1912 | status = nfs4_do_setattr(state->inode, &fattr, sattr, state); |
1774 | if (status == 0) | 1913 | if (status == 0) |
1775 | nfs_setattr_update_inode(state->inode, sattr); | 1914 | nfs_setattr_update_inode(state->inode, sattr); |
1915 | nfs_post_op_update_inode(state->inode, &fattr); | ||
1776 | } | 1916 | } |
1777 | if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN)) | 1917 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) |
1778 | status = nfs4_intent_set_file(nd, dentry, state); | 1918 | status = nfs4_intent_set_file(nd, &path, state); |
1779 | else | 1919 | else |
1780 | nfs4_close_state(state, flags); | 1920 | nfs4_close_state(&path, state, flags); |
1781 | out: | 1921 | out: |
1782 | return status; | 1922 | return status; |
1783 | } | 1923 | } |
@@ -1785,28 +1925,27 @@ out: | |||
1785 | static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | 1925 | static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) |
1786 | { | 1926 | { |
1787 | struct nfs_server *server = NFS_SERVER(dir); | 1927 | struct nfs_server *server = NFS_SERVER(dir); |
1788 | struct nfs4_remove_arg args = { | 1928 | struct nfs_removeargs args = { |
1789 | .fh = NFS_FH(dir), | 1929 | .fh = NFS_FH(dir), |
1790 | .name = name, | 1930 | .name.len = name->len, |
1931 | .name.name = name->name, | ||
1791 | .bitmask = server->attr_bitmask, | 1932 | .bitmask = server->attr_bitmask, |
1792 | }; | 1933 | }; |
1793 | struct nfs_fattr dir_attr; | 1934 | struct nfs_removeres res = { |
1794 | struct nfs4_remove_res res = { | ||
1795 | .server = server, | 1935 | .server = server, |
1796 | .dir_attr = &dir_attr, | ||
1797 | }; | 1936 | }; |
1798 | struct rpc_message msg = { | 1937 | struct rpc_message msg = { |
1799 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], | 1938 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE], |
1800 | .rpc_argp = &args, | 1939 | .rpc_argp = &args, |
1801 | .rpc_resp = &res, | 1940 | .rpc_resp = &res, |
1802 | }; | 1941 | }; |
1803 | int status; | 1942 | int status; |
1804 | 1943 | ||
1805 | nfs_fattr_init(res.dir_attr); | 1944 | nfs_fattr_init(&res.dir_attr); |
1806 | status = rpc_call_sync(server->client, &msg, 0); | 1945 | status = rpc_call_sync(server->client, &msg, 0); |
1807 | if (status == 0) { | 1946 | if (status == 0) { |
1808 | update_changeattr(dir, &res.cinfo); | 1947 | update_changeattr(dir, &res.cinfo); |
1809 | nfs_post_op_update_inode(dir, res.dir_attr); | 1948 | nfs_post_op_update_inode(dir, &res.dir_attr); |
1810 | } | 1949 | } |
1811 | return status; | 1950 | return status; |
1812 | } | 1951 | } |
@@ -1823,48 +1962,26 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
1823 | return err; | 1962 | return err; |
1824 | } | 1963 | } |
1825 | 1964 | ||
1826 | struct unlink_desc { | 1965 | static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) |
1827 | struct nfs4_remove_arg args; | ||
1828 | struct nfs4_remove_res res; | ||
1829 | struct nfs_fattr dir_attr; | ||
1830 | }; | ||
1831 | |||
1832 | static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, | ||
1833 | struct qstr *name) | ||
1834 | { | 1966 | { |
1835 | struct nfs_server *server = NFS_SERVER(dir->d_inode); | 1967 | struct nfs_server *server = NFS_SERVER(dir); |
1836 | struct unlink_desc *up; | 1968 | struct nfs_removeargs *args = msg->rpc_argp; |
1969 | struct nfs_removeres *res = msg->rpc_resp; | ||
1837 | 1970 | ||
1838 | up = kmalloc(sizeof(*up), GFP_KERNEL); | 1971 | args->bitmask = server->attr_bitmask; |
1839 | if (!up) | 1972 | res->server = server; |
1840 | return -ENOMEM; | ||
1841 | |||
1842 | up->args.fh = NFS_FH(dir->d_inode); | ||
1843 | up->args.name = name; | ||
1844 | up->args.bitmask = server->attr_bitmask; | ||
1845 | up->res.server = server; | ||
1846 | up->res.dir_attr = &up->dir_attr; | ||
1847 | |||
1848 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; | 1973 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; |
1849 | msg->rpc_argp = &up->args; | ||
1850 | msg->rpc_resp = &up->res; | ||
1851 | return 0; | ||
1852 | } | 1974 | } |
1853 | 1975 | ||
1854 | static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task) | 1976 | static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) |
1855 | { | 1977 | { |
1856 | struct rpc_message *msg = &task->tk_msg; | 1978 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
1857 | struct unlink_desc *up; | 1979 | |
1858 | 1980 | if (nfs4_async_handle_error(task, res->server) == -EAGAIN) | |
1859 | if (msg->rpc_resp != NULL) { | 1981 | return 0; |
1860 | up = container_of(msg->rpc_resp, struct unlink_desc, res); | 1982 | update_changeattr(dir, &res->cinfo); |
1861 | update_changeattr(dir->d_inode, &up->res.cinfo); | 1983 | nfs_post_op_update_inode(dir, &res->dir_attr); |
1862 | nfs_post_op_update_inode(dir->d_inode, up->res.dir_attr); | 1984 | return 1; |
1863 | kfree(up); | ||
1864 | msg->rpc_resp = NULL; | ||
1865 | msg->rpc_argp = NULL; | ||
1866 | } | ||
1867 | return 0; | ||
1868 | } | 1985 | } |
1869 | 1986 | ||
1870 | static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | 1987 | static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, |
@@ -3008,7 +3125,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3008 | if (status != 0) | 3125 | if (status != 0) |
3009 | goto out; | 3126 | goto out; |
3010 | lsp = request->fl_u.nfs4_fl.owner; | 3127 | lsp = request->fl_u.nfs4_fl.owner; |
3011 | arg.lock_owner.id = lsp->ls_id; | 3128 | arg.lock_owner.id = lsp->ls_id.id; |
3012 | status = rpc_call_sync(server->client, &msg, 0); | 3129 | status = rpc_call_sync(server->client, &msg, 0); |
3013 | switch (status) { | 3130 | switch (status) { |
3014 | case 0: | 3131 | case 0: |
@@ -3152,6 +3269,11 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3152 | { | 3269 | { |
3153 | struct nfs4_unlockdata *data; | 3270 | struct nfs4_unlockdata *data; |
3154 | 3271 | ||
3272 | /* Ensure this is an unlock - when canceling a lock, the | ||
3273 | * canceled lock is passed in, and it won't be an unlock. | ||
3274 | */ | ||
3275 | fl->fl_type = F_UNLCK; | ||
3276 | |||
3155 | data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); | 3277 | data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); |
3156 | if (data == NULL) { | 3278 | if (data == NULL) { |
3157 | nfs_free_seqid(seqid); | 3279 | nfs_free_seqid(seqid); |
@@ -3222,7 +3344,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3222 | goto out_free; | 3344 | goto out_free; |
3223 | p->arg.lock_stateid = &lsp->ls_stateid; | 3345 | p->arg.lock_stateid = &lsp->ls_stateid; |
3224 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3346 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3225 | p->arg.lock_owner.id = lsp->ls_id; | 3347 | p->arg.lock_owner.id = lsp->ls_id.id; |
3226 | p->lsp = lsp; | 3348 | p->lsp = lsp; |
3227 | atomic_inc(&lsp->ls_count); | 3349 | atomic_inc(&lsp->ls_count); |
3228 | p->ctx = get_nfs_open_context(ctx); | 3350 | p->ctx = get_nfs_open_context(ctx); |
@@ -3285,7 +3407,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3285 | memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, | 3407 | memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, |
3286 | sizeof(data->lsp->ls_stateid.data)); | 3408 | sizeof(data->lsp->ls_stateid.data)); |
3287 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 3409 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; |
3288 | renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); | 3410 | renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); |
3289 | } | 3411 | } |
3290 | nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); | 3412 | nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); |
3291 | out: | 3413 | out: |
@@ -3544,7 +3666,7 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | |||
3544 | return len; | 3666 | return len; |
3545 | } | 3667 | } |
3546 | 3668 | ||
3547 | int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name, | 3669 | int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, |
3548 | struct nfs4_fs_locations *fs_locations, struct page *page) | 3670 | struct nfs4_fs_locations *fs_locations, struct page *page) |
3549 | { | 3671 | { |
3550 | struct nfs_server *server = NFS_SERVER(dir); | 3672 | struct nfs_server *server = NFS_SERVER(dir); |