diff options
Diffstat (limited to 'fs/nfs/inode.c')
-rw-r--r-- | fs/nfs/inode.c | 124 |
1 files changed, 102 insertions, 22 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 099b3518feea..314f57164602 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include "internal.h" | 48 | #include "internal.h" |
49 | #include "fscache.h" | 49 | #include "fscache.h" |
50 | #include "dns_resolve.h" | 50 | #include "dns_resolve.h" |
51 | #include "pnfs.h" | ||
51 | 52 | ||
52 | #define NFSDBG_FACILITY NFSDBG_VFS | 53 | #define NFSDBG_FACILITY NFSDBG_VFS |
53 | 54 | ||
@@ -98,7 +99,7 @@ u64 nfs_compat_user_ino64(u64 fileid) | |||
98 | return ino; | 99 | return ino; |
99 | } | 100 | } |
100 | 101 | ||
101 | void nfs_clear_inode(struct inode *inode) | 102 | static void nfs_clear_inode(struct inode *inode) |
102 | { | 103 | { |
103 | /* | 104 | /* |
104 | * The following should never happen... | 105 | * The following should never happen... |
@@ -110,6 +111,13 @@ void nfs_clear_inode(struct inode *inode) | |||
110 | nfs_fscache_release_inode_cookie(inode); | 111 | nfs_fscache_release_inode_cookie(inode); |
111 | } | 112 | } |
112 | 113 | ||
114 | void nfs_evict_inode(struct inode *inode) | ||
115 | { | ||
116 | truncate_inode_pages(&inode->i_data, 0); | ||
117 | end_writeback(inode); | ||
118 | nfs_clear_inode(inode); | ||
119 | } | ||
120 | |||
113 | /** | 121 | /** |
114 | * nfs_sync_mapping - helper to flush all mmapped dirty data to disk | 122 | * nfs_sync_mapping - helper to flush all mmapped dirty data to disk |
115 | */ | 123 | */ |
@@ -227,9 +235,6 @@ nfs_init_locked(struct inode *inode, void *opaque) | |||
227 | return 0; | 235 | return 0; |
228 | } | 236 | } |
229 | 237 | ||
230 | /* Don't use READDIRPLUS on directories that we believe are too large */ | ||
231 | #define NFS_LIMIT_READDIRPLUS (8*PAGE_SIZE) | ||
232 | |||
233 | /* | 238 | /* |
234 | * This is our front-end to iget that looks up inodes by file handle | 239 | * This is our front-end to iget that looks up inodes by file handle |
235 | * instead of inode number. | 240 | * instead of inode number. |
@@ -284,8 +289,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
284 | } else if (S_ISDIR(inode->i_mode)) { | 289 | } else if (S_ISDIR(inode->i_mode)) { |
285 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; | 290 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; |
286 | inode->i_fop = &nfs_dir_operations; | 291 | inode->i_fop = &nfs_dir_operations; |
287 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) | 292 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)) |
288 | && fattr->size <= NFS_LIMIT_READDIRPLUS) | ||
289 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); | 293 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
290 | /* Deal with crossing mountpoints */ | 294 | /* Deal with crossing mountpoints */ |
291 | if ((fattr->valid & NFS_ATTR_FATTR_FSID) | 295 | if ((fattr->valid & NFS_ATTR_FATTR_FSID) |
@@ -413,10 +417,8 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
413 | return 0; | 417 | return 0; |
414 | 418 | ||
415 | /* Write all dirty data */ | 419 | /* Write all dirty data */ |
416 | if (S_ISREG(inode->i_mode)) { | 420 | if (S_ISREG(inode->i_mode)) |
417 | filemap_write_and_wait(inode->i_mapping); | ||
418 | nfs_wb_all(inode); | 421 | nfs_wb_all(inode); |
419 | } | ||
420 | 422 | ||
421 | fattr = nfs_alloc_fattr(); | 423 | fattr = nfs_alloc_fattr(); |
422 | if (fattr == NULL) | 424 | if (fattr == NULL) |
@@ -530,6 +532,68 @@ out: | |||
530 | return err; | 532 | return err; |
531 | } | 533 | } |
532 | 534 | ||
535 | static void nfs_init_lock_context(struct nfs_lock_context *l_ctx) | ||
536 | { | ||
537 | atomic_set(&l_ctx->count, 1); | ||
538 | l_ctx->lockowner = current->files; | ||
539 | l_ctx->pid = current->tgid; | ||
540 | INIT_LIST_HEAD(&l_ctx->list); | ||
541 | } | ||
542 | |||
543 | static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) | ||
544 | { | ||
545 | struct nfs_lock_context *pos; | ||
546 | |||
547 | list_for_each_entry(pos, &ctx->lock_context.list, list) { | ||
548 | if (pos->lockowner != current->files) | ||
549 | continue; | ||
550 | if (pos->pid != current->tgid) | ||
551 | continue; | ||
552 | atomic_inc(&pos->count); | ||
553 | return pos; | ||
554 | } | ||
555 | return NULL; | ||
556 | } | ||
557 | |||
558 | struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) | ||
559 | { | ||
560 | struct nfs_lock_context *res, *new = NULL; | ||
561 | struct inode *inode = ctx->path.dentry->d_inode; | ||
562 | |||
563 | spin_lock(&inode->i_lock); | ||
564 | res = __nfs_find_lock_context(ctx); | ||
565 | if (res == NULL) { | ||
566 | spin_unlock(&inode->i_lock); | ||
567 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
568 | if (new == NULL) | ||
569 | return NULL; | ||
570 | nfs_init_lock_context(new); | ||
571 | spin_lock(&inode->i_lock); | ||
572 | res = __nfs_find_lock_context(ctx); | ||
573 | if (res == NULL) { | ||
574 | list_add_tail(&new->list, &ctx->lock_context.list); | ||
575 | new->open_context = ctx; | ||
576 | res = new; | ||
577 | new = NULL; | ||
578 | } | ||
579 | } | ||
580 | spin_unlock(&inode->i_lock); | ||
581 | kfree(new); | ||
582 | return res; | ||
583 | } | ||
584 | |||
585 | void nfs_put_lock_context(struct nfs_lock_context *l_ctx) | ||
586 | { | ||
587 | struct nfs_open_context *ctx = l_ctx->open_context; | ||
588 | struct inode *inode = ctx->path.dentry->d_inode; | ||
589 | |||
590 | if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock)) | ||
591 | return; | ||
592 | list_del(&l_ctx->list); | ||
593 | spin_unlock(&inode->i_lock); | ||
594 | kfree(l_ctx); | ||
595 | } | ||
596 | |||
533 | /** | 597 | /** |
534 | * nfs_close_context - Common close_context() routine NFSv2/v3 | 598 | * nfs_close_context - Common close_context() routine NFSv2/v3 |
535 | * @ctx: pointer to context | 599 | * @ctx: pointer to context |
@@ -556,7 +620,7 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) | |||
556 | nfs_revalidate_inode(server, inode); | 620 | nfs_revalidate_inode(server, inode); |
557 | } | 621 | } |
558 | 622 | ||
559 | static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred) | 623 | struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode) |
560 | { | 624 | { |
561 | struct nfs_open_context *ctx; | 625 | struct nfs_open_context *ctx; |
562 | 626 | ||
@@ -566,11 +630,13 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct | |||
566 | path_get(&ctx->path); | 630 | path_get(&ctx->path); |
567 | ctx->cred = get_rpccred(cred); | 631 | ctx->cred = get_rpccred(cred); |
568 | ctx->state = NULL; | 632 | ctx->state = NULL; |
569 | ctx->lockowner = current->files; | 633 | ctx->mode = f_mode; |
570 | ctx->flags = 0; | 634 | ctx->flags = 0; |
571 | ctx->error = 0; | 635 | ctx->error = 0; |
572 | ctx->dir_cookie = 0; | 636 | ctx->dir_cookie = 0; |
573 | atomic_set(&ctx->count, 1); | 637 | nfs_init_lock_context(&ctx->lock_context); |
638 | ctx->lock_context.open_context = ctx; | ||
639 | INIT_LIST_HEAD(&ctx->list); | ||
574 | } | 640 | } |
575 | return ctx; | 641 | return ctx; |
576 | } | 642 | } |
@@ -578,7 +644,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct | |||
578 | struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) | 644 | struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) |
579 | { | 645 | { |
580 | if (ctx != NULL) | 646 | if (ctx != NULL) |
581 | atomic_inc(&ctx->count); | 647 | atomic_inc(&ctx->lock_context.count); |
582 | return ctx; | 648 | return ctx; |
583 | } | 649 | } |
584 | 650 | ||
@@ -586,11 +652,15 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) | |||
586 | { | 652 | { |
587 | struct inode *inode = ctx->path.dentry->d_inode; | 653 | struct inode *inode = ctx->path.dentry->d_inode; |
588 | 654 | ||
589 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) | 655 | if (!list_empty(&ctx->list)) { |
656 | if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock)) | ||
657 | return; | ||
658 | list_del(&ctx->list); | ||
659 | spin_unlock(&inode->i_lock); | ||
660 | } else if (!atomic_dec_and_test(&ctx->lock_context.count)) | ||
590 | return; | 661 | return; |
591 | list_del(&ctx->list); | 662 | if (inode != NULL) |
592 | spin_unlock(&inode->i_lock); | 663 | NFS_PROTO(inode)->close_context(ctx, is_sync); |
593 | NFS_PROTO(inode)->close_context(ctx, is_sync); | ||
594 | if (ctx->cred != NULL) | 664 | if (ctx->cred != NULL) |
595 | put_rpccred(ctx->cred); | 665 | put_rpccred(ctx->cred); |
596 | path_put(&ctx->path); | 666 | path_put(&ctx->path); |
@@ -606,7 +676,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx) | |||
606 | * Ensure that mmap has a recent RPC credential for use when writing out | 676 | * Ensure that mmap has a recent RPC credential for use when writing out |
607 | * shared pages | 677 | * shared pages |
608 | */ | 678 | */ |
609 | static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) | 679 | void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) |
610 | { | 680 | { |
611 | struct inode *inode = filp->f_path.dentry->d_inode; | 681 | struct inode *inode = filp->f_path.dentry->d_inode; |
612 | struct nfs_inode *nfsi = NFS_I(inode); | 682 | struct nfs_inode *nfsi = NFS_I(inode); |
@@ -663,11 +733,10 @@ int nfs_open(struct inode *inode, struct file *filp) | |||
663 | cred = rpc_lookup_cred(); | 733 | cred = rpc_lookup_cred(); |
664 | if (IS_ERR(cred)) | 734 | if (IS_ERR(cred)) |
665 | return PTR_ERR(cred); | 735 | return PTR_ERR(cred); |
666 | ctx = alloc_nfs_open_context(&filp->f_path, cred); | 736 | ctx = alloc_nfs_open_context(&filp->f_path, cred, filp->f_mode); |
667 | put_rpccred(cred); | 737 | put_rpccred(cred); |
668 | if (ctx == NULL) | 738 | if (ctx == NULL) |
669 | return -ENOMEM; | 739 | return -ENOMEM; |
670 | ctx->mode = filp->f_mode; | ||
671 | nfs_file_set_open_context(filp, ctx); | 740 | nfs_file_set_open_context(filp, ctx); |
672 | put_nfs_open_context(ctx); | 741 | put_nfs_open_context(ctx); |
673 | nfs_fscache_set_inode_cookie(inode, filp); | 742 | nfs_fscache_set_inode_cookie(inode, filp); |
@@ -1338,8 +1407,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1338 | * to open() calls that passed nfs_atomic_lookup, but failed to call | 1407 | * to open() calls that passed nfs_atomic_lookup, but failed to call |
1339 | * nfs_open(). | 1408 | * nfs_open(). |
1340 | */ | 1409 | */ |
1341 | void nfs4_clear_inode(struct inode *inode) | 1410 | void nfs4_evict_inode(struct inode *inode) |
1342 | { | 1411 | { |
1412 | truncate_inode_pages(&inode->i_data, 0); | ||
1413 | end_writeback(inode); | ||
1414 | pnfs_destroy_layout(NFS_I(inode)); | ||
1343 | /* If we are holding a delegation, return it! */ | 1415 | /* If we are holding a delegation, return it! */ |
1344 | nfs_inode_return_delegation_noreclaim(inode); | 1416 | nfs_inode_return_delegation_noreclaim(inode); |
1345 | /* First call standard NFS clear_inode() code */ | 1417 | /* First call standard NFS clear_inode() code */ |
@@ -1377,6 +1449,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi) | |||
1377 | nfsi->delegation = NULL; | 1449 | nfsi->delegation = NULL; |
1378 | nfsi->delegation_state = 0; | 1450 | nfsi->delegation_state = 0; |
1379 | init_rwsem(&nfsi->rwsem); | 1451 | init_rwsem(&nfsi->rwsem); |
1452 | nfsi->layout = NULL; | ||
1380 | #endif | 1453 | #endif |
1381 | } | 1454 | } |
1382 | 1455 | ||
@@ -1424,7 +1497,7 @@ static int nfsiod_start(void) | |||
1424 | { | 1497 | { |
1425 | struct workqueue_struct *wq; | 1498 | struct workqueue_struct *wq; |
1426 | dprintk("RPC: creating workqueue nfsiod\n"); | 1499 | dprintk("RPC: creating workqueue nfsiod\n"); |
1427 | wq = create_singlethread_workqueue("nfsiod"); | 1500 | wq = alloc_workqueue("nfsiod", WQ_RESCUER, 0); |
1428 | if (wq == NULL) | 1501 | if (wq == NULL) |
1429 | return -ENOMEM; | 1502 | return -ENOMEM; |
1430 | nfsiod_workqueue = wq; | 1503 | nfsiod_workqueue = wq; |
@@ -1452,6 +1525,10 @@ static int __init init_nfs_fs(void) | |||
1452 | { | 1525 | { |
1453 | int err; | 1526 | int err; |
1454 | 1527 | ||
1528 | err = nfs_idmap_init(); | ||
1529 | if (err < 0) | ||
1530 | goto out9; | ||
1531 | |||
1455 | err = nfs_dns_resolver_init(); | 1532 | err = nfs_dns_resolver_init(); |
1456 | if (err < 0) | 1533 | if (err < 0) |
1457 | goto out8; | 1534 | goto out8; |
@@ -1516,6 +1593,8 @@ out6: | |||
1516 | out7: | 1593 | out7: |
1517 | nfs_dns_resolver_destroy(); | 1594 | nfs_dns_resolver_destroy(); |
1518 | out8: | 1595 | out8: |
1596 | nfs_idmap_quit(); | ||
1597 | out9: | ||
1519 | return err; | 1598 | return err; |
1520 | } | 1599 | } |
1521 | 1600 | ||
@@ -1528,6 +1607,7 @@ static void __exit exit_nfs_fs(void) | |||
1528 | nfs_destroy_nfspagecache(); | 1607 | nfs_destroy_nfspagecache(); |
1529 | nfs_fscache_unregister(); | 1608 | nfs_fscache_unregister(); |
1530 | nfs_dns_resolver_destroy(); | 1609 | nfs_dns_resolver_destroy(); |
1610 | nfs_idmap_quit(); | ||
1531 | #ifdef CONFIG_PROC_FS | 1611 | #ifdef CONFIG_PROC_FS |
1532 | rpc_proc_unregister("nfs"); | 1612 | rpc_proc_unregister("nfs"); |
1533 | #endif | 1613 | #endif |