#include <linux/nfs4.h>
#include <linux/nfsd/state.h>
#include <linux/nfsd/xdr4.h>
+#include <linux/nfs4_acl.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC
{
int status;
- dprintk("NFSD: do_open_fhandle\n");
+ /* Only reclaims from previously confirmed clients are valid */
+ if ((status = nfs4_check_open_reclaim(&open->op_clientid)))
+ return status;
- /* we don't know the target directory, and therefore can not
+ /* We don't know the target directory, and therefore can not
* set the change info
*/
}
-/*
- * nfs4_unlock_state() called in encode
- */
static inline int
nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
return nfserr_grace;
- if (nfs4_in_no_grace() &&
- open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
return nfserr_no_grace;
/* This check required by spec. */
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
return nfserr_inval;
- open->op_stateowner = NULL;
nfs4_lock_state();
/* check seqid for replay. set nfs4_owner */
status = NFSERR_REPLAY_ME;
}
if (status)
- return status;
+ goto out;
if (open->op_claim_type == NFS4_OPEN_CLAIM_NULL) {
/*
* This block of code will (1) set CURRENT_FH to the file being opened,
*/
status = do_open_lookup(rqstp, current_fh, open);
if (status)
- return status;
+ goto out;
} else if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
/*
* The CURRENT_FH is already set to the file being opened. This
*/
status = do_open_fhandle(rqstp, current_fh, open);
if (status)
- return status;
+ goto out;
} else {
printk("NFSD: unsupported OPEN claim type\n");
- return nfserr_inval;
+ status = nfserr_inval;
+ goto out;
}
/*
* nfsd4_process_open2() does the actual opening of the file. If
* set, (2) sets open->op_stateid, (3) sets open->op_delegation.
*/
status = nfsd4_process_open2(rqstp, current_fh, open);
- if (status)
- return status;
- return 0;
+out:
+ if (open->op_stateowner)
+ nfs4_get_stateowner(open->op_stateowner);
+ nfs4_unlock_state();
+ return status;
}
/*
status = exp_pseudoroot(rqstp->rq_client, current_fh,
&rqstp->rq_chandle);
if (!status)
- status = nfsd_setuser(rqstp, current_fh->fh_export);
+ status = nfserrno(nfsd_setuser(rqstp, current_fh->fh_export));
return status;
}
return status;
}
-static inline int
+static int
nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create)
{
struct svc_fh resfh;
break;
default:
- BUG();
+ status = nfserr_badtype;
}
if (!status) {
return status;
}
-static inline int
+static int
nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
{
struct svc_fh tmp_fh;
return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh);
}
-static inline int
-access_bits_permit_read(unsigned long access_bmap)
-{
- return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) ||
- test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);
-}
-
-static inline int
-access_bits_permit_write(unsigned long access_bmap)
-{
- return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) ||
- test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);
-}
-
static inline int
nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
{
- struct nfs4_stateid *stp;
int status;
/* no need to check permission - this will be done in nfsd_read() */
}
/* check stateid */
if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid,
- CHECK_FH | RDWR_STATE, &stp))) {
+ CHECK_FH | RD_STATE))) {
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
goto out;
}
- status = nfserr_openmode;
- if (!access_bits_permit_read(stp->st_access_bmap)) {
- dprintk("NFSD: nfsd4_read: file not opened for read!\n");
- goto out;
- }
status = nfs_ok;
out:
nfs4_unlock_state();
static inline int
nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
{
- struct nfs4_stateid *stp;
int status = nfs_ok;
if (nfs4_in_grace())
status = nfserr_bad_stateid;
if (ZERO_STATEID(&setattr->sa_stateid) || ONE_STATEID(&setattr->sa_stateid)) {
dprintk("NFSD: nfsd4_setattr: magic stateid!\n");
- return status;
+ goto out;
}
nfs4_lock_state();
if ((status = nfs4_preprocess_stateid_op(current_fh,
&setattr->sa_stateid,
- CHECK_FH | RDWR_STATE, &stp))) {
+ CHECK_FH | WR_STATE))) {
dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
- goto out;
- }
- status = nfserr_openmode;
- if (!access_bits_permit_write(stp->st_access_bmap)) {
- dprintk("NFSD: nfsd4_setattr: not opened for write!\n");
- goto out;
+ goto out_unlock;
}
nfs4_unlock_state();
}
- return (nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, 0, (time_t)0));
+ status = nfs_ok;
+ if (setattr->sa_acl != NULL)
+ status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl);
+ if (status)
+ goto out;
+ status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr,
+ 0, (time_t)0);
out:
+ return status;
+out_unlock:
nfs4_unlock_state();
return status;
}
static inline int
nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write)
{
- struct nfs4_stateid *stp;
stateid_t *stateid = &write->wr_stateid;
u32 *p;
int status = nfs_ok;
goto zero_stateid;
}
if ((status = nfs4_preprocess_stateid_op(current_fh, stateid,
- CHECK_FH | RDWR_STATE, &stp))) {
+ CHECK_FH | WR_STATE))) {
dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
goto out;
}
- status = nfserr_openmode;
- if (!access_bits_permit_write(stp->st_access_bmap)) {
- dprintk("NFSD: nfsd4_write: file not open for write!\n");
- goto out;
- }
-
zero_stateid:
+
nfs4_unlock_state();
write->wr_bytes_written = write->wr_buflen;
write->wr_how_written = write->wr_stable_how;
struct nfsd4_compoundres *resp)
{
struct nfsd4_op *op;
- struct svc_fh current_fh;
- struct svc_fh save_fh;
+ struct svc_fh *current_fh = NULL;
+ struct svc_fh *save_fh = NULL;
+ struct nfs4_stateowner *replay_owner = NULL;
int slack_space; /* in words, not bytes! */
int status;
- fh_init(¤t_fh, NFS4_FHSIZE);
- fh_init(&save_fh, NFS4_FHSIZE);
+ status = nfserr_resource;
+ current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL);
+ if (current_fh == NULL)
+ goto out;
+ fh_init(current_fh, NFS4_FHSIZE);
+ save_fh = kmalloc(sizeof(*save_fh), GFP_KERNEL);
+ if (save_fh == NULL)
+ goto out;
+ fh_init(save_fh, NFS4_FHSIZE);
resp->xbuf = &rqstp->rq_res;
resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len;
* SETATTR NOFILEHANDLE error handled in nfsd4_setattr
* due to required returned bitmap argument
*/
- if ((!current_fh.fh_dentry) &&
+ if ((!current_fh->fh_dentry) &&
!((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) ||
(op->opnum == OP_SETCLIENTID) ||
(op->opnum == OP_SETCLIENTID_CONFIRM) ||
}
switch (op->opnum) {
case OP_ACCESS:
- op->status = nfsd4_access(rqstp, ¤t_fh, &op->u.access);
+ op->status = nfsd4_access(rqstp, current_fh, &op->u.access);
break;
case OP_CLOSE:
- op->status = nfsd4_close(rqstp, ¤t_fh, &op->u.close);
- if (op->u.close.cl_stateowner)
- op->replay =
- &op->u.close.cl_stateowner->so_replay;
+ op->status = nfsd4_close(rqstp, current_fh, &op->u.close);
+ replay_owner = op->u.close.cl_stateowner;
break;
case OP_COMMIT:
- op->status = nfsd4_commit(rqstp, ¤t_fh, &op->u.commit);
+ op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit);
break;
case OP_CREATE:
- op->status = nfsd4_create(rqstp, ¤t_fh, &op->u.create);
+ op->status = nfsd4_create(rqstp, current_fh, &op->u.create);
+ break;
+ case OP_DELEGRETURN:
+ op->status = nfsd4_delegreturn(rqstp, current_fh, &op->u.delegreturn);
break;
case OP_GETATTR:
- op->status = nfsd4_getattr(rqstp, ¤t_fh, &op->u.getattr);
+ op->status = nfsd4_getattr(rqstp, current_fh, &op->u.getattr);
break;
case OP_GETFH:
- op->status = nfsd4_getfh(¤t_fh, &op->u.getfh);
+ op->status = nfsd4_getfh(current_fh, &op->u.getfh);
break;
case OP_LINK:
- op->status = nfsd4_link(rqstp, ¤t_fh, &save_fh, &op->u.link);
+ op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link);
break;
case OP_LOCK:
- op->status = nfsd4_lock(rqstp, ¤t_fh, &op->u.lock);
- if (op->u.lock.lk_stateowner)
- op->replay =
- &op->u.lock.lk_stateowner->so_replay;
+ op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock);
+ replay_owner = op->u.lock.lk_stateowner;
break;
case OP_LOCKT:
- op->status = nfsd4_lockt(rqstp, ¤t_fh, &op->u.lockt);
+ op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt);
break;
case OP_LOCKU:
- op->status = nfsd4_locku(rqstp, ¤t_fh, &op->u.locku);
- if (op->u.locku.lu_stateowner)
- op->replay =
- &op->u.locku.lu_stateowner->so_replay;
+ op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku);
+ replay_owner = op->u.locku.lu_stateowner;
break;
case OP_LOOKUP:
- op->status = nfsd4_lookup(rqstp, ¤t_fh, &op->u.lookup);
+ op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup);
break;
case OP_LOOKUPP:
- op->status = nfsd4_lookupp(rqstp, ¤t_fh);
+ op->status = nfsd4_lookupp(rqstp, current_fh);
break;
case OP_NVERIFY:
- op->status = nfsd4_verify(rqstp, ¤t_fh, &op->u.nverify);
+ op->status = nfsd4_verify(rqstp, current_fh, &op->u.nverify);
if (op->status == nfserr_not_same)
op->status = nfs_ok;
break;
case OP_OPEN:
- op->status = nfsd4_open(rqstp, ¤t_fh, &op->u.open);
- if (op->u.open.op_stateowner)
- op->replay =
- &op->u.open.op_stateowner->so_replay;
+ op->status = nfsd4_open(rqstp, current_fh, &op->u.open);
+ replay_owner = op->u.open.op_stateowner;
break;
case OP_OPEN_CONFIRM:
- op->status = nfsd4_open_confirm(rqstp, ¤t_fh, &op->u.open_confirm);
- if (op->u.open_confirm.oc_stateowner)
- op->replay =
- &op->u.open_confirm.oc_stateowner->so_replay;
+ op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm);
+ replay_owner = op->u.open_confirm.oc_stateowner;
break;
case OP_OPEN_DOWNGRADE:
- op->status = nfsd4_open_downgrade(rqstp, ¤t_fh, &op->u.open_downgrade);
- if (op->u.open_downgrade.od_stateowner)
- op->replay =
- &op->u.open_downgrade.od_stateowner->so_replay;
+ op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade);
+ replay_owner = op->u.open_downgrade.od_stateowner;
break;
case OP_PUTFH:
- op->status = nfsd4_putfh(rqstp, ¤t_fh, &op->u.putfh);
+ op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh);
break;
case OP_PUTROOTFH:
- op->status = nfsd4_putrootfh(rqstp, ¤t_fh);
+ op->status = nfsd4_putrootfh(rqstp, current_fh);
break;
case OP_READ:
- op->status = nfsd4_read(rqstp, ¤t_fh, &op->u.read);
+ op->status = nfsd4_read(rqstp, current_fh, &op->u.read);
break;
case OP_READDIR:
- op->status = nfsd4_readdir(rqstp, ¤t_fh, &op->u.readdir);
+ op->status = nfsd4_readdir(rqstp, current_fh, &op->u.readdir);
break;
case OP_READLINK:
- op->status = nfsd4_readlink(rqstp, ¤t_fh, &op->u.readlink);
+ op->status = nfsd4_readlink(rqstp, current_fh, &op->u.readlink);
break;
case OP_REMOVE:
- op->status = nfsd4_remove(rqstp, ¤t_fh, &op->u.remove);
+ op->status = nfsd4_remove(rqstp, current_fh, &op->u.remove);
break;
case OP_RENAME:
- op->status = nfsd4_rename(rqstp, ¤t_fh, &save_fh, &op->u.rename);
+ op->status = nfsd4_rename(rqstp, current_fh, save_fh, &op->u.rename);
break;
case OP_RENEW:
op->status = nfsd4_renew(&op->u.renew);
break;
case OP_RESTOREFH:
- op->status = nfsd4_restorefh(¤t_fh, &save_fh);
+ op->status = nfsd4_restorefh(current_fh, save_fh);
break;
case OP_SAVEFH:
- op->status = nfsd4_savefh(¤t_fh, &save_fh);
+ op->status = nfsd4_savefh(current_fh, save_fh);
break;
case OP_SETATTR:
- op->status = nfsd4_setattr(rqstp, ¤t_fh, &op->u.setattr);
+ op->status = nfsd4_setattr(rqstp, current_fh, &op->u.setattr);
break;
case OP_SETCLIENTID:
op->status = nfsd4_setclientid(rqstp, &op->u.setclientid);
op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm);
break;
case OP_VERIFY:
- op->status = nfsd4_verify(rqstp, ¤t_fh, &op->u.verify);
+ op->status = nfsd4_verify(rqstp, current_fh, &op->u.verify);
if (op->status == nfserr_same)
op->status = nfs_ok;
break;
case OP_WRITE:
- op->status = nfsd4_write(rqstp, ¤t_fh, &op->u.write);
+ op->status = nfsd4_write(rqstp, current_fh, &op->u.write);
break;
case OP_RELEASE_LOCKOWNER:
op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner);
encode_op:
if (op->status == NFSERR_REPLAY_ME) {
+ op->replay = &replay_owner->so_replay;
nfsd4_encode_replay(resp, op);
status = op->status = op->replay->rp_status;
} else {
nfsd4_encode_operation(resp, op);
status = op->status;
}
+ if (replay_owner && (replay_owner != (void *)(-1))) {
+ nfs4_put_stateowner(replay_owner);
+ replay_owner = NULL;
+ }
}
out:
- if (args->ops != args->iops) {
- kfree(args->ops);
- args->ops = args->iops;
- }
- if (args->tmpp) {
- kfree(args->tmpp);
- args->tmpp = NULL;
- }
- while (args->to_free) {
- struct tmpbuf *tb = args->to_free;
- args->to_free = tb->next;
- kfree(tb->buf);
- kfree(tb);
- }
- fh_put(¤t_fh);
- fh_put(&save_fh);
+ nfsd4_release_compoundargs(args);
+ if (current_fh)
+ fh_put(current_fh);
+ kfree(current_fh);
+ if (save_fh)
+ fh_put(save_fh);
+ kfree(save_fh);
return status;
}