static void free_generic_stateid(struct nfs4_ol_stateid *stp)
{
- close_generic_stateid(stp);
kmem_cache_free(stateid_slab, stp);
}
file = find_any_file(stp->st_file);
if (file)
locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
+ close_generic_stateid(stp);
free_generic_stateid(stp);
}
}
}
-static void release_open_stateid(struct nfs4_ol_stateid *stp)
+static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
{
unhash_generic_stateid(stp);
release_stateid_lockowners(stp);
+ close_generic_stateid(stp);
+}
+
+static void release_open_stateid(struct nfs4_ol_stateid *stp)
+{
+ unhash_open_stateid(stp);
free_generic_stateid(stp);
}
{
unhash_openowner(oo);
list_del(&oo->oo_close_lru);
+ if (oo->oo_last_closed_stid)
+ free_generic_stateid(oo->oo_last_closed_stid);
nfs4_free_openowner(oo);
}
oo->oo_owner.so_seqid = open->op_seqid;
oo->oo_flags = 0;
oo->oo_time = 0;
+ oo->oo_last_closed_stid = NULL;
INIT_LIST_HEAD(&oo->oo_close_lru);
hash_openowner(oo, clp, strhashval);
return oo;
queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
}
-static struct nfs4_openowner * search_close_lru(u32 st_id)
+static struct nfs4_openowner * search_close_lru(stateid_t *s)
{
struct nfs4_openowner *local;
+ struct nfs4_ol_stateid *os;
list_for_each_entry(local, &close_lru, oo_close_lru) {
- if (local->oo_owner.so_id == st_id)
+ os = local->oo_last_closed_stid;
+ if (same_stateid(&os->st_stid.sc_stateid, s))
return local;
}
return NULL;
return status;
}
+void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so)
+{
+ struct nfs4_openowner *oo;
+ struct nfs4_ol_stateid *s;
+
+ if (!so->so_is_open_owner)
+ return;
+ oo = openowner(so);
+ s = oo->oo_last_closed_stid;
+ if (!s)
+ return;
+ if (!(oo->oo_flags & NFS4_OO_PURGE_CLOSE)) {
+ /* Release the last_closed_stid on the next seqid bump: */
+ oo->oo_flags |= NFS4_OO_PURGE_CLOSE;
+ return;
+ }
+ oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE;
+ free_generic_stateid(oo->oo_last_closed_stid);
+ oo->oo_last_closed_stid = NULL;
+}
+
/*
* nfs4_unlock_state() called after encode
*/
* Also, we should make sure this isn't just the result of
* a replayed close:
*/
- oo = search_close_lru(close->cl_stateid.si_stateownerid);
+ oo = search_close_lru(&close->cl_stateid);
/* It's not stale; let's assume it's expired: */
if (oo == NULL)
goto out;
update_stateid(&stp->st_stid.sc_stateid);
memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
- /* release_stateid() calls nfsd_close() if needed */
- release_open_stateid(stp);
+ /* unhash_open_stateid() calls nfsd_close() if needed */
+ oo->oo_last_closed_stid = stp;
+ unhash_open_stateid(stp);
/* place unused nfs4_stateowners on so_close_lru list to be
* released by the laundromat service after the lease period
struct nfs4_stateowner oo_owner; /* must be first field */
struct list_head oo_perclient;
struct list_head oo_close_lru; /* tail queue */
+ struct nfs4_ol_stateid *oo_last_closed_stid;
time_t oo_time; /* time of placement on so_close_lru */
#define NFS4_OO_CONFIRMED 1
+#define NFS4_OO_PURGE_CLOSE 2
unsigned char oo_flags;
};
extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
extern void release_session_client(struct nfsd4_session *);
extern __be32 nfs4_validate_stateid(stateid_t *, bool);
+extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
#endif /* NFSD4_STATE_H */