Introduce return value to cache_inode_lru_ref to prevent new refs to stale entry

If a cache inode is stale (dead), we should prevent handing out additional
references where possible.

We add a new flag, LRU_REQ_STALE_OK, for those cases for which we need to take
a reference anyway. Also, this flag is temporarily used for cases where dealing
with the failure to get a reference is not easy. These cases WILL be fixed in
later patches (but use of this flag allows us to introduce the feature without
making things any worse). There will be at least one place where this flag will
still be useful.

When LRU_REQ_INITIAL is set, we always allow taking the reference since this
flag is only uses when the cache inode is initially found via the hash table
and thus should be valid (or at least was valid a moment ago).

If LRU_REQ_STALE_OK or LRU_REQ_INITIAL flags are used, the only possible
return is CACHE_INODE_SUCCESS thus it is legitimate to ignore the return
value.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Move dead entry cleanup to any unref as long as LRU_UNREF_QLOCKED is not set.

Make sure we only perform the cleanup once.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Convert export->state to atomic

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Add param to getrattr callback to better handle junction processing callbacks

Instead of relying on special parameter values and flags to determine what
the getattr callback is expected to accomplish, make it explicit with a
parameter.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Introduce return value to get_gsh_export_ref to prevent new refs to stale export

If an export is stale (being unexported for any reason), we should prevent
handing out additional references where possible.

We add a new parameter for those cases for which we need to take a reference
anyway. Also, this paremeter is temporarily used for cases where dealing with
the failure to get a reference is not easy. These cases WILL be fixed in later
patches (but use of this parameter allows us to introduce the feature without
making things any worse). There will be at least one place where this parameter
will still be useful.

If export_release_ok is true, the only possible return is true (success) thus
it is legitimate to ignore the return value.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Minor code pretty up

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Move export cleanup to unexport and kill_export_root_entry

Cleanup of an export will now be handled inline with unexport or
kill_export_root_entry. This avoids deadlocks and allows the cache inodes
and state objects being cleaned up to hold export refcounts.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Add documentation to abstract_atomic.h

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Convert sle_ref_count to atomic int32_t

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Add flag for cache_inode_lru_unref that indicates the state_lock is held

If so, we can't perform cleanup, however, the fact that the state_lock is
held insures that another LRU ref MUST be held by this thread (to protect the
existence of the cache inode in order to be able to release the state_lock).

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Take an LRU reference any time we pin a cache entry for range locks

A pin ref will no longer guarantee the existence of the cache inode
entry, thus we must ALSO hold an long term LRU reference.

Because cleanup no longer depends on the LRU refcount going to zero, this
is now safe.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Take an LRU reference any time we pin a cache entry for NLM shares

A pin ref will no longer guarantee the existence of the cache inode
entry, thus we must ALSO hold an long term LRU reference.

Because cleanup no longer depends on the LRU refcount going to zero, this
is now safe.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Make every state_lock_entry_t have an export reference.

The export structure MUST be valid for the entire life of the lock entry.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Make sure state_nlm_notify properly handles stale cache inodes and exports

Now that refcounting is improved, this is actually much easier.

In state_nlm_notify we don't actually worry about stale cache inodes since
state_unlock will properly detect a stale cache inode and we can quietly
ignore the error here.

We do skip calling state_unlock() if the export is being removed since
state_unlock() does not detect that.

In either case, we can just ignore the error. We don't even need to count it
for early termination since these errors will not result in never draining
the list of locks belonging to the nsm_client.

We no longer need to take a reference on the lock entry since we only
look at it while holding the ssc_mutex (which assures the lock entry can
not become invalid since to do so, the ssc_mutex would need to be held to
remove the entry from the list of locks for the nsm_client).

Interestingly, we also don't have to worry about the locks that belong to the
current NSM state that are temporarily not on the nsm_client list. If they
get removed due to some other lock operation, they will cleanly be removed from
the newlocks list (even though that list is a stack local).

There is one vulnerability if a new SM_NOTIFY comes in while we are still
processing the one at hand. The new call to state_nlm_notify would miss the
locks on the newlocks list (which suggests that list should be attached to
the nsm_client). There is another issue in that now some THIRD NSM state is
the current state. The first state_nlm_notify will remove locks belonging to
that third state, suggesting that we need a way to terminate a
state_nlm_notify.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Add safety to struct state_t

In addition to refcounting state_t objects, we also need to protect access
to the other objects it references.

First, each state_t now also holds it's own refcount to the cache entry and
export it belongs to.

Second, a mutex is added to protect the state_entry, state_export, and
state_owner fields.

Third, inline functions are provided to safely take a reference to each
of these objects. This guards against use of a state_t object just after
it has been removed from the stateid table (which also disconnects it from
all of these objects). By taking an independent reference under the
state_mutex, we guarantee those objects will live long enough for the
caller to do what it needs to do.

Fourth, we protect against multiple calls to state_del/state_del_locked. If
we are unable to remove the state_t from the stateid table, then it must
have already been destroyed.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Make lock_entry_inc_ref static inline and lock_entry_dec_ref static

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Make sure state_nfs4_owner_unlock_all handles stale cache entry and export

And in general clean this up

Now, if we are unable to release all the owner's locks due to too many errors,
issue a LogFatal rather than having Ganesha continue with dangling pointers.

Also, just perform a single loop on lock owners belonging to the clientid.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Make state_del only deal with unlocked case, and get LRU ref

If the entry is stale, then skip.

The one place that called state_del(state, true) could just call
state_del_locked(state).

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Replace release_lockstate with cleaned up/simplified release_lock_owner

Now that release_lockstate was only being used for the release lock owner
case, simplify it.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>
Make sure release_openstate handles stale cache entry and export

Make sure everything is refcounted properly, also hold owner so_mutex
appropriately to protect looking at list of states belonging to owner.

Now, if we are unable to release all the owner's shares due to too many errors,
issue a LogFatal rather than having Ganesha continue with dangling pointers.

Signed-off-by: Frank S. Filz <ffilzlnx@mindspring.com>