|
@@ -148,7 +148,7 @@ static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
|
|
|
/* hash table for nfs4_file */
|
|
|
#define FILE_HASH_BITS 8
|
|
|
#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
|
|
|
-#define FILE_HASH_MASK (FILE_HASH_SIZE - 1)
|
|
|
+
|
|
|
/* hash table for (open)nfs4_stateid */
|
|
|
#define STATEID_HASH_BITS 10
|
|
|
#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
|
|
@@ -316,64 +316,6 @@ static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE];
|
|
|
static struct list_head client_lru;
|
|
|
static struct list_head close_lru;
|
|
|
|
|
|
-static void unhash_generic_stateid(struct nfs4_stateid *stp)
|
|
|
-{
|
|
|
- list_del(&stp->st_hash);
|
|
|
- list_del(&stp->st_perfile);
|
|
|
- list_del(&stp->st_perstateowner);
|
|
|
-}
|
|
|
-
|
|
|
-static void free_generic_stateid(struct nfs4_stateid *stp)
|
|
|
-{
|
|
|
- put_nfs4_file(stp->st_file);
|
|
|
- kmem_cache_free(stateid_slab, stp);
|
|
|
-}
|
|
|
-
|
|
|
-static void release_lock_stateid(struct nfs4_stateid *stp)
|
|
|
-{
|
|
|
- struct file *file;
|
|
|
-
|
|
|
- unhash_generic_stateid(stp);
|
|
|
- file = find_any_file(stp->st_file);
|
|
|
- if (file)
|
|
|
- locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
|
|
|
- free_generic_stateid(stp);
|
|
|
-}
|
|
|
-
|
|
|
-static void unhash_lockowner(struct nfs4_stateowner *sop)
|
|
|
-{
|
|
|
- struct nfs4_stateid *stp;
|
|
|
-
|
|
|
- list_del(&sop->so_idhash);
|
|
|
- list_del(&sop->so_strhash);
|
|
|
- list_del(&sop->so_perstateid);
|
|
|
- while (!list_empty(&sop->so_stateids)) {
|
|
|
- stp = list_first_entry(&sop->so_stateids,
|
|
|
- struct nfs4_stateid, st_perstateowner);
|
|
|
- release_lock_stateid(stp);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void release_lockowner(struct nfs4_stateowner *sop)
|
|
|
-{
|
|
|
- unhash_lockowner(sop);
|
|
|
- nfs4_put_stateowner(sop);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-release_stateid_lockowners(struct nfs4_stateid *open_stp)
|
|
|
-{
|
|
|
- struct nfs4_stateowner *lock_sop;
|
|
|
-
|
|
|
- while (!list_empty(&open_stp->st_lockowners)) {
|
|
|
- lock_sop = list_entry(open_stp->st_lockowners.next,
|
|
|
- struct nfs4_stateowner, so_perstateid);
|
|
|
- /* list_del(&open_stp->st_lockowners); */
|
|
|
- BUG_ON(lock_sop->so_is_open_owner);
|
|
|
- release_lockowner(lock_sop);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* We store the NONE, READ, WRITE, and BOTH bits separately in the
|
|
|
* st_{access,deny}_bmap field of the stateid, in order to track not
|
|
@@ -446,13 +388,71 @@ static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp)
|
|
|
return nfs4_access_to_omode(access);
|
|
|
}
|
|
|
|
|
|
-static void release_open_stateid(struct nfs4_stateid *stp)
|
|
|
+static void unhash_generic_stateid(struct nfs4_stateid *stp)
|
|
|
+{
|
|
|
+ list_del(&stp->st_hash);
|
|
|
+ list_del(&stp->st_perfile);
|
|
|
+ list_del(&stp->st_perstateowner);
|
|
|
+}
|
|
|
+
|
|
|
+static void free_generic_stateid(struct nfs4_stateid *stp)
|
|
|
{
|
|
|
int oflag = nfs4_access_bmap_to_omode(stp);
|
|
|
|
|
|
+ nfs4_file_put_access(stp->st_file, oflag);
|
|
|
+ put_nfs4_file(stp->st_file);
|
|
|
+ kmem_cache_free(stateid_slab, stp);
|
|
|
+}
|
|
|
+
|
|
|
+static void release_lock_stateid(struct nfs4_stateid *stp)
|
|
|
+{
|
|
|
+ struct file *file;
|
|
|
+
|
|
|
+ unhash_generic_stateid(stp);
|
|
|
+ file = find_any_file(stp->st_file);
|
|
|
+ if (file)
|
|
|
+ locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
|
|
|
+ free_generic_stateid(stp);
|
|
|
+}
|
|
|
+
|
|
|
+static void unhash_lockowner(struct nfs4_stateowner *sop)
|
|
|
+{
|
|
|
+ struct nfs4_stateid *stp;
|
|
|
+
|
|
|
+ list_del(&sop->so_idhash);
|
|
|
+ list_del(&sop->so_strhash);
|
|
|
+ list_del(&sop->so_perstateid);
|
|
|
+ while (!list_empty(&sop->so_stateids)) {
|
|
|
+ stp = list_first_entry(&sop->so_stateids,
|
|
|
+ struct nfs4_stateid, st_perstateowner);
|
|
|
+ release_lock_stateid(stp);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void release_lockowner(struct nfs4_stateowner *sop)
|
|
|
+{
|
|
|
+ unhash_lockowner(sop);
|
|
|
+ nfs4_put_stateowner(sop);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+release_stateid_lockowners(struct nfs4_stateid *open_stp)
|
|
|
+{
|
|
|
+ struct nfs4_stateowner *lock_sop;
|
|
|
+
|
|
|
+ while (!list_empty(&open_stp->st_lockowners)) {
|
|
|
+ lock_sop = list_entry(open_stp->st_lockowners.next,
|
|
|
+ struct nfs4_stateowner, so_perstateid);
|
|
|
+ /* list_del(&open_stp->st_lockowners); */
|
|
|
+ BUG_ON(lock_sop->so_is_open_owner);
|
|
|
+ release_lockowner(lock_sop);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void release_open_stateid(struct nfs4_stateid *stp)
|
|
|
+{
|
|
|
unhash_generic_stateid(stp);
|
|
|
release_stateid_lockowners(stp);
|
|
|
- nfs4_file_put_access(stp->st_file, oflag);
|
|
|
free_generic_stateid(stp);
|
|
|
}
|
|
|
|
|
@@ -608,7 +608,8 @@ static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4
|
|
|
u32 maxrpc = nfsd_serv->sv_max_mesg;
|
|
|
|
|
|
new->maxreqs = numslots;
|
|
|
- new->maxresp_cached = slotsize + NFSD_MIN_HDR_SEQ_SZ;
|
|
|
+ new->maxresp_cached = min_t(u32, req->maxresp_cached,
|
|
|
+ slotsize + NFSD_MIN_HDR_SEQ_SZ);
|
|
|
new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
|
|
|
new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
|
|
|
new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
|
|
@@ -3735,6 +3736,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
|
|
|
stp->st_stateid.si_stateownerid = sop->so_id;
|
|
|
stp->st_stateid.si_fileid = fp->fi_id;
|
|
|
stp->st_stateid.si_generation = 0;
|
|
|
+ stp->st_access_bmap = 0;
|
|
|
stp->st_deny_bmap = open_stp->st_deny_bmap;
|
|
|
stp->st_openstp = open_stp;
|
|
|
|
|
@@ -3749,6 +3751,17 @@ check_lock_length(u64 offset, u64 length)
|
|
|
LOFF_OVERFLOW(offset, length)));
|
|
|
}
|
|
|
|
|
|
+static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access)
|
|
|
+{
|
|
|
+ struct nfs4_file *fp = lock_stp->st_file;
|
|
|
+ int oflag = nfs4_access_to_omode(access);
|
|
|
+
|
|
|
+ if (test_bit(access, &lock_stp->st_access_bmap))
|
|
|
+ return;
|
|
|
+ nfs4_file_get_access(fp, oflag);
|
|
|
+ __set_bit(access, &lock_stp->st_access_bmap);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* LOCK operation
|
|
|
*/
|
|
@@ -3765,7 +3778,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
|
struct file_lock conflock;
|
|
|
__be32 status = 0;
|
|
|
unsigned int strhashval;
|
|
|
- unsigned int cmd;
|
|
|
int err;
|
|
|
|
|
|
dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
|
|
@@ -3847,22 +3859,18 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
|
switch (lock->lk_type) {
|
|
|
case NFS4_READ_LT:
|
|
|
case NFS4_READW_LT:
|
|
|
- if (find_readable_file(lock_stp->st_file)) {
|
|
|
- nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ);
|
|
|
- filp = find_readable_file(lock_stp->st_file);
|
|
|
- }
|
|
|
+ filp = find_readable_file(lock_stp->st_file);
|
|
|
+ if (filp)
|
|
|
+ get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
|
|
|
file_lock.fl_type = F_RDLCK;
|
|
|
- cmd = F_SETLK;
|
|
|
- break;
|
|
|
+ break;
|
|
|
case NFS4_WRITE_LT:
|
|
|
case NFS4_WRITEW_LT:
|
|
|
- if (find_writeable_file(lock_stp->st_file)) {
|
|
|
- nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE);
|
|
|
- filp = find_writeable_file(lock_stp->st_file);
|
|
|
- }
|
|
|
+ filp = find_writeable_file(lock_stp->st_file);
|
|
|
+ if (filp)
|
|
|
+ get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
|
|
|
file_lock.fl_type = F_WRLCK;
|
|
|
- cmd = F_SETLK;
|
|
|
- break;
|
|
|
+ break;
|
|
|
default:
|
|
|
status = nfserr_inval;
|
|
|
goto out;
|
|
@@ -3886,7 +3894,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
|
* Note: locks.c uses the BKL to protect the inode's lock list.
|
|
|
*/
|
|
|
|
|
|
- err = vfs_lock_file(filp, cmd, &file_lock, &conflock);
|
|
|
+ err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock);
|
|
|
switch (-err) {
|
|
|
case 0: /* success! */
|
|
|
update_stateid(&lock_stp->st_stateid);
|