diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 177 |
1 files changed, 93 insertions, 84 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index dcda0ba7af60..f0c849c98fe4 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/namei.h> | 52 | #include <linux/namei.h> |
53 | #include <linux/mount.h> | 53 | #include <linux/mount.h> |
54 | #include <linux/module.h> | 54 | #include <linux/module.h> |
55 | #include <linux/nfs_idmap.h> | ||
55 | #include <linux/sunrpc/bc_xprt.h> | 56 | #include <linux/sunrpc/bc_xprt.h> |
56 | #include <linux/xattr.h> | 57 | #include <linux/xattr.h> |
57 | #include <linux/utsname.h> | 58 | #include <linux/utsname.h> |
@@ -364,9 +365,8 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
364 | * Must be called while holding tbl->slot_tbl_lock | 365 | * Must be called while holding tbl->slot_tbl_lock |
365 | */ | 366 | */ |
366 | static void | 367 | static void |
367 | nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot) | 368 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) |
368 | { | 369 | { |
369 | int free_slotid = free_slot - tbl->slots; | ||
370 | int slotid = free_slotid; | 370 | int slotid = free_slotid; |
371 | 371 | ||
372 | BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE); | 372 | BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE); |
@@ -431,7 +431,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | |||
431 | } | 431 | } |
432 | 432 | ||
433 | spin_lock(&tbl->slot_tbl_lock); | 433 | spin_lock(&tbl->slot_tbl_lock); |
434 | nfs4_free_slot(tbl, res->sr_slot); | 434 | nfs4_free_slot(tbl, res->sr_slot - tbl->slots); |
435 | nfs4_check_drain_fc_complete(res->sr_session); | 435 | nfs4_check_drain_fc_complete(res->sr_session); |
436 | spin_unlock(&tbl->slot_tbl_lock); | 436 | spin_unlock(&tbl->slot_tbl_lock); |
437 | res->sr_slot = NULL; | 437 | res->sr_slot = NULL; |
@@ -554,13 +554,10 @@ int nfs41_setup_sequence(struct nfs4_session *session, | |||
554 | spin_lock(&tbl->slot_tbl_lock); | 554 | spin_lock(&tbl->slot_tbl_lock); |
555 | if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && | 555 | if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && |
556 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { | 556 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
557 | /* | 557 | /* The state manager will wait until the slot table is empty */ |
558 | * The state manager will wait until the slot table is empty. | ||
559 | * Schedule the reset thread | ||
560 | */ | ||
561 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | 558 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); |
562 | spin_unlock(&tbl->slot_tbl_lock); | 559 | spin_unlock(&tbl->slot_tbl_lock); |
563 | dprintk("%s Schedule Session Reset\n", __func__); | 560 | dprintk("%s session is draining\n", __func__); |
564 | return -EAGAIN; | 561 | return -EAGAIN; |
565 | } | 562 | } |
566 | 563 | ||
@@ -765,6 +762,8 @@ struct nfs4_opendata { | |||
765 | struct nfs_openres o_res; | 762 | struct nfs_openres o_res; |
766 | struct nfs_open_confirmargs c_arg; | 763 | struct nfs_open_confirmargs c_arg; |
767 | struct nfs_open_confirmres c_res; | 764 | struct nfs_open_confirmres c_res; |
765 | struct nfs4_string owner_name; | ||
766 | struct nfs4_string group_name; | ||
768 | struct nfs_fattr f_attr; | 767 | struct nfs_fattr f_attr; |
769 | struct nfs_fattr dir_attr; | 768 | struct nfs_fattr dir_attr; |
770 | struct dentry *dir; | 769 | struct dentry *dir; |
@@ -788,6 +787,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
788 | p->o_res.server = p->o_arg.server; | 787 | p->o_res.server = p->o_arg.server; |
789 | nfs_fattr_init(&p->f_attr); | 788 | nfs_fattr_init(&p->f_attr); |
790 | nfs_fattr_init(&p->dir_attr); | 789 | nfs_fattr_init(&p->dir_attr); |
790 | nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name); | ||
791 | } | 791 | } |
792 | 792 | ||
793 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | 793 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, |
@@ -819,6 +819,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
819 | p->o_arg.name = &dentry->d_name; | 819 | p->o_arg.name = &dentry->d_name; |
820 | p->o_arg.server = server; | 820 | p->o_arg.server = server; |
821 | p->o_arg.bitmask = server->attr_bitmask; | 821 | p->o_arg.bitmask = server->attr_bitmask; |
822 | p->o_arg.dir_bitmask = server->cache_consistency_bitmask; | ||
822 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 823 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
823 | if (flags & O_CREAT) { | 824 | if (flags & O_CREAT) { |
824 | u32 *s; | 825 | u32 *s; |
@@ -855,6 +856,7 @@ static void nfs4_opendata_free(struct kref *kref) | |||
855 | dput(p->dir); | 856 | dput(p->dir); |
856 | dput(p->dentry); | 857 | dput(p->dentry); |
857 | nfs_sb_deactive(sb); | 858 | nfs_sb_deactive(sb); |
859 | nfs_fattr_free_names(&p->f_attr); | ||
858 | kfree(p); | 860 | kfree(p); |
859 | } | 861 | } |
860 | 862 | ||
@@ -1579,6 +1581,8 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data) | |||
1579 | if (status != 0 || !data->rpc_done) | 1581 | if (status != 0 || !data->rpc_done) |
1580 | return status; | 1582 | return status; |
1581 | 1583 | ||
1584 | nfs_fattr_map_and_free_names(NFS_SERVER(dir), &data->f_attr); | ||
1585 | |||
1582 | nfs_refresh_inode(dir, o_res->dir_attr); | 1586 | nfs_refresh_inode(dir, o_res->dir_attr); |
1583 | 1587 | ||
1584 | if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 1588 | if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
@@ -1611,6 +1615,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1611 | return status; | 1615 | return status; |
1612 | } | 1616 | } |
1613 | 1617 | ||
1618 | nfs_fattr_map_and_free_names(server, &data->f_attr); | ||
1619 | |||
1614 | if (o_arg->open_flags & O_CREAT) { | 1620 | if (o_arg->open_flags & O_CREAT) { |
1615 | update_changeattr(dir, &o_res->cinfo); | 1621 | update_changeattr(dir, &o_res->cinfo); |
1616 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 1622 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
@@ -3431,19 +3437,6 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server) | |||
3431 | */ | 3437 | */ |
3432 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) | 3438 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) |
3433 | 3439 | ||
3434 | static void buf_to_pages(const void *buf, size_t buflen, | ||
3435 | struct page **pages, unsigned int *pgbase) | ||
3436 | { | ||
3437 | const void *p = buf; | ||
3438 | |||
3439 | *pgbase = offset_in_page(buf); | ||
3440 | p -= *pgbase; | ||
3441 | while (p < buf + buflen) { | ||
3442 | *(pages++) = virt_to_page(p); | ||
3443 | p += PAGE_CACHE_SIZE; | ||
3444 | } | ||
3445 | } | ||
3446 | |||
3447 | static int buf_to_pages_noslab(const void *buf, size_t buflen, | 3440 | static int buf_to_pages_noslab(const void *buf, size_t buflen, |
3448 | struct page **pages, unsigned int *pgbase) | 3441 | struct page **pages, unsigned int *pgbase) |
3449 | { | 3442 | { |
@@ -3540,9 +3533,19 @@ out: | |||
3540 | nfs4_set_cached_acl(inode, acl); | 3533 | nfs4_set_cached_acl(inode, acl); |
3541 | } | 3534 | } |
3542 | 3535 | ||
3536 | /* | ||
3537 | * The getxattr API returns the required buffer length when called with a | ||
3538 | * NULL buf. The NFSv4 acl tool then calls getxattr again after allocating | ||
3539 | * the required buf. On a NULL buf, we send a page of data to the server | ||
3540 | * guessing that the ACL request can be serviced by a page. If so, we cache | ||
3541 | * up to the page of ACL data, and the 2nd call to getxattr is serviced by | ||
3542 | * the cache. If not so, we throw away the page, and cache the required | ||
3543 | * length. The next getxattr call will then produce another round trip to | ||
3544 | * the server, this time with the input buf of the required size. | ||
3545 | */ | ||
3543 | static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | 3546 | static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) |
3544 | { | 3547 | { |
3545 | struct page *pages[NFS4ACL_MAXPAGES]; | 3548 | struct page *pages[NFS4ACL_MAXPAGES] = {NULL, }; |
3546 | struct nfs_getaclargs args = { | 3549 | struct nfs_getaclargs args = { |
3547 | .fh = NFS_FH(inode), | 3550 | .fh = NFS_FH(inode), |
3548 | .acl_pages = pages, | 3551 | .acl_pages = pages, |
@@ -3557,41 +3560,60 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3557 | .rpc_argp = &args, | 3560 | .rpc_argp = &args, |
3558 | .rpc_resp = &res, | 3561 | .rpc_resp = &res, |
3559 | }; | 3562 | }; |
3560 | struct page *localpage = NULL; | 3563 | int ret = -ENOMEM, npages, i, acl_len = 0; |
3561 | int ret; | ||
3562 | 3564 | ||
3563 | if (buflen < PAGE_SIZE) { | 3565 | npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; |
3564 | /* As long as we're doing a round trip to the server anyway, | 3566 | /* As long as we're doing a round trip to the server anyway, |
3565 | * let's be prepared for a page of acl data. */ | 3567 | * let's be prepared for a page of acl data. */ |
3566 | localpage = alloc_page(GFP_KERNEL); | 3568 | if (npages == 0) |
3567 | resp_buf = page_address(localpage); | 3569 | npages = 1; |
3568 | if (localpage == NULL) | 3570 | |
3569 | return -ENOMEM; | 3571 | for (i = 0; i < npages; i++) { |
3570 | args.acl_pages[0] = localpage; | 3572 | pages[i] = alloc_page(GFP_KERNEL); |
3571 | args.acl_pgbase = 0; | 3573 | if (!pages[i]) |
3572 | args.acl_len = PAGE_SIZE; | 3574 | goto out_free; |
3573 | } else { | ||
3574 | resp_buf = buf; | ||
3575 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | ||
3576 | } | 3575 | } |
3577 | ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0); | 3576 | if (npages > 1) { |
3577 | /* for decoding across pages */ | ||
3578 | args.acl_scratch = alloc_page(GFP_KERNEL); | ||
3579 | if (!args.acl_scratch) | ||
3580 | goto out_free; | ||
3581 | } | ||
3582 | args.acl_len = npages * PAGE_SIZE; | ||
3583 | args.acl_pgbase = 0; | ||
3584 | /* Let decode_getfacl know not to fail if the ACL data is larger than | ||
3585 | * the page we send as a guess */ | ||
3586 | if (buf == NULL) | ||
3587 | res.acl_flags |= NFS4_ACL_LEN_REQUEST; | ||
3588 | resp_buf = page_address(pages[0]); | ||
3589 | |||
3590 | dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", | ||
3591 | __func__, buf, buflen, npages, args.acl_len); | ||
3592 | ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), | ||
3593 | &msg, &args.seq_args, &res.seq_res, 0); | ||
3578 | if (ret) | 3594 | if (ret) |
3579 | goto out_free; | 3595 | goto out_free; |
3580 | if (res.acl_len > args.acl_len) | 3596 | |
3581 | nfs4_write_cached_acl(inode, NULL, res.acl_len); | 3597 | acl_len = res.acl_len - res.acl_data_offset; |
3598 | if (acl_len > args.acl_len) | ||
3599 | nfs4_write_cached_acl(inode, NULL, acl_len); | ||
3582 | else | 3600 | else |
3583 | nfs4_write_cached_acl(inode, resp_buf, res.acl_len); | 3601 | nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset, |
3602 | acl_len); | ||
3584 | if (buf) { | 3603 | if (buf) { |
3585 | ret = -ERANGE; | 3604 | ret = -ERANGE; |
3586 | if (res.acl_len > buflen) | 3605 | if (acl_len > buflen) |
3587 | goto out_free; | 3606 | goto out_free; |
3588 | if (localpage) | 3607 | _copy_from_pages(buf, pages, res.acl_data_offset, |
3589 | memcpy(buf, resp_buf, res.acl_len); | 3608 | res.acl_len); |
3590 | } | 3609 | } |
3591 | ret = res.acl_len; | 3610 | ret = acl_len; |
3592 | out_free: | 3611 | out_free: |
3593 | if (localpage) | 3612 | for (i = 0; i < npages; i++) |
3594 | __free_page(localpage); | 3613 | if (pages[i]) |
3614 | __free_page(pages[i]); | ||
3615 | if (args.acl_scratch) | ||
3616 | __free_page(args.acl_scratch); | ||
3595 | return ret; | 3617 | return ret; |
3596 | } | 3618 | } |
3597 | 3619 | ||
@@ -3622,6 +3644,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | |||
3622 | nfs_zap_acl_cache(inode); | 3644 | nfs_zap_acl_cache(inode); |
3623 | ret = nfs4_read_cached_acl(inode, buf, buflen); | 3645 | ret = nfs4_read_cached_acl(inode, buf, buflen); |
3624 | if (ret != -ENOENT) | 3646 | if (ret != -ENOENT) |
3647 | /* -ENOENT is returned if there is no ACL or if there is an ACL | ||
3648 | * but no cached acl data, just the acl length */ | ||
3625 | return ret; | 3649 | return ret; |
3626 | return nfs4_get_acl_uncached(inode, buf, buflen); | 3650 | return nfs4_get_acl_uncached(inode, buf, buflen); |
3627 | } | 3651 | } |
@@ -5022,23 +5046,6 @@ out: | |||
5022 | return ret; | 5046 | return ret; |
5023 | } | 5047 | } |
5024 | 5048 | ||
5025 | /* | ||
5026 | * Reset the forechannel and backchannel slot tables | ||
5027 | */ | ||
5028 | static int nfs4_reset_slot_tables(struct nfs4_session *session) | ||
5029 | { | ||
5030 | int status; | ||
5031 | |||
5032 | status = nfs4_reset_slot_table(&session->fc_slot_table, | ||
5033 | session->fc_attrs.max_reqs, 1); | ||
5034 | if (status) | ||
5035 | return status; | ||
5036 | |||
5037 | status = nfs4_reset_slot_table(&session->bc_slot_table, | ||
5038 | session->bc_attrs.max_reqs, 0); | ||
5039 | return status; | ||
5040 | } | ||
5041 | |||
5042 | /* Destroy the slot table */ | 5049 | /* Destroy the slot table */ |
5043 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | 5050 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) |
5044 | { | 5051 | { |
@@ -5084,29 +5091,35 @@ out: | |||
5084 | } | 5091 | } |
5085 | 5092 | ||
5086 | /* | 5093 | /* |
5087 | * Initialize the forechannel and backchannel tables | 5094 | * Initialize or reset the forechannel and backchannel tables |
5088 | */ | 5095 | */ |
5089 | static int nfs4_init_slot_tables(struct nfs4_session *session) | 5096 | static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) |
5090 | { | 5097 | { |
5091 | struct nfs4_slot_table *tbl; | 5098 | struct nfs4_slot_table *tbl; |
5092 | int status = 0; | 5099 | int status; |
5093 | 5100 | ||
5094 | tbl = &session->fc_slot_table; | 5101 | dprintk("--> %s\n", __func__); |
5102 | /* Fore channel */ | ||
5103 | tbl = &ses->fc_slot_table; | ||
5095 | if (tbl->slots == NULL) { | 5104 | if (tbl->slots == NULL) { |
5096 | status = nfs4_init_slot_table(tbl, | 5105 | status = nfs4_init_slot_table(tbl, ses->fc_attrs.max_reqs, 1); |
5097 | session->fc_attrs.max_reqs, 1); | 5106 | if (status) /* -ENOMEM */ |
5107 | return status; | ||
5108 | } else { | ||
5109 | status = nfs4_reset_slot_table(tbl, ses->fc_attrs.max_reqs, 1); | ||
5098 | if (status) | 5110 | if (status) |
5099 | return status; | 5111 | return status; |
5100 | } | 5112 | } |
5101 | 5113 | /* Back channel */ | |
5102 | tbl = &session->bc_slot_table; | 5114 | tbl = &ses->bc_slot_table; |
5103 | if (tbl->slots == NULL) { | 5115 | if (tbl->slots == NULL) { |
5104 | status = nfs4_init_slot_table(tbl, | 5116 | status = nfs4_init_slot_table(tbl, ses->bc_attrs.max_reqs, 0); |
5105 | session->bc_attrs.max_reqs, 0); | ||
5106 | if (status) | 5117 | if (status) |
5107 | nfs4_destroy_slot_tables(session); | 5118 | /* Fore and back channel share a connection so get |
5108 | } | 5119 | * both slot tables or neither */ |
5109 | 5120 | nfs4_destroy_slot_tables(ses); | |
5121 | } else | ||
5122 | status = nfs4_reset_slot_table(tbl, ses->bc_attrs.max_reqs, 0); | ||
5110 | return status; | 5123 | return status; |
5111 | } | 5124 | } |
5112 | 5125 | ||
@@ -5294,13 +5307,9 @@ int nfs4_proc_create_session(struct nfs_client *clp) | |||
5294 | if (status) | 5307 | if (status) |
5295 | goto out; | 5308 | goto out; |
5296 | 5309 | ||
5297 | /* Init and reset the fore channel */ | 5310 | /* Init or reset the session slot tables */ |
5298 | status = nfs4_init_slot_tables(session); | 5311 | status = nfs4_setup_session_slot_tables(session); |
5299 | dprintk("slot table initialization returned %d\n", status); | 5312 | dprintk("slot table setup returned %d\n", status); |
5300 | if (status) | ||
5301 | goto out; | ||
5302 | status = nfs4_reset_slot_tables(session); | ||
5303 | dprintk("slot table reset returned %d\n", status); | ||
5304 | if (status) | 5313 | if (status) |
5305 | goto out; | 5314 | goto out; |
5306 | 5315 | ||