aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/jfs.txt19
-rw-r--r--fs/jfs/Makefile2
-rw-r--r--fs/jfs/ioctl.c43
-rw-r--r--fs/jfs/jfs_discard.c117
-rw-r--r--fs/jfs/jfs_discard.h26
-rw-r--r--fs/jfs/jfs_dmap.c125
-rw-r--r--fs/jfs/jfs_dmap.h2
-rw-r--r--fs/jfs/jfs_filsys.h3
-rw-r--r--fs/jfs/jfs_incore.h1
-rw-r--r--fs/jfs/super.c71
10 files changed, 385 insertions, 24 deletions
diff --git a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt
index 26ebde77e821..2f94f9ca1794 100644
--- a/Documentation/filesystems/jfs.txt
+++ b/Documentation/filesystems/jfs.txt
@@ -3,6 +3,7 @@ IBM's Journaled File System (JFS) for Linux
3JFS Homepage: http://jfs.sourceforge.net/ 3JFS Homepage: http://jfs.sourceforge.net/
4 4
5The following mount options are supported: 5The following mount options are supported:
6(*) == default
6 7
7iocharset=name Character set to use for converting from Unicode to 8iocharset=name Character set to use for converting from Unicode to
8 ASCII. The default is to do no conversion. Use 9 ASCII. The default is to do no conversion. Use
@@ -21,12 +22,12 @@ nointegrity Do not write to the journal. The primary use of this option
21 from backup media. The integrity of the volume is not 22 from backup media. The integrity of the volume is not
22 guaranteed if the system abnormally abends. 23 guaranteed if the system abnormally abends.
23 24
24integrity Default. Commit metadata changes to the journal. Use this 25integrity(*) Commit metadata changes to the journal. Use this option to
25 option to remount a volume where the nointegrity option was 26 remount a volume where the nointegrity option was
26 previously specified in order to restore normal behavior. 27 previously specified in order to restore normal behavior.
27 28
28errors=continue Keep going on a filesystem error. 29errors=continue Keep going on a filesystem error.
29errors=remount-ro Default. Remount the filesystem read-only on an error. 30errors=remount-ro(*) Remount the filesystem read-only on an error.
30errors=panic Panic and halt the machine if an error occurs. 31errors=panic Panic and halt the machine if an error occurs.
31 32
32uid=value Override on-disk uid with specified value 33uid=value Override on-disk uid with specified value
@@ -35,6 +36,18 @@ umask=value Override on-disk umask with specified octal value. For
35 directories, the execute bit will be set if the corresponding 36 directories, the execute bit will be set if the corresponding
36 read bit is set. 37 read bit is set.
37 38
39discard=minlen This enables/disables the use of discard/TRIM commands.
40discard The discard/TRIM commands are sent to the underlying
41nodiscard(*) block device when blocks are freed. This is useful for SSD
42 devices and sparse/thinly-provisioned LUNs. The FITRIM ioctl
43 command is also available together with the nodiscard option.
44 The value of minlen specifies the minimum blockcount, when
45 a TRIM command to the block device is considered usefull.
46 When no value is given to the discard option, it defaults to
47 64 blocks, which means 256KiB in JFS.
48 The minlen value of discard overrides the minlen value given
49 on an FITRIM ioctl().
50
38Please send bugs, comments, cards and letters to shaggy@linux.vnet.ibm.com. 51Please send bugs, comments, cards and letters to shaggy@linux.vnet.ibm.com.
39 52
40The JFS mailing list can be subscribed to by using the link labeled 53The JFS mailing list can be subscribed to by using the link labeled
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
7jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \ 7jfs-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
22static struct { 26static 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 */
45void 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 */
80int 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
21struct fstrim_range;
22
23extern void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks);
24extern 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..174feb6a73c1 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,117 @@ 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
1645 /* prevent others from writing new stuff here, while trimming */
1646 IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
1647
1648 nblocks = bmp->db_agfree[agno];
1649 range_cnt = nblocks;
1650 do_div(range_cnt, (int)minlen);
1651 range_cnt = min(range_cnt + 1, 32 * 1024);
1652 totrim = kmalloc(sizeof(struct range2trim) * range_cnt, GFP_NOFS);
1653 if (totrim == NULL) {
1654 jfs_error(bmp->db_ipbmap->i_sb,
1655 "dbDiscardAG: no memory for trim array");
1656 IWRITE_UNLOCK(ipbmap);
1657 return 0;
1658 }
1659
1660 tt = totrim;
1661 while (nblocks >= minlen) {
1662 l2nb = BLKSTOL2(nblocks);
1663
1664 /* 0 = okay, -EIO = fatal, -ENOSPC -> try smaller block */
1665 rc = dbAllocAG(bmp, agno, nblocks, l2nb, &blkno);
1666 if (rc == 0) {
1667 tt->blkno = blkno;
1668 tt->nblocks = nblocks;
1669 tt++; count++;
1670
1671 /* the whole ag is free, trim now */
1672 if (bmp->db_agfree[agno] == 0)
1673 break;
1674
1675 /* give a hint for the next while */
1676 nblocks = bmp->db_agfree[agno];
1677 continue;
1678 } else if (rc == -ENOSPC) {
1679 /* search for next smaller log2 block */
1680 l2nb = BLKSTOL2(nblocks) - 1;
1681 nblocks = 1 << l2nb;
1682 } else {
1683 /* Trim any already allocated blocks */
1684 jfs_error(bmp->db_ipbmap->i_sb,
1685 "dbDiscardAG: -EIO");
1686 break;
1687 }
1688
1689 /* check, if our trim array is full */
1690 if (unlikely(count >= range_cnt - 1))
1691 break;
1692 }
1693 IWRITE_UNLOCK(ipbmap);
1694
1695 tt->nblocks = 0; /* mark the current end */
1696 for (tt = totrim; tt->nblocks != 0; tt++) {
1697 /* when mounted with online discard, dbFree() will
1698 * call jfs_issue_discard() itself */
1699 if (!(JFS_SBI(sb)->flag & JFS_DISCARD))
1700 jfs_issue_discard(ip, tt->blkno, tt->nblocks);
1701 dbFree(ip, tt->blkno, tt->nblocks);
1702 trimmed += tt->nblocks;
1703 }
1704 kfree(totrim);
1705
1706 return trimmed;
1707}
1708
1709/*
1593 * NAME: dbFindCtl() 1710 * NAME: dbFindCtl()
1594 * 1711 *
1595 * FUNCTION: starting at a specified dmap control page level and block 1712 * 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);
311extern int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks); 311extern int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks);
312extern void dbFinalizeBmap(struct inode *ipbmap); 312extern void dbFinalizeBmap(struct inode *ipbmap);
313extern s64 dbMapFileSizeToMapSize(struct inode *ipbmap); 313extern s64 dbMapFileSizeToMapSize(struct inode *ipbmap);
314extern 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 584a4a1a6e81..4fa958ae1986 100644
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -195,6 +195,7 @@ struct jfs_sb_info {
195 uint uid; /* uid to override on-disk uid */ 195 uint uid; /* uid to override on-disk uid */
196 uint gid; /* gid to override on-disk gid */ 196 uint 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/super.c b/fs/jfs/super.c
index c55c7452d285..6f4ac1c070f0 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)
197enum { 198enum {
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
203static const match_table_t tokens = { 205static 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:
@@ -324,23 +325,61 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
324 sbi->uid = simple_strtoul(uid, &uid, 0); 325 sbi->uid = simple_strtoul(uid, &uid, 0);
325 break; 326 break;
326 } 327 }
328
327 case Opt_gid: 329 case Opt_gid:
328 { 330 {
329 char *gid = args[0].from; 331 char *gid = args[0].from;
330 sbi->gid = simple_strtoul(gid, &gid, 0); 332 sbi->gid = simple_strtoul(gid, &gid, 0);
331 break; 333 break;
332 } 334 }
335
333 case Opt_umask: 336 case Opt_umask:
334 { 337 {
335 char *umask = args[0].from; 338 char *umask = args[0].from;
336 sbi->umask = simple_strtoul(umask, &umask, 8); 339 sbi->umask = simple_strtoul(umask, &umask, 8);
337 if (sbi->umask & ~0777) { 340 if (sbi->umask & ~0777) {
338 printk(KERN_ERR 341 pr_err("JFS: Invalid value of umask\n");
339 "JFS: Invalid value of umask\n");
340 goto cleanup; 342 goto cleanup;
341 } 343 }
342 break; 344 break;
343 } 345 }
346
347 case Opt_discard:
348 {
349 struct request_queue *q = bdev_get_queue(sb->s_bdev);
350 /* if set to 1, even copying files will cause
351 * trimming :O
352 * -> user has more control over the online trimming
353 */
354 sbi->minblks_trim = 64;
355 if (blk_queue_discard(q)) {
356 *flag |= JFS_DISCARD;
357 } else {
358 pr_err("JFS: discard option " \
359 "not supported on device\n");
360 }
361 break;
362 }
363
364 case Opt_nodiscard:
365 *flag &= ~JFS_DISCARD;
366 break;
367
368 case Opt_discard_minblk:
369 {
370 struct request_queue *q = bdev_get_queue(sb->s_bdev);
371 char *minblks_trim = args[0].from;
372 if (blk_queue_discard(q)) {
373 *flag |= JFS_DISCARD;
374 sbi->minblks_trim = simple_strtoull(
375 minblks_trim, &minblks_trim, 0);
376 } else {
377 pr_err("JFS: discard option " \
378 "not supported on device\n");
379 }
380 break;
381 }
382
344 default: 383 default:
345 printk("jfs: Unrecognized mount option \"%s\" " 384 printk("jfs: Unrecognized mount option \"%s\" "
346 " or missing value\n", p); 385 " or missing value\n", p);
@@ -374,8 +413,8 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
374 413
375 if (newLVSize) { 414 if (newLVSize) {
376 if (sb->s_flags & MS_RDONLY) { 415 if (sb->s_flags & MS_RDONLY) {
377 printk(KERN_ERR 416 pr_err("JFS: resize requires volume" \
378 "JFS: resize requires volume to be mounted read-write\n"); 417 " to be mounted read-write\n");
379 return -EROFS; 418 return -EROFS;
380 } 419 }
381 rc = jfs_extendfs(sb, newLVSize, 0); 420 rc = jfs_extendfs(sb, newLVSize, 0);
@@ -457,7 +496,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
457#endif 496#endif
458 497
459 if (newLVSize) { 498 if (newLVSize) {
460 printk(KERN_ERR "resize option for remount only\n"); 499 pr_err("resize option for remount only\n");
461 goto out_kfree; 500 goto out_kfree;
462 } 501 }
463 502
@@ -625,6 +664,8 @@ static int jfs_show_options(struct seq_file *seq, struct dentry *root)
625 seq_printf(seq, ",umask=%03o", sbi->umask); 664 seq_printf(seq, ",umask=%03o", sbi->umask);
626 if (sbi->flag & JFS_NOINTEGRITY) 665 if (sbi->flag & JFS_NOINTEGRITY)
627 seq_puts(seq, ",nointegrity"); 666 seq_puts(seq, ",nointegrity");
667 if (sbi->flag & JFS_DISCARD)
668 seq_printf(seq, ",discard=%u", sbi->minblks_trim);
628 if (sbi->nls_tab) 669 if (sbi->nls_tab)
629 seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset); 670 seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset);
630 if (sbi->flag & JFS_ERR_CONTINUE) 671 if (sbi->flag & JFS_ERR_CONTINUE)