aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/quota.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2008-11-18 08:38:48 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2009-01-05 02:39:06 -0500
commit813e0c46c9e2a0c6f0b6e774faac82afd7a2e812 (patch)
treecb09aa118f9e053f02e17f7c5ff11139e8e22244 /fs/gfs2/quota.c
parent37b2c8377c98acb60cf4d0126e385ef2153bded9 (diff)
GFS2: Fix "truncate in progress" hang
Following on from the recent clean up of gfs2_quotad, this patch moves the processing of "truncate in progress" inodes from the glock workqueue into gfs2_quotad. This fixes a hang due to the "truncate in progress" processing requiring glocks in order to complete. It might seem odd to use gfs2_quotad for this particular item, but we have to use a pre-existing thread since creating a thread implies a GFP_KERNEL memory allocation which is not allowed from the glock workqueue context. Of the existing threads, gfs2_logd and gfs2_recoverd may deadlock if used for this operation. gfs2_scand and gfs2_glockd are both scheduled for removal at some (hopefully not too distant) future point. That leaves only gfs2_quotad whose workload is generally fairly light and is easily adapted for this extra task. Also, as a result of this change, it opens the way for a future patch to make the reading of the inode's information asynchronous with respect to the glock workqueue, which is another improvement that has been on the list for some time now. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/quota.c')
-rw-r--r--fs/gfs2/quota.c31
1 files changed, 30 insertions, 1 deletions
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 0cfe44f0b6ab..b08d09696b3e 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1296,6 +1296,25 @@ static void quotad_check_timeo(struct gfs2_sbd *sdp, const char *msg,
1296 } 1296 }
1297} 1297}
1298 1298
1299static void quotad_check_trunc_list(struct gfs2_sbd *sdp)
1300{
1301 struct gfs2_inode *ip;
1302
1303 while(1) {
1304 ip = NULL;
1305 spin_lock(&sdp->sd_trunc_lock);
1306 if (!list_empty(&sdp->sd_trunc_list)) {
1307 ip = list_entry(sdp->sd_trunc_list.next,
1308 struct gfs2_inode, i_trunc_list);
1309 list_del_init(&ip->i_trunc_list);
1310 }
1311 spin_unlock(&sdp->sd_trunc_lock);
1312 if (ip == NULL)
1313 return;
1314 gfs2_glock_finish_truncate(ip);
1315 }
1316}
1317
1299/** 1318/**
1300 * gfs2_quotad - Write cached quota changes into the quota file 1319 * gfs2_quotad - Write cached quota changes into the quota file
1301 * @sdp: Pointer to GFS2 superblock 1320 * @sdp: Pointer to GFS2 superblock
@@ -1310,6 +1329,7 @@ int gfs2_quotad(void *data)
1310 unsigned long quotad_timeo = 0; 1329 unsigned long quotad_timeo = 0;
1311 unsigned long t = 0; 1330 unsigned long t = 0;
1312 DEFINE_WAIT(wait); 1331 DEFINE_WAIT(wait);
1332 int empty;
1313 1333
1314 while (!kthread_should_stop()) { 1334 while (!kthread_should_stop()) {
1315 1335
@@ -1324,12 +1344,21 @@ int gfs2_quotad(void *data)
1324 /* FIXME: This should be turned into a shrinker */ 1344 /* FIXME: This should be turned into a shrinker */
1325 gfs2_quota_scan(sdp); 1345 gfs2_quota_scan(sdp);
1326 1346
1347 /* Check for & recover partially truncated inodes */
1348 quotad_check_trunc_list(sdp);
1349
1327 if (freezing(current)) 1350 if (freezing(current))
1328 refrigerator(); 1351 refrigerator();
1329 t = min(quotad_timeo, statfs_timeo); 1352 t = min(quotad_timeo, statfs_timeo);
1330 1353
1331 prepare_to_wait(&sdp->sd_quota_wait, &wait, TASK_UNINTERRUPTIBLE); 1354 prepare_to_wait(&sdp->sd_quota_wait, &wait, TASK_UNINTERRUPTIBLE);
1332 t -= schedule_timeout(t); 1355 spin_lock(&sdp->sd_trunc_lock);
1356 empty = list_empty(&sdp->sd_trunc_list);
1357 spin_unlock(&sdp->sd_trunc_lock);
1358 if (empty)
1359 t -= schedule_timeout(t);
1360 else
1361 t = 0;
1333 finish_wait(&sdp->sd_quota_wait, &wait); 1362 finish_wait(&sdp->sd_quota_wait, &wait);
1334 } 1363 }
1335 1364