diff options
author | Steve French <sfrench@us.ibm.com> | 2007-07-18 20:38:57 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2007-07-18 20:38:57 -0400 |
commit | 1ff8392c32a2645d2665ca779ecb91bb29361c13 (patch) | |
tree | 860b95e9a499ade4060848740fc6ce1fbb4e4e8d /fs/nfs/nfs4proc.c | |
parent | 70b315b0dd3879cb3ab8aadffb14f10b2d19b9c3 (diff) | |
parent | 5bae7ac9feba925fd0099057f6b23d7be80b7b41 (diff) |
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
fs/cifs/export.c
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 760 |
1 files changed, 444 insertions, 316 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 648e0ac0f90e..fee2da856c95 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -65,6 +65,7 @@ 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); | ||
68 | 69 | ||
69 | /* Prevent leaks of NFSv4 errors into userland */ | 70 | /* Prevent leaks of NFSv4 errors into userland */ |
70 | int nfs4_map_errors(int err) | 71 | int nfs4_map_errors(int err) |
@@ -214,27 +215,39 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | |||
214 | } | 215 | } |
215 | 216 | ||
216 | struct nfs4_opendata { | 217 | struct nfs4_opendata { |
217 | atomic_t count; | 218 | struct kref kref; |
218 | struct nfs_openargs o_arg; | 219 | struct nfs_openargs o_arg; |
219 | struct nfs_openres o_res; | 220 | struct nfs_openres o_res; |
220 | struct nfs_open_confirmargs c_arg; | 221 | struct nfs_open_confirmargs c_arg; |
221 | struct nfs_open_confirmres c_res; | 222 | struct nfs_open_confirmres c_res; |
222 | struct nfs_fattr f_attr; | 223 | struct nfs_fattr f_attr; |
223 | struct nfs_fattr dir_attr; | 224 | struct nfs_fattr dir_attr; |
224 | struct dentry *dentry; | 225 | struct path path; |
225 | struct dentry *dir; | 226 | struct dentry *dir; |
226 | struct nfs4_state_owner *owner; | 227 | struct nfs4_state_owner *owner; |
228 | struct nfs4_state *state; | ||
227 | struct iattr attrs; | 229 | struct iattr attrs; |
228 | unsigned long timestamp; | 230 | unsigned long timestamp; |
231 | unsigned int rpc_done : 1; | ||
229 | int rpc_status; | 232 | int rpc_status; |
230 | int cancelled; | 233 | int cancelled; |
231 | }; | 234 | }; |
232 | 235 | ||
233 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | 236 | |
237 | static void nfs4_init_opendata_res(struct nfs4_opendata *p) | ||
238 | { | ||
239 | p->o_res.f_attr = &p->f_attr; | ||
240 | p->o_res.dir_attr = &p->dir_attr; | ||
241 | p->o_res.server = p->o_arg.server; | ||
242 | nfs_fattr_init(&p->f_attr); | ||
243 | nfs_fattr_init(&p->dir_attr); | ||
244 | } | ||
245 | |||
246 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | ||
234 | struct nfs4_state_owner *sp, int flags, | 247 | struct nfs4_state_owner *sp, int flags, |
235 | const struct iattr *attrs) | 248 | const struct iattr *attrs) |
236 | { | 249 | { |
237 | struct dentry *parent = dget_parent(dentry); | 250 | struct dentry *parent = dget_parent(path->dentry); |
238 | struct inode *dir = parent->d_inode; | 251 | struct inode *dir = parent->d_inode; |
239 | struct nfs_server *server = NFS_SERVER(dir); | 252 | struct nfs_server *server = NFS_SERVER(dir); |
240 | struct nfs4_opendata *p; | 253 | struct nfs4_opendata *p; |
@@ -245,24 +258,19 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
245 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 258 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); |
246 | if (p->o_arg.seqid == NULL) | 259 | if (p->o_arg.seqid == NULL) |
247 | goto err_free; | 260 | goto err_free; |
248 | atomic_set(&p->count, 1); | 261 | p->path.mnt = mntget(path->mnt); |
249 | p->dentry = dget(dentry); | 262 | p->path.dentry = dget(path->dentry); |
250 | p->dir = parent; | 263 | p->dir = parent; |
251 | p->owner = sp; | 264 | p->owner = sp; |
252 | atomic_inc(&sp->so_count); | 265 | atomic_inc(&sp->so_count); |
253 | p->o_arg.fh = NFS_FH(dir); | 266 | p->o_arg.fh = NFS_FH(dir); |
254 | p->o_arg.open_flags = flags, | 267 | p->o_arg.open_flags = flags, |
255 | p->o_arg.clientid = server->nfs_client->cl_clientid; | 268 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
256 | p->o_arg.id = sp->so_id; | 269 | p->o_arg.id = sp->so_owner_id.id; |
257 | p->o_arg.name = &dentry->d_name; | 270 | p->o_arg.name = &p->path.dentry->d_name; |
258 | p->o_arg.server = server; | 271 | p->o_arg.server = server; |
259 | p->o_arg.bitmask = server->attr_bitmask; | 272 | p->o_arg.bitmask = server->attr_bitmask; |
260 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 273 | 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) { | 274 | if (flags & O_EXCL) { |
267 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | 275 | u32 *s = (u32 *) p->o_arg.u.verifier.data; |
268 | s[0] = jiffies; | 276 | s[0] = jiffies; |
@@ -274,6 +282,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
274 | p->c_arg.fh = &p->o_res.fh; | 282 | p->c_arg.fh = &p->o_res.fh; |
275 | p->c_arg.stateid = &p->o_res.stateid; | 283 | p->c_arg.stateid = &p->o_res.stateid; |
276 | p->c_arg.seqid = p->o_arg.seqid; | 284 | p->c_arg.seqid = p->o_arg.seqid; |
285 | nfs4_init_opendata_res(p); | ||
286 | kref_init(&p->kref); | ||
277 | return p; | 287 | return p; |
278 | err_free: | 288 | err_free: |
279 | kfree(p); | 289 | kfree(p); |
@@ -282,27 +292,25 @@ err: | |||
282 | return NULL; | 292 | return NULL; |
283 | } | 293 | } |
284 | 294 | ||
285 | static void nfs4_opendata_free(struct nfs4_opendata *p) | 295 | static void nfs4_opendata_free(struct kref *kref) |
286 | { | 296 | { |
287 | if (p != NULL && atomic_dec_and_test(&p->count)) { | 297 | struct nfs4_opendata *p = container_of(kref, |
288 | nfs_free_seqid(p->o_arg.seqid); | 298 | struct nfs4_opendata, kref); |
289 | nfs4_put_state_owner(p->owner); | 299 | |
290 | dput(p->dir); | 300 | nfs_free_seqid(p->o_arg.seqid); |
291 | dput(p->dentry); | 301 | if (p->state != NULL) |
292 | kfree(p); | 302 | nfs4_put_open_state(p->state); |
293 | } | 303 | nfs4_put_state_owner(p->owner); |
304 | dput(p->dir); | ||
305 | dput(p->path.dentry); | ||
306 | mntput(p->path.mnt); | ||
307 | kfree(p); | ||
294 | } | 308 | } |
295 | 309 | ||
296 | /* Helper for asynchronous RPC calls */ | 310 | 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 | { | 311 | { |
300 | struct rpc_task *task; | 312 | if (p != NULL) |
301 | 313 | 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 | } | 314 | } |
307 | 315 | ||
308 | static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | 316 | static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) |
@@ -316,7 +324,34 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | |||
316 | return ret; | 324 | return ret; |
317 | } | 325 | } |
318 | 326 | ||
319 | static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | 327 | static int can_open_cached(struct nfs4_state *state, int mode) |
328 | { | ||
329 | int ret = 0; | ||
330 | switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) { | ||
331 | case FMODE_READ: | ||
332 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; | ||
333 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | ||
334 | break; | ||
335 | case FMODE_WRITE: | ||
336 | ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; | ||
337 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | ||
338 | break; | ||
339 | case FMODE_READ|FMODE_WRITE: | ||
340 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | ||
341 | } | ||
342 | return ret; | ||
343 | } | ||
344 | |||
345 | static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags) | ||
346 | { | ||
347 | if ((delegation->type & open_flags) != open_flags) | ||
348 | return 0; | ||
349 | if (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) | ||
350 | return 0; | ||
351 | return 1; | ||
352 | } | ||
353 | |||
354 | static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | ||
320 | { | 355 | { |
321 | switch (open_flags) { | 356 | switch (open_flags) { |
322 | case FMODE_WRITE: | 357 | case FMODE_WRITE: |
@@ -328,41 +363,176 @@ static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_ | |||
328 | case FMODE_READ|FMODE_WRITE: | 363 | case FMODE_READ|FMODE_WRITE: |
329 | state->n_rdwr++; | 364 | state->n_rdwr++; |
330 | } | 365 | } |
366 | nfs4_state_set_mode_locked(state, state->state | open_flags); | ||
331 | } | 367 | } |
332 | 368 | ||
333 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 369 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) |
334 | { | 370 | { |
335 | struct inode *inode = state->inode; | 371 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
372 | memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); | ||
373 | memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); | ||
374 | switch (open_flags) { | ||
375 | case FMODE_READ: | ||
376 | set_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
377 | break; | ||
378 | case FMODE_WRITE: | ||
379 | set_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
380 | break; | ||
381 | case FMODE_READ|FMODE_WRITE: | ||
382 | set_bit(NFS_O_RDWR_STATE, &state->flags); | ||
383 | } | ||
384 | } | ||
385 | |||
386 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | ||
387 | { | ||
388 | write_seqlock(&state->seqlock); | ||
389 | nfs_set_open_stateid_locked(state, stateid, open_flags); | ||
390 | write_sequnlock(&state->seqlock); | ||
391 | } | ||
336 | 392 | ||
393 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags) | ||
394 | { | ||
337 | open_flags &= (FMODE_READ|FMODE_WRITE); | 395 | open_flags &= (FMODE_READ|FMODE_WRITE); |
338 | /* Protect against nfs4_find_state_byowner() */ | 396 | /* |
397 | * Protect the call to nfs4_state_set_mode_locked and | ||
398 | * serialise the stateid update | ||
399 | */ | ||
400 | write_seqlock(&state->seqlock); | ||
401 | if (deleg_stateid != NULL) { | ||
402 | memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data)); | ||
403 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
404 | } | ||
405 | if (open_stateid != NULL) | ||
406 | nfs_set_open_stateid_locked(state, open_stateid, open_flags); | ||
407 | write_sequnlock(&state->seqlock); | ||
339 | spin_lock(&state->owner->so_lock); | 408 | 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); | 409 | 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); | 410 | spin_unlock(&state->owner->so_lock); |
346 | } | 411 | } |
347 | 412 | ||
413 | static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open_flags) | ||
414 | { | ||
415 | struct nfs_delegation *delegation; | ||
416 | |||
417 | rcu_read_lock(); | ||
418 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
419 | if (delegation == NULL || (delegation->type & open_flags) == open_flags) { | ||
420 | rcu_read_unlock(); | ||
421 | return; | ||
422 | } | ||
423 | rcu_read_unlock(); | ||
424 | nfs_inode_return_delegation(inode); | ||
425 | } | ||
426 | |||
427 | static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | ||
428 | { | ||
429 | struct nfs4_state *state = opendata->state; | ||
430 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
431 | struct nfs_delegation *delegation; | ||
432 | int open_mode = opendata->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL); | ||
433 | nfs4_stateid stateid; | ||
434 | int ret = -EAGAIN; | ||
435 | |||
436 | rcu_read_lock(); | ||
437 | delegation = rcu_dereference(nfsi->delegation); | ||
438 | for (;;) { | ||
439 | if (can_open_cached(state, open_mode)) { | ||
440 | spin_lock(&state->owner->so_lock); | ||
441 | if (can_open_cached(state, open_mode)) { | ||
442 | update_open_stateflags(state, open_mode); | ||
443 | spin_unlock(&state->owner->so_lock); | ||
444 | rcu_read_unlock(); | ||
445 | goto out_return_state; | ||
446 | } | ||
447 | spin_unlock(&state->owner->so_lock); | ||
448 | } | ||
449 | if (delegation == NULL) | ||
450 | break; | ||
451 | if (!can_open_delegated(delegation, open_mode)) | ||
452 | break; | ||
453 | /* Save the delegation */ | ||
454 | memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); | ||
455 | rcu_read_unlock(); | ||
456 | lock_kernel(); | ||
457 | ret = _nfs4_do_access(state->inode, state->owner->so_cred, open_mode); | ||
458 | unlock_kernel(); | ||
459 | if (ret != 0) | ||
460 | goto out; | ||
461 | ret = -EAGAIN; | ||
462 | rcu_read_lock(); | ||
463 | delegation = rcu_dereference(nfsi->delegation); | ||
464 | /* If no delegation, try a cached open */ | ||
465 | if (delegation == NULL) | ||
466 | continue; | ||
467 | /* Is the delegation still valid? */ | ||
468 | if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0) | ||
469 | continue; | ||
470 | rcu_read_unlock(); | ||
471 | update_open_stateid(state, NULL, &stateid, open_mode); | ||
472 | goto out_return_state; | ||
473 | } | ||
474 | rcu_read_unlock(); | ||
475 | out: | ||
476 | return ERR_PTR(ret); | ||
477 | out_return_state: | ||
478 | atomic_inc(&state->count); | ||
479 | return state; | ||
480 | } | ||
481 | |||
348 | static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) | 482 | static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) |
349 | { | 483 | { |
350 | struct inode *inode; | 484 | struct inode *inode; |
351 | struct nfs4_state *state = NULL; | 485 | struct nfs4_state *state = NULL; |
486 | struct nfs_delegation *delegation; | ||
487 | nfs4_stateid *deleg_stateid = NULL; | ||
488 | int ret; | ||
352 | 489 | ||
353 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | 490 | if (!data->rpc_done) { |
491 | state = nfs4_try_open_cached(data); | ||
354 | goto out; | 492 | goto out; |
493 | } | ||
494 | |||
495 | ret = -EAGAIN; | ||
496 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | ||
497 | goto err; | ||
355 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); | 498 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); |
499 | ret = PTR_ERR(inode); | ||
356 | if (IS_ERR(inode)) | 500 | if (IS_ERR(inode)) |
357 | goto out; | 501 | goto err; |
502 | ret = -ENOMEM; | ||
358 | state = nfs4_get_open_state(inode, data->owner); | 503 | state = nfs4_get_open_state(inode, data->owner); |
359 | if (state == NULL) | 504 | if (state == NULL) |
360 | goto put_inode; | 505 | goto err_put_inode; |
361 | update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags); | 506 | if (data->o_res.delegation_type != 0) { |
362 | put_inode: | 507 | int delegation_flags = 0; |
508 | |||
509 | rcu_read_lock(); | ||
510 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
511 | if (delegation) | ||
512 | delegation_flags = delegation->flags; | ||
513 | rcu_read_unlock(); | ||
514 | if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) | ||
515 | nfs_inode_set_delegation(state->inode, | ||
516 | data->owner->so_cred, | ||
517 | &data->o_res); | ||
518 | else | ||
519 | nfs_inode_reclaim_delegation(state->inode, | ||
520 | data->owner->so_cred, | ||
521 | &data->o_res); | ||
522 | } | ||
523 | rcu_read_lock(); | ||
524 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
525 | if (delegation != NULL) | ||
526 | deleg_stateid = &delegation->stateid; | ||
527 | update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags); | ||
528 | rcu_read_unlock(); | ||
363 | iput(inode); | 529 | iput(inode); |
364 | out: | 530 | out: |
365 | return state; | 531 | return state; |
532 | err_put_inode: | ||
533 | iput(inode); | ||
534 | err: | ||
535 | return ERR_PTR(ret); | ||
366 | } | 536 | } |
367 | 537 | ||
368 | static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) | 538 | static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) |
@@ -382,79 +552,66 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state * | |||
382 | return ERR_PTR(-ENOENT); | 552 | return ERR_PTR(-ENOENT); |
383 | } | 553 | } |
384 | 554 | ||
385 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid) | 555 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res) |
386 | { | 556 | { |
557 | struct nfs4_state *newstate; | ||
387 | int ret; | 558 | int ret; |
388 | 559 | ||
389 | opendata->o_arg.open_flags = openflags; | 560 | opendata->o_arg.open_flags = openflags; |
561 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | ||
562 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | ||
563 | nfs4_init_opendata_res(opendata); | ||
390 | ret = _nfs4_proc_open(opendata); | 564 | ret = _nfs4_proc_open(opendata); |
391 | if (ret != 0) | 565 | if (ret != 0) |
392 | return ret; | 566 | return ret; |
393 | memcpy(stateid->data, opendata->o_res.stateid.data, | 567 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
394 | sizeof(stateid->data)); | 568 | if (IS_ERR(newstate)) |
569 | return PTR_ERR(newstate); | ||
570 | nfs4_close_state(&opendata->path, newstate, openflags); | ||
571 | *res = newstate; | ||
395 | return 0; | 572 | return 0; |
396 | } | 573 | } |
397 | 574 | ||
398 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) | 575 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) |
399 | { | 576 | { |
400 | nfs4_stateid stateid; | ||
401 | struct nfs4_state *newstate; | 577 | struct nfs4_state *newstate; |
402 | int mode = 0; | ||
403 | int delegation = 0; | ||
404 | int ret; | 578 | int ret; |
405 | 579 | ||
406 | /* memory barrier prior to reading state->n_* */ | 580 | /* memory barrier prior to reading state->n_* */ |
581 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
407 | smp_rmb(); | 582 | smp_rmb(); |
408 | if (state->n_rdwr != 0) { | 583 | if (state->n_rdwr != 0) { |
409 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid); | 584 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); |
410 | if (ret != 0) | 585 | if (ret != 0) |
411 | return ret; | 586 | return ret; |
412 | mode |= FMODE_READ|FMODE_WRITE; | 587 | if (newstate != state) |
413 | if (opendata->o_res.delegation_type != 0) | 588 | return -ESTALE; |
414 | delegation = opendata->o_res.delegation_type; | ||
415 | smp_rmb(); | ||
416 | } | 589 | } |
417 | if (state->n_wronly != 0) { | 590 | if (state->n_wronly != 0) { |
418 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid); | 591 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); |
419 | if (ret != 0) | 592 | if (ret != 0) |
420 | return ret; | 593 | return ret; |
421 | mode |= FMODE_WRITE; | 594 | if (newstate != state) |
422 | if (opendata->o_res.delegation_type != 0) | 595 | return -ESTALE; |
423 | delegation = opendata->o_res.delegation_type; | ||
424 | smp_rmb(); | ||
425 | } | 596 | } |
426 | if (state->n_rdonly != 0) { | 597 | if (state->n_rdonly != 0) { |
427 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid); | 598 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); |
428 | if (ret != 0) | 599 | if (ret != 0) |
429 | return ret; | 600 | return ret; |
430 | mode |= FMODE_READ; | 601 | if (newstate != state) |
602 | return -ESTALE; | ||
431 | } | 603 | } |
432 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 604 | /* |
433 | if (mode == 0) | 605 | * We may have performed cached opens for all three recoveries. |
434 | return 0; | 606 | * Check if we need to update the current stateid. |
435 | if (opendata->o_res.delegation_type == 0) | 607 | */ |
436 | opendata->o_res.delegation_type = delegation; | 608 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && |
437 | opendata->o_arg.open_flags |= mode; | 609 | memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) { |
438 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 610 | write_seqlock(&state->seqlock); |
439 | if (newstate != NULL) { | 611 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
440 | if (opendata->o_res.delegation_type != 0) { | 612 | memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)); |
441 | struct nfs_inode *nfsi = NFS_I(newstate->inode); | 613 | 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 | } | 614 | } |
456 | if (newstate != state) | ||
457 | return -ESTALE; | ||
458 | return 0; | 615 | return 0; |
459 | } | 616 | } |
460 | 617 | ||
@@ -462,41 +619,37 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
462 | * OPEN_RECLAIM: | 619 | * OPEN_RECLAIM: |
463 | * reclaim state on the server after a reboot. | 620 | * reclaim state on the server after a reboot. |
464 | */ | 621 | */ |
465 | static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 622 | static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state) |
466 | { | 623 | { |
467 | struct nfs_delegation *delegation = NFS_I(state->inode)->delegation; | 624 | struct nfs_delegation *delegation; |
468 | struct nfs4_opendata *opendata; | 625 | struct nfs4_opendata *opendata; |
469 | int delegation_type = 0; | 626 | int delegation_type = 0; |
470 | int status; | 627 | int status; |
471 | 628 | ||
472 | if (delegation != NULL) { | 629 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); |
473 | if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { | ||
474 | memcpy(&state->stateid, &delegation->stateid, | ||
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) | 630 | if (opendata == NULL) |
483 | return -ENOMEM; | 631 | return -ENOMEM; |
484 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; | 632 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; |
485 | opendata->o_arg.fh = NFS_FH(state->inode); | 633 | opendata->o_arg.fh = NFS_FH(state->inode); |
486 | nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh); | 634 | nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh); |
635 | rcu_read_lock(); | ||
636 | delegation = rcu_dereference(NFS_I(state->inode)->delegation); | ||
637 | if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0) | ||
638 | delegation_type = delegation->flags; | ||
639 | rcu_read_unlock(); | ||
487 | opendata->o_arg.u.delegation_type = delegation_type; | 640 | opendata->o_arg.u.delegation_type = delegation_type; |
488 | status = nfs4_open_recover(opendata, state); | 641 | status = nfs4_open_recover(opendata, state); |
489 | nfs4_opendata_free(opendata); | 642 | nfs4_opendata_put(opendata); |
490 | return status; | 643 | return status; |
491 | } | 644 | } |
492 | 645 | ||
493 | static int nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 646 | static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state) |
494 | { | 647 | { |
495 | struct nfs_server *server = NFS_SERVER(state->inode); | 648 | struct nfs_server *server = NFS_SERVER(state->inode); |
496 | struct nfs4_exception exception = { }; | 649 | struct nfs4_exception exception = { }; |
497 | int err; | 650 | int err; |
498 | do { | 651 | do { |
499 | err = _nfs4_do_open_reclaim(sp, state, dentry); | 652 | err = _nfs4_do_open_reclaim(ctx, state); |
500 | if (err != -NFS4ERR_DELAY) | 653 | if (err != -NFS4ERR_DELAY) |
501 | break; | 654 | break; |
502 | nfs4_handle_exception(server, err, &exception); | 655 | nfs4_handle_exception(server, err, &exception); |
@@ -512,37 +665,35 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
512 | ctx = nfs4_state_find_open_context(state); | 665 | ctx = nfs4_state_find_open_context(state); |
513 | if (IS_ERR(ctx)) | 666 | if (IS_ERR(ctx)) |
514 | return PTR_ERR(ctx); | 667 | return PTR_ERR(ctx); |
515 | ret = nfs4_do_open_reclaim(sp, state, ctx->dentry); | 668 | ret = nfs4_do_open_reclaim(ctx, state); |
516 | put_nfs_open_context(ctx); | 669 | put_nfs_open_context(ctx); |
517 | return ret; | 670 | return ret; |
518 | } | 671 | } |
519 | 672 | ||
520 | static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | 673 | static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) |
521 | { | 674 | { |
522 | struct nfs4_state_owner *sp = state->owner; | 675 | struct nfs4_state_owner *sp = state->owner; |
523 | struct nfs4_opendata *opendata; | 676 | struct nfs4_opendata *opendata; |
524 | int ret; | 677 | int ret; |
525 | 678 | ||
526 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 679 | opendata = nfs4_opendata_alloc(&ctx->path, sp, 0, NULL); |
527 | return 0; | ||
528 | opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); | ||
529 | if (opendata == NULL) | 680 | if (opendata == NULL) |
530 | return -ENOMEM; | 681 | return -ENOMEM; |
531 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; | 682 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; |
532 | memcpy(opendata->o_arg.u.delegation.data, state->stateid.data, | 683 | memcpy(opendata->o_arg.u.delegation.data, stateid->data, |
533 | sizeof(opendata->o_arg.u.delegation.data)); | 684 | sizeof(opendata->o_arg.u.delegation.data)); |
534 | ret = nfs4_open_recover(opendata, state); | 685 | ret = nfs4_open_recover(opendata, state); |
535 | nfs4_opendata_free(opendata); | 686 | nfs4_opendata_put(opendata); |
536 | return ret; | 687 | return ret; |
537 | } | 688 | } |
538 | 689 | ||
539 | int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | 690 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) |
540 | { | 691 | { |
541 | struct nfs4_exception exception = { }; | 692 | struct nfs4_exception exception = { }; |
542 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | 693 | struct nfs_server *server = NFS_SERVER(state->inode); |
543 | int err; | 694 | int err; |
544 | do { | 695 | do { |
545 | err = _nfs4_open_delegation_recall(dentry, state); | 696 | err = _nfs4_open_delegation_recall(ctx, state, stateid); |
546 | switch (err) { | 697 | switch (err) { |
547 | case 0: | 698 | case 0: |
548 | return err; | 699 | return err; |
@@ -582,9 +733,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, | 733 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, |
583 | sizeof(data->o_res.stateid.data)); | 734 | sizeof(data->o_res.stateid.data)); |
584 | renew_lease(data->o_res.server, data->timestamp); | 735 | renew_lease(data->o_res.server, data->timestamp); |
736 | data->rpc_done = 1; | ||
585 | } | 737 | } |
586 | nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | ||
587 | nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status); | 738 | nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status); |
739 | nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | ||
588 | } | 740 | } |
589 | 741 | ||
590 | static void nfs4_open_confirm_release(void *calldata) | 742 | static void nfs4_open_confirm_release(void *calldata) |
@@ -596,14 +748,14 @@ static void nfs4_open_confirm_release(void *calldata) | |||
596 | if (data->cancelled == 0) | 748 | if (data->cancelled == 0) |
597 | goto out_free; | 749 | goto out_free; |
598 | /* In case of error, no cleanup! */ | 750 | /* In case of error, no cleanup! */ |
599 | if (data->rpc_status != 0) | 751 | if (!data->rpc_done) |
600 | goto out_free; | 752 | goto out_free; |
601 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 753 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
602 | state = nfs4_opendata_to_nfs4_state(data); | 754 | state = nfs4_opendata_to_nfs4_state(data); |
603 | if (state != NULL) | 755 | if (!IS_ERR(state)) |
604 | nfs4_close_state(state, data->o_arg.open_flags); | 756 | nfs4_close_state(&data->path, state, data->o_arg.open_flags); |
605 | out_free: | 757 | out_free: |
606 | nfs4_opendata_free(data); | 758 | nfs4_opendata_put(data); |
607 | } | 759 | } |
608 | 760 | ||
609 | static const struct rpc_call_ops nfs4_open_confirm_ops = { | 761 | static const struct rpc_call_ops nfs4_open_confirm_ops = { |
@@ -621,12 +773,9 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |||
621 | struct rpc_task *task; | 773 | struct rpc_task *task; |
622 | int status; | 774 | int status; |
623 | 775 | ||
624 | atomic_inc(&data->count); | 776 | kref_get(&data->kref); |
625 | /* | 777 | data->rpc_done = 0; |
626 | * If rpc_run_task() ends up calling ->rpc_release(), we | 778 | 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); | 779 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); |
631 | if (IS_ERR(task)) | 780 | if (IS_ERR(task)) |
632 | return PTR_ERR(task); | 781 | return PTR_ERR(task); |
@@ -653,13 +802,35 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
653 | 802 | ||
654 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) | 803 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) |
655 | return; | 804 | return; |
805 | /* | ||
806 | * Check if we still need to send an OPEN call, or if we can use | ||
807 | * a delegation instead. | ||
808 | */ | ||
809 | if (data->state != NULL) { | ||
810 | struct nfs_delegation *delegation; | ||
811 | |||
812 | if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL))) | ||
813 | goto out_no_action; | ||
814 | rcu_read_lock(); | ||
815 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); | ||
816 | if (delegation != NULL && | ||
817 | (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) { | ||
818 | rcu_read_unlock(); | ||
819 | goto out_no_action; | ||
820 | } | ||
821 | rcu_read_unlock(); | ||
822 | } | ||
656 | /* Update sequence id. */ | 823 | /* Update sequence id. */ |
657 | data->o_arg.id = sp->so_id; | 824 | data->o_arg.id = sp->so_owner_id.id; |
658 | data->o_arg.clientid = sp->so_client->cl_clientid; | 825 | data->o_arg.clientid = sp->so_client->cl_clientid; |
659 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) | 826 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) |
660 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | 827 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; |
661 | data->timestamp = jiffies; | 828 | data->timestamp = jiffies; |
662 | rpc_call_setup(task, &msg, 0); | 829 | rpc_call_setup(task, &msg, 0); |
830 | return; | ||
831 | out_no_action: | ||
832 | task->tk_action = NULL; | ||
833 | |||
663 | } | 834 | } |
664 | 835 | ||
665 | static void nfs4_open_done(struct rpc_task *task, void *calldata) | 836 | static void nfs4_open_done(struct rpc_task *task, void *calldata) |
@@ -683,8 +854,11 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
683 | data->rpc_status = -ENOTDIR; | 854 | data->rpc_status = -ENOTDIR; |
684 | } | 855 | } |
685 | renew_lease(data->o_res.server, data->timestamp); | 856 | renew_lease(data->o_res.server, data->timestamp); |
857 | if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) | ||
858 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | ||
686 | } | 859 | } |
687 | nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); | 860 | nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); |
861 | data->rpc_done = 1; | ||
688 | } | 862 | } |
689 | 863 | ||
690 | static void nfs4_open_release(void *calldata) | 864 | static void nfs4_open_release(void *calldata) |
@@ -696,17 +870,17 @@ static void nfs4_open_release(void *calldata) | |||
696 | if (data->cancelled == 0) | 870 | if (data->cancelled == 0) |
697 | goto out_free; | 871 | goto out_free; |
698 | /* In case of error, no cleanup! */ | 872 | /* In case of error, no cleanup! */ |
699 | if (data->rpc_status != 0) | 873 | if (data->rpc_status != 0 || !data->rpc_done) |
700 | goto out_free; | 874 | goto out_free; |
701 | /* In case we need an open_confirm, no cleanup! */ | 875 | /* In case we need an open_confirm, no cleanup! */ |
702 | if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) | 876 | if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) |
703 | goto out_free; | 877 | goto out_free; |
704 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 878 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
705 | state = nfs4_opendata_to_nfs4_state(data); | 879 | state = nfs4_opendata_to_nfs4_state(data); |
706 | if (state != NULL) | 880 | if (!IS_ERR(state)) |
707 | nfs4_close_state(state, data->o_arg.open_flags); | 881 | nfs4_close_state(&data->path, state, data->o_arg.open_flags); |
708 | out_free: | 882 | out_free: |
709 | nfs4_opendata_free(data); | 883 | nfs4_opendata_put(data); |
710 | } | 884 | } |
711 | 885 | ||
712 | static const struct rpc_call_ops nfs4_open_ops = { | 886 | static const struct rpc_call_ops nfs4_open_ops = { |
@@ -727,12 +901,10 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
727 | struct rpc_task *task; | 901 | struct rpc_task *task; |
728 | int status; | 902 | int status; |
729 | 903 | ||
730 | atomic_inc(&data->count); | 904 | kref_get(&data->kref); |
731 | /* | 905 | data->rpc_done = 0; |
732 | * If rpc_run_task() ends up calling ->rpc_release(), we | 906 | data->rpc_status = 0; |
733 | * want to ensure that it takes the 'error' code path. | 907 | data->cancelled = 0; |
734 | */ | ||
735 | data->rpc_status = -ENOMEM; | ||
736 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); | 908 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); |
737 | if (IS_ERR(task)) | 909 | if (IS_ERR(task)) |
738 | return PTR_ERR(task); | 910 | return PTR_ERR(task); |
@@ -743,7 +915,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
743 | } else | 915 | } else |
744 | status = data->rpc_status; | 916 | status = data->rpc_status; |
745 | rpc_put_task(task); | 917 | rpc_put_task(task); |
746 | if (status != 0) | 918 | if (status != 0 || !data->rpc_done) |
747 | return status; | 919 | return status; |
748 | 920 | ||
749 | if (o_arg->open_flags & O_CREAT) { | 921 | if (o_arg->open_flags & O_CREAT) { |
@@ -756,7 +928,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
756 | if (status != 0) | 928 | if (status != 0) |
757 | return status; | 929 | return status; |
758 | } | 930 | } |
759 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | ||
760 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) | 931 | 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); | 932 | return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); |
762 | return 0; | 933 | return 0; |
@@ -772,6 +943,8 @@ static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openf | |||
772 | mask |= MAY_READ; | 943 | mask |= MAY_READ; |
773 | if (openflags & FMODE_WRITE) | 944 | if (openflags & FMODE_WRITE) |
774 | mask |= MAY_WRITE; | 945 | mask |= MAY_WRITE; |
946 | if (openflags & FMODE_EXEC) | ||
947 | mask |= MAY_EXEC; | ||
775 | status = nfs_access_get_cached(inode, cred, &cache); | 948 | status = nfs_access_get_cached(inode, cred, &cache); |
776 | if (status == 0) | 949 | if (status == 0) |
777 | goto out; | 950 | goto out; |
@@ -811,43 +984,32 @@ static int nfs4_recover_expired_lease(struct nfs_server *server) | |||
811 | * reclaim state on the server after a network partition. | 984 | * reclaim state on the server after a network partition. |
812 | * Assumes caller holds the appropriate lock | 985 | * Assumes caller holds the appropriate lock |
813 | */ | 986 | */ |
814 | static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 987 | static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) |
815 | { | 988 | { |
816 | struct inode *inode = state->inode; | ||
817 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | ||
818 | struct nfs4_opendata *opendata; | 989 | struct nfs4_opendata *opendata; |
819 | int openflags = state->state & (FMODE_READ|FMODE_WRITE); | ||
820 | int ret; | 990 | int ret; |
821 | 991 | ||
822 | if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { | 992 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); |
823 | ret = _nfs4_do_access(inode, sp->so_cred, openflags); | ||
824 | if (ret < 0) | ||
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) | 993 | if (opendata == NULL) |
832 | return -ENOMEM; | 994 | return -ENOMEM; |
833 | ret = nfs4_open_recover(opendata, state); | 995 | ret = nfs4_open_recover(opendata, state); |
834 | if (ret == -ESTALE) { | 996 | if (ret == -ESTALE) { |
835 | /* Invalidate the state owner so we don't ever use it again */ | 997 | /* Invalidate the state owner so we don't ever use it again */ |
836 | nfs4_drop_state_owner(sp); | 998 | nfs4_drop_state_owner(state->owner); |
837 | d_drop(dentry); | 999 | d_drop(ctx->path.dentry); |
838 | } | 1000 | } |
839 | nfs4_opendata_free(opendata); | 1001 | nfs4_opendata_put(opendata); |
840 | return ret; | 1002 | return ret; |
841 | } | 1003 | } |
842 | 1004 | ||
843 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | 1005 | static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) |
844 | { | 1006 | { |
845 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | 1007 | struct nfs_server *server = NFS_SERVER(state->inode); |
846 | struct nfs4_exception exception = { }; | 1008 | struct nfs4_exception exception = { }; |
847 | int err; | 1009 | int err; |
848 | 1010 | ||
849 | do { | 1011 | do { |
850 | err = _nfs4_open_expired(sp, state, dentry); | 1012 | err = _nfs4_open_expired(ctx, state); |
851 | if (err == -NFS4ERR_DELAY) | 1013 | if (err == -NFS4ERR_DELAY) |
852 | nfs4_handle_exception(server, err, &exception); | 1014 | nfs4_handle_exception(server, err, &exception); |
853 | } while (exception.retry); | 1015 | } while (exception.retry); |
@@ -862,107 +1024,38 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
862 | ctx = nfs4_state_find_open_context(state); | 1024 | ctx = nfs4_state_find_open_context(state); |
863 | if (IS_ERR(ctx)) | 1025 | if (IS_ERR(ctx)) |
864 | return PTR_ERR(ctx); | 1026 | return PTR_ERR(ctx); |
865 | ret = nfs4_do_open_expired(sp, state, ctx->dentry); | 1027 | ret = nfs4_do_open_expired(ctx, state); |
866 | put_nfs_open_context(ctx); | 1028 | put_nfs_open_context(ctx); |
867 | return ret; | 1029 | return ret; |
868 | } | 1030 | } |
869 | 1031 | ||
870 | /* | 1032 | /* |
871 | * Returns a referenced nfs4_state if there is an open delegation on the file | 1033 | * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-* |
1034 | * fields corresponding to attributes that were used to store the verifier. | ||
1035 | * Make sure we clobber those fields in the later setattr call | ||
872 | */ | 1036 | */ |
873 | static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) | 1037 | static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr) |
874 | { | ||
875 | struct nfs_delegation *delegation; | ||
876 | struct nfs_server *server = NFS_SERVER(inode); | ||
877 | struct nfs_client *clp = server->nfs_client; | ||
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 | |||
884 | err = -ENOMEM; | ||
885 | if (!(sp = nfs4_get_state_owner(server, cred))) { | ||
886 | dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); | ||
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 | { | 1038 | { |
941 | struct nfs4_exception exception = { }; | 1039 | if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) && |
942 | struct nfs4_state *res = ERR_PTR(-EIO); | 1040 | !(sattr->ia_valid & ATTR_ATIME_SET)) |
943 | int err; | 1041 | sattr->ia_valid |= ATTR_ATIME; |
944 | 1042 | ||
945 | do { | 1043 | if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) && |
946 | err = _nfs4_open_delegated(inode, flags, cred, &res); | 1044 | !(sattr->ia_valid & ATTR_MTIME_SET)) |
947 | if (err == 0) | 1045 | sattr->ia_valid |= ATTR_MTIME; |
948 | break; | ||
949 | res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(inode), | ||
950 | err, &exception)); | ||
951 | } while (exception.retry); | ||
952 | return res; | ||
953 | } | 1046 | } |
954 | 1047 | ||
955 | /* | 1048 | /* |
956 | * Returns a referenced nfs4_state | 1049 | * Returns a referenced nfs4_state |
957 | */ | 1050 | */ |
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) | 1051 | 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 | { | 1052 | { |
960 | struct nfs4_state_owner *sp; | 1053 | struct nfs4_state_owner *sp; |
961 | struct nfs4_state *state = NULL; | 1054 | struct nfs4_state *state = NULL; |
962 | struct nfs_server *server = NFS_SERVER(dir); | 1055 | struct nfs_server *server = NFS_SERVER(dir); |
963 | struct nfs_client *clp = server->nfs_client; | 1056 | struct nfs_client *clp = server->nfs_client; |
964 | struct nfs4_opendata *opendata; | 1057 | struct nfs4_opendata *opendata; |
965 | int status; | 1058 | int status; |
966 | 1059 | ||
967 | /* Protect against reboot recovery conflicts */ | 1060 | /* Protect against reboot recovery conflicts */ |
968 | status = -ENOMEM; | 1061 | status = -ENOMEM; |
@@ -973,29 +1066,35 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
973 | status = nfs4_recover_expired_lease(server); | 1066 | status = nfs4_recover_expired_lease(server); |
974 | if (status != 0) | 1067 | if (status != 0) |
975 | goto err_put_state_owner; | 1068 | goto err_put_state_owner; |
1069 | if (path->dentry->d_inode != NULL) | ||
1070 | nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE)); | ||
976 | down_read(&clp->cl_sem); | 1071 | down_read(&clp->cl_sem); |
977 | status = -ENOMEM; | 1072 | status = -ENOMEM; |
978 | opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); | 1073 | opendata = nfs4_opendata_alloc(path, sp, flags, sattr); |
979 | if (opendata == NULL) | 1074 | if (opendata == NULL) |
980 | goto err_release_rwsem; | 1075 | goto err_release_rwsem; |
981 | 1076 | ||
1077 | if (path->dentry->d_inode != NULL) | ||
1078 | opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); | ||
1079 | |||
982 | status = _nfs4_proc_open(opendata); | 1080 | status = _nfs4_proc_open(opendata); |
983 | if (status != 0) | 1081 | if (status != 0) |
984 | goto err_opendata_free; | 1082 | goto err_opendata_put; |
1083 | |||
1084 | if (opendata->o_arg.open_flags & O_EXCL) | ||
1085 | nfs4_exclusive_attrset(opendata, sattr); | ||
985 | 1086 | ||
986 | status = -ENOMEM; | ||
987 | state = nfs4_opendata_to_nfs4_state(opendata); | 1087 | state = nfs4_opendata_to_nfs4_state(opendata); |
988 | if (state == NULL) | 1088 | status = PTR_ERR(state); |
989 | goto err_opendata_free; | 1089 | if (IS_ERR(state)) |
990 | if (opendata->o_res.delegation_type != 0) | 1090 | goto err_opendata_put; |
991 | nfs_inode_set_delegation(state->inode, cred, &opendata->o_res); | 1091 | nfs4_opendata_put(opendata); |
992 | nfs4_opendata_free(opendata); | ||
993 | nfs4_put_state_owner(sp); | 1092 | nfs4_put_state_owner(sp); |
994 | up_read(&clp->cl_sem); | 1093 | up_read(&clp->cl_sem); |
995 | *res = state; | 1094 | *res = state; |
996 | return 0; | 1095 | return 0; |
997 | err_opendata_free: | 1096 | err_opendata_put: |
998 | nfs4_opendata_free(opendata); | 1097 | nfs4_opendata_put(opendata); |
999 | err_release_rwsem: | 1098 | err_release_rwsem: |
1000 | up_read(&clp->cl_sem); | 1099 | up_read(&clp->cl_sem); |
1001 | err_put_state_owner: | 1100 | err_put_state_owner: |
@@ -1006,14 +1105,14 @@ out_err: | |||
1006 | } | 1105 | } |
1007 | 1106 | ||
1008 | 1107 | ||
1009 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred) | 1108 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred) |
1010 | { | 1109 | { |
1011 | struct nfs4_exception exception = { }; | 1110 | struct nfs4_exception exception = { }; |
1012 | struct nfs4_state *res; | 1111 | struct nfs4_state *res; |
1013 | int status; | 1112 | int status; |
1014 | 1113 | ||
1015 | do { | 1114 | do { |
1016 | status = _nfs4_do_open(dir, dentry, flags, sattr, cred, &res); | 1115 | status = _nfs4_do_open(dir, path, flags, sattr, cred, &res); |
1017 | if (status == 0) | 1116 | if (status == 0) |
1018 | break; | 1117 | break; |
1019 | /* NOTE: BAD_SEQID means the server and client disagree about the | 1118 | /* NOTE: BAD_SEQID means the server and client disagree about the |
@@ -1028,7 +1127,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, | |||
1028 | * the user though... | 1127 | * the user though... |
1029 | */ | 1128 | */ |
1030 | if (status == -NFS4ERR_BAD_SEQID) { | 1129 | if (status == -NFS4ERR_BAD_SEQID) { |
1031 | printk(KERN_WARNING "NFS: v4 server returned a bad sequence-id error!\n"); | 1130 | printk(KERN_WARNING "NFS: v4 server %s " |
1131 | " returned a bad sequence-id error!\n", | ||
1132 | NFS_SERVER(dir)->nfs_client->cl_hostname); | ||
1032 | exception.retry = 1; | 1133 | exception.retry = 1; |
1033 | continue; | 1134 | continue; |
1034 | } | 1135 | } |
@@ -1042,6 +1143,11 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, | |||
1042 | exception.retry = 1; | 1143 | exception.retry = 1; |
1043 | continue; | 1144 | continue; |
1044 | } | 1145 | } |
1146 | if (status == -EAGAIN) { | ||
1147 | /* We must have found a delegation */ | ||
1148 | exception.retry = 1; | ||
1149 | continue; | ||
1150 | } | ||
1045 | res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), | 1151 | res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), |
1046 | status, &exception)); | 1152 | status, &exception)); |
1047 | } while (exception.retry); | 1153 | } while (exception.retry); |
@@ -1101,6 +1207,7 @@ static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, | |||
1101 | } | 1207 | } |
1102 | 1208 | ||
1103 | struct nfs4_closedata { | 1209 | struct nfs4_closedata { |
1210 | struct path path; | ||
1104 | struct inode *inode; | 1211 | struct inode *inode; |
1105 | struct nfs4_state *state; | 1212 | struct nfs4_state *state; |
1106 | struct nfs_closeargs arg; | 1213 | struct nfs_closeargs arg; |
@@ -1117,6 +1224,8 @@ static void nfs4_free_closedata(void *data) | |||
1117 | nfs4_put_open_state(calldata->state); | 1224 | nfs4_put_open_state(calldata->state); |
1118 | nfs_free_seqid(calldata->arg.seqid); | 1225 | nfs_free_seqid(calldata->arg.seqid); |
1119 | nfs4_put_state_owner(sp); | 1226 | nfs4_put_state_owner(sp); |
1227 | dput(calldata->path.dentry); | ||
1228 | mntput(calldata->path.mnt); | ||
1120 | kfree(calldata); | 1229 | kfree(calldata); |
1121 | } | 1230 | } |
1122 | 1231 | ||
@@ -1134,8 +1243,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1134 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); | 1243 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); |
1135 | switch (task->tk_status) { | 1244 | switch (task->tk_status) { |
1136 | case 0: | 1245 | case 0: |
1137 | memcpy(&state->stateid, &calldata->res.stateid, | 1246 | nfs_set_open_stateid(state, &calldata->res.stateid, calldata->arg.open_flags); |
1138 | sizeof(state->stateid)); | ||
1139 | renew_lease(server, calldata->timestamp); | 1247 | renew_lease(server, calldata->timestamp); |
1140 | break; | 1248 | break; |
1141 | case -NFS4ERR_STALE_STATEID: | 1249 | case -NFS4ERR_STALE_STATEID: |
@@ -1160,26 +1268,30 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1160 | .rpc_resp = &calldata->res, | 1268 | .rpc_resp = &calldata->res, |
1161 | .rpc_cred = state->owner->so_cred, | 1269 | .rpc_cred = state->owner->so_cred, |
1162 | }; | 1270 | }; |
1163 | int mode = 0, old_mode; | 1271 | int clear_rd, clear_wr, clear_rdwr; |
1272 | int mode; | ||
1164 | 1273 | ||
1165 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 1274 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
1166 | return; | 1275 | return; |
1167 | /* Recalculate the new open mode in case someone reopened the file | 1276 | |
1168 | * while we were waiting in line to be scheduled. | 1277 | mode = FMODE_READ|FMODE_WRITE; |
1169 | */ | 1278 | clear_rd = clear_wr = clear_rdwr = 0; |
1170 | spin_lock(&state->owner->so_lock); | 1279 | spin_lock(&state->owner->so_lock); |
1171 | spin_lock(&calldata->inode->i_lock); | 1280 | /* Calculate the change in open mode */ |
1172 | mode = old_mode = state->state; | ||
1173 | if (state->n_rdwr == 0) { | 1281 | if (state->n_rdwr == 0) { |
1174 | if (state->n_rdonly == 0) | 1282 | if (state->n_rdonly == 0) { |
1175 | mode &= ~FMODE_READ; | 1283 | mode &= ~FMODE_READ; |
1176 | if (state->n_wronly == 0) | 1284 | clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); |
1285 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1286 | } | ||
1287 | if (state->n_wronly == 0) { | ||
1177 | mode &= ~FMODE_WRITE; | 1288 | mode &= ~FMODE_WRITE; |
1289 | clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1290 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1291 | } | ||
1178 | } | 1292 | } |
1179 | nfs4_state_set_mode_locked(state, mode); | ||
1180 | spin_unlock(&calldata->inode->i_lock); | ||
1181 | spin_unlock(&state->owner->so_lock); | 1293 | spin_unlock(&state->owner->so_lock); |
1182 | if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 1294 | if (!clear_rd && !clear_wr && !clear_rdwr) { |
1183 | /* Note: exit _without_ calling nfs4_close_done */ | 1295 | /* Note: exit _without_ calling nfs4_close_done */ |
1184 | task->tk_action = NULL; | 1296 | task->tk_action = NULL; |
1185 | return; | 1297 | return; |
@@ -1209,19 +1321,21 @@ static const struct rpc_call_ops nfs4_close_ops = { | |||
1209 | * | 1321 | * |
1210 | * NOTE: Caller must be holding the sp->so_owner semaphore! | 1322 | * NOTE: Caller must be holding the sp->so_owner semaphore! |
1211 | */ | 1323 | */ |
1212 | int nfs4_do_close(struct inode *inode, struct nfs4_state *state) | 1324 | int nfs4_do_close(struct path *path, struct nfs4_state *state) |
1213 | { | 1325 | { |
1214 | struct nfs_server *server = NFS_SERVER(inode); | 1326 | struct nfs_server *server = NFS_SERVER(state->inode); |
1215 | struct nfs4_closedata *calldata; | 1327 | struct nfs4_closedata *calldata; |
1328 | struct nfs4_state_owner *sp = state->owner; | ||
1329 | struct rpc_task *task; | ||
1216 | int status = -ENOMEM; | 1330 | int status = -ENOMEM; |
1217 | 1331 | ||
1218 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 1332 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); |
1219 | if (calldata == NULL) | 1333 | if (calldata == NULL) |
1220 | goto out; | 1334 | goto out; |
1221 | calldata->inode = inode; | 1335 | calldata->inode = state->inode; |
1222 | calldata->state = state; | 1336 | calldata->state = state; |
1223 | calldata->arg.fh = NFS_FH(inode); | 1337 | calldata->arg.fh = NFS_FH(state->inode); |
1224 | calldata->arg.stateid = &state->stateid; | 1338 | calldata->arg.stateid = &state->open_stateid; |
1225 | /* Serialization for the sequence id */ | 1339 | /* Serialization for the sequence id */ |
1226 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1340 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1227 | if (calldata->arg.seqid == NULL) | 1341 | if (calldata->arg.seqid == NULL) |
@@ -1229,36 +1343,55 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state) | |||
1229 | calldata->arg.bitmask = server->attr_bitmask; | 1343 | calldata->arg.bitmask = server->attr_bitmask; |
1230 | calldata->res.fattr = &calldata->fattr; | 1344 | calldata->res.fattr = &calldata->fattr; |
1231 | calldata->res.server = server; | 1345 | calldata->res.server = server; |
1346 | calldata->path.mnt = mntget(path->mnt); | ||
1347 | calldata->path.dentry = dget(path->dentry); | ||
1232 | 1348 | ||
1233 | status = nfs4_call_async(server->client, &nfs4_close_ops, calldata); | 1349 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata); |
1234 | if (status == 0) | 1350 | if (IS_ERR(task)) |
1235 | goto out; | 1351 | return PTR_ERR(task); |
1236 | 1352 | rpc_put_task(task); | |
1237 | nfs_free_seqid(calldata->arg.seqid); | 1353 | return 0; |
1238 | out_free_calldata: | 1354 | out_free_calldata: |
1239 | kfree(calldata); | 1355 | kfree(calldata); |
1240 | out: | 1356 | out: |
1357 | nfs4_put_open_state(state); | ||
1358 | nfs4_put_state_owner(sp); | ||
1241 | return status; | 1359 | return status; |
1242 | } | 1360 | } |
1243 | 1361 | ||
1244 | static int nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state) | 1362 | static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state) |
1245 | { | 1363 | { |
1246 | struct file *filp; | 1364 | struct file *filp; |
1365 | int ret; | ||
1247 | 1366 | ||
1248 | filp = lookup_instantiate_filp(nd, dentry, NULL); | 1367 | /* If the open_intent is for execute, we have an extra check to make */ |
1368 | if (nd->intent.open.flags & FMODE_EXEC) { | ||
1369 | ret = _nfs4_do_access(state->inode, | ||
1370 | state->owner->so_cred, | ||
1371 | nd->intent.open.flags); | ||
1372 | if (ret < 0) | ||
1373 | goto out_close; | ||
1374 | } | ||
1375 | filp = lookup_instantiate_filp(nd, path->dentry, NULL); | ||
1249 | if (!IS_ERR(filp)) { | 1376 | if (!IS_ERR(filp)) { |
1250 | struct nfs_open_context *ctx; | 1377 | struct nfs_open_context *ctx; |
1251 | ctx = (struct nfs_open_context *)filp->private_data; | 1378 | ctx = (struct nfs_open_context *)filp->private_data; |
1252 | ctx->state = state; | 1379 | ctx->state = state; |
1253 | return 0; | 1380 | return 0; |
1254 | } | 1381 | } |
1255 | nfs4_close_state(state, nd->intent.open.flags); | 1382 | ret = PTR_ERR(filp); |
1256 | return PTR_ERR(filp); | 1383 | out_close: |
1384 | nfs4_close_state(path, state, nd->intent.open.flags); | ||
1385 | return ret; | ||
1257 | } | 1386 | } |
1258 | 1387 | ||
1259 | struct dentry * | 1388 | struct dentry * |
1260 | nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 1389 | nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
1261 | { | 1390 | { |
1391 | struct path path = { | ||
1392 | .mnt = nd->mnt, | ||
1393 | .dentry = dentry, | ||
1394 | }; | ||
1262 | struct iattr attr; | 1395 | struct iattr attr; |
1263 | struct rpc_cred *cred; | 1396 | struct rpc_cred *cred; |
1264 | struct nfs4_state *state; | 1397 | struct nfs4_state *state; |
@@ -1277,7 +1410,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1277 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1410 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
1278 | if (IS_ERR(cred)) | 1411 | if (IS_ERR(cred)) |
1279 | return (struct dentry *)cred; | 1412 | return (struct dentry *)cred; |
1280 | state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); | 1413 | state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); |
1281 | put_rpccred(cred); | 1414 | put_rpccred(cred); |
1282 | if (IS_ERR(state)) { | 1415 | if (IS_ERR(state)) { |
1283 | if (PTR_ERR(state) == -ENOENT) | 1416 | if (PTR_ERR(state) == -ENOENT) |
@@ -1287,22 +1420,24 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1287 | res = d_add_unique(dentry, igrab(state->inode)); | 1420 | res = d_add_unique(dentry, igrab(state->inode)); |
1288 | if (res != NULL) | 1421 | if (res != NULL) |
1289 | dentry = res; | 1422 | dentry = res; |
1290 | nfs4_intent_set_file(nd, dentry, state); | 1423 | nfs4_intent_set_file(nd, &path, state); |
1291 | return res; | 1424 | return res; |
1292 | } | 1425 | } |
1293 | 1426 | ||
1294 | int | 1427 | int |
1295 | nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) | 1428 | nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) |
1296 | { | 1429 | { |
1430 | struct path path = { | ||
1431 | .mnt = nd->mnt, | ||
1432 | .dentry = dentry, | ||
1433 | }; | ||
1297 | struct rpc_cred *cred; | 1434 | struct rpc_cred *cred; |
1298 | struct nfs4_state *state; | 1435 | struct nfs4_state *state; |
1299 | 1436 | ||
1300 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1437 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
1301 | if (IS_ERR(cred)) | 1438 | if (IS_ERR(cred)) |
1302 | return PTR_ERR(cred); | 1439 | return PTR_ERR(cred); |
1303 | state = nfs4_open_delegated(dentry->d_inode, openflags, cred); | 1440 | 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); | 1441 | put_rpccred(cred); |
1307 | if (IS_ERR(state)) { | 1442 | if (IS_ERR(state)) { |
1308 | switch (PTR_ERR(state)) { | 1443 | switch (PTR_ERR(state)) { |
@@ -1318,10 +1453,10 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1318 | } | 1453 | } |
1319 | } | 1454 | } |
1320 | if (state->inode == dentry->d_inode) { | 1455 | if (state->inode == dentry->d_inode) { |
1321 | nfs4_intent_set_file(nd, dentry, state); | 1456 | nfs4_intent_set_file(nd, &path, state); |
1322 | return 1; | 1457 | return 1; |
1323 | } | 1458 | } |
1324 | nfs4_close_state(state, openflags); | 1459 | nfs4_close_state(&path, state, openflags); |
1325 | out_drop: | 1460 | out_drop: |
1326 | d_drop(dentry); | 1461 | d_drop(dentry); |
1327 | return 0; | 1462 | return 0; |
@@ -1559,8 +1694,6 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |||
1559 | dprintk("NFS call lookupfh %s\n", name->name); | 1694 | dprintk("NFS call lookupfh %s\n", name->name); |
1560 | status = rpc_call_sync(server->client, &msg, 0); | 1695 | status = rpc_call_sync(server->client, &msg, 0); |
1561 | dprintk("NFS reply lookupfh: %d\n", status); | 1696 | dprintk("NFS reply lookupfh: %d\n", status); |
1562 | if (status == -NFS4ERR_MOVED) | ||
1563 | status = -EREMOTE; | ||
1564 | return status; | 1697 | return status; |
1565 | } | 1698 | } |
1566 | 1699 | ||
@@ -1571,10 +1704,13 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |||
1571 | struct nfs4_exception exception = { }; | 1704 | struct nfs4_exception exception = { }; |
1572 | int err; | 1705 | int err; |
1573 | do { | 1706 | do { |
1574 | err = nfs4_handle_exception(server, | 1707 | err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr); |
1575 | _nfs4_proc_lookupfh(server, dirfh, name, | 1708 | /* FIXME: !!!! */ |
1576 | fhandle, fattr), | 1709 | if (err == -NFS4ERR_MOVED) { |
1577 | &exception); | 1710 | err = -EREMOTE; |
1711 | break; | ||
1712 | } | ||
1713 | err = nfs4_handle_exception(server, err, &exception); | ||
1578 | } while (exception.retry); | 1714 | } while (exception.retry); |
1579 | return err; | 1715 | return err; |
1580 | } | 1716 | } |
@@ -1582,28 +1718,10 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |||
1582 | static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, | 1718 | static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, |
1583 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 1719 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
1584 | { | 1720 | { |
1585 | int status; | 1721 | 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 | 1722 | ||
1605 | dprintk("NFS call lookup %s\n", name->name); | 1723 | dprintk("NFS call lookup %s\n", name->name); |
1606 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 1724 | status = _nfs4_proc_lookupfh(NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr); |
1607 | if (status == -NFS4ERR_MOVED) | 1725 | if (status == -NFS4ERR_MOVED) |
1608 | status = nfs4_get_referral(dir, name, fattr, fhandle); | 1726 | status = nfs4_get_referral(dir, name, fattr, fhandle); |
1609 | dprintk("NFS reply lookup: %d\n", status); | 1727 | dprintk("NFS reply lookup: %d\n", status); |
@@ -1752,6 +1870,10 @@ static int | |||
1752 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 1870 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
1753 | int flags, struct nameidata *nd) | 1871 | int flags, struct nameidata *nd) |
1754 | { | 1872 | { |
1873 | struct path path = { | ||
1874 | .mnt = nd->mnt, | ||
1875 | .dentry = dentry, | ||
1876 | }; | ||
1755 | struct nfs4_state *state; | 1877 | struct nfs4_state *state; |
1756 | struct rpc_cred *cred; | 1878 | struct rpc_cred *cred; |
1757 | int status = 0; | 1879 | int status = 0; |
@@ -1761,7 +1883,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1761 | status = PTR_ERR(cred); | 1883 | status = PTR_ERR(cred); |
1762 | goto out; | 1884 | goto out; |
1763 | } | 1885 | } |
1764 | state = nfs4_do_open(dir, dentry, flags, sattr, cred); | 1886 | state = nfs4_do_open(dir, &path, flags, sattr, cred); |
1765 | put_rpccred(cred); | 1887 | put_rpccred(cred); |
1766 | if (IS_ERR(state)) { | 1888 | if (IS_ERR(state)) { |
1767 | status = PTR_ERR(state); | 1889 | status = PTR_ERR(state); |
@@ -1773,11 +1895,12 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1773 | status = nfs4_do_setattr(state->inode, &fattr, sattr, state); | 1895 | status = nfs4_do_setattr(state->inode, &fattr, sattr, state); |
1774 | if (status == 0) | 1896 | if (status == 0) |
1775 | nfs_setattr_update_inode(state->inode, sattr); | 1897 | nfs_setattr_update_inode(state->inode, sattr); |
1898 | nfs_post_op_update_inode(state->inode, &fattr); | ||
1776 | } | 1899 | } |
1777 | if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN)) | 1900 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) |
1778 | status = nfs4_intent_set_file(nd, dentry, state); | 1901 | status = nfs4_intent_set_file(nd, &path, state); |
1779 | else | 1902 | else |
1780 | nfs4_close_state(state, flags); | 1903 | nfs4_close_state(&path, state, flags); |
1781 | out: | 1904 | out: |
1782 | return status; | 1905 | return status; |
1783 | } | 1906 | } |
@@ -3008,7 +3131,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3008 | if (status != 0) | 3131 | if (status != 0) |
3009 | goto out; | 3132 | goto out; |
3010 | lsp = request->fl_u.nfs4_fl.owner; | 3133 | lsp = request->fl_u.nfs4_fl.owner; |
3011 | arg.lock_owner.id = lsp->ls_id; | 3134 | arg.lock_owner.id = lsp->ls_id.id; |
3012 | status = rpc_call_sync(server->client, &msg, 0); | 3135 | status = rpc_call_sync(server->client, &msg, 0); |
3013 | switch (status) { | 3136 | switch (status) { |
3014 | case 0: | 3137 | case 0: |
@@ -3152,6 +3275,11 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3152 | { | 3275 | { |
3153 | struct nfs4_unlockdata *data; | 3276 | struct nfs4_unlockdata *data; |
3154 | 3277 | ||
3278 | /* Ensure this is an unlock - when canceling a lock, the | ||
3279 | * canceled lock is passed in, and it won't be an unlock. | ||
3280 | */ | ||
3281 | fl->fl_type = F_UNLCK; | ||
3282 | |||
3155 | data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); | 3283 | data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); |
3156 | if (data == NULL) { | 3284 | if (data == NULL) { |
3157 | nfs_free_seqid(seqid); | 3285 | nfs_free_seqid(seqid); |
@@ -3222,7 +3350,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3222 | goto out_free; | 3350 | goto out_free; |
3223 | p->arg.lock_stateid = &lsp->ls_stateid; | 3351 | p->arg.lock_stateid = &lsp->ls_stateid; |
3224 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3352 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3225 | p->arg.lock_owner.id = lsp->ls_id; | 3353 | p->arg.lock_owner.id = lsp->ls_id.id; |
3226 | p->lsp = lsp; | 3354 | p->lsp = lsp; |
3227 | atomic_inc(&lsp->ls_count); | 3355 | atomic_inc(&lsp->ls_count); |
3228 | p->ctx = get_nfs_open_context(ctx); | 3356 | p->ctx = get_nfs_open_context(ctx); |
@@ -3285,7 +3413,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3285 | memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, | 3413 | memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, |
3286 | sizeof(data->lsp->ls_stateid.data)); | 3414 | sizeof(data->lsp->ls_stateid.data)); |
3287 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 3415 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; |
3288 | renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); | 3416 | renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); |
3289 | } | 3417 | } |
3290 | nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); | 3418 | nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); |
3291 | out: | 3419 | out: |