42#include <sys/kernel.h>
43#include <sys/kthread.h>
51#include <sys/malloc.h>
52#include <sys/unistd.h>
54#include <sys/eventhandler.h>
56#include <security/mac/mac_framework.h>
77 LIST_ENTRY(
alq) aq_act;
78 LIST_ENTRY(
alq) aq_link;
81#define AQ_WANTED 0x0001
82#define AQ_ACTIVE 0x0002
83#define AQ_FLUSHING 0x0004
84#define AQ_SHUTDOWN 0x0008
85#define AQ_ORDERED 0x0010
86#define AQ_LEGACY 0x0020
88#define ALQ_LOCK(alq) mtx_lock_spin(&(alq)->aq_mtx)
89#define ALQ_UNLOCK(alq) mtx_unlock_spin(&(alq)->aq_mtx)
91#define HAS_PENDING_DATA(alq) ((alq)->aq_freebytes != (alq)->aq_buflen)
101static int ald_shutingdown = 0;
102struct thread *ald_thread;
103static struct proc *ald_proc;
104static eventhandler_tag alq_eventhandler_tag = NULL;
106#define ALD_LOCK() mtx_lock(&ald_mtx)
107#define ALD_UNLOCK() mtx_unlock(&ald_mtx)
110static int ald_add(
struct alq *);
134 if (ald_shutingdown) {
138 LIST_INSERT_HEAD(&ald_queues,
alq, aq_link);
156 if (ald_shutingdown) {
160 LIST_REMOVE(
alq, aq_link);
172 LIST_INSERT_HEAD(&ald_active,
alq, aq_act);
179 LIST_REMOVE(
alq, aq_act);
186 mtx_init(&
ald_mtx,
"ALDmtx", NULL, MTX_DEF|MTX_QUIET);
187 LIST_INIT(&ald_queues);
188 LIST_INIT(&ald_active);
197 ald_thread = FIRST_THREAD_IN_PROC(ald_proc);
199 alq_eventhandler_tag = EVENTHANDLER_REGISTER(shutdown_pre_sync,
205 while ((
alq = LIST_FIRST(&ald_active)) == NULL &&
207 mtx_sleep(&ald_active, &
ald_mtx, PWAIT,
"aldslp", 0);
210 if (ald_shutingdown &&
alq == NULL) {
239 while ((
alq = LIST_FIRST(&ald_queues)) != NULL) {
240 LIST_REMOVE(
alq, aq_link);
255 mtx_sleep(ald_proc, &
ald_mtx, PWAIT,
"aldslp", 0);
315 struct iovec aiov[2];
328 bzero(&aiov,
sizeof(aiov));
329 bzero(&auio,
sizeof(auio));
352 totlen = aiov[0].iov_len + aiov[1].iov_len;
358 auio.uio_iov = &aiov[0];
360 auio.uio_segflg = UIO_SYSSPACE;
361 auio.uio_rw = UIO_WRITE;
362 auio.uio_iovcnt = iov;
363 auio.uio_resid = totlen;
370 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
375 if (mac_vnode_check_write(
alq->
aq_cred, NOCRED, vp) == 0)
377 VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND,
alq->
aq_cred);
405 (
"%s: aq_writetail < 0 || aq_writetail >= aq_buflen", __func__));
439 KASSERT((size > 0), (
"%s: size <= 0", __func__));
443 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, file);
444 oflags = FWRITE | O_NOFOLLOW | O_CREAT;
446 error =
vn_open_cred(&nd, &oflags, cmode, 0, cred, NULL);
450 NDFREE(&nd, NDF_ONLY_PNBUF);
452 VOP_UNLOCK(nd.ni_vp);
458 mtx_init(&
alq->
aq_mtx,
"ALD Queue", NULL, MTX_SPIN|MTX_QUIET);
467 if (
flags & ALQ_ORDERED)
470 if ((error = ald_add(
alq)) != 0) {
481alq_open(
struct alq **alqp,
const char *file,
struct ucred *cred,
int cmode,
486 KASSERT((
count >= 0), (
"%s: count < 0", __func__));
490 size*
count, 0)) == 0) {
492 (*alqp)->aq_entmax =
count;
493 (*alqp)->aq_entlen = size;
508 int activate, copy, ret;
511 KASSERT((len > 0 && len <= alq->
aq_buflen),
512 (
"%s: len <= 0 || len > aq_buflen", __func__));
535 return (EWOULDBLOCK);
543 KASSERT(!(
flags & ALQ_NOWAIT),
544 (
"%s: ALQ_NOWAIT set but incorrectly ignored!", __func__));
558 KASSERT(!(
flags & ALQ_NOWAIT),
559 (
"%s: ALQ_NOWAIT set but incorrectly ignored!", __func__));
615 (
"%s: alq->aq_writehead (%d) > alq->aq_buflen (%d)",
632 (
"%s: aq_writehead < 0 || aq_writehead >= aq_buflen", __func__));
653 if (waitchan != NULL)
664 (
"%s: fixed length write on variable length queue", __func__));
677 KASSERT((len > 0 && len <= alq->aq_buflen),
678 (
"%s: len <= 0 || len > alq->aq_buflen", __func__));
697 if (contigbytes < len) {
739 KASSERT(!(
flags & ALQ_NOWAIT),
740 (
"%s: ALQ_NOWAIT set but incorrectly ignored!", __func__));
754 KASSERT(!(
flags & ALQ_NOWAIT),
755 (
"%s: ALQ_NOWAIT set but incorrectly ignored!", __func__));
800 if (waitchan != NULL)
820 (
"%s: fixed length get on variable length queue", __func__));
832 if (ale->ae_bytesused > 0) {
834 !(
flags & ALQ_NOACTIVATE)) {
848 (
"%s: aq_writehead < 0 || aq_writehead >= aq_buflen",
878 if (waitchan != NULL)
935 if (LIST_FIRST(&ald_queues) == NULL) {
938 EVENTHANDLER_DEREGISTER(shutdown_pre_sync,
939 alq_eventhandler_tag);
950 if (ald_shutingdown == 0)
void alq_close(struct alq *alq)
struct ale * alq_getn(struct alq *alq, int len, int flags)
static struct mtx ald_mtx
int alq_write(struct alq *alq, void *data, int flags)
static void alq_shutdown(struct alq *alq)
static void ald_deactivate(struct alq *alq)
static struct kproc_desc ald_kp
static moduledata_t alq_mod
int alq_open_flags(struct alq **alqp, const char *file, struct ucred *cred, int cmode, int size, int flags)
static int alq_doio(struct alq *alq)
void alq_flush(struct alq *alq)
struct ale * alq_get(struct alq *alq, int flags)
static void ald_daemon(void)
static void ald_startup(void *unused)
SYSINIT(aldthread, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, &ald_kp)
static MALLOC_DEFINE(M_ALD, "ALD", "ALD")
static void ald_activate(struct alq *alq)
void alq_post_flags(struct alq *alq, struct ale *ale, int flags)
static int ald_rem(struct alq *alq)
#define HAS_PENDING_DATA(alq)
int alq_writen(struct alq *alq, void *data, int len, int flags)
DECLARE_MODULE(alq, alq_mod, SI_SUB_LAST, SI_ORDER_ANY)
static int alq_load_handler(module_t mod, int what, void *arg)
static void ald_shutdown(void *arg, int howto)
void alq_destroy(struct alq *alq)
int alq_open(struct alq **alqp, const char *file, struct ucred *cred, int cmode, int size, int count)
void kproc_exit(int ecode)
void kproc_start(const void *udata)
void *() malloc(size_t size, struct malloc_type *mtp, int flags)
void free(void *addr, struct malloc_type *mtp)
struct ucred * crhold(struct ucred *cr)
void crfree(struct ucred *cr)
void wakeup(const void *ident)
void wakeup_one(const void *ident)
void() NDFREE(struct nameidata *ndp, const u_int flags)
int vn_start_write(struct vnode *vp, struct mount **mpp, int flags)
int vn_open_cred(struct nameidata *ndp, int *flagp, int cmode, u_int vn_open_flags, struct ucred *cred, struct file *fp)
int vn_close(struct vnode *vp, int flags, struct ucred *file_cred, struct thread *td)
void vn_finished_write(struct mount *mp)