aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-10-13 16:00:16 -0400
committerJ. Bruce Fields <bfields@redhat.com>2011-10-17 17:50:00 -0400
commit32513b40efdc693b3675f1c691ab901518fbcb6a (patch)
tree7d39ddbe4e421061f96d3dd5d64866b27117fd90 /fs/nfsd
parentd29b20cd589128a599e5045d4effc2d7dbc388f5 (diff)
nfsd4: preallocate nfs4_file in process_open1()
Creating a new file is an irrevocable step--once it's visible in the filesystem, other processes may have seen it and done something with it, and unlinking it wouldn't simply undo the effects of the create. Therefore, in the case where OPEN creates a new file, we shouldn't do the create until we know that the rest of the OPEN processing will succeed. For example, we should preallocate a struct file in case we need it until waiting to allocate it till process_open2(), which is already too late. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4state.c60
-rw-r--r--fs/nfsd/xdr4.h1
2 files changed, 37 insertions, 24 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2c9a1a20e014..ae5d25075f67 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -104,6 +104,11 @@ opaque_hashval(const void *ptr, int nbytes)
104 104
105static struct list_head del_recall_lru; 105static struct list_head del_recall_lru;
106 106
107static void nfsd4_free_file(struct nfs4_file *f)
108{
109 kmem_cache_free(file_slab, f);
110}
111
107static inline void 112static inline void
108put_nfs4_file(struct nfs4_file *fi) 113put_nfs4_file(struct nfs4_file *fi)
109{ 114{
@@ -111,7 +116,7 @@ put_nfs4_file(struct nfs4_file *fi)
111 list_del(&fi->fi_hash); 116 list_del(&fi->fi_hash);
112 spin_unlock(&recall_lock); 117 spin_unlock(&recall_lock);
113 iput(fi->fi_inode); 118 iput(fi->fi_inode);
114 kmem_cache_free(file_slab, fi); 119 nfsd4_free_file(fi);
115 } 120 }
116} 121}
117 122
@@ -2190,30 +2195,28 @@ out:
2190 return status; 2195 return status;
2191} 2196}
2192 2197
2198static struct nfs4_file *nfsd4_alloc_file(void)
2199{
2200 return kmem_cache_alloc(file_slab, GFP_KERNEL);
2201}
2202
2193/* OPEN Share state helper functions */ 2203/* OPEN Share state helper functions */
2194static inline struct nfs4_file * 2204static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
2195alloc_init_file(struct inode *ino)
2196{ 2205{
2197 struct nfs4_file *fp;
2198 unsigned int hashval = file_hashval(ino); 2206 unsigned int hashval = file_hashval(ino);
2199 2207
2200 fp = kmem_cache_alloc(file_slab, GFP_KERNEL); 2208 atomic_set(&fp->fi_ref, 1);
2201 if (fp) { 2209 INIT_LIST_HEAD(&fp->fi_hash);
2202 atomic_set(&fp->fi_ref, 1); 2210 INIT_LIST_HEAD(&fp->fi_stateids);
2203 INIT_LIST_HEAD(&fp->fi_hash); 2211 INIT_LIST_HEAD(&fp->fi_delegations);
2204 INIT_LIST_HEAD(&fp->fi_stateids); 2212 fp->fi_inode = igrab(ino);
2205 INIT_LIST_HEAD(&fp->fi_delegations); 2213 fp->fi_had_conflict = false;
2206 fp->fi_inode = igrab(ino); 2214 fp->fi_lease = NULL;
2207 fp->fi_had_conflict = false; 2215 memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
2208 fp->fi_lease = NULL; 2216 memset(fp->fi_access, 0, sizeof(fp->fi_access));
2209 memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 2217 spin_lock(&recall_lock);
2210 memset(fp->fi_access, 0, sizeof(fp->fi_access)); 2218 list_add(&fp->fi_hash, &file_hashtbl[hashval]);
2211 spin_lock(&recall_lock); 2219 spin_unlock(&recall_lock);
2212 list_add(&fp->fi_hash, &file_hashtbl[hashval]);
2213 spin_unlock(&recall_lock);
2214 return fp;
2215 }
2216 return NULL;
2217} 2220}
2218 2221
2219static void 2222static void
@@ -2509,6 +2512,13 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
2509 2512
2510 if (STALE_CLIENTID(&open->op_clientid)) 2513 if (STALE_CLIENTID(&open->op_clientid))
2511 return nfserr_stale_clientid; 2514 return nfserr_stale_clientid;
2515 /*
2516 * In case we need it later, after we've already created the
2517 * file and don't want to risk a further failure:
2518 */
2519 open->op_file = nfsd4_alloc_file();
2520 if (open->op_file == NULL)
2521 return nfserr_jukebox;
2512 2522
2513 strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner); 2523 strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner);
2514 oo = find_openstateowner_str(strhashval, open); 2524 oo = find_openstateowner_str(strhashval, open);
@@ -2884,9 +2894,9 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
2884 if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) 2894 if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
2885 goto out; 2895 goto out;
2886 status = nfserr_jukebox; 2896 status = nfserr_jukebox;
2887 fp = alloc_init_file(ino); 2897 fp = open->op_file;
2888 if (fp == NULL) 2898 open->op_file = NULL;
2889 goto out; 2899 nfsd4_init_file(fp, ino);
2890 } 2900 }
2891 2901
2892 /* 2902 /*
@@ -2960,6 +2970,8 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
2960 oo->oo_flags &= ~NFS4_OO_NEW; 2970 oo->oo_flags &= ~NFS4_OO_NEW;
2961 } 2971 }
2962 } 2972 }
2973 if (open->op_file)
2974 nfsd4_free_file(open->op_file);
2963} 2975}
2964 2976
2965__be32 2977__be32
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 32e6fd8d9768..502dd43634f9 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -228,6 +228,7 @@ struct nfsd4_open {
228 u32 op_rflags; /* response */ 228 u32 op_rflags; /* response */
229 int op_truncate; /* used during processing */ 229 int op_truncate; /* used during processing */
230 struct nfs4_openowner *op_openowner; /* used during processing */ 230 struct nfs4_openowner *op_openowner; /* used during processing */
231 struct nfs4_file *op_file; /* used during processing */
231 struct nfs4_acl *op_acl; 232 struct nfs4_acl *op_acl;
232}; 233};
233#define op_iattr iattr 234#define op_iattr iattr