Commit 3f1990d3 authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Add support for POSIX file locking.

parent 1f37cd43
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -278,21 +277,17 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -278,21 +277,17 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
if (!inode) if (!inode)
return -EINVAL; return -EINVAL;
/* This will be in a forthcoming patch. */
if (NFS_PROTO(inode)->version == 4) {
printk(KERN_INFO "NFS: file locking over NFSv4 is not yet supported\n");
return -EIO;
}
/* No mandatory locks over NFS */ /* No mandatory locks over NFS */
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
return -ENOLCK; return -ENOLCK;
/* Fake OK code if mounted without NLM support */ if (NFS_PROTO(inode)->version != 4) {
if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM) { /* Fake OK code if mounted without NLM support */
if (IS_GETLK(cmd)) if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM) {
status = LOCK_USE_CLNT; if (IS_GETLK(cmd))
goto out_ok; status = LOCK_USE_CLNT;
goto out_ok;
}
} }
/* /*
...@@ -302,7 +297,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -302,7 +297,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
* Not sure whether that would be unique, though, or whether * Not sure whether that would be unique, though, or whether
* that would break in other places. * that would break in other places.
*/ */
if (!fl->fl_owner || (fl->fl_flags & FL_POSIX) != FL_POSIX) if (!fl->fl_owner || !(fl->fl_flags & FL_POSIX))
return -ENOLCK; return -ENOLCK;
/* /*
...@@ -322,7 +317,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -322,7 +317,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
return status; return status;
lock_kernel(); lock_kernel();
status = nlmclnt_proc(inode, cmd, fl); status = NFS_PROTO(inode)->lock(filp, cmd, fl);
unlock_kernel(); unlock_kernel();
if (status < 0) if (status < 0)
return status; return status;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/nfs3.h> #include <linux/nfs3.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_page.h> #include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#define NFSDBG_FACILITY NFSDBG_PROC #define NFSDBG_FACILITY NFSDBG_PROC
...@@ -896,6 +897,12 @@ nfs3_request_compatible(struct nfs_page *req, struct file *filp, struct page *pa ...@@ -896,6 +897,12 @@ nfs3_request_compatible(struct nfs_page *req, struct file *filp, struct page *pa
return 1; return 1;
} }
static int
nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
}
struct nfs_rpc_ops nfs_v3_clientops = { struct nfs_rpc_ops nfs_v3_clientops = {
.version = 3, /* protocol version */ .version = 3, /* protocol version */
.dentry_ops = &nfs_dentry_operations, .dentry_ops = &nfs_dentry_operations,
...@@ -931,4 +938,5 @@ struct nfs_rpc_ops nfs_v3_clientops = { ...@@ -931,4 +938,5 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.file_release = nfs_release, .file_release = nfs_release,
.request_init = nfs3_request_init, .request_init = nfs3_request_init,
.request_compatible = nfs3_request_compatible, .request_compatible = nfs3_request_compatible,
.lock = nfs3_proc_lock,
}; };
This diff is collapsed.
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h> #include <linux/nfs_idmap.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/bitops.h>
#define OPENOWNER_POOL_SIZE 8 #define OPENOWNER_POOL_SIZE 8
...@@ -168,7 +169,7 @@ nfs4_put_client(struct nfs4_client *clp) ...@@ -168,7 +169,7 @@ nfs4_put_client(struct nfs4_client *clp)
nfs4_free_client(clp); nfs4_free_client(clp);
} }
static inline u32 u32
nfs4_alloc_lockowner_id(struct nfs4_client *clp) nfs4_alloc_lockowner_id(struct nfs4_client *clp)
{ {
return clp->cl_lockowner_id ++; return clp->cl_lockowner_id ++;
...@@ -304,8 +305,12 @@ nfs4_alloc_open_state(void) ...@@ -304,8 +305,12 @@ nfs4_alloc_open_state(void)
state->state = 0; state->state = 0;
state->nreaders = 0; state->nreaders = 0;
state->nwriters = 0; state->nwriters = 0;
state->flags = 0;
memset(state->stateid.data, 0, sizeof(state->stateid.data)); memset(state->stateid.data, 0, sizeof(state->stateid.data));
atomic_set(&state->count, 1); atomic_set(&state->count, 1);
INIT_LIST_HEAD(&state->lock_states);
init_MUTEX(&state->lock_sema);
rwlock_init(&state->state_lock);
return state; return state;
} }
...@@ -453,7 +458,7 @@ nfs4_close_state(struct nfs4_state *state, mode_t mode) ...@@ -453,7 +458,7 @@ nfs4_close_state(struct nfs4_state *state, mode_t mode)
list_del_init(&state->inode_states); list_del_init(&state->inode_states);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
do { do {
newstate = 0; newstate = 0;
if (state->state == 0) if (state->state == 0)
break; break;
if (state->nreaders) if (state->nreaders)
...@@ -478,6 +483,171 @@ nfs4_close_state(struct nfs4_state *state, mode_t mode) ...@@ -478,6 +483,171 @@ nfs4_close_state(struct nfs4_state *state, mode_t mode)
nfs4_put_open_state(state); nfs4_put_open_state(state);
} }
/*
* Search the state->lock_states for an existing lock_owner
* that is compatible with current->files
*/
static struct nfs4_lock_state *
__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
{
struct nfs4_lock_state *pos;
list_for_each_entry(pos, &state->lock_states, ls_locks) {
if (pos->ls_owner != fl_owner)
continue;
atomic_inc(&pos->ls_count);
return pos;
}
return NULL;
}
struct nfs4_lock_state *
nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
{
struct nfs4_lock_state *lsp;
read_lock(&state->state_lock);
lsp = __nfs4_find_lock_state(state, fl_owner);
read_unlock(&state->state_lock);
return lsp;
}
/*
* Return a compatible lock_state. If no initialized lock_state structure
* exists, return an uninitialized one.
*
* The caller must be holding state->lock_sema
*/
struct nfs4_lock_state *
nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
{
struct nfs4_lock_state *lsp;
struct nfs4_client *clp = state->owner->so_client;
lsp = kmalloc(sizeof(*lsp), GFP_KERNEL);
if (lsp == NULL)
return NULL;
lsp->ls_seqid = 0; /* arbitrary */
lsp->ls_id = -1;
memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data));
atomic_set(&lsp->ls_count, 1);
lsp->ls_owner = fl_owner;
lsp->ls_parent = state;
INIT_LIST_HEAD(&lsp->ls_locks);
spin_lock(&clp->cl_lock);
lsp->ls_id = nfs4_alloc_lockowner_id(clp);
spin_unlock(&clp->cl_lock);
return lsp;
}
/*
* Byte-range lock aware utility to initialize the stateid of read/write
* requests.
*/
void
nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner)
{
if (test_bit(LK_STATE_IN_USE, &state->flags)) {
struct nfs4_lock_state *lsp;
lsp = nfs4_find_lock_state(state, fl_owner);
if (lsp) {
memcpy(dst, &lsp->ls_stateid, sizeof(*dst));
nfs4_put_lock_state(lsp);
return;
}
}
memcpy(dst, &state->stateid, sizeof(*dst));
}
/*
* Called with state->lock_sema held.
*/
void
nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp)
{
if (status == NFS_OK || seqid_mutating_err(-status))
lsp->ls_seqid++;
}
/*
* Check to see if the request lock (type FL_UNLK) effects the fl lock.
*
* fl and request must have the same posix owner
*
* return:
* 0 -> fl not effected by request
* 1 -> fl consumed by request
*/
static int
nfs4_check_unlock(struct file_lock *fl, struct file_lock *request)
{
if (fl->fl_start >= request->fl_start && fl->fl_end <= request->fl_end)
return 1;
return 0;
}
/*
* Post an initialized lock_state on the state->lock_states list.
*/
void
nfs4_notify_setlk(struct inode *inode, struct file_lock *request, struct nfs4_lock_state *lsp)
{
struct nfs4_state *state = lsp->ls_parent;
if (!list_empty(&lsp->ls_locks))
return;
write_lock(&state->state_lock);
list_add(&lsp->ls_locks, &state->lock_states);
set_bit(LK_STATE_IN_USE, &state->flags);
write_unlock(&state->state_lock);
}
/*
* to decide to 'reap' lock state:
* 1) search i_flock for file_locks with fl.lock_state = to ls.
* 2) determine if unlock will consume found lock.
* if so, reap
*
* else, don't reap.
*
*/
void
nfs4_notify_unlck(struct inode *inode, struct file_lock *request, struct nfs4_lock_state *lsp)
{
struct nfs4_state *state = lsp->ls_parent;
struct file_lock *fl;
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_POSIX))
continue;
if (fl->fl_owner != lsp->ls_owner)
continue;
/* Exit if we find at least one lock which is not consumed */
if (nfs4_check_unlock(fl,request) == 0)
return;
}
write_lock(&state->state_lock);
list_del_init(&lsp->ls_locks);
if (list_empty(&state->lock_states))
clear_bit(LK_STATE_IN_USE, &state->flags);
write_unlock(&state->state_lock);
}
/*
* Release reference to lock_state, and free it if we see that
* it is no longer in use
*/
void
nfs4_put_lock_state(struct nfs4_lock_state *lsp)
{
if (!atomic_dec_and_test(&lsp->ls_count))
return;
if (!list_empty(&lsp->ls_locks))
return;
kfree(lsp);
}
/* /*
* Called with sp->so_sema held. * Called with sp->so_sema held.
* *
......
...@@ -66,6 +66,10 @@ static int nfs_stat_to_errno(int); ...@@ -66,6 +66,10 @@ static int nfs_stat_to_errno(int);
#define NFS4_MAXTAGLEN 0 #define NFS4_MAXTAGLEN 0
#endif #endif
/* lock,open owner id:
* we currently use size 1 (u32) out of (NFS4_OPAQUE_LIMIT >> 2)
*/
#define owner_id_maxsz 1 + 1
#define compound_encode_hdr_maxsz 3 + (NFS4_MAXTAGLEN >> 2) #define compound_encode_hdr_maxsz 3 + (NFS4_MAXTAGLEN >> 2)
#define compound_decode_hdr_maxsz 2 + (NFS4_MAXTAGLEN >> 2) #define compound_decode_hdr_maxsz 2 + (NFS4_MAXTAGLEN >> 2)
#define op_encode_hdr_maxsz 1 #define op_encode_hdr_maxsz 1
...@@ -222,6 +226,36 @@ static int nfs_stat_to_errno(int); ...@@ -222,6 +226,36 @@ static int nfs_stat_to_errno(int);
decode_setclientid_confirm_maxsz + \ decode_setclientid_confirm_maxsz + \
decode_putrootfh_maxsz + \ decode_putrootfh_maxsz + \
decode_fsinfo_maxsz decode_fsinfo_maxsz
#define NFS4_enc_lock_sz compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz + \
op_encode_hdr_maxsz + \
1 + 1 + 2 + 2 + \
1 + 4 + 1 + 2 + \
owner_id_maxsz
#define NFS4_dec_lock_sz compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
decode_getattr_maxsz + \
op_decode_hdr_maxsz + \
2 + 2 + 1 + 2 + \
owner_id_maxsz
#define NFS4_enc_lockt_sz compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz + \
op_encode_hdr_maxsz + \
1 + 2 + 2 + 2 + \
owner_id_maxsz
#define NFS4_dec_lockt_sz NFS4_dec_lock_sz
#define NFS4_enc_locku_sz compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz + \
op_encode_hdr_maxsz + \
1 + 1 + 4 + 2 + 2
#define NFS4_dec_locku_sz compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
decode_getattr_maxsz + \
op_decode_hdr_maxsz + 4
static struct { static struct {
...@@ -596,6 +630,80 @@ encode_link(struct xdr_stream *xdr, struct nfs4_link *link) ...@@ -596,6 +630,80 @@ encode_link(struct xdr_stream *xdr, struct nfs4_link *link)
return 0; return 0;
} }
/*
* opcode,type,reclaim,offset,length,new_lock_owner = 32
* open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
*/
static int
encode_lock(struct xdr_stream *xdr, struct nfs_lockargs *arg)
{
uint32_t *p;
struct nfs_lock_opargs *opargs = arg->u.lock;
RESERVE_SPACE(32);
WRITE32(OP_LOCK);
WRITE32(arg->type);
WRITE32(opargs->reclaim);
WRITE64(arg->offset);
WRITE64(arg->length);
WRITE32(opargs->new_lock_owner);
if (opargs->new_lock_owner){
struct nfs_open_to_lock *ol = opargs->u.open_lock;
RESERVE_SPACE(40);
WRITE32(ol->open_seqid);
WRITEMEM(&ol->open_stateid, sizeof(ol->open_stateid));
WRITE32(ol->lock_seqid);
WRITE64(ol->lock_owner.clientid);
WRITE32(4);
WRITE32(ol->lock_owner.id);
}
else {
struct nfs_exist_lock *el = opargs->u.exist_lock;
RESERVE_SPACE(20);
WRITEMEM(&el->stateid, sizeof(el->stateid));
WRITE32(el->seqid);
}
return 0;
}
static int
encode_lockt(struct xdr_stream *xdr, struct nfs_lockargs *arg)
{
uint32_t *p;
struct nfs_lowner *opargs = arg->u.lockt;
RESERVE_SPACE(40);
WRITE32(OP_LOCKT);
WRITE32(arg->type);
WRITE64(arg->offset);
WRITE64(arg->length);
WRITE64(opargs->clientid);
WRITE32(4);
WRITE32(opargs->id);
return 0;
}
static int
encode_locku(struct xdr_stream *xdr, struct nfs_lockargs *arg)
{
uint32_t *p;
struct nfs_locku_opargs *opargs = arg->u.locku;
RESERVE_SPACE(44);
WRITE32(OP_LOCKU);
WRITE32(arg->type);
WRITE32(opargs->seqid);
WRITEMEM(&opargs->stateid, sizeof(opargs->stateid));
WRITE64(arg->offset);
WRITE64(arg->length);
return 0;
}
static int static int
encode_lookup(struct xdr_stream *xdr, struct nfs4_lookup *lookup) encode_lookup(struct xdr_stream *xdr, struct nfs4_lookup *lookup)
{ {
...@@ -1175,6 +1283,72 @@ nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closea ...@@ -1175,6 +1283,72 @@ nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closea
return status; return status;
} }
/*
* Encode a LOCK request
*/
static int
nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
.nops = 2,
};
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
status = encode_putfh(&xdr, args->fh);
if(status)
goto out;
status = encode_lock(&xdr, args);
out:
return status;
}
/*
* Encode a LOCKT request
*/
static int
nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
.nops = 2,
};
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
status = encode_putfh(&xdr, args->fh);
if(status)
goto out;
status = encode_lockt(&xdr, args);
out:
return status;
}
/*
* Encode a LOCKU request
*/
static int
nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
.nops = 2,
};
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
status = encode_putfh(&xdr, args->fh);
if(status)
goto out;
status = encode_locku(&xdr, args);
out:
return status;
}
/* /*
* Encode a READ request * Encode a READ request
*/ */
...@@ -1997,6 +2171,66 @@ decode_link(struct xdr_stream *xdr, struct nfs4_link *link) ...@@ -1997,6 +2171,66 @@ decode_link(struct xdr_stream *xdr, struct nfs4_link *link)
return decode_change_info(xdr, link->ln_cinfo); return decode_change_info(xdr, link->ln_cinfo);
} }
/*
* We create the owner, so we know a proper owner.id length is 4.
*/
static int
decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied)
{
uint32_t *p;
uint32_t namelen;
READ_BUF(32);
READ64(denied->offset);
READ64(denied->length);
READ32(denied->type);
READ64(denied->owner.clientid);
READ32(namelen);
READ_BUF(namelen);
if (namelen == 4)
READ32(denied->owner.id);
return -NFS4ERR_DENIED;
}
static int
decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res)
{
uint32_t *p;
int status;
status = decode_op_hdr(xdr, OP_LOCK);
if (status == 0) {
READ_BUF(sizeof(nfs4_stateid));
COPYMEM(&res->u.stateid, sizeof(res->u.stateid));
} else if (status == -NFS4ERR_DENIED)
return decode_lock_denied(xdr, &res->u.denied);
return status;
}
static int
decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res)
{
int status;
status = decode_op_hdr(xdr, OP_LOCKT);
if (status == -NFS4ERR_DENIED)
return decode_lock_denied(xdr, &res->u.denied);
return status;
}
static int
decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res)
{
uint32_t *p;
int status;
status = decode_op_hdr(xdr, OP_LOCKU);
if (status == 0) {
READ_BUF(sizeof(nfs4_stateid));
COPYMEM(&res->u.stateid, sizeof(res->u.stateid));
}
return status;
}
static int static int
decode_lookup(struct xdr_stream *xdr) decode_lookup(struct xdr_stream *xdr)
{ {
...@@ -2037,10 +2271,11 @@ static int ...@@ -2037,10 +2271,11 @@ static int
decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res) decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
{ {
uint32_t *p; uint32_t *p;
int status;
res->status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
if (res->status) if (status)
return res->status; return status;
READ_BUF(sizeof(res->stateid.data)); READ_BUF(sizeof(res->stateid.data));
COPYMEM(res->stateid.data, sizeof(res->stateid.data)); COPYMEM(res->stateid.data, sizeof(res->stateid.data));
return 0; return 0;
...@@ -2619,6 +2854,71 @@ nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres ...@@ -2619,6 +2854,71 @@ nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres
return status; return status;
} }
/*
* Decode LOCK response
*/
static int
nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
status = decode_compound_hdr(&xdr, &hdr);
if (status)
goto out;
status = decode_putfh(&xdr);
if (status)
goto out;
status = decode_lock(&xdr, res);
out:
return status;
}
/*
* Decode LOCKT response
*/
static int
nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
status = decode_compound_hdr(&xdr, &hdr);
if (status)
goto out;
status = decode_putfh(&xdr);
if (status)
goto out;
status = decode_lockt(&xdr, res);
out:
return status;
}
/*
* Decode LOCKU response
*/
static int
nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
status = decode_compound_hdr(&xdr, &hdr);
if (status)
goto out;
status = decode_putfh(&xdr);
if (status)
goto out;
status = decode_locku(&xdr, res);
out:
return status;
}
/* /*
* Decode Read response * Decode Read response
...@@ -2915,6 +3215,9 @@ struct rpc_procinfo nfs4_procedures[] = { ...@@ -2915,6 +3215,9 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(RENEW, enc_renew, dec_renew), PROC(RENEW, enc_renew, dec_renew),
PROC(SETCLIENTID, enc_setclientid, dec_setclientid), PROC(SETCLIENTID, enc_setclientid, dec_setclientid),
PROC(SETCLIENTID_CONFIRM, enc_setclientid_confirm, dec_setclientid_confirm), PROC(SETCLIENTID_CONFIRM, enc_setclientid_confirm, dec_setclientid_confirm),
PROC(LOCK, enc_lock, dec_lock),
PROC(LOCKT, enc_lockt, dec_lockt),
PROC(LOCKU, enc_locku, dec_locku),
}; };
struct rpc_version nfs_version4 = { struct rpc_version nfs_version4 = {
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/nfs2.h> #include <linux/nfs2.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_page.h> #include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#define NFSDBG_FACILITY NFSDBG_PROC #define NFSDBG_FACILITY NFSDBG_PROC
...@@ -653,6 +654,12 @@ nfs_request_compatible(struct nfs_page *req, struct file *filp, struct page *pag ...@@ -653,6 +654,12 @@ nfs_request_compatible(struct nfs_page *req, struct file *filp, struct page *pag
return 1; return 1;
} }
static int
nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
}
struct nfs_rpc_ops nfs_v2_clientops = { struct nfs_rpc_ops nfs_v2_clientops = {
.version = 2, /* protocol version */ .version = 2, /* protocol version */
...@@ -689,4 +696,5 @@ struct nfs_rpc_ops nfs_v2_clientops = { ...@@ -689,4 +696,5 @@ struct nfs_rpc_ops nfs_v2_clientops = {
.file_release = nfs_release, .file_release = nfs_release,
.request_init = nfs_request_init, .request_init = nfs_request_init,
.request_compatible = nfs_request_compatible, .request_compatible = nfs_request_compatible,
.lock = nfs_proc_lock,
}; };
...@@ -297,6 +297,9 @@ enum { ...@@ -297,6 +297,9 @@ enum {
NFSPROC4_CLNT_RENEW, NFSPROC4_CLNT_RENEW,
NFSPROC4_CLNT_SETCLIENTID, NFSPROC4_CLNT_SETCLIENTID,
NFSPROC4_CLNT_SETCLIENTID_CONFIRM, NFSPROC4_CLNT_SETCLIENTID_CONFIRM,
NFSPROC4_CLNT_LOCK,
NFSPROC4_CLNT_LOCKT,
NFSPROC4_CLNT_LOCKU,
}; };
#endif #endif
......
...@@ -542,19 +542,43 @@ struct nfs4_state_owner { ...@@ -542,19 +542,43 @@ struct nfs4_state_owner {
/* /*
* struct nfs4_state maintains the client-side state for a given * struct nfs4_state maintains the client-side state for a given
* (state_owner,inode) tuple. * (state_owner,inode) tuple (OPEN) or state_owner (LOCK).
* *
* OPEN:
* In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server, * In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server,
* we need to know how many files are open for reading or writing on a * we need to know how many files are open for reading or writing on a
* given inode. This information too is stored here. * given inode. This information too is stored here.
*
* LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN)
*/ */
struct nfs4_lock_state {
struct list_head ls_locks; /* Other lock stateids */
fl_owner_t ls_owner; /* POSIX lock owner */
struct nfs4_state * ls_parent; /* Parent nfs4_state */
u32 ls_seqid;
u32 ls_id;
nfs4_stateid ls_stateid;
atomic_t ls_count;
};
/* bits for nfs4_state->flags */
enum {
LK_STATE_IN_USE,
};
struct nfs4_state { struct nfs4_state {
struct list_head open_states; /* List of states for the same state_owner */ struct list_head open_states; /* List of states for the same state_owner */
struct list_head inode_states; /* List of states for the same inode */ struct list_head inode_states; /* List of states for the same inode */
struct list_head lock_states; /* List of subservient lock stateids */
struct nfs4_state_owner *owner; /* Pointer to the open owner */ struct nfs4_state_owner *owner; /* Pointer to the open owner */
struct inode *inode; /* Pointer to the inode */ struct inode *inode; /* Pointer to the inode */
unsigned long flags; /* Do we hold any locks? */
struct semaphore lock_sema; /* Serializes file locking operations */
rwlock_t state_lock; /* Protects the lock_states list */
nfs4_stateid stateid; nfs4_stateid stateid;
unsigned int nreaders; unsigned int nreaders;
...@@ -589,6 +613,8 @@ extern void init_nfsv4_state(struct nfs_server *); ...@@ -589,6 +613,8 @@ extern void init_nfsv4_state(struct nfs_server *);
extern void destroy_nfsv4_state(struct nfs_server *); extern void destroy_nfsv4_state(struct nfs_server *);
extern struct nfs4_client *nfs4_get_client(struct in_addr *); extern struct nfs4_client *nfs4_get_client(struct in_addr *);
extern void nfs4_put_client(struct nfs4_client *clp); extern void nfs4_put_client(struct nfs4_client *clp);
extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *);
extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
extern void nfs4_put_state_owner(struct nfs4_state_owner *); extern void nfs4_put_state_owner(struct nfs4_state_owner *);
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
...@@ -598,6 +624,15 @@ extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mod ...@@ -598,6 +624,15 @@ extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mod
extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp);
extern int nfs4_handle_error(struct nfs_server *, int); extern int nfs4_handle_error(struct nfs_server *, int);
extern void nfs4_schedule_state_recovery(struct nfs4_client *); extern void nfs4_schedule_state_recovery(struct nfs4_client *);
extern struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t);
extern struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t);
extern void nfs4_put_lock_state(struct nfs4_lock_state *state);
extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls);
extern void nfs4_notify_setlk(struct inode *, struct file_lock *, struct nfs4_lock_state *);
extern void nfs4_notify_unlck(struct inode *, struct file_lock *, struct nfs4_lock_state *);
extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
struct nfs4_mount_data; struct nfs4_mount_data;
#else #else
......
...@@ -26,6 +26,7 @@ struct nfs_page { ...@@ -26,6 +26,7 @@ struct nfs_page {
struct list_head wb_list, /* Defines state of page: */ struct list_head wb_list, /* Defines state of page: */
*wb_list_head; /* read/write/commit */ *wb_list_head; /* read/write/commit */
struct file *wb_file; struct file *wb_file;
fl_owner_t wb_lockowner;
struct inode *wb_inode; struct inode *wb_inode;
struct rpc_cred *wb_cred; struct rpc_cred *wb_cred;
struct nfs4_state *wb_state; struct nfs4_state *wb_state;
......
...@@ -109,7 +109,6 @@ struct nfs_openargs { ...@@ -109,7 +109,6 @@ struct nfs_openargs {
}; };
struct nfs_openres { struct nfs_openres {
__u32 status;
nfs4_stateid stateid; nfs4_stateid stateid;
struct nfs_fh fh; struct nfs_fh fh;
struct nfs4_change_info * cinfo; struct nfs4_change_info * cinfo;
...@@ -129,7 +128,6 @@ struct nfs_open_confirmargs { ...@@ -129,7 +128,6 @@ struct nfs_open_confirmargs {
}; };
struct nfs_open_confirmres { struct nfs_open_confirmres {
__u32 status;
nfs4_stateid stateid; nfs4_stateid stateid;
}; };
...@@ -157,10 +155,68 @@ struct nfs_closeargs { ...@@ -157,10 +155,68 @@ struct nfs_closeargs {
}; };
struct nfs_closeres { struct nfs_closeres {
__u32 status;
nfs4_stateid stateid; nfs4_stateid stateid;
}; };
/*
* * Arguments to the lock,lockt, and locku call.
* */
struct nfs_lowner {
__u64 clientid;
u32 id;
};
struct nfs_open_to_lock {
__u32 open_seqid;
nfs4_stateid open_stateid;
__u32 lock_seqid;
struct nfs_lowner lock_owner;
};
struct nfs_exist_lock {
nfs4_stateid stateid;
__u32 seqid;
};
struct nfs_lock_opargs {
__u32 reclaim;
__u32 new_lock_owner;
union {
struct nfs_open_to_lock *open_lock;
struct nfs_exist_lock *exist_lock;
} u;
};
struct nfs_locku_opargs {
__u32 seqid;
nfs4_stateid stateid;
};
struct nfs_lockargs {
struct nfs_fh * fh;
__u32 type;
__u64 offset;
__u64 length;
union {
struct nfs_lock_opargs *lock; /* LOCK */
struct nfs_lowner *lockt; /* LOCKT */
struct nfs_locku_opargs *locku; /* LOCKU */
} u;
};
struct nfs_lock_denied {
__u64 offset;
__u64 length;
__u32 type;
struct nfs_lowner owner;
};
struct nfs_lockres {
union {
nfs4_stateid stateid;/* LOCK success, LOCKU */
struct nfs_lock_denied denied; /* LOCK failed, LOCKT success */
} u;
struct nfs_server * server;
};
/* /*
* Arguments to the read call. * Arguments to the read call.
...@@ -605,6 +661,7 @@ struct nfs_read_data { ...@@ -605,6 +661,7 @@ struct nfs_read_data {
struct rpc_task task; struct rpc_task task;
struct inode *inode; struct inode *inode;
struct rpc_cred *cred; struct rpc_cred *cred;
fl_owner_t lockowner;
struct nfs_fattr fattr; /* fattr storage */ struct nfs_fattr fattr; /* fattr storage */
struct list_head pages; /* Coalesced read requests */ struct list_head pages; /* Coalesced read requests */
struct page *pagevec[NFS_READ_MAXIOV]; struct page *pagevec[NFS_READ_MAXIOV];
...@@ -620,6 +677,7 @@ struct nfs_write_data { ...@@ -620,6 +677,7 @@ struct nfs_write_data {
struct rpc_task task; struct rpc_task task;
struct inode *inode; struct inode *inode;
struct rpc_cred *cred; struct rpc_cred *cred;
fl_owner_t lockowner;
struct nfs_fattr fattr; struct nfs_fattr fattr;
struct nfs_writeverf verf; struct nfs_writeverf verf;
struct list_head pages; /* Coalesced requests we wish to flush */ struct list_head pages; /* Coalesced requests we wish to flush */
...@@ -686,6 +744,7 @@ struct nfs_rpc_ops { ...@@ -686,6 +744,7 @@ struct nfs_rpc_ops {
int (*file_release) (struct inode *, struct file *); int (*file_release) (struct inode *, struct file *);
void (*request_init)(struct nfs_page *, struct file *); void (*request_init)(struct nfs_page *, struct file *);
int (*request_compatible)(struct nfs_page *, struct file *, struct page *); int (*request_compatible)(struct nfs_page *, struct file *, struct page *);
int (*lock)(struct file *, int, struct file_lock *);
}; };
/* /*
......
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