summaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs3proc.c11
-rw-r--r--fs/nfsd/nfs3xdr.c47
-rw-r--r--fs/nfsd/nfs4callback.c11
-rw-r--r--fs/nfsd/nfs4proc.c55
-rw-r--r--fs/nfsd/nfs4recover.c30
-rw-r--r--fs/nfsd/nfs4state.c220
-rw-r--r--fs/nfsd/nfs4xdr.c10
-rw-r--r--fs/nfsd/nfsproc.c37
-rw-r--r--fs/nfsd/nfsxdr.c52
-rw-r--r--fs/nfsd/vfs.c250
10 files changed, 341 insertions, 382 deletions
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 041380fe667..6d2dfed1de0 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -56,13 +56,20 @@ static int
nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
struct nfsd3_attrstat *resp)
{
- int nfserr;
+ int err, nfserr;
dprintk("nfsd: GETATTR(3) %s\n",
- SVCFH_fmt(&argp->fh));
+ SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
+ if (nfserr)
+ RETURN_STATUS(nfserr);
+
+ err = vfs_getattr(resp->fh.fh_export->ex_mnt,
+ resp->fh.fh_dentry, &resp->stat);
+ nfserr = nfserrno(err);
+
RETURN_STATUS(nfserr);
}
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 9147b8524d0..243d94b9653 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -154,37 +154,34 @@ decode_sattr3(u32 *p, struct iattr *iap)
}
static inline u32 *
-encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
+ struct kstat *stat)
{
- struct vfsmount *mnt = fhp->fh_export->ex_mnt;
struct dentry *dentry = fhp->fh_dentry;
- struct kstat stat;
struct timespec time;
- vfs_getattr(mnt, dentry, &stat);
-
- *p++ = htonl(nfs3_ftypes[(stat.mode & S_IFMT) >> 12]);
- *p++ = htonl((u32) stat.mode);
- *p++ = htonl((u32) stat.nlink);
- *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
- *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
- if (S_ISLNK(stat.mode) && stat.size > NFS3_MAXPATHLEN) {
+ *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
+ *p++ = htonl((u32) stat->mode);
+ *p++ = htonl((u32) stat->nlink);
+ *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
+ *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
+ if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
} else {
- p = xdr_encode_hyper(p, (u64) stat.size);
+ p = xdr_encode_hyper(p, (u64) stat->size);
}
- p = xdr_encode_hyper(p, ((u64)stat.blocks) << 9);
- *p++ = htonl((u32) MAJOR(stat.rdev));
- *p++ = htonl((u32) MINOR(stat.rdev));
+ p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
+ *p++ = htonl((u32) MAJOR(stat->rdev));
+ *p++ = htonl((u32) MINOR(stat->rdev));
if (is_fsid(fhp, rqstp->rq_reffh))
p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
else
- p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat.dev));
- p = xdr_encode_hyper(p, (u64) stat.ino);
- p = encode_time3(p, &stat.atime);
+ p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat->dev));
+ p = xdr_encode_hyper(p, (u64) stat->ino);
+ p = encode_time3(p, &stat->atime);
lease_get_mtime(dentry->d_inode, &time);
p = encode_time3(p, &time);
- p = encode_time3(p, &stat.ctime);
+ p = encode_time3(p, &stat->ctime);
return p;
}
@@ -232,8 +229,14 @@ encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
{
struct dentry *dentry = fhp->fh_dentry;
if (dentry && dentry->d_inode != NULL) {
- *p++ = xdr_one; /* attributes follow */
- return encode_fattr3(rqstp, p, fhp);
+ int err;
+ struct kstat stat;
+
+ err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat);
+ if (!err) {
+ *p++ = xdr_one; /* attributes follow */
+ return encode_fattr3(rqstp, p, fhp, &stat);
+ }
}
*p++ = xdr_zero;
return p;
@@ -616,7 +619,7 @@ nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_attrstat *resp)
{
if (resp->status == 0)
- p = encode_fattr3(rqstp, p, &resp->fh);
+ p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
return xdr_ressize_check(rqstp, p);
}
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 583c0710e45..d828662d737 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -53,7 +53,7 @@
#define NFSPROC4_CB_COMPOUND 1
/* declarations */
-static void nfs4_cb_null(struct rpc_task *task);
+static const struct rpc_call_ops nfs4_cb_null_ops;
/* Index of predefined Linux callback client operations */
@@ -431,7 +431,6 @@ nfsd4_probe_callback(struct nfs4_client *clp)
}
clnt->cl_intr = 0;
clnt->cl_softrtry = 1;
- clnt->cl_chatty = 1;
/* Kick rpciod, put the call on the wire. */
@@ -447,7 +446,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
msg.rpc_cred = nfsd4_lookupcred(clp,0);
if (IS_ERR(msg.rpc_cred))
goto out_rpciod;
- status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, nfs4_cb_null, NULL);
+ status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
put_rpccred(msg.rpc_cred);
if (status != 0) {
@@ -469,7 +468,7 @@ out_err:
}
static void
-nfs4_cb_null(struct rpc_task *task)
+nfs4_cb_null(struct rpc_task *task, void *dummy)
{
struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
struct nfs4_callback *cb = &clp->cl_callback;
@@ -488,6 +487,10 @@ out:
put_nfs4_client(clp);
}
+static const struct rpc_call_ops nfs4_cb_null_ops = {
+ .rpc_call_done = nfs4_cb_null,
+};
+
/*
* called with dp->dl_count inc'ed.
* nfs4_lock_state() may or may not have been called.
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 361b4007d4a..a00fe868629 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -192,6 +192,14 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
}
if (status)
goto out;
+
+ /* Openowner is now set, so sequence id will get bumped. Now we need
+ * these checks before we do any creates: */
+ if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+ return nfserr_grace;
+ if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ return nfserr_no_grace;
+
switch (open->op_claim_type) {
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
status = nfserr_inval;
@@ -210,6 +218,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
goto out;
break;
case NFS4_OPEN_CLAIM_PREVIOUS:
+ open->op_stateowner->so_confirmed = 1;
/*
* The CURRENT_FH is already set to the file being
* opened. (1) set open->op_cinfo, (2) set
@@ -221,6 +230,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
goto out;
break;
case NFS4_OPEN_CLAIM_DELEGATE_PREV:
+ open->op_stateowner->so_confirmed = 1;
printk("NFSD: unsupported OPEN claim type %d\n",
open->op_claim_type);
status = nfserr_notsupp;
@@ -584,31 +594,23 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se
{
int status = nfs_ok;
- if (!current_fh->fh_dentry)
- return nfserr_nofilehandle;
-
- status = nfs_ok;
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
nfs4_lock_state();
- if ((status = nfs4_preprocess_stateid_op(current_fh,
- &setattr->sa_stateid,
- CHECK_FH | WR_STATE, NULL))) {
- dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
- goto out_unlock;
- }
+ status = nfs4_preprocess_stateid_op(current_fh,
+ &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL);
nfs4_unlock_state();
+ if (status) {
+ dprintk("NFSD: nfsd4_setattr: couldn't process stateid!");
+ return status;
+ }
}
status = nfs_ok;
if (setattr->sa_acl != NULL)
status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl);
if (status)
- goto out;
+ return status;
status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr,
0, (time_t)0);
-out:
- return status;
-out_unlock:
- nfs4_unlock_state();
return status;
}
@@ -626,15 +628,17 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
return nfserr_inval;
nfs4_lock_state();
- if ((status = nfs4_preprocess_stateid_op(current_fh, stateid,
- CHECK_FH | WR_STATE, &filp))) {
- dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
- goto out;
- }
+ status = nfs4_preprocess_stateid_op(current_fh, stateid,
+ CHECK_FH | WR_STATE, &filp);
if (filp)
get_file(filp);
nfs4_unlock_state();
+ if (status) {
+ dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
+ return status;
+ }
+
write->wr_bytes_written = write->wr_buflen;
write->wr_how_written = write->wr_stable_how;
p = (u32 *)write->wr_verifier.data;
@@ -650,9 +654,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
if (status == nfserr_symlink)
status = nfserr_inval;
return status;
-out:
- nfs4_unlock_state();
- return status;
}
/* This routine never returns NFS_OK! If there are no other errors, it
@@ -768,6 +769,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
while (!status && resp->opcnt < args->opcnt) {
op = &args->ops[resp->opcnt++];
+ dprintk("nfsv4 compound op #%d: %d\n", resp->opcnt, op->opnum);
+
/*
* The XDR decode routines may have pre-set op->status;
* for example, if there is a miscellaneous XDR error
@@ -792,17 +795,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
/* All operations except RENEW, SETCLIENTID, RESTOREFH
* SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH
* require a valid current filehandle
- *
- * SETATTR NOFILEHANDLE error handled in nfsd4_setattr
- * due to required returned bitmap argument
*/
if ((!current_fh->fh_dentry) &&
!((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) ||
(op->opnum == OP_SETCLIENTID) ||
(op->opnum == OP_SETCLIENTID_CONFIRM) ||
(op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) ||
- (op->opnum == OP_RELEASE_LOCKOWNER) ||
- (op->opnum == OP_SETATTR))) {
+ (op->opnum == OP_RELEASE_LOCKOWNER))) {
op->status = nfserr_nofilehandle;
goto encode_op;
}
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 954cf893d50..06da7506363 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -121,9 +121,9 @@ out:
static void
nfsd4_sync_rec_dir(void)
{
- down(&rec_dir.dentry->d_inode->i_sem);
+ mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
nfsd_sync_dir(rec_dir.dentry);
- up(&rec_dir.dentry->d_inode->i_sem);
+ mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
}
int
@@ -143,7 +143,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
nfs4_save_user(&uid, &gid);
/* lock the parent */
- down(&rec_dir.dentry->d_inode->i_sem);
+ mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
dentry = lookup_one_len(dname, rec_dir.dentry, HEXDIR_LEN-1);
if (IS_ERR(dentry)) {
@@ -159,7 +159,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
out_put:
dput(dentry);
out_unlock:
- up(&rec_dir.dentry->d_inode->i_sem);
+ mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
if (status == 0) {
clp->cl_firststate = 1;
nfsd4_sync_rec_dir();
@@ -222,8 +222,7 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
nfs4_save_user(&uid, &gid);
- filp = dentry_open(dget(dir), mntget(rec_dir.mnt),
- O_RDWR);
+ filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY);
status = PTR_ERR(filp);
if (IS_ERR(filp))
goto out;
@@ -259,9 +258,9 @@ nfsd4_remove_clid_file(struct dentry *dir, struct dentry *dentry)
printk("nfsd4: non-file found in client recovery directory\n");
return -EINVAL;
}
- down(&dir->d_inode->i_sem);
+ mutex_lock(&dir->d_inode->i_mutex);
status = vfs_unlink(dir->d_inode, dentry);
- up(&dir->d_inode->i_sem);
+ mutex_unlock(&dir->d_inode->i_mutex);
return status;
}
@@ -274,9 +273,9 @@ nfsd4_clear_clid_dir(struct dentry *dir, struct dentry *dentry)
* any regular files anyway, just in case the directory was created by
* a kernel from the future.... */
nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file);
- down(&dir->d_inode->i_sem);
+ mutex_lock(&dir->d_inode->i_mutex);
status = vfs_rmdir(dir->d_inode, dentry);
- up(&dir->d_inode->i_sem);
+ mutex_unlock(&dir->d_inode->i_mutex);
return status;
}
@@ -288,9 +287,9 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
- down(&rec_dir.dentry->d_inode->i_sem);
+ mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
dentry = lookup_one_len(name, rec_dir.dentry, namlen);
- up(&rec_dir.dentry->d_inode->i_sem);
+ mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
if (IS_ERR(dentry)) {
status = PTR_ERR(dentry);
return status;
@@ -400,9 +399,10 @@ nfsd4_init_recdir(char *rec_dirname)
nfs4_save_user(&uid, &gid);
- status = path_lookup(rec_dirname, LOOKUP_FOLLOW, &rec_dir);
- if (status == -ENOENT)
- printk("NFSD: recovery directory %s doesn't exist\n",
+ status = path_lookup(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
+ &rec_dir);
+ if (status)
+ printk("NFSD: unable to find recovery directory %s\n",
rec_dirname);
if (!status)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6bbefd06f10..1143cfb6454 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1088,7 +1088,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
sop->so_seqid = open->op_seqid;
sop->so_confirmed = 0;
rp = &sop->so_replay;
- rp->rp_status = NFSERR_SERVERFAULT;
+ rp->rp_status = nfserr_serverfault;
rp->rp_buflen = 0;
rp->rp_buf = rp->rp_ibuf;
return sop;
@@ -1178,7 +1178,6 @@ release_stateid(struct nfs4_stateid *stp, int flags)
locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
put_nfs4_file(stp->st_file);
kmem_cache_free(stateid_slab, stp);
- stp = NULL;
}
static void
@@ -1191,22 +1190,6 @@ move_to_close_lru(struct nfs4_stateowner *sop)
sop->so_time = get_seconds();
}
-static void
-release_state_owner(struct nfs4_stateid *stp, int flag)
-{
- struct nfs4_stateowner *sop = stp->st_stateowner;
-
- dprintk("NFSD: release_state_owner\n");
- release_stateid(stp, flag);
-
- /* place unused nfs4_stateowners on so_close_lru list to be
- * released by the laundromat service after the lease period
- * to enable us to handle CLOSE replay
- */
- if (sop->so_confirmed && list_empty(&sop->so_stateids))
- move_to_close_lru(sop);
-}
-
static int
cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) {
return ((sop->so_owner.len == owner->len) &&
@@ -1446,92 +1429,61 @@ static struct lock_manager_operations nfsd_lease_mng_ops = {
};
-/*
- * nfsd4_process_open1()
- * lookup stateowner.
- * found:
- * check confirmed
- * confirmed:
- * check seqid
- * not confirmed:
- * delete owner
- * create new owner
- * notfound:
- * verify clientid
- * create new owner
- *
- * called with nfs4_lock_state() held.
- */
int
nfsd4_process_open1(struct nfsd4_open *open)
{
- int status;
clientid_t *clientid = &open->op_clientid;
struct nfs4_client *clp = NULL;
unsigned int strhashval;
struct nfs4_stateowner *sop = NULL;
- status = nfserr_inval;
if (!check_name(open->op_owner))
- goto out;
+ return nfserr_inval;
if (STALE_CLIENTID(&open->op_clientid))
return nfserr_stale_clientid;
strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
sop = find_openstateowner_str(strhashval, open);
- if (sop) {
- open->op_stateowner = sop;
- /* check for replay */
- if (open->op_seqid == sop->so_seqid - 1){
- if (sop->so_replay.rp_buflen)
- return NFSERR_REPLAY_ME;
- else {
- /* The original OPEN failed so spectacularly
- * that we don't even have replay data saved!
- * Therefore, we have no choice but to continue
- * processing this OPEN; presumably, we'll
- * fail again for the same reason.
- */
- dprintk("nfsd4_process_open1:"
- " replay with no replay cache\n");
- goto renew;
- }
- } else if (sop->so_confirmed) {
- if (open->op_seqid == sop->so_seqid)
- goto renew;
- status = nfserr_bad_seqid;
- goto out;
- } else {
- /* If we get here, we received an OPEN for an
- * unconfirmed nfs4_stateowner. Since the seqid's are
- * different, purge the existing nfs4_stateowner, and
- * instantiate a new one.
- */
- clp = sop->so_client;
- release_stateowner(sop);
- }
- } else {
- /* nfs4_stateowner not found.
- * Verify clientid and instantiate new nfs4_stateowner.
- * If verify fails this is presumably the result of the
- * client's lease expiring.
- */
- status = nfserr_expired;
+ open->op_stateowner = sop;
+ if (!sop) {
+ /* Make sure the client's lease hasn't expired. */
clp = find_confirmed_client(clientid);
if (clp == NULL)
- goto out;
+ return nfserr_expired;
+ goto renew;
}
- status = nfserr_resource;
- sop = alloc_init_open_stateowner(strhashval, clp, open);
- if (sop == NULL)
- goto out;
- open->op_stateowner = sop;
+ if (!sop->so_confirmed) {
+ /* Replace unconfirmed owners without checking for replay. */
+ clp = sop->so_client;
+ release_stateowner(sop);
+ open->op_stateowner = NULL;
+ goto renew;
+ }
+ if (open->op_seqid == sop->so_seqid - 1) {
+ if (sop->so_replay.rp_buflen)
+ return NFSERR_REPLAY_ME;
+ /* The original OPEN failed so spectacularly
+ * that we don't even have replay data saved!
+ * Therefore, we have no choice but to continue
+ * processing this OPEN; presumably, we'll
+ * fail again for the same reason.
+ */
+ dprintk("nfsd4_process_open1: replay with no replay cache\n");
+ goto renew;
+ }
+ if (open->op_seqid != sop->so_seqid)
+ return nfserr_bad_seqid;
renew:
- status = nfs_ok;
+ if (open->op_stateowner == NULL) {
+ sop = alloc_init_open_stateowner(strhashval, clp, open);
+ if (sop == NULL)
+ return nfserr_resource;
+ open->op_stateowner = sop;
+ }
+ list_del_init(&sop->so_close_lru);
renew_client(sop->so_client);
-out:
- return status;
+ return nfs_ok;
}
static inline int
@@ -1648,7 +1600,7 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
if (!open->op_truncate)
return 0;
if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
- return -EINVAL;
+ return nfserr_inval;
return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
}
@@ -1657,26 +1609,26 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta
{
struct file *filp = stp->st_vfs_file;
struct inode *inode = filp->f_dentry->d_inode;
- unsigned int share_access;
+ unsigned int share_access, new_writer;
int status;
set_access(&share_access, stp->st_access_bmap);
- share_access = ~share_access;
- share_access &= open->op_share_access;
-
- if (!(share_access & NFS4_SHARE_ACCESS_WRITE))
- return nfsd4_truncate(rqstp, cur_fh, open);
+ new_writer = (~share_access) & open->op_share_access
+ & NFS4_SHARE_ACCESS_WRITE;
- status = get_write_access(inode);
- if (status)
- return nfserrno(status);
+ if (new_writer) {
+ status = get_write_access(inode);
+ if (status)
+ return nfserrno(status);
+ }
status = nfsd4_truncate(rqstp, cur_fh, open);
if (status) {
- put_write_access(inode);
+ if (new_writer)
+ put_write_access(inode);
return status;
}
/* remember the open */
- filp->f_mode = (filp->f_mode | FMODE_WRITE) & ~FMODE_READ;
+ filp->f_mode |= open->op_share_access;
set_bit(open->op_share_access, &stp->st_access_bmap);
set_bit(open->op_share_deny, &stp->st_deny_bmap);
@@ -1780,12 +1732,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
struct nfs4_delegation *dp = NULL;
int status;
- if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
- return nfserr_grace;
-
- if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
- return nfserr_no_grace;
-
status = nfserr_inval;
if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
goto out;
@@ -2423,15 +2369,19 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos
CHECK_FH | OPEN_STATE | CLOSE_STATE,
&close->cl_stateowner, &stp, NULL)))
goto out;
- /*
- * Return success, but first update the stateid.
- */
status = nfs_ok;
update_stateid(&stp->st_stateid);
memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
- /* release_state_owner() calls nfsd_close() if needed */
- release_state_owner(stp, OPEN_STATE);
+ /* release_stateid() calls nfsd_close() if needed */
+ release_stateid(stp, OPEN_STATE);
+
+ /* place unused nfs4_stateowners on so_close_lru list to be
+ * released by the laundromat service after the lease period
+ * to enable us to handle CLOSE replay
+ */
+ if (list_empty(&close->cl_stateowner->so_stateids))
+ move_to_close_lru(close->cl_stateowner);
out:
if (close->cl_stateowner) {
nfs4_get_stateowner(close->cl_stateowner);
@@ -2633,7 +2583,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
sop->so_seqid = lock->lk_new_lock_seqid + 1;
sop->so_confirmed = 1;
rp = &sop->so_replay;
- rp->rp_status = NFSERR_SERVERFAULT;
+ rp->rp_status = nfserr_serverfault;
rp->rp_buflen = 0;
rp->rp_buf = rp->rp_ibuf;
return sop;
@@ -2700,6 +2650,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
if (check_lock_length(lock->lk_offset, lock->lk_length))
return nfserr_inval;
+ if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) {
+ dprintk("NFSD: nfsd4_lock: permission denied!\n");
+ return status;
+ }
+
nfs4_lock_state();
if (lock->lk_is_new) {
@@ -2720,11 +2675,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
lock->lk_new_open_seqid,
&lock->lk_new_open_stateid,
CHECK_FH | OPEN_STATE,
- &lock->lk_stateowner, &open_stp,
+ &lock->lk_replay_owner, &open_stp,
lock);
if (status)
goto out;
- open_sop = lock->lk_stateowner;
+ open_sop = lock->lk_replay_owner;
/* create lockowner and lock stateid */
fp = open_stp->st_file;
strhashval = lock_ownerstr_hashval(fp->fi_inode,
@@ -2739,29 +2694,22 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
if (lock_sop == NULL)
goto out;
lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp);
- if (lock_stp == NULL) {
- release_stateowner(lock_sop);
+ if (lock_stp == NULL)
goto out;
- }
} else {
/* lock (lock owner + lock stateid) already exists */
status = nfs4_preprocess_seqid_op(current_fh,
lock->lk_old_lock_seqid,
&lock->lk_old_lock_stateid,
CHECK_FH | LOCK_STATE,
- &lock->lk_stateowner, &lock_stp, lock);
+ &lock->lk_replay_owner, &lock_stp, lock);
if (status)
goto out;
- lock_sop = lock->lk_stateowner;
+ lock_sop = lock->lk_replay_owner;
}
- /* lock->lk_stateowner and lock_stp have been created or found */
+ /* lock->lk_replay_owner and lock_stp have been created or found */
filp = lock_stp->st_vfs_file;
- if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) {
- dprintk("NFSD: nfsd4_lock: permission denied!\n");
- goto out;
- }
-
status = nfserr_grace;
if (nfs4_in_grace() && !lock->lk_reclaim)
goto out;
@@ -2802,8 +2750,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
*/
status = posix_lock_file(filp, &file_lock);
- if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
- file_lock.fl_ops->fl_release_private(&file_lock);
dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status);
switch (-status) {
case 0: /* success! */
@@ -2815,9 +2761,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
goto conflicting_lock;
case (EDEADLK):
status = nfserr_deadlock;
+ dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status);
+ goto out;
default:
+ status = nfserrno(status);
dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status);
- goto out_destroy_new_stateid;
+ goto out;
}
conflicting_lock:
@@ -2831,20 +2780,12 @@ conflicting_lock:
goto out;
}
nfs4_set_lock_denied(conflock, &lock->lk_denied);
-
-out_destroy_new_stateid:
- if (lock->lk_is_new) {
- dprintk("NFSD: nfsd4_lock: destroy new stateid!\n");
- /*
- * An error encountered after instantiation of the new
- * stateid has forced us to destroy it.
- */
- release_state_owner(lock_stp, LOCK_STATE);
- }
out:
- if (lock->lk_stateowner) {
- nfs4_get_stateowner(lock->lk_stateowner);
- *replay_owner = lock->lk_stateowner;
+ if (status && lock->lk_is_new && lock_sop)
+ release_stateowner(lock_sop);
+ if (lock->lk_replay_owner) {
+ nfs4_get_stateowner(lock->lk_replay_owner);
+ *replay_owner = lock->lk_replay_owner;
}
nfs4_unlock_state();
return status;
@@ -2977,8 +2918,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
* Try to unlock the file in the VFS.
*/
status = posix_lock_file(filp, &file_lock);
- if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
- file_lock.fl_ops->fl_release_private(&file_lock);
if (status) {
dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
goto out_nfserr;
@@ -3016,9 +2955,10 @@ check_for_locks(struct file *filp, struct nfs4_stateowner *lowner)
lock_kernel();
for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
- if ((*flpp)->fl_owner == (fl_owner_t)lowner)
+ if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
status = 1;
goto out;
+ }
}
out:
unlock_kernel();
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index dcd67318694..69d3501173a 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -528,7 +528,7 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
{
DECODE_HEAD;
- lock->lk_stateowner = NULL;
+ lock->lk_replay_owner = NULL;
/*
* type, reclaim(boolean), offset, length, new_lock_owner(boolean)
*/
@@ -1764,10 +1764,11 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
*/
if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR))
goto fail;
- nfserr = nfserr_toosmall;
p = nfsd4_encode_rdattr_error(p, buflen, nfserr);
- if (p == NULL)
+ if (p == NULL) {
+ nfserr = nfserr_toosmall;
goto fail;
+ }
}
cd->buflen -= (p - cd->buffer);
cd->buffer = p;
@@ -1895,7 +1896,6 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie
static void
nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock)
{
-
ENCODE_SEQID_OP_HEAD;
if (!nfserr) {
@@ -1906,7 +1906,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock
} else if (nfserr == nfserr_denied)
nfsd4_encode_lock_denied(resp, &lock->lk_denied);
- ENCODE_SEQID_OP_TAIL(lock->lk_stateowner);
+ ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner);
}
static void
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 0aa1b9603d7..3e6b75cd90f 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -36,6 +36,22 @@ nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
return nfs_ok;
}
+static int
+nfsd_return_attrs(int err, struct nfsd_attrstat *resp)
+{
+ if (err) return err;
+ return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt,
+ resp->fh.fh_dentry,
+ &resp->stat));
+}
+static int
+nfsd_return_dirop(int err, struct nfsd_diropres *resp)
+{
+ if (err) return err;
+ return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt,
+ resp->fh.fh_dentry,
+ &resp->stat));
+}
/*
* Get a file's attributes
* N.B. After this call resp->fh needs an fh_put
@@ -44,10 +60,12 @@ static int
nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
struct nfsd_attrstat *resp)
{
+ int nfserr;
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
- return fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
+ nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
+ return nfsd_return_attrs(nfserr, resp);
}
/*
@@ -58,12 +76,14 @@ static int
nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
struct nfsd_attrstat *resp)
{
+ int nfserr;
dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
SVCFH_fmt(&argp->fh),
argp->attrs.ia_valid, (long) argp->attrs.ia_size);
fh_copy(&resp->fh, &argp->fh);
- return nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0);
+ nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0);
+ return nfsd_return_attrs(nfserr, resp);
}
/*
@@ -86,7 +106,7 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
&resp->fh);
fh_put(&argp->fh);
- return nfserr;
+ return nfsd_return_dirop(nfserr, resp);
}
/*
@@ -142,7 +162,10 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
argp->vec, argp->vlen,
&resp->count);
- return nfserr;
+ if (nfserr) return nfserr;
+ return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt,
+ resp->fh.fh_dentry,
+ &resp->stat));
}
/*
@@ -165,7 +188,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
argp->vec, argp->vlen,
argp->len,
&stable);
- return nfserr;
+ return nfsd_return_attrs(nfserr, resp);
}
/*
@@ -322,7 +345,7 @@ out_unlock:
done:
fh_put(dirfhp);
- return nfserr;
+ return nfsd_return_dirop(nfserr, resp);
}
static int
@@ -425,7 +448,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh);
fh_put(&argp->fh);
- return nfserr;
+ return nfsd_return_dirop(nfserr, resp);
}
/*
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index b45999ff33e..e3a0797dd56 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -37,7 +37,7 @@ static u32 nfs_ftypes[] = {
/*
* XDR functions for basic NFS types
*/
-static inline u32 *
+static u32 *
decode_fh(u32 *p, struct svc_fh *fhp)
{
fh_init(fhp, NFS_FHSIZE);
@@ -151,47 +151,45 @@ decode_sattr(u32 *p, struct iattr *iap)
return p;
}
-static inline u32 *
-encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+static u32 *
+encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
+ struct kstat *stat)
{
- struct vfsmount *mnt = fhp->fh_export->ex_mnt;
struct dentry *dentry = fhp->fh_dentry;
- struct kstat stat;
int type;
struct timespec time;
- vfs_getattr(mnt, dentry, &stat);
- type = (stat.mode & S_IFMT);
+ type = (stat->mode & S_IFMT);
*p++ = htonl(nfs_ftypes[type >> 12]);
- *p++ = htonl((u32) stat.mode);
- *p++ = htonl((u32) stat.nlink);
- *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
- *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
+ *p++ = htonl((u32) stat->mode);
+ *p++ = htonl((u32) stat->nlink);
+ *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
+ *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
- if (S_ISLNK(type) && stat.size > NFS_MAXPATHLEN) {
+ if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
*p++ = htonl(NFS_MAXPATHLEN);
} else {
- *p++ = htonl((u32) stat.size);
+ *p++ = htonl((u32) stat->size);
}
- *p++ = htonl((u32) stat.blksize);
+ *p++ = htonl((u32) stat->blksize);
if (S_ISCHR(type) || S_ISBLK(type))
- *p++ = htonl(new_encode_dev(stat.rdev));
+ *p++ = htonl(new_encode_dev(stat->rdev));
else
*p++ = htonl(0xffffffff);
- *p++ = htonl((u32) stat.blocks);
+ *p++ = htonl((u32) stat->blocks);
if (is_fsid(fhp, rqstp->rq_reffh))
*p++ = htonl((u32) fhp->fh_export->ex_fsid);
else
- *p++ = htonl(new_encode_dev(stat.dev));
- *p++ = htonl((u32) stat.ino);
- *p++ = htonl((u32) stat.atime.tv_sec);
- *p++ = htonl(stat.atime.tv_nsec ? stat.atime.tv_nsec / 1000 : 0);
+ *p++ = htonl(new_encode_dev(stat->dev));
+ *p++ = htonl((u32) stat->ino);
+ *p++ = htonl((u32) stat->atime.tv_sec);
+ *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0);
lease_get_mtime(dentry->d_inode, &time);
*p++ = htonl((u32) time.tv_sec);
*p++ = htonl(time.tv_nsec ? time.tv_nsec / 1000 : 0);
- *p++ = htonl((u32) stat.ctime.tv_sec);
- *p++ = htonl(stat.ctime.tv_nsec ? stat.ctime.tv_nsec / 1000 : 0);
+ *p++ = htonl((u32) stat->ctime.tv_sec);
+ *p++ = htonl(stat->ctime.tv_nsec ? stat->ctime.tv_nsec / 1000 : 0);
return p;
}
@@ -199,7 +197,9 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
/* Helper function for NFSv2 ACL code */
u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
{
- return encode_fattr(rqstp, p, fhp);
+ struct kstat stat;
+ vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, &stat);
+ return encode_fattr(rqstp, p, fhp, &stat);
}
/*
@@ -394,7 +394,7 @@ int
nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
struct nfsd_attrstat *resp)
{
- p = encode_fattr(rqstp, p, &resp->fh);
+ p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
return xdr_ressize_check(rqstp, p);
}
@@ -403,7 +403,7 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
struct nfsd_diropres *resp)
{
p = encode_fh(p, &resp->fh);
- p = encode_fattr(rqstp, p, &resp->fh);
+ p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
return xdr_ressize_check(rqstp, p);
}
@@ -428,7 +428,7 @@ int
nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
struct nfsd_readres *resp)
{
- p = encode_fattr(rqstp, p, &resp->fh);
+ p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
*p++ = htonl(resp->count);
xdr_ressize_check(rqstp, p);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index af7c3c3074b..5320e5afadd 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -48,8 +48,8 @@
#include <linux/fsnotify.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
-#ifdef CONFIG_NFSD_V4
#include <linux/xattr.h>
+#ifdef CONFIG_NFSD_V4
#include <linux/nfs4.h>
#include <linux/nfs4_acl.h>
#include <linux/nfsd_idmap.h>
@@ -365,8 +365,30 @@ out_nfserr:
goto out;
}
-#if defined(CONFIG_NFSD_V4)
+#if defined(CONFIG_NFSD_V2_ACL) || \
+ defined(CONFIG_NFSD_V3_ACL) || \
+ defined(CONFIG_NFSD_V4)
+static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
+{
+ ssize_t buflen;
+ int error;
+
+ buflen = vfs_getxattr(dentry, key, NULL, 0);
+ if (buflen <= 0)
+ return buflen;
+
+ *buf = kmalloc(buflen, GFP_KERNEL);
+ if (!*buf)
+ return -ENOMEM;
+
+ error = vfs_getxattr(dentry, key, *buf, buflen);
+ if (error < 0)
+ return error;
+ return buflen;
+}
+#endif
+#if defined(CONFIG_NFSD_V4)
static int
set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
{
@@ -374,7 +396,6 @@ set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
size_t buflen;
char *buf = NULL;
int error = 0;
- struct inode *inode = dentry->d_inode;
buflen = posix_acl_xattr_size(pacl->a_count);
buf = kmalloc(buflen, GFP_KERNEL);
@@ -388,15 +409,7 @@ set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
goto out;
}
- error = -EOPNOTSUPP;
- if (inode->i_op && inode->i_op->setxattr) {
- down(&inode->i_sem);
- security_inode_setxattr(dentry, key, buf, len, 0);
- error = inode->i_op->setxattr(dentry, key, buf, len, 0);
- if (!error)
- security_inode_post_setxattr(dentry, key, buf, len, 0);
- up(&inode->i_sem);
- }
+ error = vfs_setxattr(dentry, key, buf, len, 0);
out:
kfree(buf);
return error;
@@ -455,44 +468,19 @@ out_nfserr:
static struct posix_acl *
_get_posix_acl(struct dentry *dentry, char *key)
{
- struct inode *inode = dentry->d_inode;
- char *buf = NULL;
- int buflen, error = 0;
+ void *buf = NULL;
struct posix_acl *pacl = NULL;
+ int buflen;
- error = -EOPNOTSUPP;
- if (inode->i_op == NULL)
- goto out_err;
- if (inode->i_op->getxattr == NULL)
- goto out_err;
-
- error = security_inode_getxattr(dentry, key);
- if (error)
- goto out_err;
-
- buflen = inode->i_op->getxattr(dentry, key, NULL, 0);
- if (buflen <= 0) {
- error = buflen < 0 ? buflen : -ENODATA;
- goto out_err;
- }
-
- buf = kmalloc(buflen, GFP_KERNEL);
- if (buf == NULL) {
- error = -ENOMEM;
- goto out_err;
- }
-
- error = inode->i_op->getxattr(dentry, key, buf, buflen);
- if (error < 0)
- goto out_err;
+ buflen = nfsd_getxattr(dentry, key, &buf);
+ if (!buflen)
+ buflen = -ENODATA;
+ if (buflen <= 0)
+ return ERR_PTR(buflen);
pacl = posix_acl_from_xattr(buf, buflen);
- out:
kfree(buf);
return pacl;
- out_err:
- pacl = ERR_PTR(error);
- goto out;
}
int
@@ -717,33 +705,40 @@ nfsd_close(struct file *filp)
* As this calls fsync (not fdatasync) there is no need for a write_inode
* after it.
*/
-static inline void nfsd_dosync(struct file *filp, struct dentry *dp,
- struct file_operations *fop)
+static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
+ struct file_operations *fop)
{
struct inode *inode = dp->d_inode;
int (*fsync) (struct file *, struct dentry *, int);
+ int err;
+
+ err = filemap_fdatawrite(inode->i_mapping);
+ if (err == 0 && fop && (fsync = fop->fsync))
+ err = fsync(filp, dp, 0);
+ if (err == 0)
+ err = filemap_fdatawait(inode->i_mapping);
- filemap_fdatawrite(inode->i_mapping);
- if (fop && (fsync = fop->fsync))
- fsync(filp, dp, 0);
- filemap_fdatawait(inode->i_mapping);
+ return err;
}
-static void
+static int
nfsd_sync(struct file *filp)
{
+ int err;
struct inode *inode = filp->f_dentry->d_inode;
dprintk("nfsd: sync file %s\n", filp->f_dentry->d_name.name);
- down(&inode->i_sem);
- nfsd_dosync(filp, filp->f_dentry, filp->f_op);
- up(&inode->i_sem);
+ mutex_lock(&inode->i_mutex);
+ err=nfsd_dosync(filp, filp->f_dentry, filp->f_op);
+ mutex_unlock(&inode->i_mutex);
+
+ return err;
}
-void
+int
nfsd_sync_dir(struct dentry *dp)
{
- nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
+ return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
}
/*
@@ -820,7 +815,7 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset
return size;
}
-static inline int
+static int
nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
{
@@ -874,7 +869,17 @@ out:
return err;
}
-static inline int
+static void kill_suid(struct dentry *dentry)
+{
+ struct iattr ia;
+ ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID;
+
+ mutex_lock(&dentry->d_inode->i_mutex);
+ notify_change(dentry, &ia);
+ mutex_unlock(&dentry->d_inode->i_mutex);
+}
+
+static int
nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen,
unsigned long cnt, int *stablep)
@@ -886,9 +891,9 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
int err = 0;
int stable = *stablep;
+#ifdef MSNFS
err = nfserr_perm;
-#ifdef MSNFS
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
(!lock_may_write(file->f_dentry->d_inode, offset, cnt)))
goto out;
@@ -927,14 +932,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
}
/* clear setuid/setgid flag after write */
- if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) {
- struct iattr ia;
- ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID;
-
- down(&inode->i_sem);
- notify_change(dentry, &ia);
- up(&inode->i_sem);
- }
+ if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))
+ kill_suid(dentry);
if (err >= 0 && stable) {
static ino_t last_ino;
@@ -962,7 +961,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
if (inode->i_state & I_DIRTY) {
dprintk("nfsd: write sync %d\n", current->pid);
- nfsd_sync(file);
+ err=nfsd_sync(file);
}
#if 0
wake_up(&inode->i_wait);
@@ -1066,7 +1065,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
return err;
if (EX_ISSYNC(fhp->fh_export)) {
if (file->f_op && file->f_op->fsync) {
- nfsd_sync(file);
+ err = nfserrno(nfsd_sync(file));
} else {
err = nfserr_notsupp;
}
@@ -1134,7 +1133,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
"nfsd_create: parent %s/%s not locked!\n",
dentry->d_parent->d_name.name,
dentry->d_name.name);
- err = -EIO;
+ err = nfserr_io;
goto out;
}
}
@@ -1177,7 +1176,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export)) {
- nfsd_sync_dir(dentry);
+ err = nfserrno(nfsd_sync_dir(dentry));
write_inode_now(dchild->d_inode, 1);
}
@@ -1187,9 +1186,11 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
* send along the gid when it tries to implement setgid
* directories via NFS.
*/
- err = 0;
- if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
- err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
+ int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ if (err2)
+ err = err2;
+ }
/*
* Update the file handle to get the new inode info.
*/
@@ -1308,17 +1309,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export)) {
- nfsd_sync_dir(dentry);
+ err = nfserrno(nfsd_sync_dir(dentry));
/* setattr will sync the child (or not) */
}
- /*
- * Update the filehandle to get the new inode info.
- */
- err = fh_update(resfhp);
- if (err)
- goto out;
-
if (createmode == NFS3_CREATE_EXCLUSIVE) {
/* Cram the verifier into atime/mtime/mode */
iap->ia_valid = ATTR_MTIME|ATTR_ATIME
@@ -1339,8 +1333,17 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
* implement setgid directories via NFS. Clear out all that cruft.
*/
set_attr:
- if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0)
- err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) {
+ int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ if (err2)
+ err = err2;
+ }
+
+ /*
+ * Update the filehandle to get the new inode info.
+ */
+ if (!err)
+ err = fh_update(resfhp);
out:
fh_unlock(fhp);
@@ -1449,10 +1452,10 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
} else
err = vfs_symlink(dentry->d_inode, dnew, path, mode);
- if (!err) {
+ if (!err)
if (EX_ISSYNC(fhp->fh_export))
- nfsd_sync_dir(dentry);
- } else
+ err = nfsd_sync_dir(dentry);
+ if (err)
err = nfserrno(err);
fh_unlock(fhp);
@@ -1508,7 +1511,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
err = vfs_link(dold, dirp, dnew);
if (!err) {
if (EX_ISSYNC(ffhp->fh_export)) {
- nfsd_sync_dir(ddir);
+ err = nfserrno(nfsd_sync_dir(ddir));
write_inode_now(dest, 1);
}
} else {
@@ -1592,13 +1595,14 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
((atomic_read(&odentry->d_count) > 1)
|| (atomic_read(&ndentry->d_count) > 1))) {
- err = nfserr_perm;
+ err = -EPERM;
} else
#endif
err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
- nfsd_sync_dir(tdentry);
- nfsd_sync_dir(fdentry);
+ err = nfsd_sync_dir(tdentry);
+ if (!err)
+ err = nfsd_sync_dir(fdentry);
}
out_dput_new:
@@ -1663,7 +1667,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
#ifdef MSNFS
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
(atomic_read(&rdentry->d_count) > 1)) {
- err = nfserr_perm;
+ err = -EPERM;
} else
#endif
err = vfs_unlink(dirp, rdentry);
@@ -1673,17 +1677,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
dput(rdentry);
- if (err)
- goto out_nfserr;
- if (EX_ISSYNC(fhp->fh_export))
- nfsd_sync_dir(dentry);
-
-out:
- return err;
+ if (err == 0 &&
+ EX_ISSYNC(fhp->fh_export))
+ err = nfsd_sync_dir(dentry);
out_nfserr:
err = nfserrno(err);
- goto out;
+out:
+ return err;
}
/*
@@ -1874,39 +1875,25 @@ nfsd_get_posix_acl(struct svc_fh *fhp, int type)
ssize_t size;
struct posix_acl *acl;
- if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr)
+ if (!IS_POSIXACL(inode))
+ return ERR_PTR(-EOPNOTSUPP);
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = POSIX_ACL_XATTR_DEFAULT;
+ break;
+ default:
return ERR_PTR(-EOPNOTSUPP);
- switch(type) {
- case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
- break;
- case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
- break;
- default:
- return ERR_PTR(-EOPNOTSUPP);
}
- size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0);
+ size = nfsd_getxattr(fhp->fh_dentry, name, &value);
+ if (size < 0)
+ return ERR_PTR(size);
- if (size < 0) {
- acl = ERR_PTR(size);
- goto getout;
- } else if (size > 0) {
- value = kmalloc(size, GFP_KERNEL);
- if (!value) {
- acl = ERR_PTR(-ENOMEM);
- goto getout;
- }
- size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size);
- if (size < 0) {
- acl = ERR_PTR(size);
- goto getout;
- }
- }
acl = posix_acl_from_xattr(value, size);
-
-getout:
kfree(value);
return acl;
}
@@ -1947,16 +1934,13 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
} else
size = 0;
- if (!fhp->fh_locked)
- fh_lock(fhp); /* unlocking is done automatically */
if (size)
- error = inode->i_op->setxattr(fhp->fh_dentry, name,
- value, size, 0);
+ error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0);
else {
if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
error = 0;
else {
- error = inode->i_op->removexattr(fhp->fh_dentry, name);
+ error = vfs_removexattr(fhp->fh_dentry, name);
if (error == -ENODATA)
error = 0;
}