Commit d6846e36 authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] NFSv4 server - open-downgrade

From: "William A.(Andy) Adamson" <andros@citi.umich.edu>

Add the opendowngrade call with share state processing. it includes
nfs4_preprocess_stateid_op() which will be used in read and write
state processing.
parent 3bfa9cb8
......@@ -602,6 +602,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
case OP_OPEN_CONFIRM:
op->status = nfsd4_open_confirm(rqstp, &current_fh, &op->u.open_confirm);
break;
case OP_OPEN_DOWNGRADE:
op->status = nfsd4_open_downgrade(rqstp, &current_fh, &op->u.open_downgrade);
break;
case OP_PUTFH:
op->status = nfsd4_putfh(rqstp, &current_fh, &op->u.putfh);
break;
......
......@@ -939,6 +939,30 @@ nfs4_init_ino(nfs4_ino_desc_t *ino, struct svc_fh *fhp)
ino->generation = inode->i_generation;
}
int
nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
{
nfs4_ino_desc_t ino;
unsigned int fi_hashval;
struct nfs4_file *fp;
struct nfs4_stateid *stp;
struct list_head *pos, *next;
dprintk("NFSD: nfs4_share_conflict\n");
nfs4_init_ino(&ino, current_fh);
fi_hashval = file_hashval(&ino);
if (find_file(fi_hashval, &ino, &fp)) {
/* Search for conflicting share reservations */
list_for_each_safe(pos, next, &fp->fi_perfile) {
stp = list_entry(pos, struct nfs4_stateid, st_perfile);
if (stp->st_share_deny & deny_type)
return nfserr_share_denied;
}
}
return nfs_ok;
}
static inline int
nfs4_file_upgrade(struct file *filp, unsigned int share_access)
{
......@@ -954,6 +978,15 @@ int status;
return nfs_ok;
}
static inline void
nfs4_file_downgrade(struct file *filp, unsigned int share_access)
{
if (share_access & NFS4_SHARE_ACCESS_WRITE) {
put_write_access(filp->f_dentry->d_inode);
filp->f_mode = FMODE_READ;
}
}
/*
* nfsd4_process_open1()
......@@ -1280,6 +1313,59 @@ STALE_STATEID(stateid_t *stateid)
}
/*
* Checks for stateid operations
*/
int
nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct nfs4_stateid **stpp)
{
struct nfs4_stateid *stp;
int status;
dprintk("NFSD: preprocess_stateid_op:stateid = (%08x/%08x/%08x/%08x)\n",
stateid->si_boot, stateid->si_stateownerid,
stateid->si_fileid, stateid->si_generation);
*stpp = NULL;
/* STALE STATEID */
status = nfserr_stale_stateid;
if (STALE_STATEID(stateid))
goto out;
/* BAD STATEID */
status = nfserr_bad_stateid;
if (!(stp = find_stateid(stateid))) {
dprintk("NFSD: process stateid: no open stateid!\n");
goto out;
}
if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
goto out;
}
if (!stp->st_stateowner->so_confirmed) {
dprintk("process_stateid: lockowner not confirmed yet!\n");
goto out;
}
if (stateid->si_generation > stp->st_stateid.si_generation) {
dprintk("process_stateid: future stateid?!\n");
goto out;
}
/* OLD STATEID */
status = nfserr_old_stateid;
if (stateid->si_generation < stp->st_stateid.si_generation) {
dprintk("process_stateid: old stateid!\n");
goto out;
}
*stpp = stp;
status = nfs_ok;
renew_client(stp->st_stateowner->so_client);
out:
return status;
}
/*
* Checks for sequence id mutating operations.
*
......@@ -1398,8 +1484,9 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
struct nfs4_stateowner *sop;
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_open_confirm on file %s\n",
current_fh->fh_dentry->d_name);
dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
current_fh->fh_dentry->d_name.len,
current_fh->fh_dentry->d_name.name);
oc->oc_stateowner = NULL;
down(&client_sema); /* XXX need finer grained locking */
......@@ -1425,6 +1512,45 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
up(&client_sema);
return status;
}
int
nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
{
int status;
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
current_fh->fh_dentry->d_name.len,
current_fh->fh_dentry->d_name.name);
down(&client_sema); /* XXX need finer grained locking */
if ((status = nfs4_preprocess_seqid_op(current_fh, od->od_seqid,
&od->od_stateid,
CHECK_FH, &od->od_stateowner, &stp)))
goto out;
status = nfserr_inval;
if (od->od_share_access & ~stp->st_share_access) {
dprintk("NFSD:access not a subset current=%08x, desired=%08x\n",
stp->st_share_access, od->od_share_access);
goto out;
}
if (od->od_share_deny & ~stp->st_share_deny) {
dprintk("NFSD:deny not a subset current=%08x, desired=%08x\n",
stp->st_share_deny, od->od_share_deny);
goto out;
}
nfs4_file_downgrade(&stp->st_vfs_file,
stp->st_share_access & ~od->od_share_access);
stp->st_share_access = od->od_share_access;
stp->st_share_deny = od->od_share_deny;
update_stateid(&stp->st_stateid);
memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
status = nfs_ok;
out:
up(&client_sema);
return status;
}
int
nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
{
......
......@@ -672,6 +672,21 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con
DECODE_TAIL;
}
static int
nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
{
DECODE_HEAD;
READ_BUF(4 + sizeof(stateid_t));
READ32(open_down->od_stateid.si_generation);
COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t));
READ32(open_down->od_seqid);
READ32(open_down->od_share_access);
READ32(open_down->od_share_deny);
DECODE_TAIL;
}
static int
nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
{
......@@ -969,6 +984,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
case OP_OPEN_CONFIRM:
op->status = nfsd4_decode_open_confirm(argp, &op->u.open_confirm);
break;
case OP_OPEN_DOWNGRADE:
op->status = nfsd4_decode_open_downgrade(argp, &op->u.open_downgrade);
break;
case OP_PUTFH:
op->status = nfsd4_decode_putfh(argp, &op->u.putfh);
break;
......@@ -1747,6 +1765,21 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, int nfserr, struct nfs
ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
}
static int
nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_downgrade *od)
{
ENCODE_HEAD;
if (!nfserr) {
RESERVE_SPACE(sizeof(stateid_t));
WRITE32(od->od_stateid.si_generation);
WRITEMEM(&od->od_stateid.si_opaque, sizeof(stateid_opaque_t));
ADJUST_ARGS();
}
ENCODE_SEQID_OP_TAIL(od->od_stateowner);
}
static int
nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read)
{
......@@ -2062,6 +2095,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
case OP_OPEN_CONFIRM:
nfsd4_encode_open_confirm(resp, op->status, &op->u.open_confirm);
break;
case OP_OPEN_DOWNGRADE:
nfsd4_encode_open_downgrade(resp, op->status, &op->u.open_downgrade);
break;
case OP_PUTFH:
break;
case OP_PUTROOTFH:
......
......@@ -155,6 +155,15 @@ struct nfsd4_open_confirm {
struct nfs4_stateowner * oc_stateowner; /* response */
};
struct nfsd4_open_downgrade {
stateid_t od_stateid;
u32 od_seqid;
u32 od_share_access;
u32 od_share_deny;
struct nfs4_stateowner *od_stateowner;
};
struct nfsd4_read {
stateid_t rd_stateid; /* request */
u64 rd_offset; /* request */
......@@ -261,6 +270,7 @@ struct nfsd4_op {
struct nfsd4_verify nverify;
struct nfsd4_open open;
struct nfsd4_open_confirm open_confirm;
struct nfsd4_open_downgrade open_downgrade;
struct nfsd4_putfh putfh;
struct nfsd4_read read;
struct nfsd4_readdir readdir;
......@@ -343,7 +353,8 @@ extern int nfsd4_open_confirm(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open_confirm *oc);
extern int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh,
struct nfsd4_close *close);
extern int nfsd4_open_downgrade(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open_downgrade *od);
#endif
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment