diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-03 11:48:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-03 11:48:21 -0400 |
commit | eb0ad9c06d51edb5d18a7007fd4d77a8805b2ba7 (patch) | |
tree | 987595aa0cfa6e9fdf367a1ec3f5e8b04849c777 /fs/jfs | |
parent | 1f7df953d687860690cc0e388d0efec215c09e9c (diff) | |
parent | 84f4141ee3ea11035f741d4298cb6bbad1850fcf (diff) |
Merge tag 'jfs-3.7' of git://github.com/kleikamp/linux-shaggy
Pull JFS update from Dave Kleikamp:
"JFS TRIM support and some minor fixes"
* tag 'jfs-3.7' of git://github.com/kleikamp/linux-shaggy:
jfs: Fix do_div precision in commit b40c2e66
JFS: use list_move instead of list_del/list_add
jfs: Remove obsolete email address
fs/jfs: TRIM support for JFS Filesystem
Diffstat (limited to 'fs/jfs')
-rw-r--r-- | fs/jfs/Makefile | 2 | ||||
-rw-r--r-- | fs/jfs/ioctl.c | 43 | ||||
-rw-r--r-- | fs/jfs/jfs_discard.c | 117 | ||||
-rw-r--r-- | fs/jfs/jfs_discard.h | 26 | ||||
-rw-r--r-- | fs/jfs/jfs_dmap.c | 126 | ||||
-rw-r--r-- | fs/jfs/jfs_dmap.h | 2 | ||||
-rw-r--r-- | fs/jfs/jfs_filsys.h | 3 | ||||
-rw-r--r-- | fs/jfs/jfs_incore.h | 1 | ||||
-rw-r--r-- | fs/jfs/jfs_txnmgr.c | 9 | ||||
-rw-r--r-- | fs/jfs/super.c | 71 |
10 files changed, 373 insertions, 27 deletions
diff --git a/fs/jfs/Makefile b/fs/jfs/Makefile index a58fa72d7e59..d20d4737b3ef 100644 --- a/fs/jfs/Makefile +++ b/fs/jfs/Makefile | |||
@@ -6,7 +6,7 @@ obj-$(CONFIG_JFS_FS) += jfs.o | |||
6 | 6 | ||
7 | jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \ | 7 | jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \ |
8 | jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \ | 8 | jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \ |
9 | jfs_unicode.o jfs_dtree.o jfs_inode.o \ | 9 | jfs_unicode.o jfs_dtree.o jfs_inode.o jfs_discard.o \ |
10 | jfs_extent.o symlink.o jfs_metapage.o \ | 10 | jfs_extent.o symlink.o jfs_metapage.o \ |
11 | jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \ | 11 | jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \ |
12 | resize.o xattr.o ioctl.o | 12 | resize.o xattr.o ioctl.o |
diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c index f19d1e04a374..bc555ff417e9 100644 --- a/fs/jfs/ioctl.c +++ b/fs/jfs/ioctl.c | |||
@@ -11,13 +11,17 @@ | |||
11 | #include <linux/mount.h> | 11 | #include <linux/mount.h> |
12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/blkdev.h> | ||
14 | #include <asm/current.h> | 15 | #include <asm/current.h> |
15 | #include <asm/uaccess.h> | 16 | #include <asm/uaccess.h> |
16 | 17 | ||
18 | #include "jfs_filsys.h" | ||
19 | #include "jfs_debug.h" | ||
17 | #include "jfs_incore.h" | 20 | #include "jfs_incore.h" |
18 | #include "jfs_dinode.h" | 21 | #include "jfs_dinode.h" |
19 | #include "jfs_inode.h" | 22 | #include "jfs_inode.h" |
20 | 23 | #include "jfs_dmap.h" | |
24 | #include "jfs_discard.h" | ||
21 | 25 | ||
22 | static struct { | 26 | static struct { |
23 | long jfs_flag; | 27 | long jfs_flag; |
@@ -123,6 +127,40 @@ setflags_out: | |||
123 | mnt_drop_write_file(filp); | 127 | mnt_drop_write_file(filp); |
124 | return err; | 128 | return err; |
125 | } | 129 | } |
130 | |||
131 | case FITRIM: | ||
132 | { | ||
133 | struct super_block *sb = inode->i_sb; | ||
134 | struct request_queue *q = bdev_get_queue(sb->s_bdev); | ||
135 | struct fstrim_range range; | ||
136 | s64 ret = 0; | ||
137 | |||
138 | if (!capable(CAP_SYS_ADMIN)) | ||
139 | return -EPERM; | ||
140 | |||
141 | if (!blk_queue_discard(q)) { | ||
142 | jfs_warn("FITRIM not supported on device"); | ||
143 | return -EOPNOTSUPP; | ||
144 | } | ||
145 | |||
146 | if (copy_from_user(&range, (struct fstrim_range __user *)arg, | ||
147 | sizeof(range))) | ||
148 | return -EFAULT; | ||
149 | |||
150 | range.minlen = max_t(unsigned int, range.minlen, | ||
151 | q->limits.discard_granularity); | ||
152 | |||
153 | ret = jfs_ioc_trim(inode, &range); | ||
154 | if (ret < 0) | ||
155 | return ret; | ||
156 | |||
157 | if (copy_to_user((struct fstrim_range __user *)arg, &range, | ||
158 | sizeof(range))) | ||
159 | return -EFAULT; | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
126 | default: | 164 | default: |
127 | return -ENOTTY; | 165 | return -ENOTTY; |
128 | } | 166 | } |
@@ -142,6 +180,9 @@ long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
142 | case JFS_IOC_SETFLAGS32: | 180 | case JFS_IOC_SETFLAGS32: |
143 | cmd = JFS_IOC_SETFLAGS; | 181 | cmd = JFS_IOC_SETFLAGS; |
144 | break; | 182 | break; |
183 | case FITRIM: | ||
184 | cmd = FITRIM; | ||
185 | break; | ||
145 | } | 186 | } |
146 | return jfs_ioctl(filp, cmd, arg); | 187 | return jfs_ioctl(filp, cmd, arg); |
147 | } | 188 | } |
diff --git a/fs/jfs/jfs_discard.c b/fs/jfs/jfs_discard.c new file mode 100644 index 000000000000..9947563e4175 --- /dev/null +++ b/fs/jfs/jfs_discard.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * Copyright (C) Tino Reichardt, 2012 | ||
3 | * | ||
4 | * 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 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
12 | * the GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include <linux/fs.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/blkdev.h> | ||
22 | |||
23 | #include "jfs_incore.h" | ||
24 | #include "jfs_superblock.h" | ||
25 | #include "jfs_discard.h" | ||
26 | #include "jfs_dmap.h" | ||
27 | #include "jfs_debug.h" | ||
28 | |||
29 | |||
30 | /* | ||
31 | * NAME: jfs_issue_discard() | ||
32 | * | ||
33 | * FUNCTION: TRIM the specified block range on device, if supported | ||
34 | * | ||
35 | * PARAMETERS: | ||
36 | * ip - pointer to in-core inode | ||
37 | * blkno - starting block number to be trimmed (0..N) | ||
38 | * nblocks - number of blocks to be trimmed | ||
39 | * | ||
40 | * RETURN VALUES: | ||
41 | * none | ||
42 | * | ||
43 | * serialization: IREAD_LOCK(ipbmap) held on entry/exit; | ||
44 | */ | ||
45 | void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks) | ||
46 | { | ||
47 | struct super_block *sb = ip->i_sb; | ||
48 | int r = 0; | ||
49 | |||
50 | r = sb_issue_discard(sb, blkno, nblocks, GFP_NOFS, 0); | ||
51 | if (unlikely(r != 0)) { | ||
52 | jfs_err("JFS: sb_issue_discard" \ | ||
53 | "(%p, %llu, %llu, GFP_NOFS, 0) = %d => failed!\n", | ||
54 | sb, (unsigned long long)blkno, | ||
55 | (unsigned long long)nblocks, r); | ||
56 | } | ||
57 | |||
58 | jfs_info("JFS: sb_issue_discard" \ | ||
59 | "(%p, %llu, %llu, GFP_NOFS, 0) = %d\n", | ||
60 | sb, (unsigned long long)blkno, | ||
61 | (unsigned long long)nblocks, r); | ||
62 | |||
63 | return; | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * NAME: jfs_ioc_trim() | ||
68 | * | ||
69 | * FUNCTION: attempt to discard (TRIM) all free blocks from the | ||
70 | * filesystem. | ||
71 | * | ||
72 | * PARAMETERS: | ||
73 | * ip - pointer to in-core inode; | ||
74 | * range - the range, given by user space | ||
75 | * | ||
76 | * RETURN VALUES: | ||
77 | * 0 - success | ||
78 | * -EIO - i/o error | ||
79 | */ | ||
80 | int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range) | ||
81 | { | ||
82 | struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; | ||
83 | struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap; | ||
84 | struct super_block *sb = ipbmap->i_sb; | ||
85 | int agno, agno_end; | ||
86 | s64 start, end, minlen; | ||
87 | u64 trimmed = 0; | ||
88 | |||
89 | /** | ||
90 | * convert byte values to block size of filesystem: | ||
91 | * start: First Byte to trim | ||
92 | * len: number of Bytes to trim from start | ||
93 | * minlen: minimum extent length in Bytes | ||
94 | */ | ||
95 | start = range->start >> sb->s_blocksize_bits; | ||
96 | if (start < 0) | ||
97 | start = 0; | ||
98 | end = start + (range->len >> sb->s_blocksize_bits) - 1; | ||
99 | if (end >= bmp->db_mapsize) | ||
100 | end = bmp->db_mapsize - 1; | ||
101 | minlen = range->minlen >> sb->s_blocksize_bits; | ||
102 | if (minlen <= 0) | ||
103 | minlen = 1; | ||
104 | |||
105 | /** | ||
106 | * we trim all ag's within the range | ||
107 | */ | ||
108 | agno = BLKTOAG(start, JFS_SBI(ip->i_sb)); | ||
109 | agno_end = BLKTOAG(end, JFS_SBI(ip->i_sb)); | ||
110 | while (agno <= agno_end) { | ||
111 | trimmed += dbDiscardAG(ip, agno, minlen); | ||
112 | agno++; | ||
113 | } | ||
114 | range->len = trimmed << sb->s_blocksize_bits; | ||
115 | |||
116 | return 0; | ||
117 | } | ||
diff --git a/fs/jfs/jfs_discard.h b/fs/jfs/jfs_discard.h new file mode 100644 index 000000000000..40d1ee6081a0 --- /dev/null +++ b/fs/jfs/jfs_discard.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Copyright (C) Tino Reichardt, 2012 | ||
3 | * | ||
4 | * 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 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
12 | * the GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _H_JFS_DISCARD | ||
19 | #define _H_JFS_DISCARD | ||
20 | |||
21 | struct fstrim_range; | ||
22 | |||
23 | extern void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks); | ||
24 | extern int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range); | ||
25 | |||
26 | #endif /* _H_JFS_DISCARD */ | ||
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 |
diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h index 6dcb906c55d8..562b9a7e4311 100644 --- a/fs/jfs/jfs_dmap.h +++ b/fs/jfs/jfs_dmap.h | |||
@@ -311,4 +311,6 @@ extern int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks); | |||
311 | extern int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks); | 311 | extern int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks); |
312 | extern void dbFinalizeBmap(struct inode *ipbmap); | 312 | extern void dbFinalizeBmap(struct inode *ipbmap); |
313 | extern s64 dbMapFileSizeToMapSize(struct inode *ipbmap); | 313 | extern s64 dbMapFileSizeToMapSize(struct inode *ipbmap); |
314 | extern s64 dbDiscardAG(struct inode *ip, int agno, s64 minlen); | ||
315 | |||
314 | #endif /* _H_JFS_DMAP */ | 316 | #endif /* _H_JFS_DMAP */ |
diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h index b3f5463fbe52..b67d64671bb4 100644 --- a/fs/jfs/jfs_filsys.h +++ b/fs/jfs/jfs_filsys.h | |||
@@ -45,6 +45,9 @@ | |||
45 | /* mount time flag to disable journaling to disk */ | 45 | /* mount time flag to disable journaling to disk */ |
46 | #define JFS_NOINTEGRITY 0x00000040 | 46 | #define JFS_NOINTEGRITY 0x00000040 |
47 | 47 | ||
48 | /* mount time flag to enable TRIM to ssd disks */ | ||
49 | #define JFS_DISCARD 0x00000080 | ||
50 | |||
48 | /* commit option */ | 51 | /* commit option */ |
49 | #define JFS_COMMIT 0x00000f00 /* commit option mask */ | 52 | #define JFS_COMMIT 0x00000f00 /* commit option mask */ |
50 | #define JFS_GROUPCOMMIT 0x00000100 /* group (of 1) commit */ | 53 | #define JFS_GROUPCOMMIT 0x00000100 /* group (of 1) commit */ |
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index 680605d7bf15..cf47f09e8ac8 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h | |||
@@ -195,6 +195,7 @@ struct jfs_sb_info { | |||
195 | kuid_t uid; /* uid to override on-disk uid */ | 195 | kuid_t uid; /* uid to override on-disk uid */ |
196 | kgid_t gid; /* gid to override on-disk gid */ | 196 | kgid_t gid; /* gid to override on-disk gid */ |
197 | uint umask; /* umask to override on-disk umask */ | 197 | uint umask; /* umask to override on-disk umask */ |
198 | uint minblks_trim; /* minimum blocks, for online trim */ | ||
198 | }; | 199 | }; |
199 | 200 | ||
200 | /* jfs_sb_info commit_state */ | 201 | /* jfs_sb_info commit_state */ |
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index bb8b661bcc50..5fcc02eaa64c 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c | |||
@@ -2977,12 +2977,9 @@ int jfs_sync(void *arg) | |||
2977 | * put back on the anon_list. | 2977 | * put back on the anon_list. |
2978 | */ | 2978 | */ |
2979 | 2979 | ||
2980 | /* Take off anon_list */ | 2980 | /* Move from anon_list to anon_list2 */ |
2981 | list_del(&jfs_ip->anon_inode_list); | 2981 | list_move(&jfs_ip->anon_inode_list, |
2982 | 2982 | &TxAnchor.anon_list2); | |
2983 | /* Put on anon_list2 */ | ||
2984 | list_add(&jfs_ip->anon_inode_list, | ||
2985 | &TxAnchor.anon_list2); | ||
2986 | 2983 | ||
2987 | TXN_UNLOCK(); | 2984 | TXN_UNLOCK(); |
2988 | iput(ip); | 2985 | iput(ip); |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index efdf8835dfca..1a543be09c79 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
35 | #include <linux/seq_file.h> | 35 | #include <linux/seq_file.h> |
36 | #include <linux/blkdev.h> | ||
36 | 37 | ||
37 | #include "jfs_incore.h" | 38 | #include "jfs_incore.h" |
38 | #include "jfs_filsys.h" | 39 | #include "jfs_filsys.h" |
@@ -100,7 +101,7 @@ void jfs_error(struct super_block *sb, const char * function, ...) | |||
100 | vsnprintf(error_buf, sizeof(error_buf), function, args); | 101 | vsnprintf(error_buf, sizeof(error_buf), function, args); |
101 | va_end(args); | 102 | va_end(args); |
102 | 103 | ||
103 | printk(KERN_ERR "ERROR: (device %s): %s\n", sb->s_id, error_buf); | 104 | pr_err("ERROR: (device %s): %s\n", sb->s_id, error_buf); |
104 | 105 | ||
105 | jfs_handle_error(sb); | 106 | jfs_handle_error(sb); |
106 | } | 107 | } |
@@ -197,7 +198,8 @@ static void jfs_put_super(struct super_block *sb) | |||
197 | enum { | 198 | enum { |
198 | Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, | 199 | Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, |
199 | Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, | 200 | Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, |
200 | Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask | 201 | Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask, |
202 | Opt_discard, Opt_nodiscard, Opt_discard_minblk | ||
201 | }; | 203 | }; |
202 | 204 | ||
203 | static const match_table_t tokens = { | 205 | static const match_table_t tokens = { |
@@ -214,6 +216,9 @@ static const match_table_t tokens = { | |||
214 | {Opt_uid, "uid=%u"}, | 216 | {Opt_uid, "uid=%u"}, |
215 | {Opt_gid, "gid=%u"}, | 217 | {Opt_gid, "gid=%u"}, |
216 | {Opt_umask, "umask=%u"}, | 218 | {Opt_umask, "umask=%u"}, |
219 | {Opt_discard, "discard"}, | ||
220 | {Opt_nodiscard, "nodiscard"}, | ||
221 | {Opt_discard_minblk, "discard=%u"}, | ||
217 | {Opt_err, NULL} | 222 | {Opt_err, NULL} |
218 | }; | 223 | }; |
219 | 224 | ||
@@ -255,8 +260,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, | |||
255 | else { | 260 | else { |
256 | nls_map = load_nls(args[0].from); | 261 | nls_map = load_nls(args[0].from); |
257 | if (!nls_map) { | 262 | if (!nls_map) { |
258 | printk(KERN_ERR | 263 | pr_err("JFS: charset not found\n"); |
259 | "JFS: charset not found\n"); | ||
260 | goto cleanup; | 264 | goto cleanup; |
261 | } | 265 | } |
262 | } | 266 | } |
@@ -272,8 +276,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, | |||
272 | *newLVSize = sb->s_bdev->bd_inode->i_size >> | 276 | *newLVSize = sb->s_bdev->bd_inode->i_size >> |
273 | sb->s_blocksize_bits; | 277 | sb->s_blocksize_bits; |
274 | if (*newLVSize == 0) | 278 | if (*newLVSize == 0) |
275 | printk(KERN_ERR | 279 | pr_err("JFS: Cannot determine volume size\n"); |
276 | "JFS: Cannot determine volume size\n"); | ||
277 | break; | 280 | break; |
278 | } | 281 | } |
279 | case Opt_errors: | 282 | case Opt_errors: |
@@ -294,8 +297,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, | |||
294 | *flag &= ~JFS_ERR_REMOUNT_RO; | 297 | *flag &= ~JFS_ERR_REMOUNT_RO; |
295 | *flag |= JFS_ERR_PANIC; | 298 | *flag |= JFS_ERR_PANIC; |
296 | } else { | 299 | } else { |
297 | printk(KERN_ERR | 300 | pr_err("JFS: %s is an invalid error handler\n", |
298 | "JFS: %s is an invalid error handler\n", | ||
299 | errors); | 301 | errors); |
300 | goto cleanup; | 302 | goto cleanup; |
301 | } | 303 | } |
@@ -314,8 +316,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, | |||
314 | case Opt_usrquota: | 316 | case Opt_usrquota: |
315 | case Opt_grpquota: | 317 | case Opt_grpquota: |
316 | case Opt_quota: | 318 | case Opt_quota: |
317 | printk(KERN_ERR | 319 | pr_err("JFS: quota operations not supported\n"); |
318 | "JFS: quota operations not supported\n"); | ||
319 | break; | 320 | break; |
320 | #endif | 321 | #endif |
321 | case Opt_uid: | 322 | case Opt_uid: |
@@ -327,6 +328,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, | |||
327 | goto cleanup; | 328 | goto cleanup; |
328 | break; | 329 | break; |
329 | } | 330 | } |
331 | |||
330 | case Opt_gid: | 332 | case Opt_gid: |
331 | { | 333 | { |
332 | char *gid = args[0].from; | 334 | char *gid = args[0].from; |
@@ -336,17 +338,54 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, | |||
336 | goto cleanup; | 338 | goto cleanup; |
337 | break; | 339 | break; |
338 | } | 340 | } |
341 | |||
339 | case Opt_umask: | 342 | case Opt_umask: |
340 | { | 343 | { |
341 | char *umask = args[0].from; | 344 | char *umask = args[0].from; |
342 | sbi->umask = simple_strtoul(umask, &umask, 8); | 345 | sbi->umask = simple_strtoul(umask, &umask, 8); |
343 | if (sbi->umask & ~0777) { | 346 | if (sbi->umask & ~0777) { |
344 | printk(KERN_ERR | 347 | pr_err("JFS: Invalid value of umask\n"); |
345 | "JFS: Invalid value of umask\n"); | ||
346 | goto cleanup; | 348 | goto cleanup; |
347 | } | 349 | } |
348 | break; | 350 | break; |
349 | } | 351 | } |
352 | |||
353 | case Opt_discard: | ||
354 | { | ||
355 | struct request_queue *q = bdev_get_queue(sb->s_bdev); | ||
356 | /* if set to 1, even copying files will cause | ||
357 | * trimming :O | ||
358 | * -> user has more control over the online trimming | ||
359 | */ | ||
360 | sbi->minblks_trim = 64; | ||
361 | if (blk_queue_discard(q)) { | ||
362 | *flag |= JFS_DISCARD; | ||
363 | } else { | ||
364 | pr_err("JFS: discard option " \ | ||
365 | "not supported on device\n"); | ||
366 | } | ||
367 | break; | ||
368 | } | ||
369 | |||
370 | case Opt_nodiscard: | ||
371 | *flag &= ~JFS_DISCARD; | ||
372 | break; | ||
373 | |||
374 | case Opt_discard_minblk: | ||
375 | { | ||
376 | struct request_queue *q = bdev_get_queue(sb->s_bdev); | ||
377 | char *minblks_trim = args[0].from; | ||
378 | if (blk_queue_discard(q)) { | ||
379 | *flag |= JFS_DISCARD; | ||
380 | sbi->minblks_trim = simple_strtoull( | ||
381 | minblks_trim, &minblks_trim, 0); | ||
382 | } else { | ||
383 | pr_err("JFS: discard option " \ | ||
384 | "not supported on device\n"); | ||
385 | } | ||
386 | break; | ||
387 | } | ||
388 | |||
350 | default: | 389 | default: |
351 | printk("jfs: Unrecognized mount option \"%s\" " | 390 | printk("jfs: Unrecognized mount option \"%s\" " |
352 | " or missing value\n", p); | 391 | " or missing value\n", p); |
@@ -380,8 +419,8 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data) | |||
380 | 419 | ||
381 | if (newLVSize) { | 420 | if (newLVSize) { |
382 | if (sb->s_flags & MS_RDONLY) { | 421 | if (sb->s_flags & MS_RDONLY) { |
383 | printk(KERN_ERR | 422 | pr_err("JFS: resize requires volume" \ |
384 | "JFS: resize requires volume to be mounted read-write\n"); | 423 | " to be mounted read-write\n"); |
385 | return -EROFS; | 424 | return -EROFS; |
386 | } | 425 | } |
387 | rc = jfs_extendfs(sb, newLVSize, 0); | 426 | rc = jfs_extendfs(sb, newLVSize, 0); |
@@ -465,7 +504,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) | |||
465 | #endif | 504 | #endif |
466 | 505 | ||
467 | if (newLVSize) { | 506 | if (newLVSize) { |
468 | printk(KERN_ERR "resize option for remount only\n"); | 507 | pr_err("resize option for remount only\n"); |
469 | goto out_kfree; | 508 | goto out_kfree; |
470 | } | 509 | } |
471 | 510 | ||
@@ -633,6 +672,8 @@ static int jfs_show_options(struct seq_file *seq, struct dentry *root) | |||
633 | seq_printf(seq, ",umask=%03o", sbi->umask); | 672 | seq_printf(seq, ",umask=%03o", sbi->umask); |
634 | if (sbi->flag & JFS_NOINTEGRITY) | 673 | if (sbi->flag & JFS_NOINTEGRITY) |
635 | seq_puts(seq, ",nointegrity"); | 674 | seq_puts(seq, ",nointegrity"); |
675 | if (sbi->flag & JFS_DISCARD) | ||
676 | seq_printf(seq, ",discard=%u", sbi->minblks_trim); | ||
636 | if (sbi->nls_tab) | 677 | if (sbi->nls_tab) |
637 | seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset); | 678 | seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset); |
638 | if (sbi->flag & JFS_ERR_CONTINUE) | 679 | if (sbi->flag & JFS_ERR_CONTINUE) |