aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/callback_proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/callback_proc.c')
-rw-r--r--fs/nfs/callback_proc.c99
1 files changed, 46 insertions, 53 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 54cea8ad5a7..1b5d809a105 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -8,6 +8,7 @@
8#include <linux/nfs4.h> 8#include <linux/nfs4.h>
9#include <linux/nfs_fs.h> 9#include <linux/nfs_fs.h>
10#include <linux/slab.h> 10#include <linux/slab.h>
11#include <linux/rcupdate.h>
11#include "nfs4_fs.h" 12#include "nfs4_fs.h"
12#include "callback.h" 13#include "callback.h"
13#include "delegation.h" 14#include "delegation.h"
@@ -33,7 +34,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
33 res->bitmap[0] = res->bitmap[1] = 0; 34 res->bitmap[0] = res->bitmap[1] = 0;
34 res->status = htonl(NFS4ERR_BADHANDLE); 35 res->status = htonl(NFS4ERR_BADHANDLE);
35 36
36 dprintk("NFS: GETATTR callback request from %s\n", 37 dprintk_rcu("NFS: GETATTR callback request from %s\n",
37 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); 38 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
38 39
39 inode = nfs_delegation_find_inode(cps->clp, &args->fh); 40 inode = nfs_delegation_find_inode(cps->clp, &args->fh);
@@ -73,7 +74,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
73 if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */ 74 if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
74 goto out; 75 goto out;
75 76
76 dprintk("NFS: RECALL callback request from %s\n", 77 dprintk_rcu("NFS: RECALL callback request from %s\n",
77 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); 78 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
78 79
79 res = htonl(NFS4ERR_BADHANDLE); 80 res = htonl(NFS4ERR_BADHANDLE);
@@ -86,8 +87,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
86 res = 0; 87 res = 0;
87 break; 88 break;
88 case -ENOENT: 89 case -ENOENT:
89 if (res != 0) 90 res = htonl(NFS4ERR_BAD_STATEID);
90 res = htonl(NFS4ERR_BAD_STATEID);
91 break; 91 break;
92 default: 92 default:
93 res = htonl(NFS4ERR_RESOURCE); 93 res = htonl(NFS4ERR_RESOURCE);
@@ -98,52 +98,64 @@ out:
98 return res; 98 return res;
99} 99}
100 100
101int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
102{
103 if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
104 sizeof(delegation->stateid.data)) != 0)
105 return 0;
106 return 1;
107}
108
109#if defined(CONFIG_NFS_V4_1) 101#if defined(CONFIG_NFS_V4_1)
110 102
111static u32 initiate_file_draining(struct nfs_client *clp, 103/*
112 struct cb_layoutrecallargs *args) 104 * Lookup a layout by filehandle.
105 *
106 * Note: gets a refcount on the layout hdr and on its respective inode.
107 * Caller must put the layout hdr and the inode.
108 *
109 * TODO: keep track of all layouts (and delegations) in a hash table
110 * hashed by filehandle.
111 */
112static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh)
113{ 113{
114 struct nfs_server *server; 114 struct nfs_server *server;
115 struct pnfs_layout_hdr *lo;
116 struct inode *ino; 115 struct inode *ino;
117 bool found = false; 116 struct pnfs_layout_hdr *lo;
118 u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
119 LIST_HEAD(free_me_list);
120 117
121 spin_lock(&clp->cl_lock);
122 rcu_read_lock();
123 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { 118 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
124 list_for_each_entry(lo, &server->layouts, plh_layouts) { 119 list_for_each_entry(lo, &server->layouts, plh_layouts) {
125 if (nfs_compare_fh(&args->cbl_fh, 120 if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh))
126 &NFS_I(lo->plh_inode)->fh))
127 continue; 121 continue;
128 ino = igrab(lo->plh_inode); 122 ino = igrab(lo->plh_inode);
129 if (!ino) 123 if (!ino)
130 continue; 124 continue;
131 found = true;
132 /* Without this, layout can be freed as soon
133 * as we release cl_lock.
134 */
135 get_layout_hdr(lo); 125 get_layout_hdr(lo);
136 break; 126 return lo;
137 } 127 }
138 if (found)
139 break;
140 } 128 }
129
130 return NULL;
131}
132
133static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh)
134{
135 struct pnfs_layout_hdr *lo;
136
137 spin_lock(&clp->cl_lock);
138 rcu_read_lock();
139 lo = get_layout_by_fh_locked(clp, fh);
141 rcu_read_unlock(); 140 rcu_read_unlock();
142 spin_unlock(&clp->cl_lock); 141 spin_unlock(&clp->cl_lock);
143 142
144 if (!found) 143 return lo;
144}
145
146static u32 initiate_file_draining(struct nfs_client *clp,
147 struct cb_layoutrecallargs *args)
148{
149 struct inode *ino;
150 struct pnfs_layout_hdr *lo;
151 u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
152 LIST_HEAD(free_me_list);
153
154 lo = get_layout_by_fh(clp, &args->cbl_fh);
155 if (!lo)
145 return NFS4ERR_NOMATCHING_LAYOUT; 156 return NFS4ERR_NOMATCHING_LAYOUT;
146 157
158 ino = lo->plh_inode;
147 spin_lock(&ino->i_lock); 159 spin_lock(&ino->i_lock);
148 if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || 160 if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
149 mark_matching_lsegs_invalid(lo, &free_me_list, 161 mark_matching_lsegs_invalid(lo, &free_me_list,
@@ -213,17 +225,13 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
213static u32 do_callback_layoutrecall(struct nfs_client *clp, 225static u32 do_callback_layoutrecall(struct nfs_client *clp,
214 struct cb_layoutrecallargs *args) 226 struct cb_layoutrecallargs *args)
215{ 227{
216 u32 res = NFS4ERR_DELAY; 228 u32 res;
217 229
218 dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type); 230 dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type);
219 if (test_and_set_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state))
220 goto out;
221 if (args->cbl_recall_type == RETURN_FILE) 231 if (args->cbl_recall_type == RETURN_FILE)
222 res = initiate_file_draining(clp, args); 232 res = initiate_file_draining(clp, args);
223 else 233 else
224 res = initiate_bulk_draining(clp, args); 234 res = initiate_bulk_draining(clp, args);
225 clear_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state);
226out:
227 dprintk("%s returning %i\n", __func__, res); 235 dprintk("%s returning %i\n", __func__, res);
228 return res; 236 return res;
229 237
@@ -303,21 +311,6 @@ out:
303 return res; 311 return res;
304} 312}
305 313
306int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
307{
308 if (delegation == NULL)
309 return 0;
310
311 if (stateid->stateid.seqid != 0)
312 return 0;
313 if (memcmp(&delegation->stateid.stateid.other,
314 &stateid->stateid.other,
315 NFS4_STATEID_OTHER_SIZE))
316 return 0;
317
318 return 1;
319}
320
321/* 314/*
322 * Validate the sequenceID sent by the server. 315 * Validate the sequenceID sent by the server.
323 * Return success if the sequenceID is one more than what we last saw on 316 * Return success if the sequenceID is one more than what we last saw on
@@ -441,7 +434,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
441 int i; 434 int i;
442 __be32 status = htonl(NFS4ERR_BADSESSION); 435 __be32 status = htonl(NFS4ERR_BADSESSION);
443 436
444 clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid); 437 clp = nfs4_find_client_sessionid(cps->net, args->csa_addr, &args->csa_sessionid);
445 if (clp == NULL) 438 if (clp == NULL)
446 goto out; 439 goto out;
447 440
@@ -517,7 +510,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy,
517 if (!cps->clp) /* set in cb_sequence */ 510 if (!cps->clp) /* set in cb_sequence */
518 goto out; 511 goto out;
519 512
520 dprintk("NFS: RECALL_ANY callback request from %s\n", 513 dprintk_rcu("NFS: RECALL_ANY callback request from %s\n",
521 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); 514 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
522 515
523 status = cpu_to_be32(NFS4ERR_INVAL); 516 status = cpu_to_be32(NFS4ERR_INVAL);
@@ -552,7 +545,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
552 if (!cps->clp) /* set in cb_sequence */ 545 if (!cps->clp) /* set in cb_sequence */
553 goto out; 546 goto out;
554 547
555 dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", 548 dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
556 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR), 549 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
557 args->crsa_target_max_slots); 550 args->crsa_target_max_slots);
558 551