Permalink
Browse files

TRIM support

Signed-off-by: Samuel J. Greear <sjg@thesjg.com>
  • Loading branch information...
1 parent 4005878 commit e0fb398bfbef1fb6d12dfb8308cdc83ce663cbc2 @bissont bissont committed with thesjg Oct 7, 2011
View
@@ -6,7 +6,7 @@
#
# PROVIDE: fsck
-# REQUIRE: localswap
+# REQUIRE: disks
. /etc/rc.subr
View
@@ -6,7 +6,8 @@
#
# PROVIDE: localswap
-# REQUIRE: disks
+# REQUIRE: savecore
+# BEFORE: SERVERS
# KEYWORD: shutdown
. /etc/rc.subr
View
@@ -89,6 +89,15 @@ would otherwise wrap.
This typically causes BIOSes to properly detect
that the disk should be put in Large mode.
This option may be needed on very old PCs.
+.It Fl E
+Use TRIM to erase the device/partition before creating the file system. The
+underlying device must have the Trim sysctl enabled. Only devices that
+support TRIM will have such a sysctl option (kern.cam.da.X.trim_enabled). For
+use with the
+.Fl I
+or
+.Fl u
+option.
.It Fl f Ar configfile
Set slice values using the file
.Ar configfile .
View
@@ -30,6 +30,8 @@
#include <sys/types.h>
#include <sys/diskslice.h>
#include <sys/diskmbr.h>
+#include <sys/ioctl_compat.h>
+#include <sys/sysctl.h>
#include <sys/stat.h>
#include <ctype.h>
#include <fcntl.h>
@@ -120,6 +122,7 @@ typedef struct cmd {
static int B_flag = 0; /* replace boot code */
static int C_flag = 0; /* use wrapped values for CHS */
+static int E_flag = 0; /* Erase through TRIM */
static int I_flag = 0; /* use entire disk for DragonFly */
static int a_flag = 0; /* set active partition */
static char *b_flag = NULL; /* path to boot code */
@@ -235,6 +238,7 @@ static void change_code();
static void get_params_to_use();
static void dos(struct dos_partition *partp);
static int open_disk(int u_flag);
+static void erase_partition(int i);
static ssize_t read_disk(off_t sector, void *buf);
static ssize_t write_disk(off_t sector, void *buf);
static int get_params();
@@ -258,14 +262,17 @@ main(int argc, char *argv[])
{
int c, i;
- while ((c = getopt(argc, argv, "BCIab:f:p:istuv1234")) != -1)
+ while ((c = getopt(argc, argv, "BCEIab:f:p:istuv1234")) != -1)
switch (c) {
case 'B':
B_flag = 1;
break;
case 'C':
C_flag = 1;
break;
+ case 'E':
+ E_flag = 1;
+ break;
case 'I':
I_flag = 1;
break;
@@ -384,6 +391,12 @@ main(int argc, char *argv[])
dos(partp);
if (v_flag)
print_s0(-1);
+
+ if (E_flag) {
+ /* Trim now if we're using the entire device */
+ erase_partition(0);
+ }
+
if (!t_flag)
write_s0();
exit(0);
@@ -444,8 +457,20 @@ main(int argc, char *argv[])
}
print_s0(-1);
if (!t_flag) {
- if (ok("Should we write new partition table?"))
+ if (ok("Should we write new partition table?")) {
+ if (E_flag && u_flag) {
+ /*
+ * Trim now because we've committed to
+ * updating the partition.
+ */
+ if (partition == -1)
+ for (i = 0; i < NDOSPART; i++)
+ erase_partition(i);
+ else
+ erase_partition(partition);
+ }
write_s0();
+ }
}
else
{
@@ -762,6 +787,46 @@ dos(struct dos_partition *partp)
int fd;
+static void
+erase_partition(int i)
+{
+ struct dos_partition *partp;
+ off_t ioarg[2];
+
+ char sysctl_name[64];
+ int trim_enabled = 0;
+ size_t olen = sizeof(trim_enabled);
+ char *dev_name = strdup(disk);
+
+ dev_name = strtok(dev_name + strlen("/dev/da"),"s");
+ sprintf(sysctl_name, "kern.cam.da.%s.trim_enabled", dev_name);
+ sysctlbyname(sysctl_name, &trim_enabled, &olen, NULL, 0);
+ if(errno == ENOENT) {
+ printf("Device:%s does not support the TRIM command\n", disk);
+ usage();
+ }
+ if(!trim_enabled) {
+ printf("Erase device option selected, but sysctl (%s) "
+ "is not enabled\n",sysctl_name);
+ usage();
+ }
+ partp = ((struct dos_partition *) &mboot.parts) + i;
+ printf("erase sectors:%u %u\n",
+ partp->dp_start,
+ partp->dp_size);
+
+ /* Trim the Device */
+ ioarg[0] = partp->dp_start;
+ ioarg[0] *=secsize;
+ ioarg[1] = partp->dp_size;
+ ioarg[1] *=secsize;
+
+ if (ioctl(fd, IOCTLTRIM, ioarg) < 0) {
+ printf("Device trim failed\n");
+ usage ();
+ }
+}
+
/* Getting device status */
static int
@@ -80,6 +80,7 @@ struct volume_info {
char *name;
int fd;
off_t size;
+ off_t device_offset;
const char *type;
struct hammer_volume_ondisk *ondisk;
@@ -52,6 +52,7 @@ struct mntopt {
#define MOPT_NOEXEC { "exec", 1, MNT_NOEXEC, 0 }
#define MOPT_NOSUID { "suid", 1, MNT_NOSUID, 0 }
#define MOPT_NOSYMFOLLOW { "symfollow", 1, MNT_NOSYMFOLLOW, 0 }
+#define MOPT_TRIM { "trim", 0, MNT_TRIM, 0 }
#define MOPT_RDONLY { "rdonly", 0, MNT_RDONLY, 0 }
#define MOPT_SYNC { "sync", 0, MNT_SYNCHRONOUS, 0 }
#define MOPT_UNION { "union", 0, MNT_UNION, 0 }
View
@@ -193,6 +193,10 @@ mount the file system read-only (even the super-user may not write it).
All
.Tn I/O
to the file system should be done synchronously.
+.It Cm trim
+If the device supports trim (kern.cam.da.X.trim_enabled exists) and is set,
+the file system will perform online trim for corresponding block deletions.
+Currently UFS only supports this feature.
.It Cm suiddir
A directory on the mounted filesystem will respond to the SUID bit
being set, by setting the owner of any new files to be the same
@@ -38,11 +38,13 @@
#include <sys/param.h>
#include <sys/mount.h>
+#include <sys/sysctl.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <vfs/ufs/ufsmount.h>
@@ -59,6 +61,7 @@ static struct mntopt mopts[] = {
MOPT_SYNC,
MOPT_UPDATE,
MOPT_IGNORE,
+ MOPT_TRIM,
MOPT_NULL
};
@@ -98,6 +101,26 @@ mount_ufs(int argc, const char **argv)
else
args.export.ex_flags = 0;
+ if (mntflags & MNT_TRIM){
+ char sysctl_name[64];
+ int trim_enabled = 0;
+ size_t olen = sizeof(trim_enabled);
+ char *dev_name = strdup(args.fspec);
+ dev_name = strtok(dev_name + strlen("/dev/da"),"s");
+ sprintf(sysctl_name, "kern.cam.da.%s.trim_enabled", dev_name);
+ sysctlbyname(sysctl_name, &trim_enabled, &olen, NULL, 0);
+ if(errno == ENOENT) {
+ printf("Device:%s does not support the TRIM command\n",
+ args.fspec);
+ ufs_usage();
+ }
+ if(!trim_enabled) {
+ printf("Online TRIM selected, but sysctl (%s) "
+ "is not enabled\n",sysctl_name);
+ ufs_usage();
+ }
+ }
+
error = getvfsbyname("ufs", &vfc);
if (error && vfsisloadable("ufs")) {
if (vfsload("ufs")) {
View
@@ -38,6 +38,7 @@
#include "defs.h"
#include <stdlib.h>
+#include <sys/ioctl_compat.h>
/*
* make file system for cylinder-group style file systems
@@ -70,6 +71,8 @@ extern int Lflag; /* add a volume label */
extern int Nflag; /* run mkfs without writing file system */
extern int Oflag; /* format as an 4.3BSD file system */
extern int Uflag; /* enable soft updates for file system */
+extern int Eflag; /* erase contents using TRIM */
+extern uint64_t slice_offset; /* Pysical device slice offset */
extern u_long fssize; /* file system size */
extern int ntracks; /* # tracks/cylinder */
extern int nsectors; /* # sectors/track */
@@ -136,6 +139,7 @@ void parentready(int);
void rdfs(daddr_t, int, char *);
void setblock(struct fs *, unsigned char *, int);
void started(int);
+void erfs(off_t, off_t);
void wtfs(daddr_t, int, char *);
void wtfsflush(void);
@@ -236,6 +240,7 @@ mkfs(char *fsys, int fi, int fo, const char *mfscopy)
sblock.fs_flags |= FS_DOSOFTDEP;
if (Lflag)
strlcpy(sblock.fs_volname, volumelabel, MAXVOLLEN);
+
/*
* Validate the given file system size.
* Verify that its last block can actually be accessed.
@@ -677,6 +682,16 @@ mkfs(char *fsys, int fi, int fo, const char *mfscopy)
sblock.fs_flags & FS_DOSOFTDEP ? " SOFTUPDATES" : "");
#undef B2MBFACTOR
}
+
+ if (Eflag && !Nflag) {
+ printf("Erasing sectors [%ld --- %ld]\n",
+ (SBOFF+ slice_offset)/sectorsize,
+ fsbtodb(&sblock,sblock.fs_size) -
+ ((SBOFF + slice_offset)/ sectorsize) - 1);
+ erfs(SBOFF+ slice_offset, (fsbtodb(&sblock,sblock.fs_size) -
+ ((SBOFF + slice_offset)/ sectorsize) - 1) *
+ (unsigned long long)sectorsize);
+ }
/*
* Now build the cylinders group blocks and
* then print out indices of cylinder groups.
@@ -1246,6 +1261,20 @@ wtfsflush(void)
}
/*
+ * Issue ioctl to erase range of sectors using TRIM
+ */
+void
+erfs(off_t byte_start, off_t size)
+{
+ off_t ioarg[2];
+ ioarg[0] = byte_start;
+ ioarg[1] = size;
+ if (ioctl(fsi, IOCTLTRIM, ioarg) < 0) {
+ err(37, "Device trim failed\n");
+ }
+}
+
+/*
* write a block to the file system
*/
void
View
@@ -43,7 +43,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl L Ar volname
-.Op Fl NCOU
+.Op Fl NCOURE
.Op Fl S Ar sector-size
.Op Fl T Ar disktype
.Op Fl a Ar maxcontig
@@ -172,6 +172,10 @@ instead of trying to get geometry information from the
storage device.
.It Fl U
Enables soft updates on the new filesystem.
+.It Fl E
+Use TRIM to erase the device's data before creating the file system. The
+underlying device must have the Trim sysctl enabled. Only devices that support
+TRIM will have such a sysctl option (kern.cam.da.X.trim_enabled).
.It Fl a Ar maxcontig
Specify the maximum number of contiguous blocks that will be
laid out before forcing a rotational delay (see the
Oops, something went wrong.

0 comments on commit e0fb398

Please sign in to comment.