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);
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 (??)
locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
put_nfs4_file(stp->st_file);
kmem_cache_free(stateid_slab, stp);
- stp = NULL;
}
static void
sop->so_time = get_seconds();
}
-static void
-release_state_owner(struct nfs4_stateid *stp, int flag)
-{
- struct nfs4_stateowner *sop = stp->st_stateowner;
-
- dprintk("NFSD: release_state_owner\n");
- release_stateid(stp, flag);
-
- /* place unused nfs4_stateowners on so_close_lru list to be
- * released by the laundromat service after the lease period
- * to enable us to handle CLOSE replay
- */
- if (sop->so_confirmed && list_empty(&sop->so_stateids))
- move_to_close_lru(sop);
-}
-
static int
cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) {
return ((sop->so_owner.len == owner->len) &&
};
-/*
- * nfsd4_process_open1()
- * lookup stateowner.
- * found:
- * check confirmed
- * confirmed:
- * check seqid
- * not confirmed:
- * delete owner
- * create new owner
- * notfound:
- * verify clientid
- * create new owner
- *
- * called with nfs4_lock_state() held.
- */
int
nfsd4_process_open1(struct nfsd4_open *open)
{
- int status;
clientid_t *clientid = &open->op_clientid;
struct nfs4_client *clp = NULL;
unsigned int strhashval;
struct nfs4_stateowner *sop = NULL;
- status = nfserr_inval;
if (!check_name(open->op_owner))
- goto out;
+ return nfserr_inval;
if (STALE_CLIENTID(&open->op_clientid))
return nfserr_stale_clientid;
strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
sop = find_openstateowner_str(strhashval, open);
- if (sop) {
- open->op_stateowner = sop;
- /* check for replay */
- if (open->op_seqid == sop->so_seqid - 1){
- if (sop->so_replay.rp_buflen)
- return NFSERR_REPLAY_ME;
- else {
- /* The original OPEN failed so spectacularly
- * that we don't even have replay data saved!
- * Therefore, we have no choice but to continue
- * processing this OPEN; presumably, we'll
- * fail again for the same reason.
- */
- dprintk("nfsd4_process_open1:"
- " replay with no replay cache\n");
- goto renew;
- }
- } else if (sop->so_confirmed) {
- if (open->op_seqid == sop->so_seqid)
- goto renew;
- status = nfserr_bad_seqid;
- goto out;
- } else {
- /* If we get here, we received an OPEN for an
- * unconfirmed nfs4_stateowner. Since the seqid's are
- * different, purge the existing nfs4_stateowner, and
- * instantiate a new one.
- */
- clp = sop->so_client;
- release_stateowner(sop);
- }
- } else {
- /* nfs4_stateowner not found.
- * Verify clientid and instantiate new nfs4_stateowner.
- * If verify fails this is presumably the result of the
- * client's lease expiring.
- */
- status = nfserr_expired;
+ open->op_stateowner = sop;
+ if (!sop) {
+ /* Make sure the client's lease hasn't expired. */
clp = find_confirmed_client(clientid);
if (clp == NULL)
- goto out;
+ return nfserr_expired;
+ goto renew;
}
- status = nfserr_resource;
- sop = alloc_init_open_stateowner(strhashval, clp, open);
- if (sop == NULL)
- goto out;
- open->op_stateowner = sop;
+ if (!sop->so_confirmed) {
+ /* Replace unconfirmed owners without checking for replay. */
+ clp = sop->so_client;
+ release_stateowner(sop);
+ open->op_stateowner = NULL;
+ goto renew;
+ }
+ if (open->op_seqid == sop->so_seqid - 1) {
+ if (sop->so_replay.rp_buflen)
+ return NFSERR_REPLAY_ME;
+ /* The original OPEN failed so spectacularly
+ * that we don't even have replay data saved!
+ * Therefore, we have no choice but to continue
+ * processing this OPEN; presumably, we'll
+ * fail again for the same reason.
+ */
+ dprintk("nfsd4_process_open1: replay with no replay cache\n");
+ goto renew;
+ }
+ if (open->op_seqid != sop->so_seqid)
+ return nfserr_bad_seqid;
renew:
- status = nfs_ok;
+ if (open->op_stateowner == NULL) {
+ sop = alloc_init_open_stateowner(strhashval, clp, open);
+ if (sop == NULL)
+ return nfserr_resource;
+ open->op_stateowner = sop;
+ }
+ list_del_init(&sop->so_close_lru);
renew_client(sop->so_client);
-out:
- return status;
+ return nfs_ok;
}
static inline int
{
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;
check_replay:
if (seqid == sop->so_seqid - 1) {
- printk("NFSD: preprocess_seqid_op: retransmission?\n");
+ dprintk("NFSD: preprocess_seqid_op: retransmission?\n");
/* indicate replay to calling function */
return NFSERR_REPLAY_ME;
}
}
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;
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;
}
}
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;
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;
}
* 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;
CHECK_FH | OPEN_STATE | CLOSE_STATE,
&close->cl_stateowner, &stp, NULL)))
goto out;
- /*
- * Return success, but first update the stateid.
- */
status = nfs_ok;
update_stateid(&stp->st_stateid);
memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
- /* release_state_owner() calls nfsd_close() if needed */
- release_state_owner(stp, OPEN_STATE);
+ /* release_stateid() calls nfsd_close() if needed */
+ release_stateid(stp, OPEN_STATE);
+
+ /* place unused nfs4_stateowners on so_close_lru list to be
+ * released by the laundromat service after the lease period
+ * to enable us to handle CLOSE replay
+ */
+ if (list_empty(&close->cl_stateowner->so_stateids))
+ move_to_close_lru(close->cl_stateowner);
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;
}
(local->st_stateid.si_fileid == f_id))
return local;
}
- } else
- printk("NFSD: find_stateid: ERROR: no state flag\n");
+ }
return NULL;
}
sop->so_is_open_owner = 0;
sop->so_id = current_ownerid++;
sop->so_client = clp;
- sop->so_seqid = lock->lk_new_lock_seqid;
+ /* 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;
* 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;
if (check_lock_length(lock->lk_offset, lock->lk_length))
return nfserr_inval;
+ if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) {
+ dprintk("NFSD: nfsd4_lock: permission denied!\n");
+ return status;
+ }
+
nfs4_lock_state();
if (lock->lk_is_new) {
struct nfs4_file *fp;
status = nfserr_stale_clientid;
- if (STALE_CLIENTID(&lock->lk_new_clientid)) {
- printk("NFSD: nfsd4_lock: clientid is stale!\n");
+ if (STALE_CLIENTID(&lock->lk_new_clientid))
goto out;
- }
/* validate and update open stateid and open seqid */
status = nfs4_preprocess_seqid_op(current_fh,
lock->lk_new_open_seqid,
&lock->lk_new_open_stateid,
CHECK_FH | OPEN_STATE,
- &open_sop, &open_stp, lock);
+ &lock->lk_replay_owner, &open_stp,
+ lock);
if (status)
goto out;
+ open_sop = lock->lk_replay_owner;
/* create lockowner and lock stateid */
fp = open_stp->st_file;
strhashval = lock_ownerstr_hashval(fp->fi_inode,
* 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)
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, lock);
+ &lock->lk_replay_owner, &lock_stp, lock);
if (status)
goto out;
+ lock_sop = lock->lk_replay_owner;
}
- /* lock->lk_stateowner and lock_stp have been created or found */
+ /* lock->lk_replay_owner 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");
- goto out;
- }
-
status = nfserr_grace;
if (nfs4_in_grace() && !lock->lk_reclaim)
goto out;
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;
*/
status = posix_lock_file(filp, &file_lock);
- if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
- file_lock.fl_ops->fl_release_private(&file_lock);
dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status);
switch (-status) {
case 0: /* success! */
status = nfserr_deadlock;
default:
dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status);
- goto out_destroy_new_stateid;
+ goto out;
}
conflicting_lock:
goto out;
}
nfs4_set_lock_denied(conflock, &lock->lk_denied);
-
-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--;
-
- release_state_owner(lock_stp, LOCK_STATE);
- }
out:
- if (lock->lk_stateowner)
- nfs4_get_stateowner(lock->lk_stateowner);
+ if (status && lock->lk_is_new && lock_sop)
+ release_stateowner(lock_sop);
+ if (lock->lk_replay_owner) {
+ nfs4_get_stateowner(lock->lk_replay_owner);
+ *replay_owner = lock->lk_replay_owner;
+ }
nfs4_unlock_state();
return status;
}
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;
}
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;
* Try to unlock the file in the VFS.
*/
status = posix_lock_file(filp, &file_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;
}
/*
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;
lock_kernel();
for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
- if ((*flpp)->fl_owner == (fl_owner_t)lowner)
+ if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
status = 1;
goto out;
+ }
}
out:
unlock_kernel();
/* 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();