diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_pool.c | 28 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/vdev_impl.h | 1 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/vdev_disk.c | 20 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_fm.c | 8 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_vnops.c | 37 |
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); } |