diff options
Diffstat (limited to 'fs/jfs/jfs_dmap.c')
-rw-r--r-- | fs/jfs/jfs_dmap.c | 126 |
1 files changed, 122 insertions, 4 deletions
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 9cbd11a3f804..9a55f53be5ff 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) International Business Machines Corp., 2000-2004 | 2 | * Copyright (C) International Business Machines Corp., 2000-2004 |
3 | * Portions Copyright (C) Tino Reichardt, 2012 | ||
3 | * | 4 | * |
4 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -25,6 +26,7 @@ | |||
25 | #include "jfs_lock.h" | 26 | #include "jfs_lock.h" |
26 | #include "jfs_metapage.h" | 27 | #include "jfs_metapage.h" |
27 | #include "jfs_debug.h" | 28 | #include "jfs_debug.h" |
29 | #include "jfs_discard.h" | ||
28 | 30 | ||
29 | /* | 31 | /* |
30 | * SERIALIZATION of the Block Allocation Map. | 32 | * SERIALIZATION of the Block Allocation Map. |
@@ -104,7 +106,6 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno, | |||
104 | static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno, | 106 | static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno, |
105 | int nblocks); | 107 | int nblocks); |
106 | static int dbMaxBud(u8 * cp); | 108 | static int dbMaxBud(u8 * cp); |
107 | s64 dbMapFileSizeToMapSize(struct inode *ipbmap); | ||
108 | static int blkstol2(s64 nb); | 109 | static int blkstol2(s64 nb); |
109 | 110 | ||
110 | static int cntlz(u32 value); | 111 | static int cntlz(u32 value); |
@@ -145,7 +146,6 @@ static const s8 budtab[256] = { | |||
145 | 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 | 146 | 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 |
146 | }; | 147 | }; |
147 | 148 | ||
148 | |||
149 | /* | 149 | /* |
150 | * NAME: dbMount() | 150 | * NAME: dbMount() |
151 | * | 151 | * |
@@ -310,7 +310,6 @@ int dbSync(struct inode *ipbmap) | |||
310 | return (0); | 310 | return (0); |
311 | } | 311 | } |
312 | 312 | ||
313 | |||
314 | /* | 313 | /* |
315 | * NAME: dbFree() | 314 | * NAME: dbFree() |
316 | * | 315 | * |
@@ -337,6 +336,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks) | |||
337 | s64 lblkno, rem; | 336 | s64 lblkno, rem; |
338 | struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; | 337 | struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; |
339 | struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap; | 338 | struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap; |
339 | struct super_block *sb = ipbmap->i_sb; | ||
340 | 340 | ||
341 | IREAD_LOCK(ipbmap, RDWRLOCK_DMAP); | 341 | IREAD_LOCK(ipbmap, RDWRLOCK_DMAP); |
342 | 342 | ||
@@ -351,6 +351,13 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks) | |||
351 | return -EIO; | 351 | return -EIO; |
352 | } | 352 | } |
353 | 353 | ||
354 | /** | ||
355 | * TRIM the blocks, when mounted with discard option | ||
356 | */ | ||
357 | if (JFS_SBI(sb)->flag & JFS_DISCARD) | ||
358 | if (JFS_SBI(sb)->minblks_trim <= nblocks) | ||
359 | jfs_issue_discard(ipbmap, blkno, nblocks); | ||
360 | |||
354 | /* | 361 | /* |
355 | * free the blocks a dmap at a time. | 362 | * free the blocks a dmap at a time. |
356 | */ | 363 | */ |
@@ -1095,7 +1102,6 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) | |||
1095 | /* we were not successful */ | 1102 | /* we were not successful */ |
1096 | release_metapage(mp); | 1103 | release_metapage(mp); |
1097 | 1104 | ||
1098 | |||
1099 | return (rc); | 1105 | return (rc); |
1100 | } | 1106 | } |
1101 | 1107 | ||
@@ -1590,6 +1596,118 @@ static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results) | |||
1590 | 1596 | ||
1591 | 1597 | ||
1592 | /* | 1598 | /* |
1599 | * NAME: dbDiscardAG() | ||
1600 | * | ||
1601 | * FUNCTION: attempt to discard (TRIM) all free blocks of specific AG | ||
1602 | * | ||
1603 | * algorithm: | ||
1604 | * 1) allocate blocks, as large as possible and save them | ||
1605 | * while holding IWRITE_LOCK on ipbmap | ||
1606 | * 2) trim all these saved block/length values | ||
1607 | * 3) mark the blocks free again | ||
1608 | * | ||
1609 | * benefit: | ||
1610 | * - we work only on one ag at some time, minimizing how long we | ||
1611 | * need to lock ipbmap | ||
1612 | * - reading / writing the fs is possible most time, even on | ||
1613 | * trimming | ||
1614 | * | ||
1615 | * downside: | ||
1616 | * - we write two times to the dmapctl and dmap pages | ||
1617 | * - but for me, this seems the best way, better ideas? | ||
1618 | * /TR 2012 | ||
1619 | * | ||
1620 | * PARAMETERS: | ||
1621 | * ip - pointer to in-core inode | ||
1622 | * agno - ag to trim | ||
1623 | * minlen - minimum value of contiguous blocks | ||
1624 | * | ||
1625 | * RETURN VALUES: | ||
1626 | * s64 - actual number of blocks trimmed | ||
1627 | */ | ||
1628 | s64 dbDiscardAG(struct inode *ip, int agno, s64 minlen) | ||
1629 | { | ||
1630 | struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; | ||
1631 | struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap; | ||
1632 | s64 nblocks, blkno; | ||
1633 | u64 trimmed = 0; | ||
1634 | int rc, l2nb; | ||
1635 | struct super_block *sb = ipbmap->i_sb; | ||
1636 | |||
1637 | struct range2trim { | ||
1638 | u64 blkno; | ||
1639 | u64 nblocks; | ||
1640 | } *totrim, *tt; | ||
1641 | |||
1642 | /* max blkno / nblocks pairs to trim */ | ||
1643 | int count = 0, range_cnt; | ||
1644 | u64 max_ranges; | ||
1645 | |||
1646 | /* prevent others from writing new stuff here, while trimming */ | ||
1647 | IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP); | ||
1648 | |||
1649 | nblocks = bmp->db_agfree[agno]; | ||
1650 | max_ranges = nblocks; | ||
1651 | do_div(max_ranges, minlen); | ||
1652 | range_cnt = min_t(u64, max_ranges + 1, 32 * 1024); | ||
1653 | totrim = kmalloc(sizeof(struct range2trim) * range_cnt, GFP_NOFS); | ||
1654 | if (totrim == NULL) { | ||
1655 | jfs_error(bmp->db_ipbmap->i_sb, | ||
1656 | "dbDiscardAG: no memory for trim array"); | ||
1657 | IWRITE_UNLOCK(ipbmap); | ||
1658 | return 0; | ||
1659 | } | ||
1660 | |||
1661 | tt = totrim; | ||
1662 | while (nblocks >= minlen) { | ||
1663 | l2nb = BLKSTOL2(nblocks); | ||
1664 | |||
1665 | /* 0 = okay, -EIO = fatal, -ENOSPC -> try smaller block */ | ||
1666 | rc = dbAllocAG(bmp, agno, nblocks, l2nb, &blkno); | ||
1667 | if (rc == 0) { | ||
1668 | tt->blkno = blkno; | ||
1669 | tt->nblocks = nblocks; | ||
1670 | tt++; count++; | ||
1671 | |||
1672 | /* the whole ag is free, trim now */ | ||
1673 | if (bmp->db_agfree[agno] == 0) | ||
1674 | break; | ||
1675 | |||
1676 | /* give a hint for the next while */ | ||
1677 | nblocks = bmp->db_agfree[agno]; | ||
1678 | continue; | ||
1679 | } else if (rc == -ENOSPC) { | ||
1680 | /* search for next smaller log2 block */ | ||
1681 | l2nb = BLKSTOL2(nblocks) - 1; | ||
1682 | nblocks = 1 << l2nb; | ||
1683 | } else { | ||
1684 | /* Trim any already allocated blocks */ | ||
1685 | jfs_error(bmp->db_ipbmap->i_sb, | ||
1686 | "dbDiscardAG: -EIO"); | ||
1687 | break; | ||
1688 | } | ||
1689 | |||
1690 | /* check, if our trim array is full */ | ||
1691 | if (unlikely(count >= range_cnt - 1)) | ||
1692 | break; | ||
1693 | } | ||
1694 | IWRITE_UNLOCK(ipbmap); | ||
1695 | |||
1696 | tt->nblocks = 0; /* mark the current end */ | ||
1697 | for (tt = totrim; tt->nblocks != 0; tt++) { | ||
1698 | /* when mounted with online discard, dbFree() will | ||
1699 | * call jfs_issue_discard() itself */ | ||
1700 | if (!(JFS_SBI(sb)->flag & JFS_DISCARD)) | ||
1701 | jfs_issue_discard(ip, tt->blkno, tt->nblocks); | ||
1702 | dbFree(ip, tt->blkno, tt->nblocks); | ||
1703 | trimmed += tt->nblocks; | ||
1704 | } | ||
1705 | kfree(totrim); | ||
1706 | |||
1707 | return trimmed; | ||
1708 | } | ||
1709 | |||
1710 | /* | ||
1593 | * NAME: dbFindCtl() | 1711 | * NAME: dbFindCtl() |
1594 | * | 1712 | * |
1595 | * FUNCTION: starting at a specified dmap control page level and block | 1713 | * FUNCTION: starting at a specified dmap control page level and block |