vm: Add KPI to dynamically register pagers

Pager is allowed to inherit part of its implementation from the existing
pager, which is done by copying non-NULL virtual method slots.

Reviewed by:	markj
Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D30168
This commit is contained in:
Konstantin Belousov 2021-05-07 22:06:16 +03:00
parent 7079449b0b
commit b730fd30b7
5 changed files with 91 additions and 11 deletions

View File

@ -98,6 +98,7 @@ enum obj_type {
OBJT_SG, OBJT_SG,
OBJT_MGTDEVICE, OBJT_MGTDEVICE,
OBJT_SWAP_TMPFS, OBJT_SWAP_TMPFS,
OBJT_FIRST_DYN,
}; };
typedef u_char objtype_t; typedef u_char objtype_t;

View File

@ -430,7 +430,8 @@ vm_object_allocate(objtype_t type, vm_pindex_t size)
flags = 0; flags = 0;
break; break;
default: default:
panic("vm_object_allocate: type %d is undefined", type); panic("vm_object_allocate: type %d is undefined or dynamic",
type);
} }
object = (vm_object_t)uma_zalloc(obj_zone, M_WAITOK); object = (vm_object_t)uma_zalloc(obj_zone, M_WAITOK);
_vm_object_allocate(type, size, flags, object, NULL); _vm_object_allocate(type, size, flags, object, NULL);
@ -438,6 +439,18 @@ vm_object_allocate(objtype_t type, vm_pindex_t size)
return (object); return (object);
} }
vm_object_t
vm_object_allocate_dyn(objtype_t dyntype, vm_pindex_t size, u_short flags)
{
vm_object_t object;
MPASS(dyntype >= OBJT_FIRST_DYN /* && dyntype < nitems(pagertab) */);
object = (vm_object_t)uma_zalloc(obj_zone, M_WAITOK);
_vm_object_allocate(dyntype, size, flags, object, NULL);
return (object);
}
/* /*
* vm_object_allocate_anon: * vm_object_allocate_anon:
* *

View File

@ -356,6 +356,7 @@ extern int umtx_shm_vnobj_persistent;
vm_object_t vm_object_allocate (objtype_t, vm_pindex_t); vm_object_t vm_object_allocate (objtype_t, vm_pindex_t);
vm_object_t vm_object_allocate_anon(vm_pindex_t, vm_object_t, struct ucred *, vm_object_t vm_object_allocate_anon(vm_pindex_t, vm_object_t, struct ucred *,
vm_size_t); vm_size_t);
vm_object_t vm_object_allocate_dyn(objtype_t, vm_pindex_t, u_short);
boolean_t vm_object_coalesce(vm_object_t, vm_ooffset_t, vm_size_t, vm_size_t, boolean_t vm_object_coalesce(vm_object_t, vm_ooffset_t, vm_size_t, vm_size_t,
boolean_t); boolean_t);
void vm_object_collapse (vm_object_t); void vm_object_collapse (vm_object_t);

View File

@ -165,7 +165,7 @@ static const struct pagerops deadpagerops = {
.pgo_getvp = dead_pager_getvp, .pgo_getvp = dead_pager_getvp,
}; };
const struct pagerops *pagertab[] __read_mostly = { const struct pagerops *pagertab[16] __read_mostly = {
[OBJT_DEFAULT] = &defaultpagerops, [OBJT_DEFAULT] = &defaultpagerops,
[OBJT_SWAP] = &swappagerops, [OBJT_SWAP] = &swappagerops,
[OBJT_VNODE] = &vnodepagerops, [OBJT_VNODE] = &vnodepagerops,
@ -176,18 +176,24 @@ const struct pagerops *pagertab[] __read_mostly = {
[OBJT_MGTDEVICE] = &mgtdevicepagerops, [OBJT_MGTDEVICE] = &mgtdevicepagerops,
[OBJT_SWAP_TMPFS] = &swaptmpfspagerops, [OBJT_SWAP_TMPFS] = &swaptmpfspagerops,
}; };
static struct mtx pagertab_lock;
void void
vm_pager_init(void) vm_pager_init(void)
{ {
const struct pagerops **pgops; const struct pagerops **pgops;
int i;
mtx_init(&pagertab_lock, "dynpag", NULL, MTX_DEF);
/* /*
* Initialize known pagers * Initialize known pagers
*/ */
for (pgops = pagertab; pgops < &pagertab[nitems(pagertab)]; pgops++) for (i = 0; i < OBJT_FIRST_DYN; i++) {
pgops = &pagertab[i];
if ((*pgops)->pgo_init != NULL) if ((*pgops)->pgo_init != NULL)
(*(*pgops)->pgo_init)(); (*(*pgops)->pgo_init)();
}
} }
static int nswbuf_max; static int nswbuf_max;
@ -245,15 +251,9 @@ vm_object_t
vm_pager_allocate(objtype_t type, void *handle, vm_ooffset_t size, vm_pager_allocate(objtype_t type, void *handle, vm_ooffset_t size,
vm_prot_t prot, vm_ooffset_t off, struct ucred *cred) vm_prot_t prot, vm_ooffset_t off, struct ucred *cred)
{ {
vm_object_t ret; MPASS(type < nitems(pagertab));
const struct pagerops *ops;
ops = pagertab[type]; return ((*pagertab[type]->pgo_alloc)(handle, size, prot, off, cred));
if (ops)
ret = (*ops->pgo_alloc)(handle, size, prot, off, cred);
else
ret = NULL;
return (ret);
} }
/* /*
@ -264,6 +264,7 @@ vm_pager_deallocate(vm_object_t object)
{ {
VM_OBJECT_ASSERT_WLOCKED(object); VM_OBJECT_ASSERT_WLOCKED(object);
MPASS(object->type < nitems(pagertab));
(*pagertab[object->type]->pgo_dealloc) (object); (*pagertab[object->type]->pgo_dealloc) (object);
} }
@ -315,6 +316,7 @@ vm_pager_get_pages(vm_object_t object, vm_page_t *m, int count, int *rbehind,
#endif #endif
int r; int r;
MPASS(object->type < nitems(pagertab));
vm_pager_assert_in(object, m, count); vm_pager_assert_in(object, m, count);
r = (*pagertab[object->type]->pgo_getpages)(object, m, count, rbehind, r = (*pagertab[object->type]->pgo_getpages)(object, m, count, rbehind,
@ -348,6 +350,7 @@ vm_pager_get_pages_async(vm_object_t object, vm_page_t *m, int count,
int *rbehind, int *rahead, pgo_getpages_iodone_t iodone, void *arg) int *rbehind, int *rahead, pgo_getpages_iodone_t iodone, void *arg)
{ {
MPASS(object->type < nitems(pagertab));
vm_pager_assert_in(object, m, count); vm_pager_assert_in(object, m, count);
return ((*pagertab[object->type]->pgo_getpages_async)(object, m, return ((*pagertab[object->type]->pgo_getpages_async)(object, m,
@ -385,6 +388,60 @@ vm_pager_object_lookup(struct pagerlst *pg_list, void *handle)
return (object); return (object);
} }
int
vm_pager_alloc_dyn_type(struct pagerops *ops, int base_type)
{
int res;
mtx_lock(&pagertab_lock);
MPASS(base_type == -1 ||
(base_type >= OBJT_DEFAULT && base_type < nitems(pagertab)));
for (res = OBJT_FIRST_DYN; res < nitems(pagertab); res++) {
if (pagertab[res] == NULL)
break;
}
if (res == nitems(pagertab)) {
mtx_unlock(&pagertab_lock);
return (-1);
}
if (base_type != -1) {
MPASS(pagertab[base_type] != NULL);
#define FIX(n) \
if (ops->pgo_##n == NULL) \
ops->pgo_##n = pagertab[base_type]->pgo_##n
FIX(init);
FIX(alloc);
FIX(dealloc);
FIX(getpages);
FIX(getpages_async);
FIX(putpages);
FIX(haspage);
FIX(populate);
FIX(pageunswapped);
FIX(update_writecount);
FIX(release_writecount);
FIX(set_writeable_dirty);
FIX(mightbedirty);
FIX(getvp);
FIX(freespace);
#undef FIX
}
pagertab[res] = ops; /* XXXKIB should be rel, but acq is too much */
mtx_unlock(&pagertab_lock);
return (res);
}
void
vm_pager_free_dyn_type(objtype_t type)
{
MPASS(type >= OBJT_FIRST_DYN && type < nitems(pagertab));
mtx_lock(&pagertab_lock);
MPASS(pagertab[type] != NULL);
pagertab[type] = NULL;
mtx_unlock(&pagertab_lock);
}
static int static int
pbuf_ctor(void *mem, int size, void *arg, int flags) pbuf_ctor(void *mem, int size, void *arg, int flags)
{ {
@ -517,6 +574,8 @@ vm_object_set_writeable_dirty(vm_object_t object)
{ {
pgo_set_writeable_dirty_t *method; pgo_set_writeable_dirty_t *method;
MPASS(object->type < nitems(pagertab));
method = pagertab[object->type]->pgo_set_writeable_dirty; method = pagertab[object->type]->pgo_set_writeable_dirty;
if (method != NULL) if (method != NULL)
method(object); method(object);
@ -527,6 +586,8 @@ vm_object_mightbedirty(vm_object_t object)
{ {
pgo_mightbedirty_t *method; pgo_mightbedirty_t *method;
MPASS(object->type < nitems(pagertab));
method = pagertab[object->type]->pgo_mightbedirty; method = pagertab[object->type]->pgo_mightbedirty;
if (method == NULL) if (method == NULL)
return (false); return (false);
@ -541,6 +602,7 @@ int
vm_object_kvme_type(vm_object_t object, struct vnode **vpp) vm_object_kvme_type(vm_object_t object, struct vnode **vpp)
{ {
VM_OBJECT_ASSERT_LOCKED(object); VM_OBJECT_ASSERT_LOCKED(object);
MPASS(object->type < nitems(pagertab));
if (vpp != NULL) if (vpp != NULL)
*vpp = vm_object_vnode(object); *vpp = vm_object_vnode(object);

View File

@ -249,6 +249,9 @@ vm_pager_freespace(vm_object_t object, vm_pindex_t start,
method(object, start, size); method(object, start, size);
} }
int vm_pager_alloc_dyn_type(struct pagerops *ops, int base_type);
void vm_pager_free_dyn_type(objtype_t type);
struct cdev_pager_ops { struct cdev_pager_ops {
int (*cdev_pg_fault)(vm_object_t vm_obj, vm_ooffset_t offset, int (*cdev_pg_fault)(vm_object_t vm_obj, vm_ooffset_t offset,
int prot, vm_page_t *mres); int prot, vm_page_t *mres);