diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-12 20:31:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-12 20:31:16 -0400 |
commit | af84b99f22df115e7aec41d5dbe936e163ef4e2e (patch) | |
tree | 7f0b0ef4ee3a3985281cd50d3f629dc582f3db9f | |
parent | 05ff0e291af086f4325bac76abad250690bbbd63 (diff) | |
parent | 0edc7d0f3709e8c3bb7e69c4df614218a753361e (diff) |
Merge git://oss.sgi.com:8090/xfs/xfs-2.6
* git://oss.sgi.com:8090/xfs/xfs-2.6:
[XFS] Fix a bad pointer dereference in the quota statvfs handling.
[XFS] Fix xfs_splice_write() so appended data gets to disk.
[XFS] Fix ABBA deadlock between i_mutex and iolock. Avoid calling
[XFS] Prevent free space oversubscription and xfssyncd looping.
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 18 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_lrw.c | 27 | ||||
-rw-r--r-- | fs/xfs/quota/xfs_qm_bhv.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_alloc.h | 20 | ||||
-rw-r--r-- | fs/xfs/xfs_fsops.c | 16 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.c | 32 | ||||
-rw-r--r-- | fs/xfs/xfs_vfsops.c | 3 |
7 files changed, 76 insertions, 42 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index c40f81ba9b13..34dcb43a7837 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -1390,11 +1390,19 @@ xfs_vm_direct_IO( | |||
1390 | 1390 | ||
1391 | iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN); | 1391 | iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN); |
1392 | 1392 | ||
1393 | ret = blockdev_direct_IO_own_locking(rw, iocb, inode, | 1393 | if (rw == WRITE) { |
1394 | iomap.iomap_target->bt_bdev, | 1394 | ret = blockdev_direct_IO_own_locking(rw, iocb, inode, |
1395 | iov, offset, nr_segs, | 1395 | iomap.iomap_target->bt_bdev, |
1396 | xfs_get_blocks_direct, | 1396 | iov, offset, nr_segs, |
1397 | xfs_end_io_direct); | 1397 | xfs_get_blocks_direct, |
1398 | xfs_end_io_direct); | ||
1399 | } else { | ||
1400 | ret = blockdev_direct_IO_no_locking(rw, iocb, inode, | ||
1401 | iomap.iomap_target->bt_bdev, | ||
1402 | iov, offset, nr_segs, | ||
1403 | xfs_get_blocks_direct, | ||
1404 | xfs_end_io_direct); | ||
1405 | } | ||
1398 | 1406 | ||
1399 | if (unlikely(ret <= 0 && iocb->private)) | 1407 | if (unlikely(ret <= 0 && iocb->private)) |
1400 | xfs_destroy_ioend(iocb->private); | 1408 | xfs_destroy_ioend(iocb->private); |
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 5d9cfd91ad08..ee788b1cb364 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c | |||
@@ -264,7 +264,9 @@ xfs_read( | |||
264 | dmflags, &locktype); | 264 | dmflags, &locktype); |
265 | if (ret) { | 265 | if (ret) { |
266 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | 266 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); |
267 | goto unlock_mutex; | 267 | if (unlikely(ioflags & IO_ISDIRECT)) |
268 | mutex_unlock(&inode->i_mutex); | ||
269 | return ret; | ||
268 | } | 270 | } |
269 | } | 271 | } |
270 | 272 | ||
@@ -272,6 +274,9 @@ xfs_read( | |||
272 | bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)), | 274 | bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)), |
273 | -1, FI_REMAPF_LOCKED); | 275 | -1, FI_REMAPF_LOCKED); |
274 | 276 | ||
277 | if (unlikely(ioflags & IO_ISDIRECT)) | ||
278 | mutex_unlock(&inode->i_mutex); | ||
279 | |||
275 | xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, | 280 | xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, |
276 | (void *)iovp, segs, *offset, ioflags); | 281 | (void *)iovp, segs, *offset, ioflags); |
277 | ret = __generic_file_aio_read(iocb, iovp, segs, offset); | 282 | ret = __generic_file_aio_read(iocb, iovp, segs, offset); |
@@ -281,10 +286,6 @@ xfs_read( | |||
281 | XFS_STATS_ADD(xs_read_bytes, ret); | 286 | XFS_STATS_ADD(xs_read_bytes, ret); |
282 | 287 | ||
283 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | 288 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); |
284 | |||
285 | unlock_mutex: | ||
286 | if (unlikely(ioflags & IO_ISDIRECT)) | ||
287 | mutex_unlock(&inode->i_mutex); | ||
288 | return ret; | 289 | return ret; |
289 | } | 290 | } |
290 | 291 | ||
@@ -390,6 +391,8 @@ xfs_splice_write( | |||
390 | xfs_inode_t *ip = XFS_BHVTOI(bdp); | 391 | xfs_inode_t *ip = XFS_BHVTOI(bdp); |
391 | xfs_mount_t *mp = ip->i_mount; | 392 | xfs_mount_t *mp = ip->i_mount; |
392 | ssize_t ret; | 393 | ssize_t ret; |
394 | struct inode *inode = outfilp->f_mapping->host; | ||
395 | xfs_fsize_t isize; | ||
393 | 396 | ||
394 | XFS_STATS_INC(xs_write_calls); | 397 | XFS_STATS_INC(xs_write_calls); |
395 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | 398 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) |
@@ -416,6 +419,20 @@ xfs_splice_write( | |||
416 | if (ret > 0) | 419 | if (ret > 0) |
417 | XFS_STATS_ADD(xs_write_bytes, ret); | 420 | XFS_STATS_ADD(xs_write_bytes, ret); |
418 | 421 | ||
422 | isize = i_size_read(inode); | ||
423 | if (unlikely(ret < 0 && ret != -EFAULT && *ppos > isize)) | ||
424 | *ppos = isize; | ||
425 | |||
426 | if (*ppos > ip->i_d.di_size) { | ||
427 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
428 | if (*ppos > ip->i_d.di_size) { | ||
429 | ip->i_d.di_size = *ppos; | ||
430 | i_size_write(inode, *ppos); | ||
431 | ip->i_update_core = 1; | ||
432 | ip->i_update_size = 1; | ||
433 | } | ||
434 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
435 | } | ||
419 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 436 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
420 | return ret; | 437 | return ret; |
421 | } | 438 | } |
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c index f137856c3261..db8872be8c87 100644 --- a/fs/xfs/quota/xfs_qm_bhv.c +++ b/fs/xfs/quota/xfs_qm_bhv.c | |||
@@ -203,7 +203,7 @@ xfs_qm_statvfs( | |||
203 | if (error || !vnode) | 203 | if (error || !vnode) |
204 | return error; | 204 | return error; |
205 | 205 | ||
206 | mp = XFS_BHVTOM(bhv); | 206 | mp = xfs_vfstom(bhvtovfs(bhv)); |
207 | ip = xfs_vtoi(vnode); | 207 | ip = xfs_vtoi(vnode); |
208 | 208 | ||
209 | if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)) | 209 | if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)) |
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h index 650591f999ae..5a4256120ccc 100644 --- a/fs/xfs/xfs_alloc.h +++ b/fs/xfs/xfs_alloc.h | |||
@@ -44,6 +44,26 @@ typedef enum xfs_alloctype | |||
44 | #define XFS_ALLOC_FLAG_FREEING 0x00000002 /* indicate caller is freeing extents*/ | 44 | #define XFS_ALLOC_FLAG_FREEING 0x00000002 /* indicate caller is freeing extents*/ |
45 | 45 | ||
46 | /* | 46 | /* |
47 | * In order to avoid ENOSPC-related deadlock caused by | ||
48 | * out-of-order locking of AGF buffer (PV 947395), we place | ||
49 | * constraints on the relationship among actual allocations for | ||
50 | * data blocks, freelist blocks, and potential file data bmap | ||
51 | * btree blocks. However, these restrictions may result in no | ||
52 | * actual space allocated for a delayed extent, for example, a data | ||
53 | * block in a certain AG is allocated but there is no additional | ||
54 | * block for the additional bmap btree block due to a split of the | ||
55 | * bmap btree of the file. The result of this may lead to an | ||
56 | * infinite loop in xfssyncd when the file gets flushed to disk and | ||
57 | * all delayed extents need to be actually allocated. To get around | ||
58 | * this, we explicitly set aside a few blocks which will not be | ||
59 | * reserved in delayed allocation. Considering the minimum number of | ||
60 | * needed freelist blocks is 4 fsbs _per AG_, a potential split of file's bmap | ||
61 | * btree requires 1 fsb, so we set the number of set-aside blocks | ||
62 | * to 4 + 4*agcount. | ||
63 | */ | ||
64 | #define XFS_ALLOC_SET_ASIDE(mp) (4 + ((mp)->m_sb.sb_agcount * 4)) | ||
65 | |||
66 | /* | ||
47 | * Argument structure for xfs_alloc routines. | 67 | * Argument structure for xfs_alloc routines. |
48 | * This is turned into a structure to avoid having 20 arguments passed | 68 | * This is turned into a structure to avoid having 20 arguments passed |
49 | * down several levels of the stack. | 69 | * down several levels of the stack. |
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 077629bab532..c064e72ada9e 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
@@ -462,7 +462,7 @@ xfs_fs_counts( | |||
462 | 462 | ||
463 | xfs_icsb_sync_counters_lazy(mp); | 463 | xfs_icsb_sync_counters_lazy(mp); |
464 | s = XFS_SB_LOCK(mp); | 464 | s = XFS_SB_LOCK(mp); |
465 | cnt->freedata = mp->m_sb.sb_fdblocks; | 465 | cnt->freedata = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); |
466 | cnt->freertx = mp->m_sb.sb_frextents; | 466 | cnt->freertx = mp->m_sb.sb_frextents; |
467 | cnt->freeino = mp->m_sb.sb_ifree; | 467 | cnt->freeino = mp->m_sb.sb_ifree; |
468 | cnt->allocino = mp->m_sb.sb_icount; | 468 | cnt->allocino = mp->m_sb.sb_icount; |
@@ -519,15 +519,19 @@ xfs_reserve_blocks( | |||
519 | } | 519 | } |
520 | mp->m_resblks = request; | 520 | mp->m_resblks = request; |
521 | } else { | 521 | } else { |
522 | __int64_t free; | ||
523 | |||
524 | free = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); | ||
522 | delta = request - mp->m_resblks; | 525 | delta = request - mp->m_resblks; |
523 | lcounter = mp->m_sb.sb_fdblocks - delta; | 526 | lcounter = free - delta; |
524 | if (lcounter < 0) { | 527 | if (lcounter < 0) { |
525 | /* We can't satisfy the request, just get what we can */ | 528 | /* We can't satisfy the request, just get what we can */ |
526 | mp->m_resblks += mp->m_sb.sb_fdblocks; | 529 | mp->m_resblks += free; |
527 | mp->m_resblks_avail += mp->m_sb.sb_fdblocks; | 530 | mp->m_resblks_avail += free; |
528 | mp->m_sb.sb_fdblocks = 0; | 531 | mp->m_sb.sb_fdblocks = XFS_ALLOC_SET_ASIDE(mp); |
529 | } else { | 532 | } else { |
530 | mp->m_sb.sb_fdblocks = lcounter; | 533 | mp->m_sb.sb_fdblocks = |
534 | lcounter + XFS_ALLOC_SET_ASIDE(mp); | ||
531 | mp->m_resblks = request; | 535 | mp->m_resblks = request; |
532 | mp->m_resblks_avail += delta; | 536 | mp->m_resblks_avail += delta; |
533 | } | 537 | } |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 4be5c0b2d296..9dfae18d995f 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -1243,24 +1243,6 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) | |||
1243 | xfs_trans_log_buf(tp, bp, first, last); | 1243 | xfs_trans_log_buf(tp, bp, first, last); |
1244 | } | 1244 | } |
1245 | 1245 | ||
1246 | /* | ||
1247 | * In order to avoid ENOSPC-related deadlock caused by | ||
1248 | * out-of-order locking of AGF buffer (PV 947395), we place | ||
1249 | * constraints on the relationship among actual allocations for | ||
1250 | * data blocks, freelist blocks, and potential file data bmap | ||
1251 | * btree blocks. However, these restrictions may result in no | ||
1252 | * actual space allocated for a delayed extent, for example, a data | ||
1253 | * block in a certain AG is allocated but there is no additional | ||
1254 | * block for the additional bmap btree block due to a split of the | ||
1255 | * bmap btree of the file. The result of this may lead to an | ||
1256 | * infinite loop in xfssyncd when the file gets flushed to disk and | ||
1257 | * all delayed extents need to be actually allocated. To get around | ||
1258 | * this, we explicitly set aside a few blocks which will not be | ||
1259 | * reserved in delayed allocation. Considering the minimum number of | ||
1260 | * needed freelist blocks is 4 fsbs, a potential split of file's bmap | ||
1261 | * btree requires 1 fsb, so we set the number of set-aside blocks to 8. | ||
1262 | */ | ||
1263 | #define SET_ASIDE_BLOCKS 8 | ||
1264 | 1246 | ||
1265 | /* | 1247 | /* |
1266 | * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply | 1248 | * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply |
@@ -1306,7 +1288,8 @@ xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, | |||
1306 | return 0; | 1288 | return 0; |
1307 | case XFS_SBS_FDBLOCKS: | 1289 | case XFS_SBS_FDBLOCKS: |
1308 | 1290 | ||
1309 | lcounter = (long long)mp->m_sb.sb_fdblocks - SET_ASIDE_BLOCKS; | 1291 | lcounter = (long long) |
1292 | mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); | ||
1310 | res_used = (long long)(mp->m_resblks - mp->m_resblks_avail); | 1293 | res_used = (long long)(mp->m_resblks - mp->m_resblks_avail); |
1311 | 1294 | ||
1312 | if (delta > 0) { /* Putting blocks back */ | 1295 | if (delta > 0) { /* Putting blocks back */ |
@@ -1340,7 +1323,7 @@ xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, | |||
1340 | } | 1323 | } |
1341 | } | 1324 | } |
1342 | 1325 | ||
1343 | mp->m_sb.sb_fdblocks = lcounter + SET_ASIDE_BLOCKS; | 1326 | mp->m_sb.sb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp); |
1344 | return 0; | 1327 | return 0; |
1345 | case XFS_SBS_FREXTENTS: | 1328 | case XFS_SBS_FREXTENTS: |
1346 | lcounter = (long long)mp->m_sb.sb_frextents; | 1329 | lcounter = (long long)mp->m_sb.sb_frextents; |
@@ -2021,7 +2004,8 @@ xfs_icsb_sync_counters_lazy( | |||
2021 | * when we get near ENOSPC. | 2004 | * when we get near ENOSPC. |
2022 | */ | 2005 | */ |
2023 | #define XFS_ICSB_INO_CNTR_REENABLE 64 | 2006 | #define XFS_ICSB_INO_CNTR_REENABLE 64 |
2024 | #define XFS_ICSB_FDBLK_CNTR_REENABLE 512 | 2007 | #define XFS_ICSB_FDBLK_CNTR_REENABLE(mp) \ |
2008 | (512 + XFS_ALLOC_SET_ASIDE(mp)) | ||
2025 | STATIC void | 2009 | STATIC void |
2026 | xfs_icsb_balance_counter( | 2010 | xfs_icsb_balance_counter( |
2027 | xfs_mount_t *mp, | 2011 | xfs_mount_t *mp, |
@@ -2055,7 +2039,7 @@ xfs_icsb_balance_counter( | |||
2055 | case XFS_SBS_FDBLOCKS: | 2039 | case XFS_SBS_FDBLOCKS: |
2056 | count = mp->m_sb.sb_fdblocks; | 2040 | count = mp->m_sb.sb_fdblocks; |
2057 | resid = do_div(count, weight); | 2041 | resid = do_div(count, weight); |
2058 | if (count < XFS_ICSB_FDBLK_CNTR_REENABLE) | 2042 | if (count < XFS_ICSB_FDBLK_CNTR_REENABLE(mp)) |
2059 | goto out; | 2043 | goto out; |
2060 | break; | 2044 | break; |
2061 | default: | 2045 | default: |
@@ -2110,11 +2094,11 @@ again: | |||
2110 | case XFS_SBS_FDBLOCKS: | 2094 | case XFS_SBS_FDBLOCKS: |
2111 | BUG_ON((mp->m_resblks - mp->m_resblks_avail) != 0); | 2095 | BUG_ON((mp->m_resblks - mp->m_resblks_avail) != 0); |
2112 | 2096 | ||
2113 | lcounter = icsbp->icsb_fdblocks; | 2097 | lcounter = icsbp->icsb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); |
2114 | lcounter += delta; | 2098 | lcounter += delta; |
2115 | if (unlikely(lcounter < 0)) | 2099 | if (unlikely(lcounter < 0)) |
2116 | goto slow_path; | 2100 | goto slow_path; |
2117 | icsbp->icsb_fdblocks = lcounter; | 2101 | icsbp->icsb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp); |
2118 | break; | 2102 | break; |
2119 | default: | 2103 | default: |
2120 | BUG(); | 2104 | BUG(); |
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index b427d220a169..a34796e57afb 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c | |||
@@ -811,7 +811,8 @@ xfs_statvfs( | |||
811 | statp->f_bsize = sbp->sb_blocksize; | 811 | statp->f_bsize = sbp->sb_blocksize; |
812 | lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0; | 812 | lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0; |
813 | statp->f_blocks = sbp->sb_dblocks - lsize; | 813 | statp->f_blocks = sbp->sb_dblocks - lsize; |
814 | statp->f_bfree = statp->f_bavail = sbp->sb_fdblocks; | 814 | statp->f_bfree = statp->f_bavail = |
815 | sbp->sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); | ||
815 | fakeinos = statp->f_bfree << sbp->sb_inopblog; | 816 | fakeinos = statp->f_bfree << sbp->sb_inopblog; |
816 | #if XFS_BIG_INUMS | 817 | #if XFS_BIG_INUMS |
817 | fakeinos += mp->m_inoadd; | 818 | fakeinos += mp->m_inoadd; |