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

[PATCH] knfsd: nfsd byte range locking - LOCK

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

This implements the nfsv4 LOCK operation.
parent 902773e5
......@@ -377,7 +377,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read
}
/* check stateid */
if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid,
CHECK_FH, &stp))) {
CHECK_FH | RDWR_STATE, &stp))) {
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
goto out;
}
......@@ -467,7 +467,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se
nfs4_lock_state();
if ((status = nfs4_preprocess_stateid_op(current_fh,
&setattr->sa_stateid,
CHECK_FH, &stp))) {
CHECK_FH | RDWR_STATE, &stp))) {
dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
goto out;
}
......@@ -507,7 +507,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
goto zero_stateid;
}
if ((status = nfs4_preprocess_stateid_op(current_fh, stateid,
CHECK_FH, &stp))) {
CHECK_FH | RDWR_STATE, &stp))) {
dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
goto out;
}
......@@ -681,6 +681,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
case OP_LINK:
op->status = nfsd4_link(rqstp, &current_fh, &save_fh, &op->u.link);
break;
case OP_LOCK:
op->status = nfsd4_lock(rqstp, &current_fh, &op->u.lock);
break;
case OP_LOOKUP:
op->status = nfsd4_lookup(rqstp, &current_fh, &op->u.lookup);
break;
......
This diff is collapsed.
......@@ -567,6 +567,44 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
DECODE_TAIL;
}
static int
nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
{
DECODE_HEAD;
/*
* type, reclaim(boolean), offset, length, new_lock_owner(boolean)
*/
READ_BUF(28);
READ32(lock->lk_type);
if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT))
goto xdr_error;
READ32(lock->lk_reclaim);
READ64(lock->lk_offset);
READ64(lock->lk_length);
READ32(lock->lk_is_new);
if (lock->lk_is_new) {
READ_BUF(36);
READ32(lock->lk_new_open_seqid);
READ32(lock->lk_new_open_stateid.si_generation);
COPYMEM(&lock->lk_new_open_stateid.si_opaque, sizeof(stateid_opaque_t));
READ32(lock->lk_new_lock_seqid);
COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t));
READ32(lock->lk_new_owner.len);
READ_BUF(lock->lk_new_owner.len);
READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len);
} else {
READ_BUF(20);
READ32(lock->lk_old_lock_stateid.si_generation);
COPYMEM(&lock->lk_old_lock_stateid.si_opaque, sizeof(stateid_opaque_t));
READ32(lock->lk_old_lock_seqid);
}
DECODE_TAIL;
}
static int
nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
{
......@@ -989,6 +1027,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
case OP_LINK:
op->status = nfsd4_decode_link(argp, &op->u.link);
break;
case OP_LOCK:
op->status = nfsd4_decode_lock(argp, &op->u.lock);
break;
case OP_LOOKUP:
op->status = nfsd4_decode_lookup(argp, &op->u.lookup);
break;
......@@ -1709,6 +1750,42 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, int nfserr, struct svc_fh *fh
}
}
/*
* Including all fields other than the name, a LOCK4denied structure requires
* 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes.
*/
static void
nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld)
{
ENCODE_HEAD;
RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop->so_owner.len));
WRITE64(ld->ld_start);
WRITE64(ld->ld_length);
WRITE32(ld->ld_type);
WRITEMEM(&ld->ld_sop->so_client->cl_clientid, 8);
WRITE32(ld->ld_sop->so_owner.len);
WRITEMEM(ld->ld_sop->so_owner.data, ld->ld_sop->so_owner.len);
ADJUST_ARGS();
}
static void
nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock)
{
ENCODE_SEQID_OP_HEAD;
if (!nfserr) {
RESERVE_SPACE(4 + sizeof(stateid_t));
WRITE32(lock->lk_resp_stateid.si_generation);
WRITEMEM(&lock->lk_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
ADJUST_ARGS();
} else if (nfserr == nfserr_denied)
nfsd4_encode_lock_denied(resp, &lock->lk_denied);
ENCODE_SEQID_OP_TAIL(lock->lk_stateowner);
}
static void
nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link *link)
{
......@@ -2119,6 +2196,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
case OP_LINK:
nfsd4_encode_link(resp, op->status, &op->u.link);
break;
case OP_LOCK:
nfsd4_encode_lock(resp, op->status, &op->u.lock);
break;
case OP_LOOKUP:
break;
case OP_LOOKUPP:
......
......@@ -134,6 +134,15 @@ enum open_delegation_type4 {
NFS4_OPEN_DELEGATE_WRITE = 2
};
enum lock_type4 {
NFS4_UNLOCK_LT = 0,
NFS4_READ_LT = 1,
NFS4_WRITE_LT = 2,
NFS4_READW_LT = 3,
NFS4_WRITEW_LT = 4
};
/* Mandatory Attributes */
#define FATTR4_WORD0_SUPPORTED_ATTRS (1)
#define FATTR4_WORD0_TYPE (1 << 1)
......
......@@ -172,6 +172,8 @@ void nfsd_lockd_shutdown(void);
#define nfserr_serverfault __constant_htonl(NFSERR_SERVERFAULT)
#define nfserr_badtype __constant_htonl(NFSERR_BADTYPE)
#define nfserr_jukebox __constant_htonl(NFSERR_JUKEBOX)
#define nfserr_denied __constant_htonl(NFSERR_DENIED)
#define nfserr_deadlock __constant_htonl(NFSERR_DEADLOCK)
#define nfserr_expired __constant_htonl(NFSERR_EXPIRED)
#define nfserr_bad_cookie __constant_htonl(NFSERR_BAD_COOKIE)
#define nfserr_same __constant_htonl(NFSERR_SAME)
......
......@@ -117,16 +117,24 @@ struct nfs4_replay {
};
/*
* nfs4_stateowner can either be an open_owner, or (eventually) a lock_owner
* nfs4_stateowner can either be an open_owner, or a lock_owner
*
* o so_perfilestate list is used to ensure no dangling nfs4_stateid
* reverences when we release a stateowner.
* so_idhash: stateid_hashtbl[] for open owner, lockstateid_hashtbl[]
* for lock_owner
* so_strhash: ownerstr_hashtbl[] for open_owner, lock_ownerstr_hashtbl[]
* for lock_owner
* so_perclient: nfs4_client->cl_perclient entry - used when nfs4_client
* struct is reaped.
* so_perfilestate: heads the list of nfs4_stateid (either open or lock)
* and is used to ensure no dangling nfs4_stateid references when we
* release a stateowner.
*/
struct nfs4_stateowner {
struct list_head so_idhash; /* hash by so_id */
struct list_head so_strhash; /* hash by op_name */
struct list_head so_perclient; /* nfs4_client->cl_perclient */
struct list_head so_perfilestate; /* list: nfs4_stateid */
int so_is_open_owner; /* 1=openowner,0=lockowner */
u32 so_id;
struct nfs4_client * so_client;
u32 so_seqid;
......@@ -152,12 +160,18 @@ struct nfs4_file {
* nfs4_stateid can either be an open stateid or (eventually) a lock stateid
*
* (open)nfs4_stateid: one per (open)nfs4_stateowner, nfs4_file
*
* st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry
* st_perfile: file_hashtbl[] entry.
* st_perfile_state: nfs4_stateowner->so_perfilestate
* st_share_access: used only for open stateid
* st_share_deny: used only for open stateid
*/
struct nfs4_stateid {
struct list_head st_hash;
struct list_head st_hash;
struct list_head st_perfile;
struct list_head st_perfilestate;
struct list_head st_perfilestate;
struct nfs4_stateowner * st_stateowner;
struct nfs4_file * st_file;
stateid_t st_stateid;
......@@ -170,6 +184,9 @@ struct nfs4_stateid {
/* flags for preprocess_seqid_op() */
#define CHECK_FH 0x00000001
#define CONFIRM 0x00000002
#define OPEN_STATE 0x00000004
#define LOCK_STATE 0x00000008
#define RDWR_STATE 0x00000010
#define seqid_mutating_err(err) \
(((err) != nfserr_stale_clientid) && \
......
......@@ -40,6 +40,7 @@
#define _LINUX_NFSD_XDR4_H
#define NFSD4_MAX_TAGLEN 128
#define XDR_LEN(n) (((n) + 3) & ~3)
typedef u32 delegation_zero_t;
typedef u32 delegation_boot_t;
......@@ -111,6 +112,56 @@ struct nfsd4_link {
struct nfsd4_change_info li_cinfo; /* response */
};
struct nfsd4_lock_denied {
struct nfs4_stateowner *ld_sop;
u64 ld_start;
u64 ld_length;
u32 ld_type;
};
struct nfsd4_lock {
/* request */
u32 lk_type;
u32 lk_reclaim; /* boolean */
u64 lk_offset;
u64 lk_length;
u32 lk_is_new;
union {
struct {
u32 open_seqid;
stateid_t open_stateid;
u32 lock_seqid;
clientid_t clientid;
struct xdr_netobj owner;
} new;
struct {
stateid_t lock_stateid;
u32 lock_seqid;
} old;
} v;
/* response */
union {
struct {
stateid_t stateid;
} ok;
struct nfsd4_lock_denied denied;
} u;
struct nfs4_stateowner *lk_stateowner;
};
#define lk_new_open_seqid v.new.open_seqid
#define lk_new_open_stateid v.new.open_stateid
#define lk_new_lock_seqid v.new.lock_seqid
#define lk_new_clientid v.new.clientid
#define lk_new_owner v.new.owner
#define lk_old_lock_stateid v.old.lock_stateid
#define lk_old_lock_seqid v.old.lock_seqid
#define lk_rflags u.ok.rflags
#define lk_resp_stateid u.ok.stateid
#define lk_denied u.denied
struct nfsd4_lookup {
u32 lo_len; /* request */
char * lo_name; /* request */
......@@ -266,6 +317,7 @@ struct nfsd4_op {
struct nfsd4_getattr getattr;
struct svc_fh * getfh;
struct nfsd4_link link;
struct nfsd4_lock lock;
struct nfsd4_lookup lookup;
struct nfsd4_verify nverify;
struct nfsd4_open open;
......@@ -357,6 +409,8 @@ 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);
extern int nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh,
struct nfsd4_lock *lock);
#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