diff options
author | J. Bruce Fields <bfields@redhat.com> | 2011-10-20 06:57:46 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2011-11-07 21:10:47 -0500 |
commit | 64a284d07c7d84299a90826950079a8ef11e8204 (patch) | |
tree | a00309bb6be605383a98a805ddab5fb4da6a25f0 /fs/nfsd/nfs4state.c | |
parent | 684e563858018d27acb8f00e30c026215bbd0ffb (diff) |
nfsd4: maintain one seqid stream per (lockowner, file)
Instead of creating a new lockowner and stateid for every
open_to_lockowner call, reuse the existing lockowner if it exists.
Reported-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 58 |
1 files changed, 38 insertions, 20 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9354ddebbee2..d09d5242c088 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -3905,6 +3905,37 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) | |||
3905 | __set_bit(access, &lock_stp->st_access_bmap); | 3905 | __set_bit(access, &lock_stp->st_access_bmap); |
3906 | } | 3906 | } |
3907 | 3907 | ||
3908 | __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) | ||
3909 | { | ||
3910 | struct nfs4_file *fi = ost->st_file; | ||
3911 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); | ||
3912 | struct nfs4_client *cl = oo->oo_owner.so_client; | ||
3913 | struct nfs4_lockowner *lo; | ||
3914 | unsigned int strhashval; | ||
3915 | |||
3916 | lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner); | ||
3917 | if (lo) { | ||
3918 | if (!cstate->minorversion) | ||
3919 | return nfserr_bad_seqid; | ||
3920 | /* XXX: a lockowner always has exactly one stateid: */ | ||
3921 | *lst = list_first_entry(&lo->lo_owner.so_stateids, | ||
3922 | struct nfs4_ol_stateid, st_perstateowner); | ||
3923 | return nfs_ok; | ||
3924 | } | ||
3925 | strhashval = lock_ownerstr_hashval(fi->fi_inode, cl->cl_clientid.cl_id, | ||
3926 | &lock->v.new.owner); | ||
3927 | lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); | ||
3928 | if (lo == NULL) | ||
3929 | return nfserr_jukebox; | ||
3930 | *lst = alloc_init_lock_stateid(lo, fi, ost); | ||
3931 | if (*lst == NULL) { | ||
3932 | release_lockowner(lo); | ||
3933 | return nfserr_jukebox; | ||
3934 | } | ||
3935 | *new = true; | ||
3936 | return nfs_ok; | ||
3937 | } | ||
3938 | |||
3908 | /* | 3939 | /* |
3909 | * LOCK operation | 3940 | * LOCK operation |
3910 | */ | 3941 | */ |
@@ -3920,7 +3951,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3920 | struct file_lock file_lock; | 3951 | struct file_lock file_lock; |
3921 | struct file_lock conflock; | 3952 | struct file_lock conflock; |
3922 | __be32 status = 0; | 3953 | __be32 status = 0; |
3923 | unsigned int strhashval; | 3954 | bool new_state = false; |
3924 | int lkflg; | 3955 | int lkflg; |
3925 | int err; | 3956 | int err; |
3926 | 3957 | ||
@@ -3969,21 +4000,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3969 | if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, | 4000 | if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, |
3970 | &lock->v.new.clientid)) | 4001 | &lock->v.new.clientid)) |
3971 | goto out; | 4002 | goto out; |
3972 | /* create lockowner and lock stateid */ | 4003 | status = lookup_or_create_lock_state(cstate, open_stp, lock, |
3973 | fp = open_stp->st_file; | 4004 | &lock_stp, &new_state); |
3974 | strhashval = lock_ownerstr_hashval(fp->fi_inode, | 4005 | if (status) |
3975 | open_sop->oo_owner.so_client->cl_clientid.cl_id, | ||
3976 | &lock->v.new.owner); | ||
3977 | /* XXX: Do we need to check for duplicate stateowners on | ||
3978 | * the same file, or should they just be allowed (and | ||
3979 | * create new stateids)? */ | ||
3980 | status = nfserr_jukebox; | ||
3981 | lock_sop = alloc_init_lock_stateowner(strhashval, | ||
3982 | open_sop->oo_owner.so_client, open_stp, lock); | ||
3983 | if (lock_sop == NULL) | ||
3984 | goto out; | ||
3985 | lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); | ||
3986 | if (lock_stp == NULL) | ||
3987 | goto out; | 4006 | goto out; |
3988 | } else { | 4007 | } else { |
3989 | /* lock (lock owner + lock stateid) already exists */ | 4008 | /* lock (lock owner + lock stateid) already exists */ |
@@ -3993,10 +4012,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3993 | NFS4_LOCK_STID, &lock_stp); | 4012 | NFS4_LOCK_STID, &lock_stp); |
3994 | if (status) | 4013 | if (status) |
3995 | goto out; | 4014 | goto out; |
3996 | lock_sop = lockowner(lock_stp->st_stateowner); | ||
3997 | fp = lock_stp->st_file; | ||
3998 | } | 4015 | } |
3999 | /* lock_sop and lock_stp have been created or found */ | 4016 | lock_sop = lockowner(lock_stp->st_stateowner); |
4017 | fp = lock_stp->st_file; | ||
4000 | 4018 | ||
4001 | lkflg = setlkflg(lock->lk_type); | 4019 | lkflg = setlkflg(lock->lk_type); |
4002 | status = nfs4_check_openmode(lock_stp, lkflg); | 4020 | status = nfs4_check_openmode(lock_stp, lkflg); |
@@ -4071,7 +4089,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4071 | break; | 4089 | break; |
4072 | } | 4090 | } |
4073 | out: | 4091 | out: |
4074 | if (status && lock->lk_is_new && lock_sop) | 4092 | if (status && new_state) |
4075 | release_lockowner(lock_sop); | 4093 | release_lockowner(lock_sop); |
4076 | if (!cstate->replay_owner) | 4094 | if (!cstate->replay_owner) |
4077 | nfs4_unlock_state(); | 4095 | nfs4_unlock_state(); |