git: d48d1f29888c - stable/13 - tmpfs: implement FIOSEEKDATA and FIOSEEKHOLE
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 26 Oct 2022 00:44:06 UTC
The branch stable/13 has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=d48d1f29888cf1dd68ca5b06974ab9005beb932c
commit d48d1f29888cf1dd68ca5b06974ab9005beb932c
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2022-10-17 15:26:43 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2022-10-26 00:43:43 +0000
tmpfs: implement FIOSEEKDATA and FIOSEEKHOLE
(cherry picked from commit 85cff1455a8c3422c6ba8a9f895b5d65118f3499)
---
sys/fs/tmpfs/tmpfs_vnops.c | 130 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 130 insertions(+)
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index fdadad364ca2..825e3571b599 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/dirent.h>
#include <sys/fcntl.h>
#include <sys/file.h>
+#include <sys/filio.h>
#include <sys/limits.h>
#include <sys/lockf.h>
#include <sys/lock.h>
@@ -63,6 +64,9 @@ __FBSDID("$FreeBSD$");
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/swap_pager.h>
#include <fs/tmpfs/tmpfs_vnops.h>
#include <fs/tmpfs/tmpfs.h>
@@ -1824,6 +1828,131 @@ restart_locked:
return (ENOENT);
}
+static off_t
+tmpfs_seek_data_locked(vm_object_t obj, off_t noff)
+{
+ vm_page_t m;
+ vm_pindex_t p, p_m, p_swp;
+
+ p = OFF_TO_IDX(noff);
+ m = vm_page_find_least(obj, p);
+
+ /*
+ * Microoptimize the most common case for SEEK_DATA, where
+ * there is no hole and the page is resident.
+ */
+ if (m != NULL && vm_page_any_valid(m) && m->pindex == p)
+ return (noff);
+
+ p_swp = swap_pager_find_least(obj, p);
+ if (p_swp == p)
+ return (noff);
+
+ p_m = m == NULL ? obj->size : m->pindex;
+ return (IDX_TO_OFF(MIN(p_m, p_swp)));
+}
+
+static off_t
+tmpfs_seek_next(off_t noff)
+{
+ return (noff + PAGE_SIZE - (noff & PAGE_MASK));
+}
+
+static int
+tmpfs_seek_clamp(struct tmpfs_node *tn, off_t *noff, bool seekdata)
+{
+ if (*noff < tn->tn_size)
+ return (0);
+ if (seekdata)
+ return (ENXIO);
+ *noff = tn->tn_size;
+ return (0);
+}
+
+static off_t
+tmpfs_seek_hole_locked(vm_object_t obj, off_t noff)
+{
+ vm_page_t m;
+ vm_pindex_t p, p_swp;
+
+ for (;; noff = tmpfs_seek_next(noff)) {
+ /*
+ * Walk over the largest sequential run of the valid pages.
+ */
+ for (m = vm_page_lookup(obj, OFF_TO_IDX(noff));
+ m != NULL && vm_page_any_valid(m);
+ m = vm_page_next(m), noff = tmpfs_seek_next(noff))
+ ;
+
+ /*
+ * Found a hole in the object's page queue. Check if
+ * there is a hole in the swap at the same place.
+ */
+ p = OFF_TO_IDX(noff);
+ p_swp = swap_pager_find_least(obj, p);
+ if (p_swp != p) {
+ noff = IDX_TO_OFF(p);
+ break;
+ }
+ }
+ return (noff);
+}
+
+static int
+tmpfs_seek_datahole(struct vnode *vp, off_t *off, bool seekdata)
+{
+ struct tmpfs_node *tn;
+ vm_object_t obj;
+ off_t noff;
+ int error;
+
+ if (vp->v_type != VREG)
+ return (ENOTTY);
+ tn = VP_TO_TMPFS_NODE(vp);
+ noff = *off;
+ if (noff < 0)
+ return (ENXIO);
+ error = tmpfs_seek_clamp(tn, &noff, seekdata);
+ if (error != 0)
+ return (error);
+ obj = tn->tn_reg.tn_aobj;
+
+ VM_OBJECT_RLOCK(obj);
+ noff = seekdata ? tmpfs_seek_data_locked(obj, noff) :
+ tmpfs_seek_hole_locked(obj, noff);
+ VM_OBJECT_RUNLOCK(obj);
+
+ error = tmpfs_seek_clamp(tn, &noff, seekdata);
+ if (error == 0)
+ *off = noff;
+ return (error);
+}
+
+static int
+tmpfs_ioctl(struct vop_ioctl_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ int error = 0;
+
+ switch (ap->a_command) {
+ case FIOSEEKDATA:
+ case FIOSEEKHOLE:
+ error = vn_lock(vp, LK_SHARED);
+ if (error != 0) {
+ error = EBADF;
+ break;
+ }
+ error = tmpfs_seek_datahole(vp, (off_t *)ap->a_data,
+ ap->a_command == FIOSEEKDATA);
+ VOP_UNLOCK(vp);
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
/*
* Vnode operations vector used for files stored in a tmpfs file system.
*/
@@ -1865,6 +1994,7 @@ struct vop_vector tmpfs_vnodeop_entries = {
.vop_lock1 = vop_lock,
.vop_unlock = vop_unlock,
.vop_islocked = vop_islocked,
+ .vop_ioctl = tmpfs_ioctl,
};
VFS_VOP_VECTOR_REGISTER(tmpfs_vnodeop_entries);