From a5f04cc32d97c55e9cc40135ed1aed950ba95e3d Mon Sep 17 00:00:00 2001 From: zam Date: Wed, 4 Mar 2009 20:04:50 +0000 Subject: [PATCH] Branch HEAD 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 | 21 ++++++++++----------- lustre/obdfilter/filter_io.c | 11 ++++++++++- lustre/obdfilter/filter_io_26.c | 2 ++ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/lustre/obdfilter/filter.c b/lustre/obdfilter/filter.c index 7ed88fc..f53a23c 100644 --- a/lustre/obdfilter/filter.c +++ b/lustre/obdfilter/filter.c @@ -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)); diff --git a/lustre/obdfilter/filter_io.c b/lustre/obdfilter/filter_io.c index fa9a96f1..7e75c80 100644 --- a/lustre/obdfilter/filter_io.c +++ b/lustre/obdfilter/filter_io.c @@ -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); diff --git a/lustre/obdfilter/filter_io_26.c b/lustre/obdfilter/filter_io_26.c index 68b2ef4..95835a3 100644 --- a/lustre/obdfilter/filter_io_26.c +++ b/lustre/obdfilter/filter_io_26.c @@ -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); } -- 1.8.3.1