aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/delegation.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-01-30 03:54:24 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-01-30 03:54:24 -0500
commit85004cc367abc000aa36c0d0e270ab609a68b0cb (patch)
tree5739aae778d67b6d119fe5c668313fc2823e9836 /fs/nfs/delegation.c
parent149a051f82d2b3860fe32fa182dbc83a66274894 (diff)
parent3fbd67ad61f6d5a09ea717b56c50bc5c3d8042a8 (diff)
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (118 commits) NFSv4: Iterate through all nfs_clients when the server recalls a delegation NFSv4: Deal more correctly with duplicate delegations NFS: Fix a potential race between umount and nfs_access_cache_shrinker() NFS: Add an asynchronous delegreturn operation for use in nfs_clear_inode nfs: convert NFS_*(inode) helpers to static inline nfs: obliterate NFS_FLAGS macro NFS: Address memory leaks in the NFS client mount option parser nfs4: allow nfsv4 acls on non-regular-files NFS: Optimise away the sigmask code in aio/dio reads and writes SUNRPC: Don't bother changing the sigmask for asynchronous RPC calls SUNRPC: rpcb_getport_sync() passes incorrect address size to rpc_create() SUNRPC: Clean up block comment preceding rpcb_getport_sync() SUNRPC: Use appropriate argument types in rpcb client SUNRPC: rpcb_getport_sync() should use built-in hostname generator SUNRPC: Clean up functions that free address_strings array NFS: NFS version number is unsigned NLM: Fix a bogus 'return' in nlmclnt_rpc_release NLM: Introduce an arguments structure for nlmclnt_init() NLM/NFS: Use cached nlm_host when calling nlmclnt_proc() NFS: Invoke nlmclnt_init during NFS mount processing ...
Diffstat (limited to 'fs/nfs/delegation.c')
-rw-r--r--fs/nfs/delegation.c110
1 files changed, 73 insertions, 37 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 11833f4caeaa..b9eadd18ba70 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -125,6 +125,32 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
125 put_rpccred(oldcred); 125 put_rpccred(oldcred);
126} 126}
127 127
128static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
129{
130 int res = 0;
131
132 res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync);
133 nfs_free_delegation(delegation);
134 return res;
135}
136
137static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid)
138{
139 struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
140
141 if (delegation == NULL)
142 goto nomatch;
143 if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data,
144 sizeof(delegation->stateid.data)) != 0)
145 goto nomatch;
146 list_del_rcu(&delegation->super_list);
147 nfsi->delegation_state = 0;
148 rcu_assign_pointer(nfsi->delegation, NULL);
149 return delegation;
150nomatch:
151 return NULL;
152}
153
128/* 154/*
129 * Set up a delegation on an inode 155 * Set up a delegation on an inode
130 */ 156 */
@@ -133,6 +159,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
133 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; 159 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
134 struct nfs_inode *nfsi = NFS_I(inode); 160 struct nfs_inode *nfsi = NFS_I(inode);
135 struct nfs_delegation *delegation; 161 struct nfs_delegation *delegation;
162 struct nfs_delegation *freeme = NULL;
136 int status = 0; 163 int status = 0;
137 164
138 delegation = kmalloc(sizeof(*delegation), GFP_KERNEL); 165 delegation = kmalloc(sizeof(*delegation), GFP_KERNEL);
@@ -147,41 +174,45 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
147 delegation->inode = inode; 174 delegation->inode = inode;
148 175
149 spin_lock(&clp->cl_lock); 176 spin_lock(&clp->cl_lock);
150 if (rcu_dereference(nfsi->delegation) == NULL) { 177 if (rcu_dereference(nfsi->delegation) != NULL) {
151 list_add_rcu(&delegation->super_list, &clp->cl_delegations);
152 nfsi->delegation_state = delegation->type;
153 rcu_assign_pointer(nfsi->delegation, delegation);
154 delegation = NULL;
155 } else {
156 if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, 178 if (memcmp(&delegation->stateid, &nfsi->delegation->stateid,
157 sizeof(delegation->stateid)) != 0 || 179 sizeof(delegation->stateid)) == 0 &&
158 delegation->type != nfsi->delegation->type) { 180 delegation->type == nfsi->delegation->type) {
159 printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n", 181 goto out;
160 __FUNCTION__, NIPQUAD(clp->cl_addr.sin_addr)); 182 }
161 status = -EIO; 183 /*
184 * Deal with broken servers that hand out two
185 * delegations for the same file.
186 */
187 dfprintk(FILE, "%s: server %s handed out "
188 "a duplicate delegation!\n",
189 __FUNCTION__, clp->cl_hostname);
190 if (delegation->type <= nfsi->delegation->type) {
191 freeme = delegation;
192 delegation = NULL;
193 goto out;
162 } 194 }
195 freeme = nfs_detach_delegation_locked(nfsi, NULL);
163 } 196 }
197 list_add_rcu(&delegation->super_list, &clp->cl_delegations);
198 nfsi->delegation_state = delegation->type;
199 rcu_assign_pointer(nfsi->delegation, delegation);
200 delegation = NULL;
164 201
165 /* Ensure we revalidate the attributes and page cache! */ 202 /* Ensure we revalidate the attributes and page cache! */
166 spin_lock(&inode->i_lock); 203 spin_lock(&inode->i_lock);
167 nfsi->cache_validity |= NFS_INO_REVAL_FORCED; 204 nfsi->cache_validity |= NFS_INO_REVAL_FORCED;
168 spin_unlock(&inode->i_lock); 205 spin_unlock(&inode->i_lock);
169 206
207out:
170 spin_unlock(&clp->cl_lock); 208 spin_unlock(&clp->cl_lock);
171 if (delegation != NULL) 209 if (delegation != NULL)
172 nfs_free_delegation(delegation); 210 nfs_free_delegation(delegation);
211 if (freeme != NULL)
212 nfs_do_return_delegation(inode, freeme, 0);
173 return status; 213 return status;
174} 214}
175 215
176static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation)
177{
178 int res = 0;
179
180 res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid);
181 nfs_free_delegation(delegation);
182 return res;
183}
184
185/* Sync all data to disk upon delegation return */ 216/* Sync all data to disk upon delegation return */
186static void nfs_msync_inode(struct inode *inode) 217static void nfs_msync_inode(struct inode *inode)
187{ 218{
@@ -207,24 +238,28 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat
207 up_read(&clp->cl_sem); 238 up_read(&clp->cl_sem);
208 nfs_msync_inode(inode); 239 nfs_msync_inode(inode);
209 240
210 return nfs_do_return_delegation(inode, delegation); 241 return nfs_do_return_delegation(inode, delegation, 1);
211} 242}
212 243
213static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) 244/*
245 * This function returns the delegation without reclaiming opens
246 * or protecting against delegation reclaims.
247 * It is therefore really only safe to be called from
248 * nfs4_clear_inode()
249 */
250void nfs_inode_return_delegation_noreclaim(struct inode *inode)
214{ 251{
215 struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); 252 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
253 struct nfs_inode *nfsi = NFS_I(inode);
254 struct nfs_delegation *delegation;
216 255
217 if (delegation == NULL) 256 if (rcu_dereference(nfsi->delegation) != NULL) {
218 goto nomatch; 257 spin_lock(&clp->cl_lock);
219 if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, 258 delegation = nfs_detach_delegation_locked(nfsi, NULL);
220 sizeof(delegation->stateid.data)) != 0) 259 spin_unlock(&clp->cl_lock);
221 goto nomatch; 260 if (delegation != NULL)
222 list_del_rcu(&delegation->super_list); 261 nfs_do_return_delegation(inode, delegation, 0);
223 nfsi->delegation_state = 0; 262 }
224 rcu_assign_pointer(nfsi->delegation, NULL);
225 return delegation;
226nomatch:
227 return NULL;
228} 263}
229 264
230int nfs_inode_return_delegation(struct inode *inode) 265int nfs_inode_return_delegation(struct inode *inode)
@@ -314,8 +349,9 @@ void nfs_expire_all_delegations(struct nfs_client *clp)
314 __module_get(THIS_MODULE); 349 __module_get(THIS_MODULE);
315 atomic_inc(&clp->cl_count); 350 atomic_inc(&clp->cl_count);
316 task = kthread_run(nfs_do_expire_all_delegations, clp, 351 task = kthread_run(nfs_do_expire_all_delegations, clp,
317 "%u.%u.%u.%u-delegreturn", 352 "%s-delegreturn",
318 NIPQUAD(clp->cl_addr.sin_addr)); 353 rpc_peeraddr2str(clp->cl_rpcclient,
354 RPC_DISPLAY_ADDR));
319 if (!IS_ERR(task)) 355 if (!IS_ERR(task))
320 return; 356 return;
321 nfs_put_client(clp); 357 nfs_put_client(clp);
@@ -386,7 +422,7 @@ static int recall_thread(void *data)
386 nfs_msync_inode(inode); 422 nfs_msync_inode(inode);
387 423
388 if (delegation != NULL) 424 if (delegation != NULL)
389 nfs_do_return_delegation(inode, delegation); 425 nfs_do_return_delegation(inode, delegation, 1);
390 iput(inode); 426 iput(inode);
391 module_put_and_exit(0); 427 module_put_and_exit(0);
392} 428}