Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b40c2e66 authored by Tino Reichardt's avatar Tino Reichardt Committed by Dave Kleikamp
Browse files

fs/jfs: TRIM support for JFS Filesystem



This patch adds support for the two linux interfaces of the discard/TRIM
command for SSD devices and sparse/thinly-provisioned LUNs.

JFS will support batched discard via FITRIM ioctl and online discard
with the discard mount option.

Signed-off-by: default avatarTino Reichardt <list-jfs@mcmilk.de>
Signed-off-by: default avatarDave Kleikamp <dave.kleikamp@oracle.com>
parent fbcbe2b3
Loading
Loading
Loading
Loading
+16 −3
Original line number Original line Diff line number Diff line
@@ -3,6 +3,7 @@ IBM's Journaled File System (JFS) for Linux
JFS Homepage:  http://jfs.sourceforge.net/
JFS Homepage:  http://jfs.sourceforge.net/


The following mount options are supported:
The following mount options are supported:
(*) == default


iocharset=name	Character set to use for converting from Unicode to
iocharset=name	Character set to use for converting from Unicode to
		ASCII.  The default is to do no conversion.  Use
		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
		from backup media.  The integrity of the volume is not
		from backup media.  The integrity of the volume is not
		guaranteed if the system abnormally abends.
		guaranteed if the system abnormally abends.


integrity	Default.  Commit metadata changes to the journal.  Use this
integrity(*)	Commit metadata changes to the journal.  Use this option to
		option to remount a volume where the nointegrity option was
		remount a volume where the nointegrity option was
		previously specified in order to restore normal behavior.
		previously specified in order to restore normal behavior.


errors=continue		Keep going on a filesystem error.
errors=continue		Keep going on a filesystem error.
errors=remount-ro	Default. Remount the filesystem read-only on an error.
errors=remount-ro(*)	Remount the filesystem read-only on an error.
errors=panic		Panic and halt the machine if an error occurs.
errors=panic		Panic and halt the machine if an error occurs.


uid=value	Override on-disk uid with specified value
uid=value	Override on-disk uid with specified value
@@ -35,6 +36,18 @@ umask=value Override on-disk umask with specified octal value. For
		directories, the execute bit will be set if the corresponding
		directories, the execute bit will be set if the corresponding
		read bit is set.
		read bit is set.


discard=minlen	This enables/disables the use of discard/TRIM commands.
discard		The discard/TRIM commands are sent to the underlying
nodiscard(*)	block device when blocks are freed. This is useful for SSD
		devices and sparse/thinly-provisioned LUNs.  The FITRIM ioctl
		command is also available together with the nodiscard option.
		The value of minlen specifies the minimum blockcount, when
		a TRIM command to the block device is considered usefull.
		When no value is given to the discard option, it defaults to
		64 blocks, which means 256KiB in JFS.
		The minlen value of discard overrides the minlen value given
		on an FITRIM ioctl().

Please send bugs, comments, cards and letters to shaggy@linux.vnet.ibm.com.
Please send bugs, comments, cards and letters to shaggy@linux.vnet.ibm.com.


The JFS mailing list can be subscribed to by using the link labeled
The JFS mailing list can be subscribed to by using the link labeled
+1 −1
Original line number Original line Diff line number Diff line
@@ -6,7 +6,7 @@ obj-$(CONFIG_JFS_FS) += jfs.o


jfs-y    := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \
jfs-y    := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \
	    jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \
	    jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \
	    jfs_unicode.o jfs_dtree.o jfs_inode.o \
	    jfs_unicode.o jfs_dtree.o jfs_inode.o jfs_discard.o \
	    jfs_extent.o symlink.o jfs_metapage.o \
	    jfs_extent.o symlink.o jfs_metapage.o \
	    jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \
	    jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \
	    resize.o xattr.o ioctl.o
	    resize.o xattr.o ioctl.o
+42 −1
Original line number Original line Diff line number Diff line
@@ -11,13 +11,17 @@
#include <linux/mount.h>
#include <linux/mount.h>
#include <linux/time.h>
#include <linux/time.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/blkdev.h>
#include <asm/current.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>


#include "jfs_filsys.h"
#include "jfs_debug.h"
#include "jfs_incore.h"
#include "jfs_incore.h"
#include "jfs_dinode.h"
#include "jfs_dinode.h"
#include "jfs_inode.h"
#include "jfs_inode.h"

#include "jfs_dmap.h"
#include "jfs_discard.h"


static struct {
static struct {
	long jfs_flag;
	long jfs_flag;
@@ -123,6 +127,40 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		mnt_drop_write_file(filp);
		mnt_drop_write_file(filp);
		return err;
		return err;
	}
	}

	case FITRIM:
	{
		struct super_block *sb = inode->i_sb;
		struct request_queue *q = bdev_get_queue(sb->s_bdev);
		struct fstrim_range range;
		s64 ret = 0;

		if (!capable(CAP_SYS_ADMIN))
			return -EPERM;

		if (!blk_queue_discard(q)) {
			jfs_warn("FITRIM not supported on device");
			return -EOPNOTSUPP;
		}

		if (copy_from_user(&range, (struct fstrim_range __user *)arg,
		    sizeof(range)))
			return -EFAULT;

		range.minlen = max_t(unsigned int, range.minlen,
			q->limits.discard_granularity);

		ret = jfs_ioc_trim(inode, &range);
		if (ret < 0)
			return ret;

		if (copy_to_user((struct fstrim_range __user *)arg, &range,
		    sizeof(range)))
			return -EFAULT;

		return 0;
	}

	default:
	default:
		return -ENOTTY;
		return -ENOTTY;
	}
	}
@@ -142,6 +180,9 @@ long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
	case JFS_IOC_SETFLAGS32:
	case JFS_IOC_SETFLAGS32:
		cmd = JFS_IOC_SETFLAGS;
		cmd = JFS_IOC_SETFLAGS;
		break;
		break;
	case FITRIM:
		cmd = FITRIM;
		break;
	}
	}
	return jfs_ioctl(filp, cmd, arg);
	return jfs_ioctl(filp, cmd, arg);
}
}

fs/jfs/jfs_discard.c

0 → 100644
+117 −0
Original line number Original line Diff line number Diff line
/*
 *   Copyright (C) Tino Reichardt, 2012
 *
 *   This program is free software;  you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program;  if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/blkdev.h>

#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_discard.h"
#include "jfs_dmap.h"
#include "jfs_debug.h"


/*
 * NAME:	jfs_issue_discard()
 *
 * FUNCTION:	TRIM the specified block range on device, if supported
 *
 * PARAMETERS:
 *	ip	- pointer to in-core inode
 *	blkno	- starting block number to be trimmed (0..N)
 *	nblocks	- number of blocks to be trimmed
 *
 * RETURN VALUES:
 *	none
 *
 * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
 */
void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks)
{
	struct super_block *sb = ip->i_sb;
	int r = 0;

	r = sb_issue_discard(sb, blkno, nblocks, GFP_NOFS, 0);
	if (unlikely(r != 0)) {
		jfs_err("JFS: sb_issue_discard" \
			"(%p, %llu, %llu, GFP_NOFS, 0) = %d => failed!\n",
			sb, (unsigned long long)blkno,
			(unsigned long long)nblocks, r);
	}

	jfs_info("JFS: sb_issue_discard" \
		"(%p, %llu, %llu, GFP_NOFS, 0) = %d\n",
		sb, (unsigned long long)blkno,
		(unsigned long long)nblocks, r);

	return;
}

/*
 * NAME:	jfs_ioc_trim()
 *
 * FUNCTION:	attempt to discard (TRIM) all free blocks from the
 *              filesystem.
 *
 * PARAMETERS:
 *	ip	- pointer to in-core inode;
 *	range	- the range, given by user space
 *
 * RETURN VALUES:
 *	0	- success
 *	-EIO	- i/o error
 */
int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
{
	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
	struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
	struct super_block *sb = ipbmap->i_sb;
	int agno, agno_end;
	s64 start, end, minlen;
	u64 trimmed = 0;

	/**
	 * convert byte values to block size of filesystem:
	 * start:	First Byte to trim
	 * len:		number of Bytes to trim from start
	 * minlen:	minimum extent length in Bytes
	 */
	start = range->start >> sb->s_blocksize_bits;
	if (start < 0)
		start = 0;
	end = start + (range->len >> sb->s_blocksize_bits) - 1;
	if (end >= bmp->db_mapsize)
		end = bmp->db_mapsize - 1;
	minlen = range->minlen >> sb->s_blocksize_bits;
	if (minlen <= 0)
		minlen = 1;

	/**
	 * we trim all ag's within the range
	 */
	agno = BLKTOAG(start, JFS_SBI(ip->i_sb));
	agno_end = BLKTOAG(end, JFS_SBI(ip->i_sb));
	while (agno <= agno_end) {
		trimmed += dbDiscardAG(ip, agno, minlen);
		agno++;
	}
	range->len = trimmed << sb->s_blocksize_bits;

	return 0;
}

fs/jfs/jfs_discard.h

0 → 100644
+26 −0
Original line number Original line Diff line number Diff line
/*
 *   Copyright (C) Tino Reichardt, 2012
 *
 *   This program is free software;  you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program;  if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#ifndef _H_JFS_DISCARD
#define _H_JFS_DISCARD

struct fstrim_range;

extern void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks);
extern int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range);

#endif /* _H_JFS_DISCARD */
Loading