Implement experimental support to pass notifications that a file
was deleted from the filesystem to the disk driver, commonly known as "discard" or "trim". fs/driver support is in ffs and ata wd for now. This is what was posted here: http://mail-index.netbsd.org/tech-kern/2012/02/28/msg012813.html with minor cleanup, and the global switch replaced by a mount option.
This commit is contained in:
parent
ba854cbddd
commit
5724e77fda
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: mntopts.h,v 1.14 2011/06/17 14:23:50 manu Exp $ */
|
||||
/* $NetBSD: mntopts.h,v 1.15 2012/10/19 17:09:06 drochner Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1994
|
||||
|
@ -58,6 +58,7 @@ struct mntopt {
|
|||
#define MOPT_LOG { "log", 0, MNT_LOG, 0 }
|
||||
#define MOPT_IGNORE { "hidden", 0, MNT_IGNORE, 0 }
|
||||
#define MOPT_EXTATTR { "extattr", 0, MNT_EXTATTR, 0 }
|
||||
#define MOPT_DISCARD { "discard", 0, MNT_DISCARD, 0 }
|
||||
|
||||
/* Control flags. */
|
||||
#define MOPT_FORCE { "force", 0, MNT_FORCE, 0 }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: atactl.c,v 1.66 2011/10/31 15:26:11 jakllsch Exp $ */
|
||||
/* $NetBSD: atactl.c,v 1.67 2012/10/19 17:09:07 drochner Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
|
@ -35,7 +35,7 @@
|
|||
#include <sys/cdefs.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: atactl.c,v 1.66 2011/10/31 15:26:11 jakllsch Exp $");
|
||||
__RCSID("$NetBSD: atactl.c,v 1.67 2012/10/19 17:09:07 drochner Exp $");
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -177,6 +177,7 @@ static const struct bitinfo ata_vers[] = {
|
|||
{ WDC_VER_ATA5, "ATA-5" },
|
||||
{ WDC_VER_ATA6, "ATA-6" },
|
||||
{ WDC_VER_ATA7, "ATA-7" },
|
||||
{ WDC_VER_ATA8, "ATA-8" },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
|
@ -1041,6 +1042,10 @@ device_identify(int argc, char *argv[])
|
|||
inqbuf->atap_sata_features_supp, ata_sata_feat);
|
||||
}
|
||||
|
||||
if ((inqbuf->atap_ata_major & WDC_VER_ATA8) &&
|
||||
(inqbuf->support_dsm & ATA_SUPPORT_DSM_TRIM))
|
||||
printf("TRIM supported\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: mount.8,v 1.77 2012/10/03 19:36:11 wiz Exp $
|
||||
.\" $NetBSD: mount.8,v 1.78 2012/10/19 17:09:07 drochner Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1989, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
|
@ -190,6 +190,9 @@ recovery mechanism, or are willing to recreate the file system from scratch.
|
|||
Clear
|
||||
.Cm async
|
||||
mode.
|
||||
.It Cm discard
|
||||
Use DISCARD/TRIM commands if disk and driver support it.
|
||||
EXPERIMENTAL!
|
||||
.It Cm extattr
|
||||
Enable extended attributes, if the filesystem supports them and
|
||||
does not enable them by default.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: mount_ffs.c,v 1.27 2011/08/29 14:35:01 joerg Exp $ */
|
||||
/* $NetBSD: mount_ffs.c,v 1.28 2012/10/19 17:09:07 drochner Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993, 1994
|
||||
|
@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1993, 1994\
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)mount_ufs.c 8.4 (Berkeley) 4/26/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: mount_ffs.c,v 1.27 2011/08/29 14:35:01 joerg Exp $");
|
||||
__RCSID("$NetBSD: mount_ffs.c,v 1.28 2012/10/19 17:09:07 drochner Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -75,6 +75,7 @@ static const struct mntopt mopts[] = {
|
|||
MOPT_LOG,
|
||||
MOPT_GETARGS,
|
||||
MOPT_EXTATTR,
|
||||
MOPT_DISCARD,
|
||||
MOPT_NULL,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: atareg.h,v 1.40 2011/10/24 20:52:34 jakllsch Exp $ */
|
||||
/* $NetBSD: atareg.h,v 1.41 2012/10/19 17:09:07 drochner Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998, 2001 Manuel Bouyer.
|
||||
|
@ -90,6 +90,7 @@
|
|||
|
||||
/* Commands for Disk Controller. */
|
||||
#define WDCC_NOP 0x00 /* Always fail with "aborted command" */
|
||||
#define ATA_DATA_SET_MANAGEMENT 0x06
|
||||
#define WDCC_RECAL 0x10 /* disk restore code -- resets cntlr */
|
||||
|
||||
#define WDCC_READ 0x20 /* disk read code */
|
||||
|
@ -387,6 +388,7 @@ struct ataparams {
|
|||
#define WDC_VER_ATA5 0x0020
|
||||
#define WDC_VER_ATA6 0x0040
|
||||
#define WDC_VER_ATA7 0x0080
|
||||
#define WDC_VER_ATA8 0x0100
|
||||
uint16_t atap_ata_minor; /* 81: Minor version number */
|
||||
uint16_t atap_cmd_set1; /* 82: command set supported */
|
||||
#define WDC_CMD1_NOP 0x4000 /* NOP */
|
||||
|
@ -451,7 +453,8 @@ struct ataparams {
|
|||
uint16_t atap_apm_val; /* 91: current APM value */
|
||||
uint16_t __reserved5[8]; /* 92-99: reserved */
|
||||
uint16_t atap_max_lba[4]; /* 100-103: Max. user LBA addr */
|
||||
uint16_t __reserved6[2]; /* 104-105: reserved */
|
||||
uint16_t __reserved6; /* 104: reserved */
|
||||
uint16_t max_dsm_blocks; /* 105: DSM (ATA-8/ACS-2) */
|
||||
uint16_t atap_secsz; /* 106: physical/logical sector size */
|
||||
#define ATA_SECSZ_VALID_MASK 0xc000
|
||||
#define ATA_SECSZ_VALID 0x4000
|
||||
|
@ -480,7 +483,10 @@ struct ataparams {
|
|||
#define ATA_CFA_MODE1_DIS 0x1000 /* CFA Mode 1 Disabled */
|
||||
#define ATA_CFA_MODE1_REQ 0x2000 /* CFA Mode 1 Required */
|
||||
#define ATA_CFA_WORD160 0x8000 /* Word 160 supported */
|
||||
uint16_t __reserved10[15]; /* 161-175: reserved for CFA */
|
||||
uint16_t __reserved10[8]; /* 161-168: reserved for CFA */
|
||||
uint16_t support_dsm; /* 169: DSM (ATA-8/ACS-2) */
|
||||
#define ATA_SUPPORT_DSM_TRIM 0x0001
|
||||
uint16_t __reserved10a[6]; /* 170-175: reserved for CFA */
|
||||
uint8_t atap_media_serial[60]; /* 176-205: media serial number */
|
||||
uint16_t __reserved11[3]; /* 206-208: */
|
||||
uint16_t atap_logical_align; /* 209: logical/physical alignment */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: wd.c,v 1.400 2012/07/31 15:50:34 bouyer Exp $ */
|
||||
/* $NetBSD: wd.c,v 1.401 2012/10/19 17:09:07 drochner Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
|
||||
|
@ -54,7 +54,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.400 2012/07/31 15:50:34 bouyer Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.401 2012/10/19 17:09:07 drochner Exp $");
|
||||
|
||||
#include "opt_ata.h"
|
||||
|
||||
|
@ -178,6 +178,7 @@ void wdrestart(void *);
|
|||
void wddone(void *);
|
||||
int wd_get_params(struct wd_softc *, u_int8_t, struct ataparams *);
|
||||
int wd_flushcache(struct wd_softc *, int);
|
||||
int wd_trim(struct wd_softc *, int, struct disk_discard_range *);
|
||||
bool wd_shutdown(device_t, int);
|
||||
|
||||
int wd_getcache(struct wd_softc *, int *);
|
||||
|
@ -1526,6 +1527,20 @@ wdioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l)
|
|||
return 0;
|
||||
}
|
||||
|
||||
case DIOCGDISCARDPARAMS: {
|
||||
struct disk_discard_params * tp;
|
||||
|
||||
if (!(wd->sc_params.atap_ata_major & WDC_VER_ATA8)
|
||||
|| !(wd->sc_params.support_dsm & ATA_SUPPORT_DSM_TRIM))
|
||||
return ENOTTY;
|
||||
tp = (struct disk_discard_params *)addr;
|
||||
tp->maxsize = 0xffff; /*wd->sc_params.max_dsm_blocks*/
|
||||
printf("wd: maxtrimsize %ld\n", tp->maxsize);
|
||||
return 0;
|
||||
}
|
||||
case DIOCDISCARD:
|
||||
return wd_trim(wd, WDPART(dev), (struct disk_discard_range *)addr);
|
||||
|
||||
default:
|
||||
return ENOTTY;
|
||||
}
|
||||
|
@ -1934,6 +1949,57 @@ wd_flushcache(struct wd_softc *wd, int flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
wd_trim(struct wd_softc *wd, int part, struct disk_discard_range *tr)
|
||||
{
|
||||
struct ata_command ata_c;
|
||||
unsigned char *req;
|
||||
daddr_t bno = tr->bno;
|
||||
|
||||
if (part != RAW_PART)
|
||||
bno += wd->sc_dk.dk_label->d_partitions[part].p_offset;;
|
||||
|
||||
req = kmem_zalloc(512, KM_SLEEP);
|
||||
req[0] = bno & 0xff;
|
||||
req[1] = (bno >> 8) & 0xff;
|
||||
req[2] = (bno >> 16) & 0xff;
|
||||
req[3] = (bno >> 24) & 0xff;
|
||||
req[4] = (bno >> 32) & 0xff;
|
||||
req[5] = (bno >> 40) & 0xff;
|
||||
req[6] = tr->size & 0xff;
|
||||
req[7] = (tr->size >> 8) & 0xff;
|
||||
|
||||
memset(&ata_c, 0, sizeof(struct ata_command));
|
||||
ata_c.r_command = ATA_DATA_SET_MANAGEMENT;
|
||||
ata_c.r_count = 1;
|
||||
ata_c.r_features = ATA_SUPPORT_DSM_TRIM;
|
||||
ata_c.r_st_bmask = WDCS_DRDY;
|
||||
ata_c.r_st_pmask = WDCS_DRDY;
|
||||
ata_c.timeout = 30000; /* 30s timeout */
|
||||
ata_c.data = req;
|
||||
ata_c.bcount = 512;
|
||||
ata_c.flags |= AT_WRITE | AT_WAIT;
|
||||
if (wd->atabus->ata_exec_command(wd->drvp, &ata_c) != ATACMD_COMPLETE) {
|
||||
aprint_error_dev(wd->sc_dev,
|
||||
"trim command didn't complete\n");
|
||||
kmem_free(req, 512);
|
||||
return EIO;
|
||||
}
|
||||
kmem_free(req, 512);
|
||||
if (ata_c.flags & AT_ERROR) {
|
||||
if (ata_c.r_error == WDCE_ABRT) /* command not supported */
|
||||
return ENODEV;
|
||||
}
|
||||
if (ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
|
||||
char sbuf[sizeof(at_errbits) + 64];
|
||||
snprintb(sbuf, sizeof(sbuf), at_errbits, ata_c.flags);
|
||||
aprint_error_dev(wd->sc_dev, "wd_trim: status=%s\n",
|
||||
sbuf);
|
||||
return EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
wd_shutdown(device_t dev, int how)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: dkio.h,v 1.17 2011/01/18 19:52:24 matt Exp $ */
|
||||
/* $NetBSD: dkio.h,v 1.18 2012/10/19 17:09:07 drochner Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1987, 1988, 1993
|
||||
|
@ -109,4 +109,15 @@
|
|||
|
||||
#define DIOCTUR _IOR('d', 128, int) /* test unit ready */
|
||||
|
||||
struct disk_discard_params {
|
||||
long maxsize; /* in DEV_BSIZE units */
|
||||
};
|
||||
#define DIOCGDISCARDPARAMS _IOR('d', 129, struct disk_discard_params)
|
||||
|
||||
struct disk_discard_range {
|
||||
daddr_t bno;
|
||||
long size;
|
||||
};
|
||||
#define DIOCDISCARD _IOW('d', 130, struct disk_discard_range)
|
||||
|
||||
#endif /* _SYS_DKIO_H_ */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: fstypes.h,v 1.30 2011/11/18 21:17:45 christos Exp $ */
|
||||
/* $NetBSD: fstypes.h,v 1.31 2012/10/19 17:09:07 drochner Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1991, 1993
|
||||
|
@ -84,7 +84,6 @@ typedef struct fhandle fhandle_t;
|
|||
*/
|
||||
|
||||
#define __MNT_UNUSED1 0x00200000
|
||||
#define __MNT_UNUSED2 0x00800000
|
||||
|
||||
#define MNT_RDONLY 0x00000001 /* read only filesystem */
|
||||
#define MNT_SYNCHRONOUS 0x00000002 /* file system written synchronously */
|
||||
|
@ -96,6 +95,7 @@ typedef struct fhandle fhandle_t;
|
|||
#define MNT_NOCOREDUMP 0x00008000 /* don't write core dumps to this FS */
|
||||
#define MNT_RELATIME 0x00020000 /* only update access time if mod/ch */
|
||||
#define MNT_IGNORE 0x00100000 /* don't show entry in df */
|
||||
#define MNT_DISCARD 0x00800000 /* use DISCARD/TRIM if supported */
|
||||
#define MNT_EXTATTR 0x01000000 /* enable extended attributes */
|
||||
#define MNT_LOG 0x02000000 /* Use logging */
|
||||
#define MNT_NOATIME 0x04000000 /* Never update access times in fs */
|
||||
|
@ -105,6 +105,7 @@ typedef struct fhandle fhandle_t;
|
|||
|
||||
#define __MNT_BASIC_FLAGS \
|
||||
{ MNT_ASYNC, 0, "asynchronous" }, \
|
||||
{ MNT_DISCARD, 0, "discard" }, \
|
||||
{ MNT_EXTATTR, 0, "extattr" }, \
|
||||
{ MNT_IGNORE, 0, "hidden" }, \
|
||||
{ MNT_LOG, 0, "log" }, \
|
||||
|
@ -121,9 +122,9 @@ typedef struct fhandle fhandle_t;
|
|||
{ MNT_SYNCHRONOUS, 0, "synchronous" }, \
|
||||
{ MNT_UNION, 0, "union" }, \
|
||||
|
||||
#define MNT_BASIC_FLAGS (MNT_ASYNC | MNT_EXTATTR | MNT_LOG | MNT_NOATIME | \
|
||||
MNT_NOCOREDUMP | MNT_NODEV | MNT_NODEVMTIME | MNT_NOEXEC | MNT_NOSUID | \
|
||||
MNT_RDONLY | MNT_RELATIME | MNT_SOFTDEP | MNT_SYMPERM | \
|
||||
#define MNT_BASIC_FLAGS (MNT_ASYNC | MNT_DISCARD | MNT_EXTATTR | MNT_LOG | \
|
||||
MNT_NOATIME | MNT_NOCOREDUMP | MNT_NODEV | MNT_NODEVMTIME | MNT_NOEXEC | \
|
||||
MNT_NOSUID | MNT_RDONLY | MNT_RELATIME | MNT_SOFTDEP | MNT_SYMPERM | \
|
||||
MNT_SYNCHRONOUS | MNT_UNION)
|
||||
/*
|
||||
* exported mount flags.
|
||||
|
@ -235,7 +236,7 @@ typedef struct fhandle fhandle_t;
|
|||
"\33MNT_NOATIME" \
|
||||
"\32MNT_LOG" \
|
||||
"\31MNT_EXTATTR" \
|
||||
"\30MNT_UNUSED" \
|
||||
"\30MNT_DISCARD" \
|
||||
"\27MNT_GETARGS" \
|
||||
"\26MNT_UNUSED" \
|
||||
"\25MNT_IGNORE" \
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ffs_alloc.c,v 1.130 2011/11/28 08:05:07 tls Exp $ */
|
||||
/* $NetBSD: ffs_alloc.c,v 1.131 2012/10/19 17:09:08 drochner Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
|
||||
|
@ -70,7 +70,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_alloc.c,v 1.130 2011/11/28 08:05:07 tls Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_alloc.c,v 1.131 2012/10/19 17:09:08 drochner Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_ffs.h"
|
||||
|
@ -1552,9 +1552,8 @@ ffs_blkalloc_ump(struct ufsmount *ump, daddr_t bno, long size)
|
|||
*
|
||||
* => um_lock not held on entry or exit
|
||||
*/
|
||||
void
|
||||
ffs_blkfree(struct fs *fs, struct vnode *devvp, daddr_t bno, long size,
|
||||
ino_t inum)
|
||||
static void
|
||||
ffs_blkfree_cg(struct fs *fs, struct vnode *devvp, daddr_t bno, long size)
|
||||
{
|
||||
struct cg *cgp;
|
||||
struct buf *bp;
|
||||
|
@ -1574,12 +1573,6 @@ ffs_blkfree(struct fs *fs, struct vnode *devvp, daddr_t bno, long size,
|
|||
ump = VFSTOUFS(devvp->v_specmountpoint);
|
||||
KASSERT(fs == ump->um_fs);
|
||||
cgblkno = fsbtodb(fs, cgtod(fs, cg));
|
||||
if (ffs_snapblkfree(fs, devvp, bno, size, inum))
|
||||
return;
|
||||
|
||||
error = ffs_check_bad_allocation(__func__, fs, bno, size, dev, inum);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
error = bread(devvp, cgblkno, (int)fs->fs_cgsize,
|
||||
NOCRED, B_MODIFY, &bp);
|
||||
|
@ -1598,6 +1591,225 @@ ffs_blkfree(struct fs *fs, struct vnode *devvp, daddr_t bno, long size,
|
|||
bdwrite(bp);
|
||||
}
|
||||
|
||||
struct discardopdata {
|
||||
struct work wk; /* must be first */
|
||||
struct vnode *devvp;
|
||||
daddr_t bno;
|
||||
long size;
|
||||
};
|
||||
|
||||
struct discarddata {
|
||||
struct fs *fs;
|
||||
struct discardopdata *entry;
|
||||
long maxsize;
|
||||
kmutex_t entrylk;
|
||||
struct workqueue *wq;
|
||||
int wqcnt, wqdraining;
|
||||
kmutex_t wqlk;
|
||||
kcondvar_t wqcv;
|
||||
/* timer for flush? */
|
||||
};
|
||||
|
||||
static void
|
||||
ffs_blkfree_td(struct fs *fs, struct discardopdata *td)
|
||||
{
|
||||
long todo;
|
||||
|
||||
while (td->size) {
|
||||
todo = min(td->size,
|
||||
lfragtosize(fs, (fs->fs_frag - fragnum(fs, td->bno))));
|
||||
ffs_blkfree_cg(fs, td->devvp, td->bno, todo);
|
||||
td->bno += numfrags(fs, todo);
|
||||
td->size -= todo;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ffs_discardcb(struct work *wk, void *arg)
|
||||
{
|
||||
struct discardopdata *td = (void *)wk;
|
||||
struct discarddata *ts = arg;
|
||||
struct fs *fs = ts->fs;
|
||||
struct disk_discard_range ta;
|
||||
int error;
|
||||
|
||||
ta.bno = fsbtodb(fs, td->bno);
|
||||
ta.size = td->size >> DEV_BSHIFT;
|
||||
error = VOP_IOCTL(td->devvp, DIOCDISCARD, &ta, FWRITE, FSCRED);
|
||||
#ifdef TRIMDEBUG
|
||||
printf("trim(%" PRId64 ",%ld):%d\n", td->bno, td->size, error);
|
||||
#endif
|
||||
|
||||
ffs_blkfree_td(fs, td);
|
||||
kmem_free(td, sizeof(*td));
|
||||
mutex_enter(&ts->wqlk);
|
||||
ts->wqcnt--;
|
||||
if (ts->wqdraining && !ts->wqcnt)
|
||||
cv_signal(&ts->wqcv);
|
||||
mutex_exit(&ts->wqlk);
|
||||
}
|
||||
|
||||
void *
|
||||
ffs_discard_init(struct vnode *devvp, struct fs *fs)
|
||||
{
|
||||
struct disk_discard_params tp;
|
||||
struct discarddata *ts;
|
||||
int error;
|
||||
|
||||
error = VOP_IOCTL(devvp, DIOCGDISCARDPARAMS, &tp, FREAD, FSCRED);
|
||||
if (error) {
|
||||
printf("DIOCGDISCARDPARAMS: %d\n", error);
|
||||
return NULL;
|
||||
}
|
||||
if (tp.maxsize * DEV_BSIZE < fs->fs_bsize) {
|
||||
printf("tp.maxsize=%ld, fs_bsize=%d\n", tp.maxsize, fs->fs_bsize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ts = kmem_zalloc(sizeof (*ts), KM_SLEEP);
|
||||
error = workqueue_create(&ts->wq, "trimwq", ffs_discardcb, ts,
|
||||
0, 0, 0);
|
||||
if (error) {
|
||||
kmem_free(ts, sizeof (*ts));
|
||||
return NULL;
|
||||
}
|
||||
mutex_init(&ts->entrylk, MUTEX_DEFAULT, IPL_NONE);
|
||||
mutex_init(&ts->wqlk, MUTEX_DEFAULT, IPL_NONE);
|
||||
cv_init(&ts->wqcv, "trimwqcv");
|
||||
ts->maxsize = max(tp.maxsize * DEV_BSIZE, 100*1024); /* XXX */
|
||||
ts->fs = fs;
|
||||
return ts;
|
||||
}
|
||||
|
||||
void
|
||||
ffs_discard_finish(void *vts, int flags)
|
||||
{
|
||||
struct discarddata *ts = vts;
|
||||
struct discardopdata *td = NULL;
|
||||
int res = 0;
|
||||
|
||||
/* wait for workqueue to drain */
|
||||
mutex_enter(&ts->wqlk);
|
||||
if (ts->wqcnt) {
|
||||
ts->wqdraining = 1;
|
||||
res = cv_timedwait(&ts->wqcv, &ts->wqlk, mstohz(5000));
|
||||
}
|
||||
mutex_exit(&ts->wqlk);
|
||||
if (res)
|
||||
printf("ffs_discarddata drain timeout\n");
|
||||
|
||||
mutex_enter(&ts->entrylk);
|
||||
if (ts->entry) {
|
||||
td = ts->entry;
|
||||
ts->entry = NULL;
|
||||
}
|
||||
mutex_exit(&ts->entrylk);
|
||||
if (td) {
|
||||
/* XXX don't tell disk, its optional */
|
||||
ffs_blkfree_td(ts->fs, td);
|
||||
#ifdef TRIMDEBUG
|
||||
printf("finish(%" PRId64 ",%ld)\n", td->bno, td->size);
|
||||
#endif
|
||||
kmem_free(td, sizeof(*td));
|
||||
}
|
||||
|
||||
cv_destroy(&ts->wqcv);
|
||||
mutex_destroy(&ts->entrylk);
|
||||
mutex_destroy(&ts->wqlk);
|
||||
workqueue_destroy(ts->wq);
|
||||
kmem_free(ts, sizeof(*ts));
|
||||
}
|
||||
|
||||
void
|
||||
ffs_blkfree(struct fs *fs, struct vnode *devvp, daddr_t bno, long size,
|
||||
ino_t inum)
|
||||
{
|
||||
struct ufsmount *ump;
|
||||
int error;
|
||||
dev_t dev;
|
||||
struct discarddata *ts;
|
||||
struct discardopdata *td;
|
||||
|
||||
dev = devvp->v_rdev;
|
||||
ump = VFSTOUFS(devvp->v_specmountpoint);
|
||||
if (ffs_snapblkfree(fs, devvp, bno, size, inum))
|
||||
return;
|
||||
|
||||
error = ffs_check_bad_allocation(__func__, fs, bno, size, dev, inum);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
if (!ump->um_discarddata) {
|
||||
ffs_blkfree_cg(fs, devvp, bno, size);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TRIMDEBUG
|
||||
printf("blkfree(%" PRId64 ",%ld)\n", bno, size);
|
||||
#endif
|
||||
ts = ump->um_discarddata;
|
||||
td = NULL;
|
||||
|
||||
mutex_enter(&ts->entrylk);
|
||||
if (ts->entry) {
|
||||
td = ts->entry;
|
||||
/* ffs deallocs backwards, check for prepend only */
|
||||
if (td->bno == bno + numfrags(fs, size)
|
||||
&& td->size + size <= ts->maxsize) {
|
||||
td->bno = bno;
|
||||
td->size += size;
|
||||
if (td->size < ts->maxsize) {
|
||||
#ifdef TRIMDEBUG
|
||||
printf("defer(%" PRId64 ",%ld)\n", td->bno, td->size);
|
||||
#endif
|
||||
mutex_exit(&ts->entrylk);
|
||||
return;
|
||||
}
|
||||
size = 0; /* mark done */
|
||||
}
|
||||
ts->entry = NULL;
|
||||
}
|
||||
mutex_exit(&ts->entrylk);
|
||||
|
||||
if (td) {
|
||||
#ifdef TRIMDEBUG
|
||||
printf("enq old(%" PRId64 ",%ld)\n", td->bno, td->size);
|
||||
#endif
|
||||
mutex_enter(&ts->wqlk);
|
||||
ts->wqcnt++;
|
||||
mutex_exit(&ts->wqlk);
|
||||
workqueue_enqueue(ts->wq, &td->wk, NULL);
|
||||
}
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
td = kmem_alloc(sizeof(*td), KM_SLEEP);
|
||||
td->devvp = devvp;
|
||||
td->bno = bno;
|
||||
td->size = size;
|
||||
|
||||
if (td->size < ts->maxsize) { /* XXX always the case */
|
||||
mutex_enter(&ts->entrylk);
|
||||
if (!ts->entry) { /* possible race? */
|
||||
#ifdef TRIMDEBUG
|
||||
printf("defer(%" PRId64 ",%ld)\n", td->bno, td->size);
|
||||
#endif
|
||||
ts->entry = td;
|
||||
td = NULL;
|
||||
}
|
||||
mutex_exit(&ts->entrylk);
|
||||
}
|
||||
if (td) {
|
||||
#ifdef TRIMDEBUG
|
||||
printf("enq new(%" PRId64 ",%ld)\n", td->bno, td->size);
|
||||
#endif
|
||||
mutex_enter(&ts->wqlk);
|
||||
ts->wqcnt++;
|
||||
mutex_exit(&ts->wqlk);
|
||||
workqueue_enqueue(ts->wq, &td->wk, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a block or fragment from a snapshot cg copy.
|
||||
*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ffs_extern.h,v 1.78 2011/06/17 14:23:52 manu Exp $ */
|
||||
/* $NetBSD: ffs_extern.h,v 1.79 2012/10/19 17:09:08 drochner Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993, 1994
|
||||
|
@ -98,6 +98,8 @@ daddr_t ffs_blkpref_ufs2(struct inode *, daddr_t, int, int, int64_t *);
|
|||
int ffs_blkalloc(struct inode *, daddr_t, long);
|
||||
int ffs_blkalloc_ump(struct ufsmount *, daddr_t, long);
|
||||
void ffs_blkfree(struct fs *, struct vnode *, daddr_t, long, ino_t);
|
||||
void *ffs_discard_init(struct vnode *, struct fs *);
|
||||
void ffs_discard_finish(void *, int);
|
||||
void ffs_blkfree_snap(struct fs *, struct vnode *, daddr_t, long, ino_t);
|
||||
int ffs_vfree(struct vnode *, ino_t, int);
|
||||
int ffs_checkfreefile(struct fs *, struct vnode *, ino_t);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ffs_vfsops.c,v 1.278 2012/09/10 07:57:50 manu Exp $ */
|
||||
/* $NetBSD: ffs_vfsops.c,v 1.279 2012/10/19 17:09:08 drochner Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
|
||||
|
@ -61,7 +61,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.278 2012/09/10 07:57:50 manu Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.279 2012/10/19 17:09:08 drochner Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_ffs.h"
|
||||
|
@ -1306,6 +1306,9 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
|
|||
ufs_extattr_uepm_init(&ump->um_extattr);
|
||||
#endif /* UFS_EXTATTR */
|
||||
|
||||
if (mp->mnt_flag & MNT_DISCARD)
|
||||
ump->um_discarddata = ffs_discard_init(devvp, fs);
|
||||
|
||||
return (0);
|
||||
out:
|
||||
#ifdef WAPBL
|
||||
|
@ -1462,6 +1465,11 @@ ffs_unmount(struct mount *mp, int mntflags)
|
|||
extern int doforce;
|
||||
#endif
|
||||
|
||||
if (ump->um_discarddata) {
|
||||
ffs_discard_finish(ump->um_discarddata, mntflags);
|
||||
ump->um_discarddata = NULL;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ufsmount.h,v 1.38 2012/05/09 00:21:18 riastradh Exp $ */
|
||||
/* $NetBSD: ufsmount.h,v 1.39 2012/10/19 17:09:08 drochner Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1989, 1993
|
||||
|
@ -124,6 +124,8 @@ struct ufsmount {
|
|||
void *um_snapinfo; /* snapshot private data */
|
||||
|
||||
const struct ufs_ops *um_ops;
|
||||
|
||||
void *um_discarddata;
|
||||
};
|
||||
|
||||
struct ufs_ops {
|
||||
|
|
Loading…
Reference in New Issue