Whamcloud - gitweb
b=22520 make sure cl_inode_fini() to destroy the cl_object.
authorEric Mei <eric.mei@oracle.com>
Fri, 4 Jun 2010 23:21:14 +0000 (17:21 -0600)
committerRobert Read <robert.read@oracle.com>
Fri, 4 Jun 2010 23:39:37 +0000 (16:39 -0700)
r=rread
r=wangdi

lustre/lclient/lcommon_cl.c
lustre/obdclass/lu_object.c

index a593621..580226f 100644 (file)
@@ -1189,6 +1189,41 @@ int cl_inode_init(struct inode *inode, struct lustre_md *md)
         return result;
 }
 
+/**
+ * Wait for others drop their references of the object at first, then we drop
+ * the last one, which will lead to the object be destroyed immediately.
+ * Must be called after cl_object_kill() against this object.
+ *
+ * The reason we want to do this is: destroying top object will wait for sub
+ * objects being destroyed first, so we can't let bottom layer (e.g. from ASTs)
+ * to initiate top object destroying which may deadlock. See bz22520.
+ */
+static void cl_object_put_last(struct lu_env *env, struct cl_object *obj)
+{
+        struct lu_object_header *header = obj->co_lu.lo_header;
+        struct lu_site          *site;
+        cfs_waitlink_t           waiter;
+
+        if (unlikely(cfs_atomic_read(&header->loh_ref) != 1)) {
+                site = obj->co_lu.lo_dev->ld_site;
+
+                cfs_waitlink_init(&waiter);
+                cfs_waitq_add(&site->ls_marche_funebre, &waiter);
+
+                while (1) {
+                        cfs_set_current_state(CFS_TASK_UNINT);
+                        if (cfs_atomic_read(&header->loh_ref) == 1)
+                                break;
+                        cfs_waitq_wait(&waiter, CFS_TASK_UNINT);
+                }
+
+                cfs_set_current_state(CFS_TASK_RUNNING);
+                cfs_waitq_del(&site->ls_marche_funebre, &waiter);
+        }
+
+        cl_object_put(env, obj);
+}
+
 void cl_inode_fini(struct inode *inode)
 {
         struct lu_env           *env;
@@ -1216,7 +1251,7 @@ void cl_inode_fini(struct inode *inode)
                  */
                 cl_object_kill(env, clob);
                 lu_object_ref_del(&clob->co_lu, "inode", inode);
-                cl_object_put(env, clob);
+                cl_object_put_last(env, clob);
                 lli->lli_clob = NULL;
                 if (emergency) {
                         cl_env_unplant(ccc_inode_fini_env, &refcheck);
index fe5ee83..a0f93ec 100644 (file)
@@ -113,6 +113,12 @@ void lu_object_put(const struct lu_env *env, struct lu_object *o)
                         -- site->ls_total;
                         kill_it = 1;
                 }
+        } else if (lu_object_is_dying(top)) {
+                /*
+                 * somebody may be waiting for this, currently only used
+                 * for cl_object, see cl_object_put_last().
+                 */
+                cfs_waitq_broadcast(&site->ls_marche_funebre);
         }
         cfs_write_unlock(&site->ls_guard);
         if (kill_it)