Whamcloud - gitweb
Branch HEAD
authorzam <zam>
Wed, 4 Mar 2009 20:04:50 +0000 (20:04 +0000)
committerzam <zam>
Wed, 4 Mar 2009 20:04:50 +0000 (20:04 +0000)
b=17397
i=alexey.zhuravlev
i=andrew.perepechko

To avoid a deadlock in case of concurrent punch/write requests from one
client, filter writes and filter truncates are serialized by i_alloc_sem,
allowing multiple writes or single truncate.

lustre/obdfilter/filter.c
lustre/obdfilter/filter_io.c
lustre/obdfilter/filter_io_26.c

index 7ed88fc..f53a23c 100644 (file)
@@ -3210,7 +3210,7 @@ int filter_setattr_internal(struct obd_export *exp, struct dentry *dentry,
         unsigned int orig_ids[MAXQUOTAS] = {0, 0};
         struct llog_cookie *fcc = NULL;
         struct filter_obd *filter;
-        int rc, err, locked = 0, sync = 0;
+        int rc, err, sync = 0;
         loff_t old_size = 0;
         unsigned int ia_valid;
         struct inode *inode;
@@ -3233,12 +3233,15 @@ int filter_setattr_internal(struct obd_export *exp, struct dentry *dentry,
                 if (fcc != NULL)
                         *fcc = oa->o_lcookie;
         }
-
-        if (ia_valid & ATTR_SIZE || ia_valid & (ATTR_UID | ATTR_GID)) {
+        if (ia_valid & (ATTR_SIZE | ATTR_UID | ATTR_GID)) {
                 DQUOT_INIT(inode);
+                /* Filter truncates and writes are serialized by
+                 * i_alloc_sem, see the comment in
+                 * filter_preprw_write.*/
+                if (ia_valid & ATTR_SIZE)
+                        down_write(&inode->i_alloc_sem);
                 LOCK_INODE_MUTEX(inode);
                 old_size = i_size_read(inode);
-                locked = 1;
         }
 
         /* If the inode still has SUID+SGID bits set (see filter_precreate())
@@ -3328,16 +3331,12 @@ int filter_setattr_internal(struct obd_export *exp, struct dentry *dentry,
                         rc = err;
         }
 
-        if (locked) {
-                UNLOCK_INODE_MUTEX(inode);
-                locked = 0;
-        }
-
         EXIT;
 out_unlock:
-        if (locked)
+        if (ia_valid & (ATTR_SIZE | ATTR_UID | ATTR_GID))
                 UNLOCK_INODE_MUTEX(inode);
-
+        if (ia_valid & ATTR_SIZE)
+                up_write(&inode->i_alloc_sem);
         if (fcc)
                 OBD_FREE(fcc, sizeof(*fcc));
 
index fa9a96f..7e75c80 100644 (file)
@@ -722,6 +722,15 @@ static int filter_preprw_write(int cmd, struct obd_export *exp, struct obdo *oa,
 
         if (rc)
                 GOTO(cleanup, rc);
+        cleanup_phase = 4;
+
+        /* Filter truncate first locks i_mutex then partally truncated
+         * page, filter write code first locks pages then take
+         * i_mutex.  To avoid a deadlock in case of concurrent
+         * punch/write requests from one client, filter writes and
+         * filter truncates are serialized by i_alloc_sem, allowing
+         * multiple writes or single truncate. */
+        down_read(&dentry->d_inode->i_alloc_sem);
 
         do_gettimeofday(&start);
         for (i = 0, lnb = res; i < *npages; i++, lnb++) {
@@ -734,7 +743,6 @@ static int filter_preprw_write(int cmd, struct obd_export *exp, struct obdo *oa,
                 lnb->page = filter_get_page(obd, dentry->d_inode, lnb->offset);
                 if (lnb->page == NULL)
                         GOTO(cleanup, rc = -ENOMEM);
-                cleanup_phase = 4;
 
                 /* DLM locking protects us from write and truncate competing
                  * for same region, but truncate can leave dirty page in the
@@ -811,6 +819,7 @@ cleanup:
                                         lnb->page = NULL;
                                 }
                         }
+                        up_read(&dentry->d_inode->i_alloc_sem);
                 }
         case 3:
                 filter_iobuf_put(&obd->u.filter, iobuf, oti);
index 68b2ef4..95835a3 100644 (file)
@@ -774,5 +774,7 @@ cleanup:
                         i_size_read(inode) > fo->fo_readcache_max_filesize))
                 filter_invalidate_cache(obd, obj, nb, inode);
 
+        up_read(&inode->i_alloc_sem);
+
         RETURN(rc);
 }