md: Add MD_MUSTDEALLOC support
This adds an option to detect if hole-punching is implemented by the underlying file system. If this flag is set, and if the underlying file system does not support hole-punching, md(4) fails BIO_DELETE requests with EOPNOTSUPP. Sponsored by: The FreeBSD Foundation Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D31883
This commit is contained in:
parent
71a1ae7ceb
commit
3703c18883
@ -37,7 +37,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd November 6, 2020
|
.Dd August 27, 2021
|
||||||
.Dt MDCONFIG 8
|
.Dt MDCONFIG 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -246,6 +246,34 @@ This can be used with the
|
|||||||
flag to forcibly destroy an
|
flag to forcibly destroy an
|
||||||
.Xr md 4
|
.Xr md 4
|
||||||
disk that is still in use.
|
disk that is still in use.
|
||||||
|
.It Oo Cm no Oc Ns Cm mustdealloc
|
||||||
|
For
|
||||||
|
.Cm vnode
|
||||||
|
backed devices: detect whether hole-punching is supported by the underlying file
|
||||||
|
system.
|
||||||
|
If the file system supports hole-punching, then to handle a
|
||||||
|
.Dv BIO_DELETE
|
||||||
|
request, some or all of the request's operation range may be turned into a hole
|
||||||
|
in the file used for backing store.
|
||||||
|
Any parts which are not turned into holes are zero-filled in
|
||||||
|
the file.
|
||||||
|
If the file system does not support
|
||||||
|
hole-punching,
|
||||||
|
.Dv BIO_DELETE
|
||||||
|
requests to the device are not handled and will fail with
|
||||||
|
.Er EOPNOTSUPP .
|
||||||
|
.Pp
|
||||||
|
When
|
||||||
|
.Cm mustdealloc
|
||||||
|
is not specified or
|
||||||
|
.Oo Cm no Oc Ns Cm mustdealloc
|
||||||
|
is specified, for a
|
||||||
|
.Dv BIO_DELETE
|
||||||
|
request, if the file system supports hole-punching, some or all of the request's
|
||||||
|
operation range may be turned into a hole in the file used for backing store.
|
||||||
|
Any parts which are not turned into holes are zero-filled in the file.
|
||||||
|
If the file system of the vnode type memory disk does not support hole-punching,
|
||||||
|
the request's operation range is zero-filled in the file.
|
||||||
.It Oo Cm no Oc Ns Cm readonly
|
.It Oo Cm no Oc Ns Cm readonly
|
||||||
Enable/disable readonly mode.
|
Enable/disable readonly mode.
|
||||||
.It Oo Cm no Oc Ns Cm verify
|
.It Oo Cm no Oc Ns Cm verify
|
||||||
@ -339,12 +367,15 @@ gnop create -o 512K md1
|
|||||||
mount /dev/md1.nop /mnt
|
mount /dev/md1.nop /mnt
|
||||||
.Ed
|
.Ed
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
|
.Xr fpathconf 2 ,
|
||||||
|
.Xr fspacectl 2 ,
|
||||||
.Xr open 2 ,
|
.Xr open 2 ,
|
||||||
.Xr md 4 ,
|
.Xr md 4 ,
|
||||||
.Xr ffs 7 ,
|
.Xr ffs 7 ,
|
||||||
.Xr gpart 8 ,
|
.Xr gpart 8 ,
|
||||||
.Xr mdmfs 8 ,
|
.Xr mdmfs 8 ,
|
||||||
.Xr malloc 9
|
.Xr malloc 9 ,
|
||||||
|
.Xr vn_deallocate 9
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
|
@ -89,7 +89,8 @@ usage(void)
|
|||||||
" mdconfig file\n");
|
" mdconfig file\n");
|
||||||
fprintf(stderr, "\t\ttype = {malloc, vnode, swap}\n");
|
fprintf(stderr, "\t\ttype = {malloc, vnode, swap}\n");
|
||||||
fprintf(stderr, "\t\toption = {cache, cluster, compress, force,\n");
|
fprintf(stderr, "\t\toption = {cache, cluster, compress, force,\n");
|
||||||
fprintf(stderr, "\t\t readonly, reserve, ro, verify}\n");
|
fprintf(stderr, "\t\t mustdealloc, readonly, reserve, ro,\n");
|
||||||
|
fprintf(stderr, "\t\t verify}\n");
|
||||||
fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%db (B),\n");
|
fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%db (B),\n");
|
||||||
fprintf(stderr, "\t\t %%dk (kB), %%dm (MB), %%dg (GB), \n");
|
fprintf(stderr, "\t\t %%dk (kB), %%dm (MB), %%dg (GB), \n");
|
||||||
fprintf(stderr, "\t\t %%dt (TB), or %%dp (PB)\n");
|
fprintf(stderr, "\t\t %%dt (TB), or %%dp (PB)\n");
|
||||||
@ -194,6 +195,10 @@ main(int argc, char **argv)
|
|||||||
mdio.md_options |= MD_FORCE;
|
mdio.md_options |= MD_FORCE;
|
||||||
else if (!strcmp(optarg, "noforce"))
|
else if (!strcmp(optarg, "noforce"))
|
||||||
mdio.md_options &= ~MD_FORCE;
|
mdio.md_options &= ~MD_FORCE;
|
||||||
|
else if (!strcmp(optarg, "mustdealloc"))
|
||||||
|
mdio.md_options |= MD_MUSTDEALLOC;
|
||||||
|
else if (!strcmp(optarg, "nomustdealloc"))
|
||||||
|
mdio.md_options &= ~MD_MUSTDEALLOC;
|
||||||
else if (!strcmp(optarg, "readonly"))
|
else if (!strcmp(optarg, "readonly"))
|
||||||
mdio.md_options |= MD_READONLY;
|
mdio.md_options |= MD_READONLY;
|
||||||
else if (!strcmp(optarg, "noreadonly"))
|
else if (!strcmp(optarg, "noreadonly"))
|
||||||
|
@ -90,6 +90,7 @@
|
|||||||
#include <sys/sf_buf.h>
|
#include <sys/sf_buf.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
#include <sys/unistd.h>
|
||||||
#include <sys/vnode.h>
|
#include <sys/vnode.h>
|
||||||
#include <sys/disk.h>
|
#include <sys/disk.h>
|
||||||
|
|
||||||
@ -259,6 +260,7 @@ struct md_s {
|
|||||||
struct g_provider *pp;
|
struct g_provider *pp;
|
||||||
int (*start)(struct md_s *sc, struct bio *bp);
|
int (*start)(struct md_s *sc, struct bio *bp);
|
||||||
struct devstat *devstat;
|
struct devstat *devstat;
|
||||||
|
bool candelete;
|
||||||
|
|
||||||
/* MD_MALLOC related fields */
|
/* MD_MALLOC related fields */
|
||||||
struct indir *indir;
|
struct indir *indir;
|
||||||
@ -885,9 +887,12 @@ mdstart_vnode(struct md_s *sc, struct bio *bp)
|
|||||||
case BIO_WRITE:
|
case BIO_WRITE:
|
||||||
auio.uio_rw = UIO_WRITE;
|
auio.uio_rw = UIO_WRITE;
|
||||||
break;
|
break;
|
||||||
case BIO_DELETE:
|
|
||||||
case BIO_FLUSH:
|
case BIO_FLUSH:
|
||||||
break;
|
break;
|
||||||
|
case BIO_DELETE:
|
||||||
|
if (sc->candelete)
|
||||||
|
break;
|
||||||
|
/* FALLTHROUGH */
|
||||||
default:
|
default:
|
||||||
return (EOPNOTSUPP);
|
return (EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
@ -1176,7 +1181,7 @@ md_handleattr(struct md_s *sc, struct bio *bp)
|
|||||||
(g_handleattr_int(bp, "GEOM::fwsectors", sc->fwsectors) != 0 ||
|
(g_handleattr_int(bp, "GEOM::fwsectors", sc->fwsectors) != 0 ||
|
||||||
g_handleattr_int(bp, "GEOM::fwheads", sc->fwheads) != 0))
|
g_handleattr_int(bp, "GEOM::fwheads", sc->fwheads) != 0))
|
||||||
return;
|
return;
|
||||||
if (g_handleattr_int(bp, "GEOM::candelete", 1) != 0)
|
if (g_handleattr_int(bp, "GEOM::candelete", sc->candelete) != 0)
|
||||||
return;
|
return;
|
||||||
if (sc->ident[0] != '\0' &&
|
if (sc->ident[0] != '\0' &&
|
||||||
g_handleattr_str(bp, "GEOM::ident", sc->ident) != 0)
|
g_handleattr_str(bp, "GEOM::ident", sc->ident) != 0)
|
||||||
@ -1405,6 +1410,7 @@ mdcreate_vnode(struct md_s *sc, struct md_req *mdr, struct thread *td)
|
|||||||
struct nameidata nd;
|
struct nameidata nd;
|
||||||
char *fname;
|
char *fname;
|
||||||
int error, flags;
|
int error, flags;
|
||||||
|
long v;
|
||||||
|
|
||||||
fname = mdr->md_file;
|
fname = mdr->md_file;
|
||||||
if (mdr->md_file_seg == UIO_USERSPACE) {
|
if (mdr->md_file_seg == UIO_USERSPACE) {
|
||||||
@ -1434,6 +1440,13 @@ mdcreate_vnode(struct md_s *sc, struct md_req *mdr, struct thread *td)
|
|||||||
error = VOP_GETATTR(nd.ni_vp, &vattr, td->td_ucred);
|
error = VOP_GETATTR(nd.ni_vp, &vattr, td->td_ucred);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
if ((mdr->md_options & MD_MUSTDEALLOC) != 0) {
|
||||||
|
error = VOP_PATHCONF(nd.ni_vp, _PC_DEALLOC_PRESENT, &v);
|
||||||
|
if (error != 0)
|
||||||
|
goto bad;
|
||||||
|
if (v == 0)
|
||||||
|
sc->candelete = false;
|
||||||
|
}
|
||||||
if (VOP_ISLOCKED(nd.ni_vp) != LK_EXCLUSIVE) {
|
if (VOP_ISLOCKED(nd.ni_vp) != LK_EXCLUSIVE) {
|
||||||
vn_lock(nd.ni_vp, LK_UPGRADE | LK_RETRY);
|
vn_lock(nd.ni_vp, LK_UPGRADE | LK_RETRY);
|
||||||
if (VN_IS_DOOMED(nd.ni_vp)) {
|
if (VN_IS_DOOMED(nd.ni_vp)) {
|
||||||
@ -1690,6 +1703,7 @@ kern_mdattach_locked(struct thread *td, struct md_req *mdr)
|
|||||||
mdr->md_unit = sc->unit;
|
mdr->md_unit = sc->unit;
|
||||||
sc->mediasize = mdr->md_mediasize;
|
sc->mediasize = mdr->md_mediasize;
|
||||||
sc->sectorsize = sectsize;
|
sc->sectorsize = sectsize;
|
||||||
|
sc->candelete = true;
|
||||||
error = EDOOFUS;
|
error = EDOOFUS;
|
||||||
switch (sc->type) {
|
switch (sc->type) {
|
||||||
case MD_MALLOC:
|
case MD_MALLOC:
|
||||||
|
@ -92,5 +92,6 @@ struct md_ioctl {
|
|||||||
#define MD_ASYNC 0x40 /* Asynchronous mode */
|
#define MD_ASYNC 0x40 /* Asynchronous mode */
|
||||||
#define MD_VERIFY 0x80 /* Open file with O_VERIFY (vnode only) */
|
#define MD_VERIFY 0x80 /* Open file with O_VERIFY (vnode only) */
|
||||||
#define MD_CACHE 0x100 /* Cache vnode data */
|
#define MD_CACHE 0x100 /* Cache vnode data */
|
||||||
|
#define MD_MUSTDEALLOC 0x200 /* BIO_DELETE only if dealloc is available */
|
||||||
|
|
||||||
#endif /* _SYS_MDIOCTL_H_*/
|
#endif /* _SYS_MDIOCTL_H_*/
|
||||||
|
Loading…
Reference in New Issue
Block a user