/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#include <nfs/nfs4_clnt.h>
nfs4_oo_hash_bucket_t *, mntinfo4_t *);
#ifdef DEBUG
/*
* If this is non-zero, the lockowner and openowner seqid sync primitives
* will intermittently return errors.
*/
static int seqid_sync_faults = 0;
#endif
0,
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
0xffffffff,
{
(char)0xff, (char)0xff, (char)0xff, (char)0xff,
(char)0xff, (char)0xff, (char)0xff, (char)0xff,
(char)0xff, (char)0xff, (char)0xff, (char)0xff
}
};
/* finds hash bucket and locks it */
static nfs4_oo_hash_bucket_t *
{
return (bucketp);
}
/* unlocks hash bucket pointed by bucket_ptr */
static void
{
}
/*
* Removes the lock owner from the rnode's lock_owners list and frees the
* corresponding reference.
*/
void
{
"nfs4_rnode_remove_lock_owner"));
/* already removed from list */
return;
}
/*
* This would be an appropriate place for
* RELEASE_LOCKOWNER. For now, this is overkill
* because in the common case, close is going to
* release any lockowners anyway.
*/
}
/*
* Remove all lock owners from the rnode's lock_owners list. Frees up
* their references from the list.
*/
void
{
}
}
void
{
}
}
void
{
oop->oo_ref_count++;
}
/*
* Frees the open owner if the ref count hits zero.
*/
void
{
"open_owner_rele"));
oop->oo_ref_count--;
if (oop->oo_ref_count == 0) {
"open_owner_rele: freeing open owner"));
/*
* Ok, we don't destroy the open owner, nor do we put it on
* the mntinfo4's free list just yet. We are lazy about it
* and let callers to find_open_owner() do that to keep locking
* simple.
*/
} else {
}
}
void
{
osp->os_ref_count++;
}
/*
* Frees the open stream and removes it from the rnode4's open streams list if
* the ref count drops to zero.
*/
void
{
"open_stream_rele"));
osp->os_ref_count--;
if (osp->os_ref_count == 0) {
"open_stream_rele: freeing open stream"));
/* now see if we need to destroy the open owner */
/* free up osp */
} else {
}
}
void
{
lop->lo_ref_count++;
}
/*
* Frees the lock owner if the ref count hits zero and
* the structure no longer has no locks.
*/
void
{
"lock_owner_rele"));
lop->lo_ref_count--;
if (lop->lo_ref_count == 0) {
"lock_owner_rele: freeing lock owner: "
/*
* If there are no references, the lock_owner should
* already be off the rnode's list.
*/
/* free up lop */
} else {
}
}
/*
* This increments the open owner ref count if found.
* The argument 'just_created' determines whether we are looking for open
* owners with the 'oo_just_created' flag set or not.
*/
{
"find_open_owner: cred %p, just_created %d",
(void*)cr, just_created));
/* got hash bucket, search through open owners */
just_created == NFS4_JUST_CREATED)) {
/* match */
/* reactivate the open owner */
}
oop->oo_ref_count++;
return (oop);
}
/*
* Now we go ahead and put this open owner
* on the freed list. This is our lazy method.
*/
}
}
/* search through recently freed open owners */
return (oop);
}
{
return (oop);
}
/*
* This increments osp's ref count if found.
* Returns with 'os_sync_lock' held.
*/
{
"find_open_stream"));
/* Now, no one can add or delete to rp's open streams list */
/* match */
(CE_NOTE, "find_open_stream "
"got a match"));
osp->os_ref_count++;
return (osp);
}
}
return (NULL);
}
/*
* Find the lock owner for the given file and process ID. If "which" is
* LOWN_VALID_STATEID, require that the lock owner contain a valid stateid
* from the server.
*
* This increments the lock owner's ref count if found. Returns NULL if
* there was no match.
*/
{
/* search by pid */
/* Found a matching lock owner */
(CE_NOTE, "find_lock_owner: "
"got a match"));
lop->lo_ref_count++;
return (lop);
}
}
}
return (NULL);
}
/*
* This returns the delegation stateid as 'sid'. Returns 1 if a successful
* delegation stateid was found, otherwise returns 0.
*/
static int
{
!rp->r_deleg_return_pending) {
return (1);
}
return (0);
}
/*
* This returns the lock stateid as 'sid'. Returns 1 if a successful lock
* stateid was found, otherwise returns 0.
*/
static int
{
if (lop) {
/*
* Found a matching lock owner, so use a lock
* stateid rather than an open stateid.
*/
return (1);
}
"nfs4_get_lock_stateid: no lop"));
return (0);
}
/*
* This returns the open stateid as 'sid'. Returns 1 if a successful open
* stateid was found, otherwise returns 0.
*
* Once the stateid is returned to the caller, it is no longer protected;
* so the caller must be prepared to handle OLD/BAD_STATEID where
* appropiate.
*/
static int
{
if (!oop) {
"nfs4_get_open_stateid: no oop"));
return (0);
}
if (!osp) {
"nfs4_get_open_stateid: no osp"));
return (0);
}
if (osp->os_failed_reopen) {
"nfs4_get_open_stateid: osp %p failed reopen",
(void *)osp));
return (0);
}
return (1);
}
/*
* Returns the delegation stateid if this 'op' is OP_WRITE and the
* delegation we hold is a write delegation, OR this 'op' is not
* OP_WRITE and we have a delegation held (read or write), otherwise
* returns the lock stateid if there is a lock owner, otherwise
* returns the open stateid if there is a open stream, otherwise
* returns special stateid <seqid = 0, other = 0>.
*
* Used for WRITE operations.
*/
{
return (sid);
}
}
return (sid);
}
}
return (sid);
}
}
return (sid);
}
/*
* Returns the delegation stateid if this 'op' is OP_WRITE and the
* delegation we hold is a write delegation, OR this 'op' is not
* OP_WRITE and we have a delegation held (read or write), otherwise
* returns the lock stateid if there is a lock owner, otherwise
* returns the open stateid if there is a open stream, otherwise
* returns special stateid <seqid = 0, other = 0>.
*
* This also updates which stateid we are using in 'sid_tp', skips
* previously attempted stateids, and skips checking higher priority
* stateids than the current level as dictated by 'sid_tp->cur_sid_type'
* for async reads.
*
* Used for READ and SETATTR operations.
*/
{
/*
* For asynchronous READs, do not attempt to retry from the start of
* the stateid priority list, just continue from where you last left
* off.
*/
if (async_read) {
switch (sid_tp->cur_sid_type) {
case NO_SID:
break;
case DEL_SID:
goto lock_stateid;
case LOCK_SID:
goto open_stateid;
case OPEN_SID:
goto special_stateid;
case SPEC_SID:
default:
}
}
return (sid);
}
}
return (sid);
}
}
return (sid);
}
}
return (sid);
}
void
{
"nfs4_set_lock_stateid"));
}
/*
* Sequence number used when a new open owner is needed.
* This is used so as to not confuse the server. Since a open owner
* is based off of cred, a cred could be re-used quickly, and the server
* may not release all state for a cred.
*/
nfs4_get_new_oo_name(void)
{
return (atomic_inc_64_nv(&open_owner_seq_num));
}
/*
* Create a new open owner and add it to the open owner hash table.
*/
{
/*
* Make sure the cred doesn't go away when we put this open owner
* on the free list, as well as make crcmp() a valid check.
*/
oop->oo_seqid_inuse = 0;
oop->oo_last_good_seqid = 0;
/*
* A Solaris open_owner is <oo_seq_num>
*/
/* now add the struct into the cred hash table */
return (oop);
}
/*
* Create a new open stream and it to the rnode's list.
* Increments the ref count on oop.
* Returns with 'os_sync_lock' held.
*/
{
#ifdef DEBUG
#endif
osp->os_share_acc_read = 0;
osp->os_share_acc_write = 0;
osp->os_mmap_read = 0;
osp->os_mmap_write = 0;
osp->os_share_deny_none = 0;
osp->os_share_deny_read = 0;
osp->os_share_deny_write = 0;
osp->os_delegation = 0;
osp->os_dc_openacc = 0;
osp->os_final_close = 0;
osp->os_pending_close = 0;
osp->os_failed_reopen = 0;
osp->os_force_close = 0;
/* open owner gets a reference */
/* now add the open stream to rp */
return (osp);
}
/*
* Returns an open stream with 'os_sync_lock' held.
* If the open stream is found (rather than created), its
* 'os_open_ref_count' is bumped.
*
* There is no race with two threads entering this function
* and creating two open streams for the same <oop, rp> pair.
* This is because the open seqid sync must be acquired, thus
* only allowing one thread in at a time.
*/
int *created_osp)
{
#ifdef DEBUG
#endif
if (!osp) {
if (osp)
*created_osp = 1;
} else {
*created_osp = 0;
osp->os_open_ref_count++;
}
return (osp);
}
/*
* Create a new lock owner and add it to the rnode's list.
* Assumes the rnode's r_statev4_lock is held.
* The created lock owner has a reference count of 2: one for the list and
* one for the caller to use. Returns the lock owner locked down.
*/
{
"create_lock_owner: pid %x", pid));
lop->lock_seqid = 0;
lop->lo_pending_rqsts = 0;
/*
* A Solaris lock_owner is <seq_num><pid>
*/
/* now add the lock owner to rp */
return (lop);
}
/*
* This sets the lock seqid of a lock owner.
*/
void
{
"nfs4_set_lock_seqid"));
}
static void
{
"nfs4_set_new_lock_owner_args"));
/*
* A Solaris lock_owner is <seq_num><pid>
*/
}
/*
* Fill in the lock owner args.
*/
void
{
"nfs4_setlockowner_args"));
/* This increments lop's ref count */
if (!lop)
goto make_up_args;
return;
}
/*
* This ends our use of the open owner's open seqid by setting
* the appropiate flags and issuing a cv_signal to wake up another
* thread waiting to use the open seqid.
*/
void
{
oop->oo_seqid_inuse = 0;
}
/*
* This starts our use of the open owner's open seqid by setting
* the oo_seqid_inuse to true. We will wait (forever) with a
* cv_wait() until we are woken up.
*
* Return values:
* 0 no problems
* EAGAIN caller should retry (like a recovery retry)
*/
int
{
int error = 0;
#ifdef DEBUG
#endif
#ifdef DEBUG
++ops % 5 == 0)
return (EAGAIN);
#endif
if (error != 0)
goto done;
while (oop->oo_seqid_inuse) {
"nfs4_start_open_seqid_sync waiting on cv"));
}
"nfs4_start_open_seqid_sync: error=%d", error));
done:
return (error);
}
#ifdef DEBUG
#endif
/*
* Checks to see if the OPEN OTW is necessary that is, if it's already
* been opened with the same access and deny bits we are now asking for.
* Note, this assumes that *vpp is a rnode.
*/
int
{
/*
* Grab the delegation type. This function is protected against
* the delegation being returned by virtue of start_op (called
* by nfs4open_otw) taking the r_deleg_recall_lock in read mode,
* delegreturn requires this lock in write mode to proceed.
*/
/* returns with 'os_sync_lock' held */
if (osp) {
if (osp->os_failed_reopen) {
"nfs4_is_otw_open_necessary: os_failed_reopen "
"set on osp %p, cr %p, rp %s", (void *)osp,
rnode4info(rp)));
do_otw = 1;
}
/*
*/
if (osp->os_share_acc_read == 0 &&
dt == OPEN_DELEGATE_NONE)
do_otw = 1;
if (osp->os_share_acc_write == 0 &&
do_otw = 1;
if (!do_otw) {
"nfs4_is_otw_open_necessary: can skip this "
"open OTW"));
if (!just_been_created) {
osp->os_open_ref_count++;
osp->os_share_acc_read++;
}
/*
* Need to reset this bitfield for the possible case
* where we were going to OTW CLOSE the file, got a
* non-recoverable error, and before we could retry
* the CLOSE, OPENed the file again.
*/
osp->os_final_close = 0;
osp->os_force_close = 0;
#ifdef DEBUG
bypass_otw[0]++;
#endif
*errorp = 0;
return (0);
}
} else if (dt != OPEN_DELEGATE_NONE) {
/*
* Even if there isn't an open_stream yet, we may still be
* able to bypass the otw open if the client owns a delegation.
*
* If you are asking for for WRITE, but I only have
* a read delegation, then you still have to go otw.
*/
return (1);
/*
* TODO - evaluate the nfsace4
*/
/*
* Check the access flags to make sure the caller
* had permission.
*/
return (1);
return (1);
/*
* create_open_stream will add a reference to oop,
* this will prevent the open_owner_rele done in
* nfs4open_otw from destroying the open_owner.
*/
/* returns with 'os_sync_lock' held */
return (1);
osp->os_share_acc_read++;
}
#ifdef DEBUG
bypass_otw[1]++;
#endif
*errorp = 0;
return (0);
}
return (1);
}
static open_delegation_type4
{
if (rp->r_deleg_return_pending)
else
return (dt);
}
/*
* Fill in *locker with the lock state arguments for a LOCK call. If
* lop->lo_just_created == NFS4_JUST_CREATED, oop and osp must be non-NULL.
* Caller must already hold the necessary seqid sync lock(s).
*/
void
{
/* this is a new lock request */
} else {
/* have an existing lock owner */
}
}
/*
* This starts our use of the lock owner's lock seqid by setting
* the lo_flags to NFS4_LOCK_SEQID_INUSE. We will wait (forever)
* with a cv_wait() until we are woken up.
*
* Return values:
* 0 no problems
* EAGAIN caller should retry (like a recovery retry)
*/
int
{
int error = 0;
#ifdef DEBUG
#endif
#ifdef DEBUG
++ops % 7 == 0)
return (EAGAIN);
#endif
if (error != 0)
goto done;
"nfs4_start_lock_seqid_sync: waiting on cv"));
}
"NFS4_LOCK_SEQID_INUSE"));
"nfs4_start_lock_seqid_sync: error=%d", error));
done:
return (error);
}
/*
* This ends our use of the lock owner's lock seqid by setting
* the appropiate flags and issuing a cv_signal to wake up another
* thread waiting to use the lock seqid.
*/
void
{
}
/*
* Returns a reference to a lock owner via lopp, which has its lock seqid
* synchronization started.
* If the lock owner is in the 'just_created' state, then we return its open
* owner and open stream and start the open seqid synchronization.
*
* Return value:
* NFS4_OK no problems
* NFS4ERR_DELAY there is lost state to recover; caller should retry
* NFS4ERR_IO no open stream
*/
{
int error = 0;
/* Found a matching lock owner */
(CE_NOTE, "nfs4_find_or_create_lock_owner: "
"got a match"));
lop->lo_ref_count++;
break;
}
}
/* create temporary lock owner */
}
/* Have a locked down lock owner struct now */
/* This is an existing lock owner */
} else {
/* Lock owner doesn't exist yet */
/* First grab open owner seqid synchronization */
goto kill_new_lop;
goto failed;
}
goto kill_new_lop;
}
if ((*ospp)->os_failed_reopen) {
"nfs4_find_or_create_lock_owner: os_failed_reopen;"
"osp %p, cr %p, rp %s", (void *)(*ospp),
stat = NFS4ERR_IO;
goto failed;
}
/*
* Now see if the lock owner has become permanent while we
* had released our lock.
*/
}
}
goto failed;
}
return (NFS4_OK);
/*
* A previous CLOSE was attempted but got EINTR, but the application
* continued to use the unspecified state file descriptor. But now the
* open stream is gone (which could also destroy the open owner), hence
* we can no longer continue. The calling function should return EIO
* to the application.
*/
(CE_NOTE, "nfs4_find_or_create_lock_owner: destroy newly created "
(void *)(*ospp)));
stat = NFS4ERR_IO;
if (*oopp) {
}
if (*ospp) {
}
return (stat);
}
/*
* This function grabs a recently freed open owner off of the freed open
* owner list if there is a match on the cred 'cr'. It returns NULL if no
* such match is found. It will set the 'oo_ref_count' and 'oo_valid' back
* to both 1 (sane values) in the case a match is found.
*/
static nfs4_open_owner_t *
mntinfo4_t *mi)
{
"find_freed_open_owner: cred %p", (void*)cr));
/* got hash bucket, search through freed open owners */
"find_freed_open_owner: got a match open owner "
"%p", (void *)foop));
mi->mi_foo_num--;
/* now add the struct into the cred hash table */
return (foop);
}
}
return (NULL);
}
/*
* Insert the newly freed 'oop' into the mi's freed oop list,
* always at the head of the list. If we've already reached
* our maximum allowed number of freed open owners (mi_foo_max),
* then remove the LRU open owner on the list (namely the tail).
*/
static void
{
"nfs4_free_open_owner: num free %d, max free %d, "
"insert open owner %p for mntinfo4 %p",
(void *)mi));
mi->mi_foo_num++;
return;
}
/* need to replace a freed open owner */
"nfs4_free_open_owner: destroy %p, insert %p",
/* head always has latest freed oop */
}
void
{
if (oop->oo_cred_otw)
}
{
}
/*
* This set's the open seqid for a <open owner/ mntinfo4> pair.
*/
void
{
}
/*
* This bumps the current open seqid for the open owner 'oop'.
*/
void
{
}
/*
* If no open owner was provided, this function takes the cred to find an
* open owner within the given mntinfo4_t. Either way we return the
* open owner's OTW credential if it exists; otherwise returns the
* supplied 'cr'.
*
* A hold is put on the returned credential, and it is up to the caller
* to free the cred.
*/
cred_t *
{
if (oop->oo_cred_otw)
else
if (provided_oop == NULL)
} else {
}
return (ret_cr);
}
/*
* Retrieves the next open stream in the rnode's list if an open stream
* is provided; otherwise gets the first open stream in the list.
* The open owner for that open stream is then retrieved, and if its
* oo_cred_otw exists then it is returned; otherwise the provided 'cr'
* is returned. *osp is set to the 'found' open stream.
*
* Note: we don't set *osp to the open stream retrieved via the
* optimized check since that won't necessarily be at the beginning
* of the rnode list, and if that osp doesn't work we'd like to
* check _all_ open streams (starting from the beginning of the
* rnode list).
*/
cred_t *
{
/*
* As an optimization, try to find the open owner
* for the cred provided since that's most likely
* to work.
*/
if (*first_time) {
if (oop) {
if (next_osp)
}
}
int delay_rele = 0;
*first_time = FALSE;
/* return the next open stream for this rnode */
/* Now, no one can add or delete to rp's open streams list */
if (*osp) {
/*
* Delay the rele of *osp until after we drop
* r_os_lock to not deadlock with oo_lock
* via an open_stream_rele()->open_owner_rele().
*/
delay_rele = 1;
} else {
}
if (next_osp) {
/* find the next valid open stream */
tmp_osp =
if (next_osp)
}
if (next_osp) {
next_osp->os_ref_count++;
}
}
if (delay_rele)
}
if (next_osp) {
if (oop->oo_cred_otw)
else
if (*first_time) {
} else
} else {
/* just return the cred provided to us */
}
*first_time = FALSE;
return (ret_cr);
}
void
{
}
void
{
"nfs4_save_stateid: saved %s stateid",
switch (sid_tp->cur_sid_type) {
case DEL_SID:
break;
case LOCK_SID:
break;
case OPEN_SID:
break;
case SPEC_SID:
default:
}
}
/*
* We got NFS4ERR_BAD_SEQID. Setup some arguments to pass to recovery.
* Caller is responsible for freeing.
*/
{
return (bsep);
}
void
{
"nfs4open_dg_save_lost_rqst: error %d", error));
/*
* The vp is held and rele'd via the recovery code.
* See nfs4_save_lost_rqst.
*/
} else {
lost_rqstp->lr_op = 0;
}
}
/*
* Change the access and deny bits of an OPEN.
* If recovery is needed, *recov_credpp is set to the cred used OTW,
* a hold is placed on it, and *recov_seqidp is set to the seqid used OTW.
*/
void
{
hrtime_t t;
#if DEBUG
#endif
if (access_close == 0 && deny_close == 0) {
return;
}
downgrade_acc = 0;
downgrade_deny = 0;
/*
* Check to see if the open stream got closed before we go OTW,
* now that we have acquired the 'os_sync_lock'.
*/
" open stream has already been closed, return success"));
/* error has already been set */
goto no_args_out;
}
/* If the file failed recovery, just quit. */
goto no_args_out;
}
/* If we're closing the last READ, need to downgrade */
/* if we're closing the last WRITE, need to downgrade */
new_acc = 0;
new_deny = 0;
/* set our new access and deny share bits */
if ((osp->os_share_acc_read > 0) &&
if ((osp->os_share_acc_write > 0) &&
/*
* Check to see if we aren't actually doing any downgrade or
* if this is the last 'close' but the file is still mmapped.
* Skip this if this a lost request resend so we don't decrement
* the osp's share counts more than once.
*/
if (!lrp &&
((downgrade_acc == 0 && downgrade_deny == 0) ||
/*
* No downgrade to do, but still need to
* update osp's os_share_* counts.
*/
"nfs4_open_downgrade: just lower the osp's count by %s",
if (access_close & FREAD)
osp->os_share_acc_read--;
if (access_close & FWRITE)
goto no_args_out;
}
goto no_args_out;
}
/* setup the COMPOUND args */
if (lrp)
else
/* putfh */
/* open downgrade */
t = gethrtime();
goto cred_retry;
}
if (needrecov && recov_credpp) {
*recov_credpp = cred_otw;
if (recov_seqidp)
*recov_seqidp = seqid;
}
/* get the open downgrade results */
if (access_close & FREAD)
osp->os_share_acc_read--;
if (access_close & FWRITE)
}
}
/*
* If an OPEN request gets ETIMEDOUT or EINTR (that includes bailing out
* because the filesystem was forcibly unmounted) then we don't know if we
* potentially left state dangling on the server, therefore the recovery
* framework makes this call to resend the OPEN request and then undo it.
*/
void
{
char *destcfp;
int destclen;
int created_osp = 0;
hrtime_t t;
int fh_different;
int reopen = 0;
if (vp) {
}
if (rp) {
/* If the file failed recovery, just quit. */
return;
}
}
if (dvp) {
/* If the parent directory failed recovery, just quit. */
return;
}
} else
if (reopen) {
/*
* if this is a file mount then
* use the mntinfo parentfh
*/
} else {
}
/*
* If we sent over a OPEN with CREATE then the only
* thing we care about is to not leave dangling state
* on the server, not whether the file we potentially
* created remains on the server. So even though the
* lost open request specified a CREATE, we only wish
* to do a non-CREATE OPEN.
*/
if (claim == CLAIM_DELEGATE_CUR) {
} else {
}
/* this length never changes */
/*
* We can get away with not saving the seqid upon detection
* of a lost request, and now just use the open owner's current
* seqid since we only allow one op OTW per seqid and lost
* requests are saved FIFO.
*/
/* getfh */
/* Construct the getattr part of the compound */
t = gethrtime();
goto err_out;
if (!vp) {
int rnode_err = 0;
/*
* If we can't decode all the attributes they are not usable,
* just make the vnode.
*/
"nfs4_resend_open_otw: made vp %p for file %s",
/*
* For the newly created *vpp case, make sure the rnode
* isn't bad before using it.
*/
if (rnode_err) {
"nfs4_resend_open_otw: rp %p is bad",
goto err_out;
}
}
if (reopen) {
/*
* Check if the path we reopened really is the same
* file. We could end up in a situation were the file
* was removed and a new file created with the same name.
*/
if (fh_different) {
/* Oops, we don't have the same file */
"Couldn't reopen: Persistant "
"file handle changed";
else
"Couldn't reopen: Volatile "
"(no expire on open) file handle "
"changed";
(void) xdr_free(xdr_COMPOUND4res_clnt,
return;
} else {
/*
* We have volatile file handles that don't
* compare. If the fids are the same then we
* assume that the file handle expired but the
* renode still refers to the same file object.
*
* First check that we have fids or not.
* If we don't we have a dumb server so we will
* just assume every thing is ok for now.
*/
/*
* We have fids, but they don't
* compare. So kill the file.
*/
"Couldn't reopen: file handle "
"changed due to mismatched fids";
(void) xdr_free(xdr_COMPOUND4res_clnt,
return;
} else {
/*
* We have volatile file handles that
* refers to the same file (at least
* they have the same fid) or we don't
* have fids so we can't tell. :(. We'll
* be a kind and accepting client so
* we'll update the rnode's file
* handle with the otw handle.
*
* We need to drop mi->mi_fh_lock since
* sh4_update acquires it. Since there
* is only one recovery thread there is
* no race.
*/
}
}
} else {
}
}
return;
}
if (reopen) {
/*
* Doing a reopen here so the osp should already exist.
* If not, something changed or went very wrong.
*
* returns with 'os_sync_lock' held
*/
if (!osp) {
"nfs4_resend_open_otw: couldn't find osp"));
goto err_out;
}
osp->os_open_ref_count++;
} else {
/* returns with 'os_sync_lock' held */
if (!osp) {
"nfs4_resend_open_otw: couldn't create osp"));
goto err_out;
}
}
/*
* Need to reset this bitfield for the possible case where we were
* going to OTW CLOSE the file, got a non-recoverable error, and before
* we could retry the CLOSE, OPENed the file again.
*/
osp->os_final_close = 0;
osp->os_force_close = 0;
if (!reopen) {
osp->os_share_acc_read++;
}
if (created_osp)
/* accept delegation, if any */
if (claim == CLAIM_DELEGATE_CUR)
else
return;
}