diff options
author | Andy Adamson <andros@netapp.com> | 2013-09-06 14:14:00 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-09-06 14:49:16 -0400 |
commit | 0e20162ed1e9a639fc61d62c71327169fb1a1970 (patch) | |
tree | 299ac444cffc3087c5221c30bce9fbbf4ba9d133 /fs/nfs | |
parent | 4109bb7496640aa97a12904527ba8e3a19b7ce7a (diff) |
NFSv4.1 Use MDS auth flavor for data server connection
Commit 4edaa308 "NFS: Use "krb5i" to establish NFSv4 state whenever possible"
uses the nfs_client cl_rpcclient for all state management operations, and
will use krb5i or auth_sys with no regard to the mount command authflavor
choice.
The MDS, as any NFSv4.1 mount point, uses the nfs_server rpc client for all
non-state management operations with a different nfs_server for each fsid
encountered traversing the mount point, each with a potentially different
auth flavor.
pNFS data servers are not mounted in the normal sense as there is no associated
nfs_server structure. Data servers can also export multiple fsids, each with
a potentially different auth flavor.
Data servers need to use the same authflavor as the MDS server rpc client for
non-state management operations. Populate a list of rpc clients with the MDS
server rpc client auth flavor for the DS to use.
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/internal.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 116 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 35 |
3 files changed, 145 insertions, 8 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 2415198d29ad..23ec6e8e8a4d 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -186,6 +186,8 @@ extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | |||
186 | int ds_addrlen, int ds_proto, | 186 | int ds_addrlen, int ds_proto, |
187 | unsigned int ds_timeo, | 187 | unsigned int ds_timeo, |
188 | unsigned int ds_retrans); | 188 | unsigned int ds_retrans); |
189 | extern struct rpc_clnt *nfs4_find_or_create_ds_client(struct nfs_client *, | ||
190 | struct inode *); | ||
189 | #ifdef CONFIG_PROC_FS | 191 | #ifdef CONFIG_PROC_FS |
190 | extern int __init nfs_fs_proc_init(void); | 192 | extern int __init nfs_fs_proc_init(void); |
191 | extern void nfs_fs_proc_exit(void); | 193 | extern void nfs_fs_proc_exit(void); |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 98c0104bb0c4..f798925d8291 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -41,9 +41,124 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) | |||
41 | } | 41 | } |
42 | 42 | ||
43 | #ifdef CONFIG_NFS_V4_1 | 43 | #ifdef CONFIG_NFS_V4_1 |
44 | /** | ||
45 | * Per auth flavor data server rpc clients | ||
46 | */ | ||
47 | struct nfs4_ds_server { | ||
48 | struct list_head list; /* ds_clp->cl_ds_clients */ | ||
49 | struct rpc_clnt *rpc_clnt; | ||
50 | }; | ||
51 | |||
52 | /** | ||
53 | * Common lookup case for DS I/O | ||
54 | */ | ||
55 | static struct nfs4_ds_server * | ||
56 | nfs4_find_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor) | ||
57 | { | ||
58 | struct nfs4_ds_server *dss; | ||
59 | |||
60 | rcu_read_lock(); | ||
61 | list_for_each_entry_rcu(dss, &ds_clp->cl_ds_clients, list) { | ||
62 | if (dss->rpc_clnt->cl_auth->au_flavor != flavor) | ||
63 | continue; | ||
64 | goto out; | ||
65 | } | ||
66 | dss = NULL; | ||
67 | out: | ||
68 | rcu_read_unlock(); | ||
69 | return dss; | ||
70 | } | ||
71 | |||
72 | static struct nfs4_ds_server * | ||
73 | nfs4_add_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor, | ||
74 | struct nfs4_ds_server *new) | ||
75 | { | ||
76 | struct nfs4_ds_server *dss; | ||
77 | |||
78 | spin_lock(&ds_clp->cl_lock); | ||
79 | list_for_each_entry(dss, &ds_clp->cl_ds_clients, list) { | ||
80 | if (dss->rpc_clnt->cl_auth->au_flavor != flavor) | ||
81 | continue; | ||
82 | goto out; | ||
83 | } | ||
84 | if (new) | ||
85 | list_add_rcu(&new->list, &ds_clp->cl_ds_clients); | ||
86 | dss = new; | ||
87 | out: | ||
88 | spin_unlock(&ds_clp->cl_lock); /* need some lock to protect list */ | ||
89 | return dss; | ||
90 | } | ||
91 | |||
92 | static struct nfs4_ds_server * | ||
93 | nfs4_alloc_ds_server(struct nfs_client *ds_clp, rpc_authflavor_t flavor) | ||
94 | { | ||
95 | struct nfs4_ds_server *dss; | ||
96 | |||
97 | dss = kmalloc(sizeof(*dss), GFP_NOFS); | ||
98 | if (dss == NULL) | ||
99 | return ERR_PTR(-ENOMEM); | ||
100 | |||
101 | dss->rpc_clnt = rpc_clone_client_set_auth(ds_clp->cl_rpcclient, flavor); | ||
102 | if (IS_ERR(dss->rpc_clnt)) { | ||
103 | int err = PTR_ERR(dss->rpc_clnt); | ||
104 | kfree (dss); | ||
105 | return ERR_PTR(err); | ||
106 | } | ||
107 | INIT_LIST_HEAD(&dss->list); | ||
108 | |||
109 | return dss; | ||
110 | } | ||
111 | |||
112 | static void | ||
113 | nfs4_free_ds_server(struct nfs4_ds_server *dss) | ||
114 | { | ||
115 | rpc_release_client(dss->rpc_clnt); | ||
116 | kfree(dss); | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * Find or create a DS rpc client with th MDS server rpc client auth flavor | ||
121 | * in the nfs_client cl_ds_clients list. | ||
122 | */ | ||
123 | struct rpc_clnt * | ||
124 | nfs4_find_or_create_ds_client(struct nfs_client *ds_clp, struct inode *inode) | ||
125 | { | ||
126 | struct nfs4_ds_server *dss, *new; | ||
127 | rpc_authflavor_t flavor = NFS_SERVER(inode)->client->cl_auth->au_flavor; | ||
128 | |||
129 | dss = nfs4_find_ds_client(ds_clp, flavor); | ||
130 | if (dss != NULL) | ||
131 | goto out; | ||
132 | new = nfs4_alloc_ds_server(ds_clp, flavor); | ||
133 | if (IS_ERR(new)) | ||
134 | return ERR_CAST(new); | ||
135 | dss = nfs4_add_ds_client(ds_clp, flavor, new); | ||
136 | if (dss != new) | ||
137 | nfs4_free_ds_server(new); | ||
138 | out: | ||
139 | return dss->rpc_clnt; | ||
140 | } | ||
141 | EXPORT_SYMBOL_GPL(nfs4_find_or_create_ds_client); | ||
142 | |||
143 | static void | ||
144 | nfs4_shutdown_ds_clients(struct nfs_client *clp) | ||
145 | { | ||
146 | struct nfs4_ds_server *dss; | ||
147 | LIST_HEAD(shutdown_list); | ||
148 | |||
149 | while (!list_empty(&clp->cl_ds_clients)) { | ||
150 | dss = list_entry(clp->cl_ds_clients.next, | ||
151 | struct nfs4_ds_server, list); | ||
152 | list_del(&dss->list); | ||
153 | rpc_shutdown_client(dss->rpc_clnt); | ||
154 | kfree (dss); | ||
155 | } | ||
156 | } | ||
157 | |||
44 | void nfs41_shutdown_client(struct nfs_client *clp) | 158 | void nfs41_shutdown_client(struct nfs_client *clp) |
45 | { | 159 | { |
46 | if (nfs4_has_session(clp)) { | 160 | if (nfs4_has_session(clp)) { |
161 | nfs4_shutdown_ds_clients(clp); | ||
47 | nfs4_destroy_session(clp->cl_session); | 162 | nfs4_destroy_session(clp->cl_session); |
48 | nfs4_destroy_clientid(clp); | 163 | nfs4_destroy_clientid(clp); |
49 | } | 164 | } |
@@ -77,6 +192,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) | |||
77 | 192 | ||
78 | spin_lock_init(&clp->cl_lock); | 193 | spin_lock_init(&clp->cl_lock); |
79 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); | 194 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); |
195 | INIT_LIST_HEAD(&clp->cl_ds_clients); | ||
80 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | 196 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); |
81 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 197 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
82 | clp->cl_minorversion = cl_init->minorversion; | 198 | clp->cl_minorversion = cl_init->minorversion; |
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index a70cb3a0b96e..b86464ba25e1 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -528,6 +528,7 @@ filelayout_read_pagelist(struct nfs_read_data *data) | |||
528 | struct nfs_pgio_header *hdr = data->header; | 528 | struct nfs_pgio_header *hdr = data->header; |
529 | struct pnfs_layout_segment *lseg = hdr->lseg; | 529 | struct pnfs_layout_segment *lseg = hdr->lseg; |
530 | struct nfs4_pnfs_ds *ds; | 530 | struct nfs4_pnfs_ds *ds; |
531 | struct rpc_clnt *ds_clnt; | ||
531 | loff_t offset = data->args.offset; | 532 | loff_t offset = data->args.offset; |
532 | u32 j, idx; | 533 | u32 j, idx; |
533 | struct nfs_fh *fh; | 534 | struct nfs_fh *fh; |
@@ -542,6 +543,11 @@ filelayout_read_pagelist(struct nfs_read_data *data) | |||
542 | ds = nfs4_fl_prepare_ds(lseg, idx); | 543 | ds = nfs4_fl_prepare_ds(lseg, idx); |
543 | if (!ds) | 544 | if (!ds) |
544 | return PNFS_NOT_ATTEMPTED; | 545 | return PNFS_NOT_ATTEMPTED; |
546 | |||
547 | ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, hdr->inode); | ||
548 | if (IS_ERR(ds_clnt)) | ||
549 | return PNFS_NOT_ATTEMPTED; | ||
550 | |||
545 | dprintk("%s USE DS: %s cl_count %d\n", __func__, | 551 | dprintk("%s USE DS: %s cl_count %d\n", __func__, |
546 | ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count)); | 552 | ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count)); |
547 | 553 | ||
@@ -556,7 +562,7 @@ filelayout_read_pagelist(struct nfs_read_data *data) | |||
556 | data->mds_offset = offset; | 562 | data->mds_offset = offset; |
557 | 563 | ||
558 | /* Perform an asynchronous read to ds */ | 564 | /* Perform an asynchronous read to ds */ |
559 | nfs_initiate_read(ds->ds_clp->cl_rpcclient, data, | 565 | nfs_initiate_read(ds_clnt, data, |
560 | &filelayout_read_call_ops, RPC_TASK_SOFTCONN); | 566 | &filelayout_read_call_ops, RPC_TASK_SOFTCONN); |
561 | return PNFS_ATTEMPTED; | 567 | return PNFS_ATTEMPTED; |
562 | } | 568 | } |
@@ -568,6 +574,7 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) | |||
568 | struct nfs_pgio_header *hdr = data->header; | 574 | struct nfs_pgio_header *hdr = data->header; |
569 | struct pnfs_layout_segment *lseg = hdr->lseg; | 575 | struct pnfs_layout_segment *lseg = hdr->lseg; |
570 | struct nfs4_pnfs_ds *ds; | 576 | struct nfs4_pnfs_ds *ds; |
577 | struct rpc_clnt *ds_clnt; | ||
571 | loff_t offset = data->args.offset; | 578 | loff_t offset = data->args.offset; |
572 | u32 j, idx; | 579 | u32 j, idx; |
573 | struct nfs_fh *fh; | 580 | struct nfs_fh *fh; |
@@ -578,6 +585,11 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) | |||
578 | ds = nfs4_fl_prepare_ds(lseg, idx); | 585 | ds = nfs4_fl_prepare_ds(lseg, idx); |
579 | if (!ds) | 586 | if (!ds) |
580 | return PNFS_NOT_ATTEMPTED; | 587 | return PNFS_NOT_ATTEMPTED; |
588 | |||
589 | ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, hdr->inode); | ||
590 | if (IS_ERR(ds_clnt)) | ||
591 | return PNFS_NOT_ATTEMPTED; | ||
592 | |||
581 | dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s cl_count %d\n", | 593 | dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s cl_count %d\n", |
582 | __func__, hdr->inode->i_ino, sync, (size_t) data->args.count, | 594 | __func__, hdr->inode->i_ino, sync, (size_t) data->args.count, |
583 | offset, ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count)); | 595 | offset, ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count)); |
@@ -595,7 +607,7 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) | |||
595 | data->args.offset = filelayout_get_dserver_offset(lseg, offset); | 607 | data->args.offset = filelayout_get_dserver_offset(lseg, offset); |
596 | 608 | ||
597 | /* Perform an asynchronous write */ | 609 | /* Perform an asynchronous write */ |
598 | nfs_initiate_write(ds->ds_clp->cl_rpcclient, data, | 610 | nfs_initiate_write(ds_clnt, data, |
599 | &filelayout_write_call_ops, sync, | 611 | &filelayout_write_call_ops, sync, |
600 | RPC_TASK_SOFTCONN); | 612 | RPC_TASK_SOFTCONN); |
601 | return PNFS_ATTEMPTED; | 613 | return PNFS_ATTEMPTED; |
@@ -1105,16 +1117,19 @@ static int filelayout_initiate_commit(struct nfs_commit_data *data, int how) | |||
1105 | { | 1117 | { |
1106 | struct pnfs_layout_segment *lseg = data->lseg; | 1118 | struct pnfs_layout_segment *lseg = data->lseg; |
1107 | struct nfs4_pnfs_ds *ds; | 1119 | struct nfs4_pnfs_ds *ds; |
1120 | struct rpc_clnt *ds_clnt; | ||
1108 | u32 idx; | 1121 | u32 idx; |
1109 | struct nfs_fh *fh; | 1122 | struct nfs_fh *fh; |
1110 | 1123 | ||
1111 | idx = calc_ds_index_from_commit(lseg, data->ds_commit_index); | 1124 | idx = calc_ds_index_from_commit(lseg, data->ds_commit_index); |
1112 | ds = nfs4_fl_prepare_ds(lseg, idx); | 1125 | ds = nfs4_fl_prepare_ds(lseg, idx); |
1113 | if (!ds) { | 1126 | if (!ds) |
1114 | prepare_to_resend_writes(data); | 1127 | goto out_err; |
1115 | filelayout_commit_release(data); | 1128 | |
1116 | return -EAGAIN; | 1129 | ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, data->inode); |
1117 | } | 1130 | if (IS_ERR(ds_clnt)) |
1131 | goto out_err; | ||
1132 | |||
1118 | dprintk("%s ino %lu, how %d cl_count %d\n", __func__, | 1133 | dprintk("%s ino %lu, how %d cl_count %d\n", __func__, |
1119 | data->inode->i_ino, how, atomic_read(&ds->ds_clp->cl_count)); | 1134 | data->inode->i_ino, how, atomic_read(&ds->ds_clp->cl_count)); |
1120 | data->commit_done_cb = filelayout_commit_done_cb; | 1135 | data->commit_done_cb = filelayout_commit_done_cb; |
@@ -1123,9 +1138,13 @@ static int filelayout_initiate_commit(struct nfs_commit_data *data, int how) | |||
1123 | fh = select_ds_fh_from_commit(lseg, data->ds_commit_index); | 1138 | fh = select_ds_fh_from_commit(lseg, data->ds_commit_index); |
1124 | if (fh) | 1139 | if (fh) |
1125 | data->args.fh = fh; | 1140 | data->args.fh = fh; |
1126 | return nfs_initiate_commit(ds->ds_clp->cl_rpcclient, data, | 1141 | return nfs_initiate_commit(ds_clnt, data, |
1127 | &filelayout_commit_call_ops, how, | 1142 | &filelayout_commit_call_ops, how, |
1128 | RPC_TASK_SOFTCONN); | 1143 | RPC_TASK_SOFTCONN); |
1144 | out_err: | ||
1145 | prepare_to_resend_writes(data); | ||
1146 | filelayout_commit_release(data); | ||
1147 | return -EAGAIN; | ||
1129 | } | 1148 | } |
1130 | 1149 | ||
1131 | static int | 1150 | static int |