summaryrefslogtreecommitdiffstats
path: root/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c229
1 files changed, 137 insertions, 92 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
index 6b6f537..330c753 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
@@ -1203,6 +1203,12 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
DMU_READ_NO_PREFETCH);
if (error == 0) {
+ blkptr_t *obp = dmu_buf_get_blkptr(db);
+ if (obp) {
+ ASSERT(BP_IS_HOLE(bp));
+ *bp = *obp;
+ }
+
zgd->zgd_db = db;
zgd->zgd_bp = bp;
@@ -1908,6 +1914,9 @@ top:
}
if (delete_now) {
+#ifdef __FreeBSD__
+ panic("zfs_remove: delete_now branch taken");
+#endif
if (xattr_obj_unlinked) {
ASSERT3U(xzp->z_links, ==, 2);
mutex_enter(&xzp->z_lock);
@@ -1937,6 +1946,9 @@ top:
} else if (unlinked) {
mutex_exit(&zp->z_lock);
zfs_unlinked_add(zp, tx);
+#ifdef __FreeBSD__
+ vp->v_vflag |= VV_NOSYNC;
+#endif
}
txtype = TX_REMOVE;
@@ -2667,7 +2679,7 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL, &mtime, 16);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, &ctime, 16);
- SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, &crtime, 16);
+ SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CRTIME(zfsvfs), NULL, &crtime, 16);
if (vp->v_type == VBLK || vp->v_type == VCHR)
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_RDEV(zfsvfs), NULL,
&rdev, 8);
@@ -3245,6 +3257,12 @@ top:
uint64_t acl_obj;
new_mode = (pmode & S_IFMT) | (vap->va_mode & ~S_IFMT);
+ if (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_RESTRICTED &&
+ !(zp->z_pflags & ZFS_ACL_TRIVIAL)) {
+ err = EPERM;
+ goto out;
+ }
+
if (err = zfs_acl_chmod_setattr(zp, &aclp, new_mode))
goto out;
@@ -4560,14 +4578,22 @@ zfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
* The fs has been unmounted, or we did a
* suspend/resume and this file no longer exists.
*/
- VI_LOCK(vp);
- ASSERT(vp->v_count <= 1);
- vp->v_count = 0;
- VI_UNLOCK(vp);
+ rw_exit(&zfsvfs->z_teardown_inactive_lock);
vrecycle(vp);
+ return;
+ }
+
+ mutex_enter(&zp->z_lock);
+ if (zp->z_unlinked) {
+ /*
+ * Fast path to recycle a vnode of a removed file.
+ */
+ mutex_exit(&zp->z_lock);
rw_exit(&zfsvfs->z_teardown_inactive_lock);
+ vrecycle(vp);
return;
}
+ mutex_exit(&zp->z_lock);
if (zp->z_atime_dirty && zp->z_unlinked == 0) {
dmu_tx_t *tx = dmu_tx_create(zfsvfs->z_os);
@@ -4586,8 +4612,6 @@ zfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
dmu_tx_commit(tx);
}
}
-
- zfs_zinactive(zp);
rw_exit(&zfsvfs->z_teardown_inactive_lock);
}
@@ -5550,34 +5574,61 @@ zfs_getpages(struct vnode *vp, vm_page_t *m, int count, int reqpage)
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
objset_t *os = zp->z_zfsvfs->z_os;
- vm_page_t mreq;
+ vm_page_t mfirst, mlast, mreq;
vm_object_t object;
caddr_t va;
struct sf_buf *sf;
+ off_t startoff, endoff;
int i, error;
- int pcount, size;
+ vm_pindex_t reqstart, reqend;
+ int pcount, lsize, reqsize, size;
ZFS_ENTER(zfsvfs);
ZFS_VERIFY_ZP(zp);
- pcount = round_page(count) / PAGE_SIZE;
+ pcount = OFF_TO_IDX(round_page(count));
mreq = m[reqpage];
object = mreq->object;
error = 0;
KASSERT(vp->v_object == object, ("mismatching object"));
+ if (pcount > 1 && zp->z_blksz > PAGESIZE) {
+ startoff = rounddown(IDX_TO_OFF(mreq->pindex), zp->z_blksz);
+ reqstart = OFF_TO_IDX(round_page(startoff));
+ if (reqstart < m[0]->pindex)
+ reqstart = 0;
+ else
+ reqstart = reqstart - m[0]->pindex;
+ endoff = roundup(IDX_TO_OFF(mreq->pindex) + PAGE_SIZE,
+ zp->z_blksz);
+ reqend = OFF_TO_IDX(trunc_page(endoff)) - 1;
+ if (reqend > m[pcount - 1]->pindex)
+ reqend = m[pcount - 1]->pindex;
+ reqsize = reqend - m[reqstart]->pindex + 1;
+ KASSERT(reqstart <= reqpage && reqpage < reqstart + reqsize,
+ ("reqpage beyond [reqstart, reqstart + reqsize[ bounds"));
+ } else {
+ reqstart = reqpage;
+ reqsize = 1;
+ }
+ mfirst = m[reqstart];
+ mlast = m[reqstart + reqsize - 1];
+
VM_OBJECT_LOCK(object);
- for (i = 0; i < pcount; i++) {
- if (i != reqpage) {
- vm_page_lock(m[i]);
- vm_page_free(m[i]);
- vm_page_unlock(m[i]);
- }
+ for (i = 0; i < reqstart; i++) {
+ vm_page_lock(m[i]);
+ vm_page_free(m[i]);
+ vm_page_unlock(m[i]);
+ }
+ for (i = reqstart + reqsize; i < pcount; i++) {
+ vm_page_lock(m[i]);
+ vm_page_free(m[i]);
+ vm_page_unlock(m[i]);
}
- if (mreq->valid) {
+ if (mreq->valid && reqsize == 1) {
if (mreq->valid != VM_PAGE_BITS_ALL)
vm_page_zero_invalid(mreq, TRUE);
VM_OBJECT_UNLOCK(object);
@@ -5586,30 +5637,50 @@ zfs_getpages(struct vnode *vp, vm_page_t *m, int count, int reqpage)
}
PCPU_INC(cnt.v_vnodein);
- PCPU_INC(cnt.v_vnodepgsin);
+ PCPU_ADD(cnt.v_vnodepgsin, reqsize);
if (IDX_TO_OFF(mreq->pindex) >= object->un_pager.vnp.vnp_size) {
+ for (i = reqstart; i < reqstart + reqsize; i++) {
+ if (i != reqpage) {
+ vm_page_lock(m[i]);
+ vm_page_free(m[i]);
+ vm_page_unlock(m[i]);
+ }
+ }
VM_OBJECT_UNLOCK(object);
ZFS_EXIT(zfsvfs);
return (VM_PAGER_BAD);
}
- size = PAGE_SIZE;
- if (IDX_TO_OFF(mreq->pindex) + size > object->un_pager.vnp.vnp_size)
- size = object->un_pager.vnp.vnp_size - IDX_TO_OFF(mreq->pindex);
+ lsize = PAGE_SIZE;
+ if (IDX_TO_OFF(mlast->pindex) + lsize > object->un_pager.vnp.vnp_size)
+ lsize = object->un_pager.vnp.vnp_size - IDX_TO_OFF(mlast->pindex);
VM_OBJECT_UNLOCK(object);
- va = zfs_map_page(mreq, &sf);
- error = dmu_read(os, zp->z_id, IDX_TO_OFF(mreq->pindex),
- size, va, DMU_READ_PREFETCH);
- if (size != PAGE_SIZE)
- bzero(va + size, PAGE_SIZE - size);
- zfs_unmap_page(sf);
+
+ for (i = reqstart; i < reqstart + reqsize; i++) {
+ size = PAGE_SIZE;
+ if (i == (reqstart + reqsize - 1))
+ size = lsize;
+ va = zfs_map_page(m[i], &sf);
+ error = dmu_read(os, zp->z_id, IDX_TO_OFF(m[i]->pindex),
+ size, va, DMU_READ_PREFETCH);
+ if (size != PAGE_SIZE)
+ bzero(va + size, PAGE_SIZE - size);
+ zfs_unmap_page(sf);
+ if (error != 0)
+ break;
+ }
+
VM_OBJECT_LOCK(object);
- if (!error)
- mreq->valid = VM_PAGE_BITS_ALL;
- KASSERT(mreq->dirty == 0, ("zfs_getpages: page %p is dirty", mreq));
+ for (i = reqstart; i < reqstart + reqsize; i++) {
+ if (!error)
+ m[i]->valid = VM_PAGE_BITS_ALL;
+ KASSERT(m[i]->dirty == 0, ("zfs_getpages: page %p is dirty", m[i]));
+ if (i != reqpage)
+ vm_page_readahead_finish(m[i]);
+ }
VM_OBJECT_UNLOCK(object);
@@ -5633,6 +5704,30 @@ zfs_freebsd_getpages(ap)
}
static int
+zfs_freebsd_bmap(ap)
+ struct vop_bmap_args /* {
+ struct vnode *a_vp;
+ daddr_t a_bn;
+ struct bufobj **a_bop;
+ daddr_t *a_bnp;
+ int *a_runp;
+ int *a_runb;
+ } */ *ap;
+{
+
+ if (ap->a_bop != NULL)
+ *ap->a_bop = &ap->a_vp->v_bufobj;
+ if (ap->a_bnp != NULL)
+ *ap->a_bnp = ap->a_bn;
+ if (ap->a_runp != NULL)
+ *ap->a_runp = 0;
+ if (ap->a_runb != NULL)
+ *ap->a_runb = 0;
+
+ return (0);
+}
+
+static int
zfs_freebsd_open(ap)
struct vop_open_args /* {
struct vnode *a_vp;
@@ -6103,28 +6198,6 @@ zfs_freebsd_inactive(ap)
return (0);
}
-static void
-zfs_reclaim_complete(void *arg, int pending)
-{
- znode_t *zp = arg;
- zfsvfs_t *zfsvfs = zp->z_zfsvfs;
-
- rw_enter(&zfsvfs->z_teardown_inactive_lock, RW_READER);
- if (zp->z_sa_hdl != NULL) {
- ZFS_OBJ_HOLD_ENTER(zfsvfs, zp->z_id);
- zfs_znode_dmu_fini(zp);
- ZFS_OBJ_HOLD_EXIT(zfsvfs, zp->z_id);
- }
- zfs_znode_free(zp);
- rw_exit(&zfsvfs->z_teardown_inactive_lock);
- /*
- * If the file system is being unmounted, there is a process waiting
- * for us, wake it up.
- */
- if (zfsvfs->z_unmounted)
- wakeup_one(zfsvfs);
-}
-
static int
zfs_freebsd_reclaim(ap)
struct vop_reclaim_args /* {
@@ -6135,53 +6208,25 @@ zfs_freebsd_reclaim(ap)
vnode_t *vp = ap->a_vp;
znode_t *zp = VTOZ(vp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
- boolean_t rlocked;
-
- rlocked = rw_tryenter(&zfsvfs->z_teardown_inactive_lock, RW_READER);
ASSERT(zp != NULL);
- /*
- * Destroy the vm object and flush associated pages.
- */
+ /* Destroy the vm object and flush associated pages. */
vnode_destroy_vobject(vp);
- mutex_enter(&zp->z_lock);
- zp->z_vnode = NULL;
- mutex_exit(&zp->z_lock);
-
- if (zp->z_unlinked) {
- ; /* Do nothing. */
- } else if (!rlocked) {
- TASK_INIT(&zp->z_task, 0, zfs_reclaim_complete, zp);
- taskqueue_enqueue(taskqueue_thread, &zp->z_task);
- } else if (zp->z_sa_hdl == NULL) {
+ /*
+ * z_teardown_inactive_lock protects from a race with
+ * zfs_znode_dmu_fini in zfsvfs_teardown during
+ * force unmount.
+ */
+ rw_enter(&zfsvfs->z_teardown_inactive_lock, RW_READER);
+ if (zp->z_sa_hdl == NULL)
zfs_znode_free(zp);
- } else /* if (!zp->z_unlinked && zp->z_dbuf != NULL) */ {
- int locked;
+ else
+ zfs_zinactive(zp);
+ rw_exit(&zfsvfs->z_teardown_inactive_lock);
- locked = MUTEX_HELD(ZFS_OBJ_MUTEX(zfsvfs, zp->z_id)) ? 2 :
- ZFS_OBJ_HOLD_TRYENTER(zfsvfs, zp->z_id);
- if (locked == 0) {
- /*
- * Lock can't be obtained due to deadlock possibility,
- * so defer znode destruction.
- */
- TASK_INIT(&zp->z_task, 0, zfs_reclaim_complete, zp);
- taskqueue_enqueue(taskqueue_thread, &zp->z_task);
- } else {
- zfs_znode_dmu_fini(zp);
- if (locked == 1)
- ZFS_OBJ_HOLD_EXIT(zfsvfs, zp->z_id);
- zfs_znode_free(zp);
- }
- }
- VI_LOCK(vp);
vp->v_data = NULL;
- ASSERT(vp->v_holdcnt >= 1);
- VI_UNLOCK(vp);
- if (rlocked)
- rw_exit(&zfsvfs->z_teardown_inactive_lock);
return (0);
}
@@ -6737,7 +6782,7 @@ struct vop_vector zfs_vnodeops = {
.vop_remove = zfs_freebsd_remove,
.vop_rename = zfs_freebsd_rename,
.vop_pathconf = zfs_freebsd_pathconf,
- .vop_bmap = VOP_EOPNOTSUPP,
+ .vop_bmap = zfs_freebsd_bmap,
.vop_fid = zfs_freebsd_fid,
.vop_getextattr = zfs_getextattr,
.vop_deleteextattr = zfs_deleteextattr,
OpenPOWER on IntegriCloud