summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c28
-rw-r--r--usr/src/uts/common/fs/zfs/sys/vdev_impl.h1
-rw-r--r--usr/src/uts/common/fs/zfs/vdev_disk.c20
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_fm.c8
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c37
5 files changed, 88 insertions, 6 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index 2889725027..1fe6fa2d27 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -46,12 +46,30 @@
* 'buf'.
*/
static int
-zpool_name_valid(const char *pool, char *buf, size_t buflen)
+zpool_name_valid(const char *pool, boolean_t isopen, char *buf, size_t buflen)
{
namecheck_err_t why;
char what;
+ int ret;
+
+ ret = pool_namecheck(pool, &why, &what);
+
+ /*
+ * The rules for reserved pool names were extended at a later point.
+ * But we need to support users with existing pools that may now be
+ * invalid. So we only check for this expanded set of names during a
+ * create (or import), and only in userland.
+ */
+ if (ret == 0 && !isopen &&
+ (strncmp(pool, "mirror", 6) == 0 ||
+ strncmp(pool, "raidz", 5) == 0 ||
+ strncmp(pool, "spare", 5) == 0)) {
+ ret = -1;
+ why = NAME_ERR_RESERVED;
+ }
+
- if (pool_namecheck(pool, &why, &what) != 0) {
+ if (ret != 0) {
if (buf != NULL) {
switch (why) {
case NAME_ERR_TOOLONG:
@@ -142,7 +160,7 @@ zpool_open_canfail(const char *pool)
/*
* Make sure the pool name is valid.
*/
- if (!zpool_name_valid(pool, NULL, 0)) {
+ if (!zpool_name_valid(pool, B_TRUE, NULL, 0)) {
zfs_error(dgettext(TEXT_DOMAIN, "cannot open '%s': invalid "
"pool name"), pool);
return (NULL);
@@ -338,7 +356,7 @@ zpool_create(const char *pool, nvlist_t *nvroot, const char *altroot)
int err;
char reason[64];
- if (!zpool_name_valid(pool, reason, sizeof (reason))) {
+ if (!zpool_name_valid(pool, B_FALSE, reason, sizeof (reason))) {
zfs_error(dgettext(TEXT_DOMAIN, "cannot create '%s': %s"),
pool, reason);
return (-1);
@@ -688,7 +706,7 @@ zpool_import(nvlist_t *config, const char *newname, const char *altroot)
&origname) == 0);
if (newname != NULL) {
- if (!zpool_name_valid(newname, NULL, 0)) {
+ if (!zpool_name_valid(newname, B_FALSE, NULL, 0)) {
zfs_error(dgettext(TEXT_DOMAIN, "cannot import '%s': "
"invalid pool name"), newname);
return (-1);
diff --git a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h
index 8c094fba12..9ea2ca5373 100644
--- a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h
@@ -173,6 +173,7 @@ struct vdev {
vdev_cache_t vdev_cache; /* physical block cache */
uint64_t vdev_not_present; /* not present during import */
hrtime_t vdev_last_try; /* last reopen time */
+ boolean_t vdev_nowritecache; /* true if flushwritecache failed */
/*
* For DTrace to work in userland (libzpool) context, these fields must
diff --git a/usr/src/uts/common/fs/zfs/vdev_disk.c b/usr/src/uts/common/fs/zfs/vdev_disk.c
index 0b4c2c9696..2c50ba3837 100644
--- a/usr/src/uts/common/fs/zfs/vdev_disk.c
+++ b/usr/src/uts/common/fs/zfs/vdev_disk.c
@@ -174,6 +174,12 @@ vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
*ashift = highbit(MAX(dkm.dki_lbsize, SPA_MINBLOCKSIZE)) - 1;
+ /*
+ * Clear the nowritecache bit, so that on a vdev_reopen() we will
+ * try again.
+ */
+ vd->vdev_nowritecache = B_FALSE;
+
return (0);
}
@@ -249,6 +255,11 @@ vdev_disk_io_start(zio_t *zio)
case DKIOCFLUSHWRITECACHE:
+ if (vd->vdev_nowritecache) {
+ zio->io_error = ENOTSUP;
+ break;
+ }
+
zio->io_dk_callback.dkc_callback = vdev_disk_ioctl_done;
zio->io_dk_callback.dkc_cookie = zio;
@@ -263,8 +274,17 @@ vdev_disk_io_start(zio_t *zio)
* upon completion.
*/
return;
+ } else if (error == ENOTSUP) {
+ /*
+ * If we get ENOTSUP, we know that no future
+ * attempts will ever succeed. In this case we
+ * set a persistent bit so that we don't bother
+ * with the ioctl in the future.
+ */
+ vd->vdev_nowritecache = B_TRUE;
}
zio->io_error = error;
+
break;
default:
diff --git a/usr/src/uts/common/fs/zfs/zfs_fm.c b/usr/src/uts/common/fs/zfs/zfs_fm.c
index 007445c713..f0fdb8f6ea 100644
--- a/usr/src/uts/common/fs/zfs/zfs_fm.c
+++ b/usr/src/uts/common/fs/zfs/zfs_fm.c
@@ -122,6 +122,14 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio,
if (zio && zio_should_retry(zio))
return;
+ /*
+ * If this is not a read or write zio, ignore the error. This can occur
+ * if the DKIOCFLUSHWRITECACHE ioctl fails.
+ */
+ if (zio && zio->io_type != ZIO_TYPE_READ &&
+ zio->io_type != ZIO_TYPE_WRITE)
+ return;
+
if ((ereport = fm_nvlist_create(NULL)) == NULL)
return;
diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c
index 76e2069e63..67e886cac2 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c
@@ -1815,13 +1815,22 @@ update:
return (error);
}
-/* ARGSUSED */
static int
zfs_fsync(vnode_t *vp, int syncflag, cred_t *cr)
{
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
+ /*
+ * Regardless of whether this is required for standards conformance,
+ * this is the logical behavior when fsync() is called on a file with
+ * dirty pages. We use B_ASYNC since the ZIL transactions are already
+ * going to be pushed out as part of the zil_commit().
+ */
+ if (vn_has_cached_data(vp) && !(syncflag & FNODSYNC) &&
+ (vp->v_type == VREG) && !(IS_SWAPVP(vp)))
+ (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_ASYNC, cr);
+
ZFS_ENTER(zfsvfs);
zil_commit(zfsvfs->z_log, zp->z_last_itx, FSYNC);
ZFS_EXIT(zfsvfs);
@@ -3358,6 +3367,27 @@ zfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
return (0);
}
+/*
+ * The reason we push dirty pages as part of zfs_delmap() is so that we get a
+ * more accurate mtime for the associated file. Since we don't have a way of
+ * detecting when the data was actually modified, we have to resort to
+ * heuristics. If an explicit msync() is done, then we mark the mtime when the
+ * last page is pushed. The problem occurs when the msync() call is omitted,
+ * which by far the most common case:
+ *
+ * open()
+ * mmap()
+ * <modify memory>
+ * munmap()
+ * close()
+ * <time lapse>
+ * putpage() via fsflush
+ *
+ * If we wait until fsflush to come along, we can have a modification time that
+ * is some arbitrary point in the future. In order to prevent this in the
+ * common case, we flush pages whenever a (MAP_SHARED, PROT_WRITE) mapping is
+ * torn down.
+ */
/* ARGSUSED */
static int
zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
@@ -3367,6 +3397,11 @@ zfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
ASSERT3U(VTOZ(vp)->z_mapcnt, >=, pages);
atomic_add_64(&VTOZ(vp)->z_mapcnt, -pages);
+
+ if ((flags & MAP_SHARED) && (prot & PROT_WRITE) &&
+ vn_has_cached_data(vp))
+ (void) VOP_PUTPAGE(vp, off, len, B_ASYNC, cr);
+
return (0);
}