Page MenuHomeFreeBSD

D11392.id30185.diff
No OneTemporary

D11392.id30185.diff

Index: sys/fs/cuse/cuse.c
===================================================================
--- sys/fs/cuse/cuse.c
+++ sys/fs/cuse/cuse.c
@@ -1,6 +1,6 @@
/* $FreeBSD$ */
/*-
- * Copyright (c) 2010-2013 Hans Petter Selasky. All rights reserved.
+ * Copyright (c) 2010-2017 Hans Petter Selasky. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -46,6 +46,7 @@
#include <sys/uio.h>
#include <sys/poll.h>
#include <sys/sx.h>
+#include <sys/rwlock.h>
#include <sys/queue.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
@@ -57,6 +58,9 @@
#include <vm/vm.h>
#include <vm/pmap.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
#include <fs/cuse/cuse_defs.h>
#include <fs/cuse/cuse_ioctl.h>
@@ -69,8 +73,6 @@
*/
MODULE_VERSION(cuse4bsd, 1);
-#define NBUSY ((uint8_t *)1)
-
#ifdef FEATURE
FEATURE(cuse, "Userspace character devices");
#endif
@@ -95,9 +97,12 @@
struct cuse_memory {
struct cuse_server *owner;
- uint8_t *virtaddr;
uint32_t page_count;
uint32_t is_allocated;
+#define CUSE_MEM_ALLOCATED (1 << 0)
+#define CUSE_MEM_SERVER_BUSY (1 << 1)
+#define CUSE_MEM_CLIENT_BUSY (1 << 2)
+#define CUSE_MEM_OBJECT_BUSY (1 << 3)
};
struct cuse_server_dev {
@@ -173,7 +178,7 @@
static d_read_t cuse_client_read;
static d_write_t cuse_client_write;
static d_poll_t cuse_client_poll;
-static d_mmap_t cuse_client_mmap;
+static d_mmap_single_t cuse_client_mmap_single;
static d_kqfilter_t cuse_client_kqfilter;
static struct cdevsw cuse_client_devsw = {
@@ -186,7 +191,7 @@
.d_read = cuse_client_read,
.d_write = cuse_client_write,
.d_poll = cuse_client_poll,
- .d_mmap = cuse_client_mmap,
+ .d_mmap_single = cuse_client_mmap_single,
.d_kqfilter = cuse_client_kqfilter,
};
@@ -196,7 +201,7 @@
static d_read_t cuse_server_read;
static d_write_t cuse_server_write;
static d_poll_t cuse_server_poll;
-static d_mmap_t cuse_server_mmap;
+static d_mmap_single_t cuse_server_mmap_single;
static struct cdevsw cuse_server_devsw = {
.d_version = D_VERSION,
@@ -208,7 +213,7 @@
.d_read = cuse_server_read,
.d_write = cuse_server_write,
.d_poll = cuse_server_poll,
- .d_mmap = cuse_server_mmap,
+ .d_mmap_single = cuse_server_mmap_single,
};
static void cuse_client_is_closing(struct cuse_client *);
@@ -255,6 +260,21 @@
SYSINIT(cuse_kern_init, SI_SUB_DEVFS, SI_ORDER_ANY, cuse_kern_init, 0);
+static void *
+cuse_memory_busy_locked(void)
+{
+ struct cuse_memory *mem;
+ uint32_t n;
+
+ for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
+ mem = &cuse_mem[n];
+
+ if (mem->is_allocated != 0)
+ return (mem);
+ }
+ return (NULL);
+}
+
static void
cuse_kern_uninit(void *arg)
{
@@ -269,6 +289,8 @@
cuse_lock();
ptr = TAILQ_FIRST(&cuse_server_head);
+ if (ptr == NULL)
+ ptr = cuse_memory_busy_locked();
cuse_unlock();
if (ptr == NULL)
@@ -396,7 +418,7 @@
}
static void
-cuse_server_free_memory(struct cuse_server *pcs)
+cuse_server_free_memory_locked(struct cuse_server *pcs)
{
struct cuse_memory *mem;
uint32_t n;
@@ -404,10 +426,10 @@
for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
mem = &cuse_mem[n];
- /* this memory is never freed */
if (mem->owner == pcs) {
mem->owner = NULL;
- mem->is_allocated = 0;
+ mem->page_count = 0;
+ mem->is_allocated &= ~CUSE_MEM_ALLOCATED;
}
}
}
@@ -416,54 +438,16 @@
cuse_server_alloc_memory(struct cuse_server *pcs,
struct cuse_memory *mem, uint32_t page_count)
{
- void *ptr;
- int error;
cuse_lock();
-
- if (mem->virtaddr == NBUSY) {
- cuse_unlock();
- return (EBUSY);
- }
- if (mem->virtaddr != NULL) {
- if (mem->is_allocated != 0) {
- cuse_unlock();
- return (EBUSY);
- }
- if (mem->page_count == page_count) {
- mem->is_allocated = 1;
- mem->owner = pcs;
- cuse_unlock();
- return (0);
- }
+ if (mem->is_allocated != 0) {
cuse_unlock();
return (EBUSY);
}
- memset(mem, 0, sizeof(*mem));
-
- mem->virtaddr = NBUSY;
-
- cuse_unlock();
-
- ptr = malloc(page_count * PAGE_SIZE, M_CUSE, M_WAITOK | M_ZERO);
- if (ptr == NULL)
- error = ENOMEM;
- else
- error = 0;
-
- cuse_lock();
-
- if (error) {
- mem->virtaddr = NULL;
- cuse_unlock();
- return (error);
- }
- mem->virtaddr = ptr;
+ mem->is_allocated |= CUSE_MEM_ALLOCATED;
mem->page_count = page_count;
- mem->is_allocated = 1;
mem->owner = pcs;
cuse_unlock();
-
return (0);
}
@@ -670,7 +654,7 @@
cuse_lock();
}
- cuse_server_free_memory(pcs);
+ cuse_server_free_memory_locked(pcs);
knlist_clear(&pcs->selinfo.si_note, 1);
knlist_destroy(&pcs->selinfo.si_note);
@@ -1110,7 +1094,8 @@
cuse_lock();
if (cuse_mem[pai->alloc_nr].owner == pcs) {
- cuse_mem[pai->alloc_nr].is_allocated = 0;
+ cuse_mem[pai->alloc_nr].is_allocated &= ~CUSE_MEM_ALLOCATED;
+ cuse_mem[pai->alloc_nr].page_count = 0;
cuse_mem[pai->alloc_nr].owner = NULL;
} else {
error = EINVAL;
@@ -1274,13 +1259,42 @@
}
static int
-cuse_server_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr)
+cuse_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
+ vm_ooffset_t foff, struct ucred *cred, u_short *color)
+{
+ struct cuse_memory *mem = handle;
+
+ cuse_lock();
+ mem->is_allocated |= CUSE_MEM_OBJECT_BUSY;
+ cuse_unlock();
+
+ *color = 0;
+ return (0);
+}
+
+static void
+cuse_pager_dtor(void *handle)
{
- uint32_t page_nr = offset / PAGE_SIZE;
+ struct cuse_memory *mem = handle;
+
+ cuse_lock();
+ mem->is_allocated &= ~CUSE_MEM_OBJECT_BUSY;
+ cuse_unlock();
+}
+
+static struct cdev_pager_ops cuse_pager_ops = {
+ .cdev_pg_ctor = cuse_pager_ctor,
+ .cdev_pg_dtor = cuse_pager_dtor
+};
+
+static int
+cuse_server_mmap_single(struct cdev *dev, vm_ooffset_t *offset,
+ vm_size_t size, struct vm_object **object, int nprot)
+{
+ uint32_t page_nr = *offset / PAGE_SIZE;
uint32_t alloc_nr = page_nr / CUSE_ALLOC_PAGES_MAX;
struct cuse_memory *mem;
struct cuse_server *pcs;
- uint8_t *ptr;
int error;
if (alloc_nr >= CUSE_ALLOC_UNIT_MAX)
@@ -1288,35 +1302,49 @@
error = cuse_server_get(&pcs);
if (error != 0)
- pcs = NULL;
+ return (error);
cuse_lock();
mem = &cuse_mem[alloc_nr];
- /* try to enforce slight ownership */
- if ((pcs != NULL) && (mem->owner != pcs)) {
- cuse_unlock();
- return (EINVAL);
- }
- if (mem->virtaddr == NULL) {
+ /* enforce ownership */
+ if (mem->owner != pcs) {
cuse_unlock();
- return (ENOMEM);
+ return (EPERM);
}
- if (mem->virtaddr == NBUSY) {
+ /* serialize */
+ if (mem->is_allocated & CUSE_MEM_SERVER_BUSY) {
cuse_unlock();
- return (ENOMEM);
+ return (EBUSY);
}
+ /* verify page offset */
page_nr %= CUSE_ALLOC_PAGES_MAX;
-
if (page_nr >= mem->page_count) {
cuse_unlock();
- return (ENXIO);
+ return (EINVAL);
+ }
+ /* verify mmap size */
+ if (size < PAGE_SIZE || size > ((mem->page_count - page_nr) * PAGE_SIZE)) {
+ cuse_unlock();
+ return (EINVAL);
}
- ptr = mem->virtaddr + (page_nr * PAGE_SIZE);
+ mem->is_allocated |= CUSE_MEM_SERVER_BUSY;
+ cuse_unlock();
+
+ *object = cdev_pager_allocate(mem, OBJT_MGTDEVICE, &cuse_pager_ops,
+ size, nprot, page_nr * PAGE_SIZE, curthread->td_ucred);
+
+ cuse_lock();
+ mem->is_allocated &= ~CUSE_MEM_SERVER_BUSY;
cuse_unlock();
- *paddr = vtophys(ptr);
+ if (*object == NULL)
+ return (ENXIO);
+
+ /* set new VM object offset to use */
+ *offset = 0;
+ /* success */
return (0);
}
@@ -1758,14 +1786,14 @@
}
static int
-cuse_client_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr)
+cuse_client_mmap_single(struct cdev *dev, vm_ooffset_t *offset,
+ vm_size_t size, struct vm_object **object, int nprot)
{
- uint32_t page_nr = offset / PAGE_SIZE;
+ uint32_t page_nr = *offset / PAGE_SIZE;
uint32_t alloc_nr = page_nr / CUSE_ALLOC_PAGES_MAX;
struct cuse_memory *mem;
struct cuse_server *pcs;
struct cuse_client *pcc;
- uint8_t *ptr;
int error;
if (alloc_nr >= CUSE_ALLOC_UNIT_MAX)
@@ -1773,37 +1801,53 @@
error = cuse_client_get(&pcc);
if (error != 0)
- pcs = NULL;
- else
- pcs = pcc->server;
+ return (error);
cuse_lock();
+
+ /* get pointer to server */
+ pcs = pcc->server;
+
mem = &cuse_mem[alloc_nr];
- /* try to enforce slight ownership */
- if ((pcs != NULL) && (mem->owner != pcs)) {
+ /* enforce ownership */
+ if (mem->owner != pcs) {
cuse_unlock();
- return (EINVAL);
- }
- if (mem->virtaddr == NULL) {
- cuse_unlock();
- return (ENOMEM);
+ return (EPERM);
}
- if (mem->virtaddr == NBUSY) {
+ /* serialize */
+ if (mem->is_allocated & CUSE_MEM_CLIENT_BUSY) {
cuse_unlock();
- return (ENOMEM);
+ return (EBUSY);
}
+ /* verify page offset */
page_nr %= CUSE_ALLOC_PAGES_MAX;
-
if (page_nr >= mem->page_count) {
cuse_unlock();
- return (ENXIO);
+ return (EINVAL);
+ }
+ /* verify mmap size */
+ if (size < PAGE_SIZE || size > ((mem->page_count - page_nr) * PAGE_SIZE)) {
+ cuse_unlock();
+ return (EINVAL);
}
- ptr = mem->virtaddr + (page_nr * PAGE_SIZE);
+ mem->is_allocated |= CUSE_MEM_CLIENT_BUSY;
cuse_unlock();
- *paddr = vtophys(ptr);
+ *object = cdev_pager_allocate(mem, OBJT_MGTDEVICE, &cuse_pager_ops,
+ size, nprot, page_nr * PAGE_SIZE, curthread->td_ucred);
+
+ cuse_lock();
+ mem->is_allocated &= ~CUSE_MEM_CLIENT_BUSY;
+ cuse_unlock();
+
+ if (*object == NULL)
+ return (ENXIO);
+
+ /* set new VM object offset to use */
+ *offset = 0;
+ /* success */
return (0);
}

File Metadata

Mime Type
text/plain
Expires
Wed, Feb 19, 7:21 PM (21 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16726709
Default Alt Text
D11392.id30185.diff (9 KB)

Event Timeline