33 #include <sys/cdefs.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/kthread.h>
43 #include <sys/mount.h>
44 #include <sys/mutex.h>
45 #include <sys/namei.h>
47 #include <sys/vnode.h>
49 #include <sys/malloc.h>
50 #include <sys/unistd.h>
51 #include <sys/fcntl.h>
52 #include <sys/eventhandler.h>
54 #include <security/mac/mac_framework.h>
75 LIST_ENTRY(
alq) aq_act;
76 LIST_ENTRY(
alq) aq_link;
79 #define AQ_WANTED 0x0001
80 #define AQ_ACTIVE 0x0002
81 #define AQ_FLUSHING 0x0004
82 #define AQ_SHUTDOWN 0x0008
83 #define AQ_ORDERED 0x0010
84 #define AQ_LEGACY 0x0020
86 #define ALQ_LOCK(alq) mtx_lock_spin(&(alq)->aq_mtx)
87 #define ALQ_UNLOCK(alq) mtx_unlock_spin(&(alq)->aq_mtx)
89 #define HAS_PENDING_DATA(alq) ((alq)->aq_freebytes != (alq)->aq_buflen)
99 static
int ald_shutingdown = 0;
100 struct thread *ald_thread;
101 static struct proc *ald_proc;
102 static eventhandler_tag alq_eventhandler_tag = NULL;
104 #define ALD_LOCK() mtx_lock(&ald_mtx)
105 #define ALD_UNLOCK() mtx_unlock(&ald_mtx)
108 static int ald_add(
struct alq *);
133 if (ald_shutingdown) {
137 LIST_INSERT_HEAD(&ald_queues, alq, aq_link);
155 if (ald_shutingdown) {
159 LIST_REMOVE(alq, aq_link);
171 LIST_INSERT_HEAD(&ald_active, alq, aq_act);
178 LIST_REMOVE(alq, aq_act);
186 LIST_INIT(&ald_queues);
187 LIST_INIT(&ald_active);
196 ald_thread = FIRST_THREAD_IN_PROC(ald_proc);
198 alq_eventhandler_tag = EVENTHANDLER_REGISTER(shutdown_pre_sync,
204 while ((alq = LIST_FIRST(&ald_active)) == NULL &&
206 mtx_sleep(&ald_active, &
ald_mtx, PWAIT,
"aldslp", 0);
209 if (ald_shutingdown && alq == NULL) {
238 while ((alq = LIST_FIRST(&ald_queues)) != NULL) {
239 LIST_REMOVE(alq, aq_link);
254 mtx_sleep(ald_proc, &
ald_mtx, PWAIT,
"aldslp", 0);
314 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;
369 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
371 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
376 if (mac_vnode_check_write(alq->
aq_cred, NOCRED, vp) == 0)
378 VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, alq->
aq_cred);
381 VFS_UNLOCK_GIANT(vfslocked);
407 (
"%s: aq_writetail < 0 || aq_writetail >= aq_buflen", __func__));
434 alq_open_flags(
struct alq **alqp,
const char *file,
struct ucred *cred,
int cmode,
444 KASSERT((size > 0), (
"%s: size <= 0", __func__));
449 NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, file, td);
450 oflags = FWRITE | O_NOFOLLOW | O_CREAT;
452 error =
vn_open_cred(&nd, &oflags, cmode, 0, cred, NULL);
456 vfslocked = NDHASGIANT(&nd);
457 NDFREE(&nd, NDF_ONLY_PNBUF);
459 VOP_UNLOCK(nd.ni_vp, 0);
460 VFS_UNLOCK_GIANT(vfslocked);
462 alq =
malloc(
sizeof(*alq), M_ALD, M_WAITOK|M_ZERO);
463 alq->
aq_vp = nd.ni_vp;
475 if (flags & ALQ_ORDERED)
478 if ((error = ald_add(alq)) != 0) {
489 alq_open(
struct alq **alqp,
const char *file,
struct ucred *cred,
int cmode,
494 KASSERT((count >= 0), (
"%s: count < 0", __func__));
498 size*count, 0)) == 0) {
500 (*alqp)->aq_entmax =
count;
501 (*alqp)->aq_entlen = size;
517 int activate, copy, ret;
520 KASSERT((len > 0 && len <= alq->aq_buflen),
521 (
"%s: len <= 0 || len > aq_buflen", __func__));
544 return (EWOULDBLOCK);
552 KASSERT(!(flags & ALQ_NOWAIT),
553 (
"%s: ALQ_NOWAIT set but incorrectly ignored!", __func__));
567 KASSERT(!(flags & ALQ_NOWAIT),
568 (
"%s: ALQ_NOWAIT set but incorrectly ignored!", __func__));
624 (
"%s: alq->aq_writehead (%d) > alq->aq_buflen (%d)",
636 bcopy(((uint8_t *)data)+copy, alq->
aq_entbuf, len - copy);
641 (
"%s: aq_writehead < 0 || aq_writehead >= aq_buflen", __func__));
662 if (waitchan != NULL)
673 (
"%s: fixed length write on variable length queue", __func__));
686 KASSERT((len > 0 && len <= alq->aq_buflen),
687 (
"%s: len <= 0 || len > alq->aq_buflen", __func__));
706 if (contigbytes < len) {
748 KASSERT(!(flags & ALQ_NOWAIT),
749 (
"%s: ALQ_NOWAIT set but incorrectly ignored!", __func__));
763 KASSERT(!(flags & ALQ_NOWAIT),
764 (
"%s: ALQ_NOWAIT set but incorrectly ignored!", __func__));
809 if (waitchan != NULL)
829 (
"%s: fixed length get on variable length queue", __func__));
841 if (ale->ae_bytesused > 0) {
843 !(flags & ALQ_NOACTIVATE)) {
857 (
"%s: aq_writehead < 0 || aq_writehead >= aq_buflen",
887 if (waitchan != NULL)
944 if (LIST_FIRST(&ald_queues) == NULL) {
947 EVENTHANDLER_DEREGISTER(shutdown_pre_sync,
948 alq_eventhandler_tag);
959 if (ald_shutingdown == 0)
static struct kproc_desc ald_kp
void NDFREE(struct nameidata *ndp, const u_int flags)
static void ald_deactivate(struct alq *alq)
void * malloc(unsigned long size, struct malloc_type *mtp, int flags)
static void ald_shutdown(void *arg, int howto)
void vn_finished_write(struct mount *mp)
#define HAS_PENDING_DATA(alq)
int alq_write(struct alq *alq, void *data, int flags)
int alq_open(struct alq **alqp, const char *file, struct ucred *cred, int cmode, int size, int count)
void alq_destroy(struct alq *alq)
void alq_close(struct alq *alq)
void wakeup_one(void *ident)
struct ale * alq_getn(struct alq *alq, int len, int flags)
int vn_open_cred(struct nameidata *ndp, int *flagp, int cmode, u_int vn_open_flags, struct ucred *cred, struct file *fp)
void kproc_exit(int ecode)
int alq_writen(struct alq *alq, void *data, int len, int flags)
SYSINIT(aldthread, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start,&ald_kp)
void crfree(struct ucred *cr)
struct ale * alq_get(struct alq *alq, int flags)
int alq_open_flags(struct alq **alqp, const char *file, struct ucred *cred, int cmode, int size, int flags)
DECLARE_MODULE(alq, alq_mod, SI_SUB_SMP, SI_ORDER_ANY)
static void alq_shutdown(struct alq *alq)
static MALLOC_DEFINE(M_ALD,"ALD","ALD")
static int alq_load_handler(module_t mod, int what, void *arg)
void alq_flush(struct alq *alq)
int msleep_spin(void *ident, struct mtx *mtx, const char *wmesg, int timo)
struct ucred * crhold(struct ucred *cr)
static int ald_rem(struct alq *alq)
void free(void *addr, struct malloc_type *mtp)
int vn_close(struct vnode *vp, int flags, struct ucred *file_cred, struct thread *td)
static void ald_activate(struct alq *alq)
static void ald_daemon(void)
void mtx_init(struct mtx *m, const char *name, const char *type, int opts)
int vn_start_write(struct vnode *vp, struct mount **mpp, int flags)
void alq_post_flags(struct alq *alq, struct ale *ale, int flags)
void kproc_start(void *udata) const
static int alq_doio(struct alq *alq)
static moduledata_t alq_mod
void mtx_destroy(struct mtx *m)
static struct mtx ald_mtx
static void ald_startup(void *unused)