summaryrefslogtreecommitdiff
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/export.c3
-rw-r--r--fs/nfsd/nfs4idmap.c8
-rw-r--r--fs/nfsd/nfs4proc.c30
-rw-r--r--fs/nfsd/nfs4recover.c37
-rw-r--r--fs/nfsd/nfs4state.c317
-rw-r--r--fs/nfsd/nfs4xdr.c15
-rw-r--r--fs/nfsd/nfssvc.c1
-rw-r--r--fs/nfsd/vfs.c8
8 files changed, 199 insertions, 220 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 9a11aa39e2e4..057aff745506 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -26,6 +26,7 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/hash.h>
+#include <linux/module.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
@@ -221,6 +222,7 @@ static int expkey_show(struct seq_file *m,
}
struct cache_detail svc_expkey_cache = {
+ .owner = THIS_MODULE,
.hash_size = EXPKEY_HASHMAX,
.hash_table = expkey_table,
.name = "nfsd.fh",
@@ -456,6 +458,7 @@ static int svc_export_show(struct seq_file *m,
return 0;
}
struct cache_detail svc_export_cache = {
+ .owner = THIS_MODULE,
.hash_size = EXPORT_HASHMAX,
.hash_table = export_table,
.name = "nfsd.export",
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 5605a26efc57..13369650cdf9 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -187,6 +187,7 @@ static int idtoname_parse(struct cache_detail *, char *, int);
static struct ent *idtoname_lookup(struct ent *, int);
static struct cache_detail idtoname_cache = {
+ .owner = THIS_MODULE,
.hash_size = ENT_HASHMAX,
.hash_table = idtoname_table,
.name = "nfs4.idtoname",
@@ -320,6 +321,7 @@ static struct ent *nametoid_lookup(struct ent *, int);
static int nametoid_parse(struct cache_detail *, char *, int);
static struct cache_detail nametoid_cache = {
+ .owner = THIS_MODULE,
.hash_size = ENT_HASHMAX,
.hash_table = nametoid_table,
.name = "nfs4.nametoid",
@@ -404,8 +406,10 @@ nfsd_idmap_init(void)
void
nfsd_idmap_shutdown(void)
{
- cache_unregister(&idtoname_cache);
- cache_unregister(&nametoid_cache);
+ if (cache_unregister(&idtoname_cache))
+ printk(KERN_ERR "nfsd: failed to unregister idtoname cache\n");
+ if (cache_unregister(&nametoid_cache))
+ printk(KERN_ERR "nfsd: failed to unregister nametoid cache\n");
}
/*
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index d71f14517b9c..361b4007d4a0 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -162,19 +162,13 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
static inline int
-nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner)
{
int status;
dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
(int)open->op_fname.len, open->op_fname.data,
open->op_stateowner);
- if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
- return nfserr_grace;
-
- if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
- return nfserr_no_grace;
-
/* This check required by spec. */
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
return nfserr_inval;
@@ -244,8 +238,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
*/
status = nfsd4_process_open2(rqstp, current_fh, open);
out:
- if (open->op_stateowner)
+ if (open->op_stateowner) {
nfs4_get_stateowner(open->op_stateowner);
+ *replay_owner = open->op_stateowner;
+ }
nfs4_unlock_state();
return status;
}
@@ -815,8 +811,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
op->status = nfsd4_access(rqstp, current_fh, &op->u.access);
break;
case OP_CLOSE:
- op->status = nfsd4_close(rqstp, current_fh, &op->u.close);
- replay_owner = op->u.close.cl_stateowner;
+ op->status = nfsd4_close(rqstp, current_fh, &op->u.close, &replay_owner);
break;
case OP_COMMIT:
op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit);
@@ -837,15 +832,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
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);
- replay_owner = op->u.lock.lk_stateowner;
+ op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock, &replay_owner);
break;
case OP_LOCKT:
op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt);
break;
case OP_LOCKU:
- op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku);
- replay_owner = op->u.locku.lu_stateowner;
+ op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku, &replay_owner);
break;
case OP_LOOKUP:
op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup);
@@ -859,16 +852,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
op->status = nfs_ok;
break;
case OP_OPEN:
- op->status = nfsd4_open(rqstp, current_fh, &op->u.open);
- replay_owner = op->u.open.op_stateowner;
+ op->status = nfsd4_open(rqstp, current_fh, &op->u.open, &replay_owner);
break;
case OP_OPEN_CONFIRM:
- op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm);
- replay_owner = op->u.open_confirm.oc_stateowner;
+ op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm, &replay_owner);
break;
case OP_OPEN_DOWNGRADE:
- op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade);
- replay_owner = op->u.open_downgrade.od_stateowner;
+ op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade, &replay_owner);
break;
case OP_PUTFH:
op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh);
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 095f1740f3ae..954cf893d50c 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -93,7 +93,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
clname->len, clname->data);
- tfm = crypto_alloc_tfm("md5", 0);
+ tfm = crypto_alloc_tfm("md5", CRYPTO_TFM_REQ_MAY_SLEEP);
if (tfm == NULL)
goto out;
cksum.len = crypto_tfm_alg_digestsize(tfm);
@@ -114,30 +114,16 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
kfree(cksum.data);
status = nfs_ok;
out:
- if (tfm)
- crypto_free_tfm(tfm);
+ crypto_free_tfm(tfm);
return status;
}
-static int
-nfsd4_rec_fsync(struct dentry *dentry)
+static void
+nfsd4_sync_rec_dir(void)
{
- struct file *filp;
- int status = nfs_ok;
-
- dprintk("NFSD: nfs4_fsync_rec_dir\n");
- filp = dentry_open(dget(dentry), mntget(rec_dir.mnt), O_RDWR);
- if (IS_ERR(filp)) {
- status = PTR_ERR(filp);
- goto out;
- }
- if (filp->f_op && filp->f_op->fsync)
- status = filp->f_op->fsync(filp, filp->f_dentry, 0);
- fput(filp);
-out:
- if (status)
- printk("nfsd4: unable to sync recovery directory\n");
- return status;
+ down(&rec_dir.dentry->d_inode->i_sem);
+ nfsd_sync_dir(rec_dir.dentry);
+ up(&rec_dir.dentry->d_inode->i_sem);
}
int
@@ -176,7 +162,7 @@ out_unlock:
up(&rec_dir.dentry->d_inode->i_sem);
if (status == 0) {
clp->cl_firststate = 1;
- status = nfsd4_rec_fsync(rec_dir.dentry);
+ nfsd4_sync_rec_dir();
}
nfs4_reset_user(uid, gid);
dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
@@ -302,7 +288,9 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
+ down(&rec_dir.dentry->d_inode->i_sem);
dentry = lookup_one_len(name, rec_dir.dentry, namlen);
+ up(&rec_dir.dentry->d_inode->i_sem);
if (IS_ERR(dentry)) {
status = PTR_ERR(dentry);
return status;
@@ -327,11 +315,12 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
if (!rec_dir_init || !clp->cl_firststate)
return;
+ clp->cl_firststate = 0;
nfs4_save_user(&uid, &gid);
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
nfs4_reset_user(uid, gid);
if (status == 0)
- status = nfsd4_rec_fsync(rec_dir.dentry);
+ nfsd4_sync_rec_dir();
if (status)
printk("NFSD: Failed to remove expired client state directory"
" %.*s\n", HEXDIR_LEN, clp->cl_recdir);
@@ -362,7 +351,7 @@ nfsd4_recdir_purge_old(void) {
return;
status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old);
if (status == 0)
- status = nfsd4_rec_fsync(rec_dir.dentry);
+ nfsd4_sync_rec_dir();
if (status)
printk("nfsd4: failed to purge old clients from recovery"
" directory %s\n", rec_dir.dentry->d_name.name);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 89e36526d7f2..6bbefd06f10d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -624,7 +624,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
cb->cb_ident = se->se_callback_ident;
return;
out_err:
- printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
+ dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
"will not receive delegations\n",
clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
@@ -678,13 +678,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
int status;
char dname[HEXDIR_LEN];
- status = nfserr_inval;
if (!check_name(clname))
- goto out;
+ return nfserr_inval;
status = nfs4_make_rec_clidname(dname, &clname);
if (status)
- goto out;
+ return status;
/*
* XXX The Duplicate Request Cache (DRC) has been checked (??)
@@ -874,6 +873,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
* change request correctly. */
atomic_set(&conf->cl_callback.cb_set, 0);
gen_confirm(conf);
+ nfsd4_remove_clid_dir(unconf);
expire_client(unconf);
status = nfs_ok;
@@ -1159,6 +1159,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
stp->st_deny_bmap = 0;
__set_bit(open->op_share_access, &stp->st_access_bmap);
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
+ stp->st_openstp = NULL;
}
static void
@@ -1294,7 +1295,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
fp = find_file(ino);
if (!fp)
return nfs_ok;
- ret = nfserr_share_denied;
+ ret = nfserr_locked;
/* Search for conflicting share reservations */
list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
if (test_bit(deny_type, &stp->st_deny_bmap) ||
@@ -1482,7 +1483,7 @@ nfsd4_process_open1(struct nfsd4_open *open)
if (sop) {
open->op_stateowner = sop;
/* check for replay */
- if (open->op_seqid == sop->so_seqid){
+ if (open->op_seqid == sop->so_seqid - 1){
if (sop->so_replay.rp_buflen)
return NFSERR_REPLAY_ME;
else {
@@ -1497,7 +1498,7 @@ nfsd4_process_open1(struct nfsd4_open *open)
goto renew;
}
} else if (sop->so_confirmed) {
- if (open->op_seqid == sop->so_seqid + 1)
+ if (open->op_seqid == sop->so_seqid)
goto renew;
status = nfserr_bad_seqid;
goto out;
@@ -1530,8 +1531,6 @@ renew:
status = nfs_ok;
renew_client(sop->so_client);
out:
- if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
- status = nfserr_reclaim_bad;
return status;
}
@@ -1685,19 +1684,11 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta
}
-/* decrement seqid on successful reclaim, it will be bumped in encode_open */
static void
-nfs4_set_claim_prev(struct nfsd4_open *open, int *status)
+nfs4_set_claim_prev(struct nfsd4_open *open)
{
- if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
- if (*status)
- *status = nfserr_reclaim_bad;
- else {
- open->op_stateowner->so_confirmed = 1;
- open->op_stateowner->so_client->cl_firststate = 1;
- open->op_stateowner->so_seqid--;
- }
- }
+ open->op_stateowner->so_confirmed = 1;
+ open->op_stateowner->so_client->cl_firststate = 1;
}
/*
@@ -1789,6 +1780,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
struct nfs4_delegation *dp = NULL;
int status;
+ if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+ return nfserr_grace;
+
+ if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ return nfserr_no_grace;
+
status = nfserr_inval;
if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
goto out;
@@ -1823,6 +1820,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
status = nfs4_upgrade_open(rqstp, current_fh, stp, open);
if (status)
goto out;
+ update_stateid(&stp->st_stateid);
} else {
/* Stateid was not found, this is a new OPEN */
int flags = 0;
@@ -1856,8 +1854,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
out:
if (fp)
put_nfs4_file(fp);
- /* CLAIM_PREVIOUS has different error returns */
- nfs4_set_claim_prev(open, &status);
+ if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ nfs4_set_claim_prev(open);
/*
* To finish the open response, we just need to set the rflags.
*/
@@ -1990,14 +1988,11 @@ laundromat_main(void *not_used)
queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
}
-/* search ownerid_hashtbl[] and close_lru for stateid owner
- * (stateid->si_stateownerid)
- */
static struct nfs4_stateowner *
-find_openstateowner_id(u32 st_id, int flags) {
+search_close_lru(u32 st_id, int flags)
+{
struct nfs4_stateowner *local = NULL;
- dprintk("NFSD: find_openstateowner_id %d\n", st_id);
if (flags & CLOSE_STATE) {
list_for_each_entry(local, &close_lru, so_close_lru) {
if (local->so_id == st_id)
@@ -2018,7 +2013,7 @@ STALE_STATEID(stateid_t *stateid)
{
if (stateid->si_boot == boot_time)
return 0;
- printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
+ dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
stateid->si_generation);
return 1;
@@ -2163,14 +2158,19 @@ out:
return status;
}
+static inline int
+setlkflg (int type)
+{
+ return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
+ RD_STATE : WR_STATE;
+}
/*
* Checks for sequence id mutating operations.
*/
static int
-nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid)
+nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
{
- int status;
struct nfs4_stateid *stp;
struct nfs4_stateowner *sop;
@@ -2178,53 +2178,65 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
"stateid = (%08x/%08x/%08x/%08x)\n", seqid,
stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
stateid->si_generation);
-
+
*stpp = NULL;
*sopp = NULL;
- status = nfserr_bad_stateid;
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
printk("NFSD: preprocess_seqid_op: magic stateid!\n");
- goto out;
+ return nfserr_bad_stateid;
}
- status = nfserr_stale_stateid;
if (STALE_STATEID(stateid))
- goto out;
+ return nfserr_stale_stateid;
/*
* We return BAD_STATEID if filehandle doesn't match stateid,
* the confirmed flag is incorrecly set, or the generation
* number is incorrect.
- * If there is no entry in the openfile table for this id,
- * we can't always return BAD_STATEID;
- * this might be a retransmitted CLOSE which has arrived after
- * the openfile has been released.
*/
- if (!(stp = find_stateid(stateid, flags)))
- goto no_nfs4_stateid;
-
- status = nfserr_bad_stateid;
+ stp = find_stateid(stateid, flags);
+ if (stp == NULL) {
+ /*
+ * Also, we should make sure this isn't just the result of
+ * a replayed close:
+ */
+ sop = search_close_lru(stateid->si_stateownerid, flags);
+ if (sop == NULL)
+ return nfserr_bad_stateid;
+ *sopp = sop;
+ goto check_replay;
+ }
- /* for new lock stateowners:
- * check that the lock->v.new.open_stateid
- * refers to an open stateowner
- *
- * check that the lockclid (nfs4_lock->v.new.clientid) is the same
- * as the open_stateid->st_stateowner->so_client->clientid
- */
- if (lockclid) {
+ if (lock) {
struct nfs4_stateowner *sop = stp->st_stateowner;
+ clientid_t *lockclid = &lock->v.new.clientid;
struct nfs4_client *clp = sop->so_client;
+ int lkflg = 0;
+ int status;
+
+ lkflg = setlkflg(lock->lk_type);
+
+ if (lock->lk_is_new) {
+ if (!sop->so_is_open_owner)
+ return nfserr_bad_stateid;
+ if (!cmp_clid(&clp->cl_clientid, lockclid))
+ return nfserr_bad_stateid;
+ /* stp is the open stateid */
+ status = nfs4_check_openmode(stp, lkflg);
+ if (status)
+ return status;
+ } else {
+ /* stp is the lock stateid */
+ status = nfs4_check_openmode(stp->st_openstp, lkflg);
+ if (status)
+ return status;
+ }
- if (!sop->so_is_open_owner)
- goto out;
- if (!cmp_clid(&clp->cl_clientid, lockclid))
- goto out;
}
if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
- goto out;
+ return nfserr_bad_stateid;
}
*stpp = stp;
@@ -2235,67 +2247,45 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
* For the moment, we ignore the possibility of
* generation number wraparound.
*/
- if (seqid != sop->so_seqid + 1)
+ if (seqid != sop->so_seqid)
goto check_replay;
- if (sop->so_confirmed) {
- if (flags & CONFIRM) {
- printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n");
- goto out;
- }
+ if (sop->so_confirmed && flags & CONFIRM) {
+ printk("NFSD: preprocess_seqid_op: expected"
+ " unconfirmed stateowner!\n");
+ return nfserr_bad_stateid;
}
- else {
- if (!(flags & CONFIRM)) {
- printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n");
- goto out;
- }
+ if (!sop->so_confirmed && !(flags & CONFIRM)) {
+ printk("NFSD: preprocess_seqid_op: stateowner not"
+ " confirmed yet!\n");
+ return nfserr_bad_stateid;
}
if (stateid->si_generation > stp->st_stateid.si_generation) {
printk("NFSD: preprocess_seqid_op: future stateid?!\n");
- goto out;
+ return nfserr_bad_stateid;
}
- status = nfserr_old_stateid;
if (stateid->si_generation < stp->st_stateid.si_generation) {
printk("NFSD: preprocess_seqid_op: old stateid!\n");
- goto out;
+ return nfserr_old_stateid;
}
- /* XXX renew the client lease here */
- status = nfs_ok;
-
-out:
- return status;
-
-no_nfs4_stateid:
-
- /*
- * We determine whether this is a bad stateid or a replay,
- * starting by trying to look up the stateowner.
- * If stateowner is not found - stateid is bad.
- */
- if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) {
- printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
- status = nfserr_bad_stateid;
- goto out;
- }
- *sopp = sop;
+ renew_client(sop->so_client);
+ return nfs_ok;
check_replay:
- if (seqid == sop->so_seqid) {
- printk("NFSD: preprocess_seqid_op: retransmission?\n");
+ if (seqid == sop->so_seqid - 1) {
+ dprintk("NFSD: preprocess_seqid_op: retransmission?\n");
/* indicate replay to calling function */
- status = NFSERR_REPLAY_ME;
- } else {
- printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
-
- *sopp = NULL;
- status = nfserr_bad_seqid;
+ return NFSERR_REPLAY_ME;
}
- goto out;
+ printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
+ sop->so_seqid, seqid);
+ *sopp = NULL;
+ return nfserr_bad_seqid;
}
int
-nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
+nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner)
{
int status;
struct nfs4_stateowner *sop;
@@ -2329,8 +2319,10 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
nfsd4_create_clid_dir(sop->so_client);
out:
- if (oc->oc_stateowner)
+ if (oc->oc_stateowner) {
nfs4_get_stateowner(oc->oc_stateowner);
+ *replay_owner = oc->oc_stateowner;
+ }
nfs4_unlock_state();
return status;
}
@@ -2361,7 +2353,7 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
}
int
-nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
+nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner)
{
int status;
struct nfs4_stateid *stp;
@@ -2403,8 +2395,10 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n
memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
status = nfs_ok;
out:
- if (od->od_stateowner)
+ if (od->od_stateowner) {
nfs4_get_stateowner(od->od_stateowner);
+ *replay_owner = od->od_stateowner;
+ }
nfs4_unlock_state();
return status;
}
@@ -2413,7 +2407,7 @@ out:
* nfs4_unlock_state() called after encode
*/
int
-nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
+nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner)
{
int status;
struct nfs4_stateid *stp;
@@ -2439,8 +2433,10 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos
/* release_state_owner() calls nfsd_close() if needed */
release_state_owner(stp, OPEN_STATE);
out:
- if (close->cl_stateowner)
+ if (close->cl_stateowner) {
nfs4_get_stateowner(close->cl_stateowner);
+ *replay_owner = close->cl_stateowner;
+ }
nfs4_unlock_state();
return status;
}
@@ -2509,8 +2505,7 @@ find_stateid(stateid_t *stid, int flags)
(local->st_stateid.si_fileid == f_id))
return local;
}
- } else
- printk("NFSD: find_stateid: ERROR: no state flag\n");
+ }
return NULL;
}
@@ -2609,7 +2604,6 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
* occured.
*
* strhashval = lock_ownerstr_hashval
- * so_seqid = lock->lk_new_lock_seqid - 1: it gets bumped in encode
*/
static struct nfs4_stateowner *
@@ -2634,7 +2628,9 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
sop->so_is_open_owner = 0;
sop->so_id = current_ownerid++;
sop->so_client = clp;
- sop->so_seqid = lock->lk_new_lock_seqid - 1;
+ /* It is the openowner seqid that will be incremented in encode in the
+ * case of new lockowners; so increment the lock seqid manually: */
+ sop->so_seqid = lock->lk_new_lock_seqid + 1;
sop->so_confirmed = 1;
rp = &sop->so_replay;
rp->rp_status = NFSERR_SERVERFAULT;
@@ -2669,6 +2665,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
stp->st_access_bmap = open_stp->st_access_bmap;
stp->st_deny_bmap = open_stp->st_deny_bmap;
+ stp->st_openstp = open_stp;
out:
return stp;
@@ -2685,9 +2682,10 @@ check_lock_length(u64 offset, u64 length)
* LOCK operation
*/
int
-nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
+nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner)
{
struct nfs4_stateowner *open_sop = NULL;
+ struct nfs4_stateowner *lock_sop = NULL;
struct nfs4_stateid *lock_stp;
struct file *filp;
struct file_lock file_lock;
@@ -2699,34 +2697,22 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
(long long) lock->lk_offset,
(long long) lock->lk_length);
- if (nfs4_in_grace() && !lock->lk_reclaim)
- return nfserr_grace;
- if (!nfs4_in_grace() && lock->lk_reclaim)
- return nfserr_no_grace;
-
if (check_lock_length(lock->lk_offset, lock->lk_length))
return nfserr_inval;
nfs4_lock_state();
if (lock->lk_is_new) {
- /*
- * Client indicates that this is a new lockowner.
- * Use open owner and open stateid to create lock owner and lock
- * stateid.
- */
+ /*
+ * Client indicates that this is a new lockowner.
+ * Use open owner and open stateid to create lock owner and
+ * lock stateid.
+ */
struct nfs4_stateid *open_stp = NULL;
struct nfs4_file *fp;
status = nfserr_stale_clientid;
- if (STALE_CLIENTID(&lock->lk_new_clientid)) {
- printk("NFSD: nfsd4_lock: clientid is stale!\n");
- goto out;
- }
-
- /* is the new lock seqid presented by the client zero? */
- status = nfserr_bad_seqid;
- if (lock->v.new.lock_seqid != 0)
+ if (STALE_CLIENTID(&lock->lk_new_clientid))
goto out;
/* validate and update open stateid and open seqid */
@@ -2734,13 +2720,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
lock->lk_new_open_seqid,
&lock->lk_new_open_stateid,
CHECK_FH | OPEN_STATE,
- &open_sop, &open_stp,
- &lock->v.new.clientid);
- if (status) {
- if (lock->lk_reclaim)
- status = nfserr_reclaim_bad;
+ &lock->lk_stateowner, &open_stp,
+ lock);
+ if (status)
goto out;
- }
+ open_sop = lock->lk_stateowner;
/* create lockowner and lock stateid */
fp = open_stp->st_file;
strhashval = lock_ownerstr_hashval(fp->fi_inode,
@@ -2750,34 +2734,41 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
* the same file, or should they just be allowed (and
* create new stateids)? */
status = nfserr_resource;
- if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
+ lock_sop = alloc_init_lock_stateowner(strhashval,
+ open_sop->so_client, open_stp, lock);
+ if (lock_sop == NULL)
goto out;
- if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner,
- fp, open_stp)) == NULL) {
- release_stateowner(lock->lk_stateowner);
- lock->lk_stateowner = NULL;
+ lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp);
+ if (lock_stp == NULL) {
+ release_stateowner(lock_sop);
goto out;
}
- /* bump the open seqid used to create the lock */
- open_sop->so_seqid++;
} else {
/* lock (lock owner + lock stateid) already exists */
status = nfs4_preprocess_seqid_op(current_fh,
lock->lk_old_lock_seqid,
&lock->lk_old_lock_stateid,
CHECK_FH | LOCK_STATE,
- &lock->lk_stateowner, &lock_stp, NULL);
+ &lock->lk_stateowner, &lock_stp, lock);
if (status)
goto out;
+ lock_sop = lock->lk_stateowner;
}
/* lock->lk_stateowner and lock_stp have been created or found */
filp = lock_stp->st_vfs_file;
if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) {
- printk("NFSD: nfsd4_lock: permission denied!\n");
+ dprintk("NFSD: nfsd4_lock: permission denied!\n");
goto out;
}
+ status = nfserr_grace;
+ if (nfs4_in_grace() && !lock->lk_reclaim)
+ goto out;
+ status = nfserr_no_grace;
+ if (!nfs4_in_grace() && lock->lk_reclaim)
+ goto out;
+
locks_init_lock(&file_lock);
switch (lock->lk_type) {
case NFS4_READ_LT:
@@ -2792,7 +2783,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
status = nfserr_inval;
goto out;
}
- file_lock.fl_owner = (fl_owner_t) lock->lk_stateowner;
+ file_lock.fl_owner = (fl_owner_t)lock_sop;
file_lock.fl_pid = current->tgid;
file_lock.fl_file = filp;
file_lock.fl_flags = FL_POSIX;
@@ -2844,18 +2835,17 @@ conflicting_lock:
out_destroy_new_stateid:
if (lock->lk_is_new) {
dprintk("NFSD: nfsd4_lock: destroy new stateid!\n");
- /*
- * An error encountered after instantiation of the new
- * stateid has forced us to destroy it.
- */
- if (!seqid_mutating_err(status))
- open_sop->so_seqid--;
-
+ /*
+ * An error encountered after instantiation of the new
+ * stateid has forced us to destroy it.
+ */
release_state_owner(lock_stp, LOCK_STATE);
}
out:
- if (lock->lk_stateowner)
+ if (lock->lk_stateowner) {
nfs4_get_stateowner(lock->lk_stateowner);
+ *replay_owner = lock->lk_stateowner;
+ }
nfs4_unlock_state();
return status;
}
@@ -2882,13 +2872,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
nfs4_lock_state();
status = nfserr_stale_clientid;
- if (STALE_CLIENTID(&lockt->lt_clientid)) {
- printk("NFSD: nfsd4_lockt: clientid is stale!\n");
+ if (STALE_CLIENTID(&lockt->lt_clientid))
goto out;
- }
if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) {
- printk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
+ dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
if (status == nfserr_symlink)
status = nfserr_inval;
goto out;
@@ -2946,7 +2934,7 @@ out:
}
int
-nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku)
+nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner)
{
struct nfs4_stateid *stp;
struct file *filp = NULL;
@@ -2992,7 +2980,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
file_lock.fl_ops->fl_release_private(&file_lock);
if (status) {
- printk("NFSD: nfs4_locku: posix_lock_file failed!\n");
+ dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
goto out_nfserr;
}
/*
@@ -3002,8 +2990,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t));
out:
- if (locku->lu_stateowner)
+ if (locku->lu_stateowner) {
nfs4_get_stateowner(locku->lu_stateowner);
+ *replay_owner = locku->lu_stateowner;
+ }
nfs4_unlock_state();
return status;
@@ -3052,10 +3042,8 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
/* XXX check for lease expiration */
status = nfserr_stale_clientid;
- if (STALE_CLIENTID(clid)) {
- printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n");
+ if (STALE_CLIENTID(clid))
return status;
- }
nfs4_lock_state();
@@ -3083,7 +3071,12 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
* of the lockowner state released; so don't release any until all
* have been checked. */
status = nfs_ok;
- list_for_each_entry(sop, &matches, so_perclient) {
+ while (!list_empty(&matches)) {
+ sop = list_entry(matches.next, struct nfs4_stateowner,
+ so_perclient);
+ /* unhash_stateowner deletes so_perclient only
+ * for openowners. */
+ list_del(&sop->so_perclient);
release_stateowner(sop);
}
out:
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 91fb171d2ace..4c4146350236 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1210,16 +1210,15 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
save = resp->p;
/*
- * Routine for encoding the result of a
- * "seqid-mutating" NFSv4 operation. This is
- * where seqids are incremented, and the
- * replay cache is filled.
+ * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This
+ * is where sequence id's are incremented, and the replay cache is filled.
+ * Note that we increment sequence id's here, at the last moment, so we're sure
+ * we know whether the error to be returned is a sequence id mutating error.
*/
#define ENCODE_SEQID_OP_TAIL(stateowner) do { \
if (seqid_mutating_err(nfserr) && stateowner) { \
- if (stateowner->so_confirmed) \
- stateowner->so_seqid++; \
+ stateowner->so_seqid++; \
stateowner->so_replay.rp_status = nfserr; \
stateowner->so_replay.rp_buflen = \
(((char *)(resp)->p - (char *)save)); \
@@ -1367,9 +1366,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if ((buflen -= 4) < 0)
goto out_resource;
if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
- WRITE32(NFS4_FH_VOLATILE_ANY);
+ WRITE32(NFS4_FH_PERSISTENT);
else
- WRITE32(NFS4_FH_VOLATILE_ANY|NFS4_FH_VOL_RENAME);
+ WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME);
}
if (bmval0 & FATTR4_WORD0_CHANGE) {
/*
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 07b9a065e9da..1697539a7171 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -287,6 +287,7 @@ out:
svc_exit_thread(rqstp);
/* Release module */
+ unlock_kernel();
module_put_and_exit(0);
}
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index be24ead89d94..4f2cd3d27566 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -45,7 +45,7 @@
#endif /* CONFIG_NFSD_V3 */
#include <linux/nfsd/nfsfh.h>
#include <linux/quotaops.h>
-#include <linux/dnotify.h>
+#include <linux/fsnotify.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#ifdef CONFIG_NFSD_V4
@@ -733,7 +733,7 @@ nfsd_sync(struct file *filp)
up(&inode->i_sem);
}
-static void
+void
nfsd_sync_dir(struct dentry *dp)
{
nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
@@ -860,7 +860,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
nfsdstats.io_read += err;
*count = err;
err = 0;
- dnotify_parent(file->f_dentry, DN_ACCESS);
+ fsnotify_access(file->f_dentry);
} else
err = nfserrno(err);
out:
@@ -916,7 +916,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
set_fs(oldfs);
if (err >= 0) {
nfsdstats.io_write += cnt;
- dnotify_parent(file->f_dentry, DN_MODIFY);
+ fsnotify_modify(file->f_dentry);
}
/* clear setuid/setgid flag after write */