1 /* 2 * linux/fs/nfs/delegation.c 3 * 4 * Copyright (C) 2004 Trond Myklebust 5 * 6 * NFS file delegation management 7 * 8 */ 9 #include <linux/config.h> 10 #include <linux/completion.h> 11 #include <linux/module.h> 12 #include <linux/sched.h> 13 #include <linux/spinlock.h> 14 15 #include <linux/nfs4.h> 16 #include <linux/nfs_fs.h> 17 #include <linux/nfs_xdr.h> 18 19 #include "delegation.h" 20 21 static struct nfs_delegation *nfs_alloc_delegation(void) 22 { 23 return (struct nfs_delegation *)kmalloc(sizeof(struct nfs_delegation), GFP_KERNEL); 24 } 25 26 static void nfs_free_delegation(struct nfs_delegation *delegation) 27 { 28 if (delegation->cred) 29 put_rpccred(delegation->cred); 30 kfree(delegation); 31 } 32 33 static void nfs_delegation_claim_opens(struct inode *inode) 34 { 35 struct nfs_inode *nfsi = NFS_I(inode); 36 struct nfs_open_context *ctx; 37 struct nfs4_state *state; 38 39 again: 40 spin_lock(&inode->i_lock); 41 list_for_each_entry(ctx, &nfsi->open_files, list) { 42 state = ctx->state; 43 if (state == NULL) 44 continue; 45 if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) 46 continue; 47 get_nfs_open_context(ctx); 48 spin_unlock(&inode->i_lock); 49 if (nfs4_open_delegation_recall(ctx->dentry, state) < 0) 50 return; 51 put_nfs_open_context(ctx); 52 goto again; 53 } 54 spin_unlock(&inode->i_lock); 55 } 56 57 /* 58 * Set up a delegation on an inode 59 */ 60 void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) 61 { 62 struct nfs_delegation *delegation = NFS_I(inode)->delegation; 63 64 if (delegation == NULL) 65 return; 66 memcpy(delegation->stateid.data, res->delegation.data, 67 sizeof(delegation->stateid.data)); 68 delegation->type = res->delegation_type; 69 delegation->maxsize = res->maxsize; 70 put_rpccred(cred); 71 delegation->cred = get_rpccred(cred); 72 delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM; 73 NFS_I(inode)->delegation_state = delegation->type; 74 smp_wmb(); 75 } 76 77 /* 78 * Set up a delegation on an inode 79 */ 80 int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) 81 { 82 struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; 83 struct nfs_inode *nfsi = NFS_I(inode); 84 struct nfs_delegation *delegation; 85 int status = 0; 86 87 delegation = nfs_alloc_delegation(); 88 if (delegation == NULL) 89 return -ENOMEM; 90 memcpy(delegation->stateid.data, res->delegation.data, 91 sizeof(delegation->stateid.data)); 92 delegation->type = res->delegation_type; 93 delegation->maxsize = res->maxsize; 94 delegation->cred = get_rpccred(cred); 95 delegation->inode = inode; 96 97 spin_lock(&clp->cl_lock); 98 if (nfsi->delegation == NULL) { 99 list_add(&delegation->super_list, &clp->cl_delegations); 100 nfsi->delegation = delegation; 101 nfsi->delegation_state = delegation->type; 102 delegation = NULL; 103 } else { 104 if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, 105 sizeof(delegation->stateid)) != 0 || 106 delegation->type != nfsi->delegation->type) { 107 printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n", 108 __FUNCTION__, NIPQUAD(clp->cl_addr)); 109 status = -EIO; 110 } 111 } 112 spin_unlock(&clp->cl_lock); 113 if (delegation != NULL) 114 kfree(delegation); 115 return status; 116 } 117 118 static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation) 119 { 120 int res = 0; 121 122 __nfs_revalidate_inode(NFS_SERVER(inode), inode); 123 124 res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); 125 nfs_free_delegation(delegation); 126 return res; 127 } 128 129 /* Sync all data to disk upon delegation return */ 130 static void nfs_msync_inode(struct inode *inode) 131 { 132 filemap_fdatawrite(inode->i_mapping); 133 nfs_wb_all(inode); 134 filemap_fdatawait(inode->i_mapping); 135 } 136 137 /* 138 * Basic procedure for returning a delegation to the server 139 */ 140 int nfs_inode_return_delegation(struct inode *inode) 141 { 142 struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; 143 struct nfs_inode *nfsi = NFS_I(inode); 144 struct nfs_delegation *delegation; 145 int res = 0; 146 147 nfs_msync_inode(inode); 148 down_read(&clp->cl_sem); 149 /* Guard against new delegated open calls */ 150 down_write(&nfsi->rwsem); 151 spin_lock(&clp->cl_lock); 152 delegation = nfsi->delegation; 153 if (delegation != NULL) { 154 list_del_init(&delegation->super_list); 155 nfsi->delegation = NULL; 156 nfsi->delegation_state = 0; 157 } 158 spin_unlock(&clp->cl_lock); 159 nfs_delegation_claim_opens(inode); 160 up_write(&nfsi->rwsem); 161 up_read(&clp->cl_sem); 162 nfs_msync_inode(inode); 163 164 if (delegation != NULL) 165 res = nfs_do_return_delegation(inode, delegation); 166 return res; 167 } 168 169 /* 170 * Return all delegations associated to a super block 171 */ 172 void nfs_return_all_delegations(struct super_block *sb) 173 { 174 struct nfs4_client *clp = NFS_SB(sb)->nfs4_state; 175 struct nfs_delegation *delegation; 176 struct inode *inode; 177 178 if (clp == NULL) 179 return; 180 restart: 181 spin_lock(&clp->cl_lock); 182 list_for_each_entry(delegation, &clp->cl_delegations, super_list) { 183 if (delegation->inode->i_sb != sb) 184 continue; 185 inode = igrab(delegation->inode); 186 if (inode == NULL) 187 continue; 188 spin_unlock(&clp->cl_lock); 189 nfs_inode_return_delegation(inode); 190 iput(inode); 191 goto restart; 192 } 193 spin_unlock(&clp->cl_lock); 194 } 195 196 /* 197 * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. 198 */ 199 void nfs_handle_cb_pathdown(struct nfs4_client *clp) 200 { 201 struct nfs_delegation *delegation; 202 struct inode *inode; 203 204 if (clp == NULL) 205 return; 206 restart: 207 spin_lock(&clp->cl_lock); 208 list_for_each_entry(delegation, &clp->cl_delegations, super_list) { 209 inode = igrab(delegation->inode); 210 if (inode == NULL) 211 continue; 212 spin_unlock(&clp->cl_lock); 213 nfs_inode_return_delegation(inode); 214 iput(inode); 215 goto restart; 216 } 217 spin_unlock(&clp->cl_lock); 218 } 219 220 struct recall_threadargs { 221 struct inode *inode; 222 struct nfs4_client *clp; 223 const nfs4_stateid *stateid; 224 225 struct completion started; 226 int result; 227 }; 228 229 static int recall_thread(void *data) 230 { 231 struct recall_threadargs *args = (struct recall_threadargs *)data; 232 struct inode *inode = igrab(args->inode); 233 struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; 234 struct nfs_inode *nfsi = NFS_I(inode); 235 struct nfs_delegation *delegation; 236 237 daemonize("nfsv4-delegreturn"); 238 239 nfs_msync_inode(inode); 240 down_read(&clp->cl_sem); 241 down_write(&nfsi->rwsem); 242 spin_lock(&clp->cl_lock); 243 delegation = nfsi->delegation; 244 if (delegation != NULL && memcmp(delegation->stateid.data, 245 args->stateid->data, 246 sizeof(delegation->stateid.data)) == 0) { 247 list_del_init(&delegation->super_list); 248 nfsi->delegation = NULL; 249 nfsi->delegation_state = 0; 250 args->result = 0; 251 } else { 252 delegation = NULL; 253 args->result = -ENOENT; 254 } 255 spin_unlock(&clp->cl_lock); 256 complete(&args->started); 257 nfs_delegation_claim_opens(inode); 258 up_write(&nfsi->rwsem); 259 up_read(&clp->cl_sem); 260 nfs_msync_inode(inode); 261 262 if (delegation != NULL) 263 nfs_do_return_delegation(inode, delegation); 264 iput(inode); 265 module_put_and_exit(0); 266 } 267 268 /* 269 * Asynchronous delegation recall! 270 */ 271 int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) 272 { 273 struct recall_threadargs data = { 274 .inode = inode, 275 .stateid = stateid, 276 }; 277 int status; 278 279 init_completion(&data.started); 280 __module_get(THIS_MODULE); 281 status = kernel_thread(recall_thread, &data, CLONE_KERNEL); 282 if (status < 0) 283 goto out_module_put; 284 wait_for_completion(&data.started); 285 return data.result; 286 out_module_put: 287 module_put(THIS_MODULE); 288 return status; 289 } 290 291 /* 292 * Retrieve the inode associated with a delegation 293 */ 294 struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle) 295 { 296 struct nfs_delegation *delegation; 297 struct inode *res = NULL; 298 spin_lock(&clp->cl_lock); 299 list_for_each_entry(delegation, &clp->cl_delegations, super_list) { 300 if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) { 301 res = igrab(delegation->inode); 302 break; 303 } 304 } 305 spin_unlock(&clp->cl_lock); 306 return res; 307 } 308 309 /* 310 * Mark all delegations as needing to be reclaimed 311 */ 312 void nfs_delegation_mark_reclaim(struct nfs4_client *clp) 313 { 314 struct nfs_delegation *delegation; 315 spin_lock(&clp->cl_lock); 316 list_for_each_entry(delegation, &clp->cl_delegations, super_list) 317 delegation->flags |= NFS_DELEGATION_NEED_RECLAIM; 318 spin_unlock(&clp->cl_lock); 319 } 320 321 /* 322 * Reap all unclaimed delegations after reboot recovery is done 323 */ 324 void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) 325 { 326 struct nfs_delegation *delegation, *n; 327 LIST_HEAD(head); 328 spin_lock(&clp->cl_lock); 329 list_for_each_entry_safe(delegation, n, &clp->cl_delegations, super_list) { 330 if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) 331 continue; 332 list_move(&delegation->super_list, &head); 333 NFS_I(delegation->inode)->delegation = NULL; 334 NFS_I(delegation->inode)->delegation_state = 0; 335 } 336 spin_unlock(&clp->cl_lock); 337 while(!list_empty(&head)) { 338 delegation = list_entry(head.next, struct nfs_delegation, super_list); 339 list_del(&delegation->super_list); 340 nfs_free_delegation(delegation); 341 } 342 } 343