aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jfs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-03 11:48:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-03 11:48:21 -0400
commiteb0ad9c06d51edb5d18a7007fd4d77a8805b2ba7 (patch)
tree987595aa0cfa6e9fdf367a1ec3f5e8b04849c777 /fs/jfs
parent1f7df953d687860690cc0e388d0efec215c09e9c (diff)
parent84f4141ee3ea11035f741d4298cb6bbad1850fcf (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/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.c126
-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/jfs_txnmgr.c9
-rw-r--r--fs/jfs/super.c71
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
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..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
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 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)
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:
@@ -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)