Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/md/md.c
Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
#include <sys/unistd.h> | #include <sys/unistd.h> | ||||
#include <sys/vnode.h> | #include <sys/vnode.h> | ||||
#include <sys/disk.h> | #include <sys/disk.h> | ||||
#include <geom/geom.h> | #include <geom/geom.h> | ||||
#include <geom/geom_int.h> | #include <geom/geom_int.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_extern.h> | |||||
#include <vm/vm_param.h> | #include <vm/vm_param.h> | ||||
#include <vm/vm_object.h> | #include <vm/vm_object.h> | ||||
#include <vm/vm_page.h> | #include <vm/vm_page.h> | ||||
#include <vm/vm_pager.h> | #include <vm/vm_pager.h> | ||||
#include <vm/swap_pager.h> | #include <vm/swap_pager.h> | ||||
#include <vm/uma.h> | #include <vm/uma.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | |||||
MODULE_VERSION(geom_md, 0); | MODULE_VERSION(geom_md, 0); | ||||
static LIST_HEAD(, md_s) md_softc_list = LIST_HEAD_INITIALIZER(md_softc_list); | static LIST_HEAD(, md_s) md_softc_list = LIST_HEAD_INITIALIZER(md_softc_list); | ||||
#define NINDIR (PAGE_SIZE / sizeof(uintptr_t)) | #define NINDIR (PAGE_SIZE / sizeof(uintptr_t)) | ||||
#define NMASK (NINDIR-1) | #define NMASK (NINDIR-1) | ||||
static int nshift; | static int nshift; | ||||
static uma_zone_t md_pbuf_zone; | |||||
struct indir { | struct indir { | ||||
uintptr_t *array; | uintptr_t *array; | ||||
u_int total; | u_int total; | ||||
u_int used; | u_int used; | ||||
u_int shift; | u_int shift; | ||||
}; | }; | ||||
struct md_s { | struct md_s { | ||||
Show All 26 Lines | struct md_s { | ||||
u_char *pl_ptr; | u_char *pl_ptr; | ||||
size_t pl_len; | size_t pl_len; | ||||
/* MD_VNODE related fields */ | /* MD_VNODE related fields */ | ||||
struct vnode *vnode; | struct vnode *vnode; | ||||
char file[PATH_MAX]; | char file[PATH_MAX]; | ||||
char label[PATH_MAX]; | char label[PATH_MAX]; | ||||
struct ucred *cred; | struct ucred *cred; | ||||
vm_offset_t kva; | |||||
/* MD_SWAP related fields */ | /* MD_SWAP related fields */ | ||||
vm_object_t object; | vm_object_t object; | ||||
}; | }; | ||||
static struct indir * | static struct indir * | ||||
new_indir(u_int shift) | new_indir(u_int shift) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 585 Lines • ▼ Show 20 Lines | |||||
mdstart_vnode(struct md_s *sc, struct bio *bp) | mdstart_vnode(struct md_s *sc, struct bio *bp) | ||||
{ | { | ||||
int error; | int error; | ||||
struct uio auio; | struct uio auio; | ||||
struct iovec aiov; | struct iovec aiov; | ||||
struct iovec *piov; | struct iovec *piov; | ||||
struct mount *mp; | struct mount *mp; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
struct buf *pb; | |||||
bus_dma_segment_t *vlist; | bus_dma_segment_t *vlist; | ||||
struct thread *td; | struct thread *td; | ||||
off_t iolen, iostart, off, len; | off_t iolen, iostart, off, len; | ||||
int ma_offs, npages; | int ma_offs, npages; | ||||
bool mapped; | |||||
switch (bp->bio_cmd) { | switch (bp->bio_cmd) { | ||||
case BIO_READ: | case BIO_READ: | ||||
auio.uio_rw = UIO_READ; | auio.uio_rw = UIO_READ; | ||||
break; | break; | ||||
case BIO_WRITE: | case BIO_WRITE: | ||||
auio.uio_rw = UIO_WRITE; | auio.uio_rw = UIO_WRITE; | ||||
break; | break; | ||||
case BIO_FLUSH: | case BIO_FLUSH: | ||||
break; | break; | ||||
case BIO_DELETE: | case BIO_DELETE: | ||||
if (sc->candelete) | if (sc->candelete) | ||||
break; | break; | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
default: | default: | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
} | } | ||||
td = curthread; | td = curthread; | ||||
vp = sc->vnode; | vp = sc->vnode; | ||||
pb = NULL; | |||||
piov = NULL; | piov = NULL; | ||||
ma_offs = bp->bio_ma_offset; | ma_offs = bp->bio_ma_offset; | ||||
off = bp->bio_offset; | off = bp->bio_offset; | ||||
len = bp->bio_length; | len = bp->bio_length; | ||||
mapped = false; | |||||
/* | /* | ||||
* VNODE I/O | * VNODE I/O | ||||
* | * | ||||
* If an error occurs, we set BIO_ERROR but we do not set | * If an error occurs, we set BIO_ERROR but we do not set | ||||
* B_INVAL because (for a write anyway), the buffer is | * B_INVAL because (for a write anyway), the buffer is | ||||
* still valid. | * still valid. | ||||
*/ | */ | ||||
Show All 32 Lines | while (len > 0) { | ||||
len -= piov->iov_len; | len -= piov->iov_len; | ||||
ma_offs = 0; | ma_offs = 0; | ||||
vlist++; | vlist++; | ||||
piov++; | piov++; | ||||
} | } | ||||
auio.uio_iovcnt = piov - auio.uio_iov; | auio.uio_iovcnt = piov - auio.uio_iov; | ||||
piov = auio.uio_iov; | piov = auio.uio_iov; | ||||
} else if ((bp->bio_flags & BIO_UNMAPPED) != 0) { | } else if ((bp->bio_flags & BIO_UNMAPPED) != 0) { | ||||
pb = uma_zalloc(md_pbuf_zone, M_WAITOK); | |||||
MPASS((pb->b_flags & B_MAXPHYS) != 0); | |||||
bp->bio_resid = len; | bp->bio_resid = len; | ||||
unmapped_step: | unmapped_step: | ||||
npages = atop(min(maxphys, round_page(len + (ma_offs & | npages = atop(min(maxphys, round_page(len + (ma_offs & | ||||
PAGE_MASK)))); | PAGE_MASK)))); | ||||
iolen = min(ptoa(npages) - (ma_offs & PAGE_MASK), len); | iolen = min(ptoa(npages) - (ma_offs & PAGE_MASK), len); | ||||
KASSERT(iolen > 0, ("zero iolen")); | KASSERT(iolen > 0, ("zero iolen")); | ||||
pmap_qenter((vm_offset_t)pb->b_data, | KASSERT(npages <= atop(MAXPHYS + PAGE_SIZE), | ||||
&bp->bio_ma[atop(ma_offs)], npages); | ("npages %d too large", npages)); | ||||
aiov.iov_base = (void *)((vm_offset_t)pb->b_data + | pmap_qenter(sc->kva, &bp->bio_ma[atop(ma_offs)], npages); | ||||
(ma_offs & PAGE_MASK)); | aiov.iov_base = (void *)(sc->kva + (ma_offs & PAGE_MASK)); | ||||
aiov.iov_len = iolen; | aiov.iov_len = iolen; | ||||
auio.uio_iov = &aiov; | auio.uio_iov = &aiov; | ||||
auio.uio_iovcnt = 1; | auio.uio_iovcnt = 1; | ||||
auio.uio_resid = iolen; | auio.uio_resid = iolen; | ||||
mapped = true; | |||||
} else { | } else { | ||||
aiov.iov_base = bp->bio_data; | aiov.iov_base = bp->bio_data; | ||||
aiov.iov_len = bp->bio_length; | aiov.iov_len = bp->bio_length; | ||||
auio.uio_iov = &aiov; | auio.uio_iov = &aiov; | ||||
auio.uio_iovcnt = 1; | auio.uio_iovcnt = 1; | ||||
} | } | ||||
iostart = auio.uio_offset; | iostart = auio.uio_offset; | ||||
if (auio.uio_rw == UIO_READ) { | if (auio.uio_rw == UIO_READ) { | ||||
Show All 11 Lines | if (error == 0) | ||||
sc->flags &= ~MD_VERIFY; | sc->flags &= ~MD_VERIFY; | ||||
} | } | ||||
/* When MD_CACHE is set, try to avoid double-caching the data. */ | /* When MD_CACHE is set, try to avoid double-caching the data. */ | ||||
if (error == 0 && (sc->flags & MD_CACHE) == 0) | if (error == 0 && (sc->flags & MD_CACHE) == 0) | ||||
VOP_ADVISE(vp, iostart, auio.uio_offset - 1, | VOP_ADVISE(vp, iostart, auio.uio_offset - 1, | ||||
POSIX_FADV_DONTNEED); | POSIX_FADV_DONTNEED); | ||||
if (pb != NULL) { | if (mapped) { | ||||
pmap_qremove((vm_offset_t)pb->b_data, npages); | pmap_qremove(sc->kva, npages); | ||||
if (error == 0) { | if (error == 0) { | ||||
len -= iolen; | len -= iolen; | ||||
bp->bio_resid -= iolen; | bp->bio_resid -= iolen; | ||||
ma_offs += iolen; | ma_offs += iolen; | ||||
if (len > 0) | if (len > 0) | ||||
goto unmapped_step; | goto unmapped_step; | ||||
} | } | ||||
uma_zfree(md_pbuf_zone, pb); | |||||
} else { | } else { | ||||
bp->bio_resid = auio.uio_resid; | bp->bio_resid = auio.uio_resid; | ||||
} | } | ||||
free(piov, M_MD); | free(piov, M_MD); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 252 Lines • ▼ Show 20 Lines | mdnew(int unit, int *errp, enum md_types type) | ||||
else | else | ||||
unit = alloc_unr_specific(md_uh, unit); | unit = alloc_unr_specific(md_uh, unit); | ||||
if (unit == -1) { | if (unit == -1) { | ||||
*errp = EBUSY; | *errp = EBUSY; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
sc = (struct md_s *)malloc(sizeof *sc, M_MD, M_WAITOK | M_ZERO); | sc = malloc(sizeof(*sc), M_MD, M_WAITOK | M_ZERO); | ||||
sc->type = type; | sc->type = type; | ||||
bioq_init(&sc->bio_queue); | bioq_init(&sc->bio_queue); | ||||
mtx_init(&sc->queue_mtx, "md bio queue", NULL, MTX_DEF); | mtx_init(&sc->queue_mtx, "md bio queue", NULL, MTX_DEF); | ||||
sc->unit = unit; | sc->unit = unit; | ||||
sprintf(sc->name, "md%d", unit); | sprintf(sc->name, "md%d", unit); | ||||
LIST_INSERT_HEAD(&md_softc_list, sc, list); | LIST_INSERT_HEAD(&md_softc_list, sc, list); | ||||
error = kproc_create(md_kthread, sc, &sc->procp, 0, 0,"%s", sc->name); | error = kproc_create(md_kthread, sc, &sc->procp, 0, 0,"%s", sc->name); | ||||
if (error == 0) | if (error == 0) | ||||
▲ Show 20 Lines • Show All 191 Lines • ▼ Show 20 Lines | mdcreate_vnode(struct md_s *sc, struct md_req *mdr, struct thread *td) | ||||
error = mdsetcred(sc, td->td_ucred); | error = mdsetcred(sc, td->td_ucred); | ||||
if (error != 0) { | if (error != 0) { | ||||
sc->vnode = NULL; | sc->vnode = NULL; | ||||
vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); | ||||
nd.ni_vp->v_vflag &= ~VV_MD; | nd.ni_vp->v_vflag &= ~VV_MD; | ||||
goto bad; | goto bad; | ||||
} | } | ||||
sc->kva = kva_alloc(MAXPHYS + PAGE_SIZE); | |||||
return (0); | return (0); | ||||
bad: | bad: | ||||
VOP_UNLOCK(nd.ni_vp); | VOP_UNLOCK(nd.ni_vp); | ||||
(void)vn_close(nd.ni_vp, flags, td->td_ucred, td); | (void)vn_close(nd.ni_vp, flags, td->td_ucred, td); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | mddestroy(struct md_s *sc, struct thread *td) | ||||
if (sc->cred != NULL) | if (sc->cred != NULL) | ||||
crfree(sc->cred); | crfree(sc->cred); | ||||
if (sc->object != NULL) | if (sc->object != NULL) | ||||
vm_object_deallocate(sc->object); | vm_object_deallocate(sc->object); | ||||
if (sc->indir) | if (sc->indir) | ||||
destroy_indir(sc, sc->indir); | destroy_indir(sc, sc->indir); | ||||
if (sc->uma) | if (sc->uma) | ||||
uma_zdestroy(sc->uma); | uma_zdestroy(sc->uma); | ||||
if (sc->kva) | |||||
kva_free(sc->kva, MAXPHYS + PAGE_SIZE); | |||||
LIST_REMOVE(sc, list); | LIST_REMOVE(sc, list); | ||||
free_unr(md_uh, sc->unit); | free_unr(md_uh, sc->unit); | ||||
free(sc, M_MD); | free(sc, M_MD); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 518 Lines • ▼ Show 20 Lines | while ((mod = preload_search_next_name(mod)) != NULL) { | ||||
ptr = preload_fetch_addr(mod); | ptr = preload_fetch_addr(mod); | ||||
len = preload_fetch_size(mod); | len = preload_fetch_size(mod); | ||||
if (ptr != NULL && len != 0) { | if (ptr != NULL && len != 0) { | ||||
sx_xlock(&md_sx); | sx_xlock(&md_sx); | ||||
md_preloaded(ptr, len, name); | md_preloaded(ptr, len, name); | ||||
sx_xunlock(&md_sx); | sx_xunlock(&md_sx); | ||||
} | } | ||||
} | } | ||||
md_pbuf_zone = pbuf_zsecond_create("mdpbuf", nswbuf / 10); | |||||
status_dev = make_dev(&mdctl_cdevsw, INT_MAX, UID_ROOT, GID_WHEEL, | status_dev = make_dev(&mdctl_cdevsw, INT_MAX, UID_ROOT, GID_WHEEL, | ||||
0600, MDCTL_NAME); | 0600, MDCTL_NAME); | ||||
g_topology_lock(); | g_topology_lock(); | ||||
} | } | ||||
static void | static void | ||||
g_md_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, | g_md_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, | ||||
struct g_consumer *cp __unused, struct g_provider *pp) | struct g_consumer *cp __unused, struct g_provider *pp) | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
g_md_fini(struct g_class *mp __unused) | g_md_fini(struct g_class *mp __unused) | ||||
{ | { | ||||
sx_destroy(&md_sx); | sx_destroy(&md_sx); | ||||
if (status_dev != NULL) | if (status_dev != NULL) | ||||
destroy_dev(status_dev); | destroy_dev(status_dev); | ||||
uma_zdestroy(md_pbuf_zone); | |||||
delete_unrhdr(md_uh); | delete_unrhdr(md_uh); | ||||
} | } |