aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jfs/jfs_dmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jfs/jfs_dmap.c')
-rw-r--r--fs/jfs/jfs_dmap.c126
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,
104static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno, 106static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
105 int nblocks); 107 int nblocks);
106static int dbMaxBud(u8 * cp); 108static int dbMaxBud(u8 * cp);
107s64 dbMapFileSizeToMapSize(struct inode *ipbmap);
108static int blkstol2(s64 nb); 109static int blkstol2(s64 nb);
109 110
110static int cntlz(u32 value); 111static 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 */
1628s64 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