Details : link_raw functions used to call d_instantiate without obtaining
extra inode reference first.
+Severity : minor
+Frequency : rare
+Bugzilla : 9942,9903
+Description: Referencing freed requests leading to crash, memleask with NFS.
+Details : We used to require that call to ll_revalidate_it was always
+ followed by ll_lookup_it. Also with revalidate_special() it is
+ possible to call ll_revalidate_it() twice for the same dentry
+ even if first occurence returned success. This fix changes semantic
+ between DISP_ENQ_COMPLETE disposition flag to mean there is extra
+ reference on a request referred from the intent.
+ ll_intent_release() then releases such a request.
+
------------------------------------------------------------------------------
08-26-2005 Cluster File Systems, Inc. <info@clusterfs.com>
ll_intent_drop_lock(it);
it->it_magic = 0;
it->it_op_release = 0;
+ if (it_disposition(it, DISP_ENQ_COMPLETE)) {
+ /* We are still holding extra reference on a request, need to
+ free it */
+ struct ptlrpc_request *request = it->d.lustre.it_data;
+ ptlrpc_req_finished(request);
+ }
it->d.lustre.it_disposition = 0;
it->d.lustre.it_data = NULL;
EXIT;
spin_unlock(&dcache_lock);
out:
- /* If we had succesful it lookup on mds, but it happened to be negative,
- we do not free request as it will be reused during lookup (see
- comment in mdc/mdc_locks.c::mdc_intent_lock(). But if
+ /* We do not free request as it may be reused during following lookup
+ (see comment in mdc/mdc_locks.c::mdc_intent_lock()), request will
+ be freed in ll_lookup_it or in ll_intent_release. But if
request was not completed, we need to free it. (bug 5154) */
- if (req != NULL && (rc == 1 || !it_disposition(it, DISP_ENQ_COMPLETE)))
+ if (req != NULL && !it_disposition(it, DISP_ENQ_COMPLETE))
ptlrpc_req_finished(req);
if (rc == 0) {
ll_unhash_aliases(de->d_inode);
}
EXPORT_SYMBOL(it_set_disposition);
+void it_clear_disposition(struct lookup_intent *it, int flag)
+{
+ it->d.lustre.it_disposition &= ~flag;
+}
+
static int it_to_lock_mode(struct lookup_intent *it)
{
/* CREAT needs to be tested before open (both could be set) */
if (rc < 0)
RETURN(rc);
memcpy(&it->d.lustre.it_lock_handle, &lockh, sizeof(lockh));
+ } else if (!op_data->fid2.id) {
+ /* DISP_ENQ_COMPLETE set means there is extra reference on
+ request referenced from this intent, saved for subsequent
+ lookup. This path is executed when we proceed to this
+ lookup, so we clear DISP_ENQ_COMPLETE */
+ it_clear_disposition(it, DISP_ENQ_COMPLETE);
}
request = *reqp = it->d.lustre.it_data;
LASSERT(request != NULL);