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 ...@@ -377,7 +377,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read
} }
/* check stateid */ /* check stateid */
if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_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"); dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
goto out; goto out;
} }
...@@ -467,7 +467,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se ...@@ -467,7 +467,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se
nfs4_lock_state(); nfs4_lock_state();
if ((status = nfs4_preprocess_stateid_op(current_fh, if ((status = nfs4_preprocess_stateid_op(current_fh,
&setattr->sa_stateid, &setattr->sa_stateid,
CHECK_FH, &stp))) { CHECK_FH | RDWR_STATE, &stp))) {
dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
goto out; goto out;
} }
...@@ -507,7 +507,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ ...@@ -507,7 +507,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
goto zero_stateid; goto zero_stateid;
} }
if ((status = nfs4_preprocess_stateid_op(current_fh, 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"); dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
goto out; goto out;
} }
...@@ -681,6 +681,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -681,6 +681,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
case OP_LINK: case OP_LINK:
op->status = nfsd4_link(rqstp, &current_fh, &save_fh, &op->u.link); op->status = nfsd4_link(rqstp, &current_fh, &save_fh, &op->u.link);
break; break;
case OP_LOCK:
op->status = nfsd4_lock(rqstp, &current_fh, &op->u.lock);
break;
case OP_LOOKUP: case OP_LOOKUP:
op->status = nfsd4_lookup(rqstp, &current_fh, &op->u.lookup); op->status = nfsd4_lookup(rqstp, &current_fh, &op->u.lookup);
break; break;
......
This diff is collapsed.
...@@ -567,6 +567,44 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) ...@@ -567,6 +567,44 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
DECODE_TAIL; 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 static int
nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
{ {
...@@ -989,6 +1027,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) ...@@ -989,6 +1027,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
case OP_LINK: case OP_LINK:
op->status = nfsd4_decode_link(argp, &op->u.link); op->status = nfsd4_decode_link(argp, &op->u.link);
break; break;
case OP_LOCK:
op->status = nfsd4_decode_lock(argp, &op->u.lock);
break;
case OP_LOOKUP: case OP_LOOKUP:
op->status = nfsd4_decode_lookup(argp, &op->u.lookup); op->status = nfsd4_decode_lookup(argp, &op->u.lookup);
break; break;
...@@ -1709,6 +1750,42 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, int nfserr, struct svc_fh *fh ...@@ -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 static void
nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link *link) 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) ...@@ -2119,6 +2196,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
case OP_LINK: case OP_LINK:
nfsd4_encode_link(resp, op->status, &op->u.link); nfsd4_encode_link(resp, op->status, &op->u.link);
break; break;
case OP_LOCK:
nfsd4_encode_lock(resp, op->status, &op->u.lock);
break;
case OP_LOOKUP: case OP_LOOKUP:
break; break;
case OP_LOOKUPP: case OP_LOOKUPP:
......
...@@ -134,6 +134,15 @@ enum open_delegation_type4 { ...@@ -134,6 +134,15 @@ enum open_delegation_type4 {
NFS4_OPEN_DELEGATE_WRITE = 2 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 */ /* Mandatory Attributes */
#define FATTR4_WORD0_SUPPORTED_ATTRS (1) #define FATTR4_WORD0_SUPPORTED_ATTRS (1)
#define FATTR4_WORD0_TYPE (1 << 1) #define FATTR4_WORD0_TYPE (1 << 1)
......
...@@ -172,6 +172,8 @@ void nfsd_lockd_shutdown(void); ...@@ -172,6 +172,8 @@ void nfsd_lockd_shutdown(void);
#define nfserr_serverfault __constant_htonl(NFSERR_SERVERFAULT) #define nfserr_serverfault __constant_htonl(NFSERR_SERVERFAULT)
#define nfserr_badtype __constant_htonl(NFSERR_BADTYPE) #define nfserr_badtype __constant_htonl(NFSERR_BADTYPE)
#define nfserr_jukebox __constant_htonl(NFSERR_JUKEBOX) #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_expired __constant_htonl(NFSERR_EXPIRED)
#define nfserr_bad_cookie __constant_htonl(NFSERR_BAD_COOKIE) #define nfserr_bad_cookie __constant_htonl(NFSERR_BAD_COOKIE)
#define nfserr_same __constant_htonl(NFSERR_SAME) #define nfserr_same __constant_htonl(NFSERR_SAME)
......
...@@ -117,16 +117,24 @@ struct nfs4_replay { ...@@ -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 * so_idhash: stateid_hashtbl[] for open owner, lockstateid_hashtbl[]
* reverences when we release a stateowner. * 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 nfs4_stateowner {
struct list_head so_idhash; /* hash by so_id */ struct list_head so_idhash; /* hash by so_id */
struct list_head so_strhash; /* hash by op_name */ struct list_head so_strhash; /* hash by op_name */
struct list_head so_perclient; /* nfs4_client->cl_perclient */ struct list_head so_perclient; /* nfs4_client->cl_perclient */
struct list_head so_perfilestate; /* list: nfs4_stateid */ struct list_head so_perfilestate; /* list: nfs4_stateid */
int so_is_open_owner; /* 1=openowner,0=lockowner */
u32 so_id; u32 so_id;
struct nfs4_client * so_client; struct nfs4_client * so_client;
u32 so_seqid; u32 so_seqid;
...@@ -152,12 +160,18 @@ struct nfs4_file { ...@@ -152,12 +160,18 @@ struct nfs4_file {
* nfs4_stateid can either be an open stateid or (eventually) a lock stateid * nfs4_stateid can either be an open stateid or (eventually) a lock stateid
* *
* (open)nfs4_stateid: one per (open)nfs4_stateowner, nfs4_file * (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 nfs4_stateid {
struct list_head st_hash; struct list_head st_hash;
struct list_head st_perfile; struct list_head st_perfile;
struct list_head st_perfilestate; struct list_head st_perfilestate;
struct nfs4_stateowner * st_stateowner; struct nfs4_stateowner * st_stateowner;
struct nfs4_file * st_file; struct nfs4_file * st_file;
stateid_t st_stateid; stateid_t st_stateid;
...@@ -170,6 +184,9 @@ struct nfs4_stateid { ...@@ -170,6 +184,9 @@ struct nfs4_stateid {
/* flags for preprocess_seqid_op() */ /* flags for preprocess_seqid_op() */
#define CHECK_FH 0x00000001 #define CHECK_FH 0x00000001
#define CONFIRM 0x00000002 #define CONFIRM 0x00000002
#define OPEN_STATE 0x00000004
#define LOCK_STATE 0x00000008
#define RDWR_STATE 0x00000010
#define seqid_mutating_err(err) \ #define seqid_mutating_err(err) \
(((err) != nfserr_stale_clientid) && \ (((err) != nfserr_stale_clientid) && \
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define _LINUX_NFSD_XDR4_H #define _LINUX_NFSD_XDR4_H
#define NFSD4_MAX_TAGLEN 128 #define NFSD4_MAX_TAGLEN 128
#define XDR_LEN(n) (((n) + 3) & ~3)
typedef u32 delegation_zero_t; typedef u32 delegation_zero_t;
typedef u32 delegation_boot_t; typedef u32 delegation_boot_t;
...@@ -111,6 +112,56 @@ struct nfsd4_link { ...@@ -111,6 +112,56 @@ struct nfsd4_link {
struct nfsd4_change_info li_cinfo; /* response */ 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 { struct nfsd4_lookup {
u32 lo_len; /* request */ u32 lo_len; /* request */
char * lo_name; /* request */ char * lo_name; /* request */
...@@ -266,6 +317,7 @@ struct nfsd4_op { ...@@ -266,6 +317,7 @@ struct nfsd4_op {
struct nfsd4_getattr getattr; struct nfsd4_getattr getattr;
struct svc_fh * getfh; struct svc_fh * getfh;
struct nfsd4_link link; struct nfsd4_link link;
struct nfsd4_lock lock;
struct nfsd4_lookup lookup; struct nfsd4_lookup lookup;
struct nfsd4_verify nverify; struct nfsd4_verify nverify;
struct nfsd4_open open; struct nfsd4_open open;
...@@ -357,6 +409,8 @@ extern int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, ...@@ -357,6 +409,8 @@ extern int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh,
struct nfsd4_close *close); struct nfsd4_close *close);
extern int nfsd4_open_downgrade(struct svc_rqst *rqstp, extern int nfsd4_open_downgrade(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open_downgrade *od); 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 #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