#pragma once #include #include #include #include struct ReqQueue { VfsReq *head; VfsReq **slot; /* points to the place where new entries should be placed */ }; struct VfsBackend { /* amount of using references * VfsMount * VfsReq * Handle * once it reaches 0, it'll never increase */ size_t usehcnt; /* VfsMount */ bool is_user; union { struct { Proc *handler; ReqQueue queue; /* kernel backends keep their own queues */ /* amount of processes that control this backend * won't ever increase if it becomes 0 */ size_t provhcnt; } user; struct { void (*accept)(VfsReq *); void (*cleanup)(VfsBackend *); void *data; } kern; }; }; /* describes an in-progress vfs call */ struct VfsReq { enum vfs_op type; /* "kernel" input - an allocation owned by this struct, contains a NUL * terminated string. the NUL isn't counted in the kinlen (for compat * with old code). used for the path in open() */ char *kin; size_t kinlen; /* user inputs and outputs - just point to some buffer in the caller */ char __user *uin; size_t uinlen; char __user *out; size_t outlen; /* those correspond to handle.file.id * id2 is used for duplex() */ void __user *id, *id2; long offset; int flags; Proc *caller; VfsBackend *backend; VfsReq *reqqueue_next; }; /** Assigns the vfs_request to the caller, and dispatches the call */ void vfsreq_dispatchcopy(VfsReq); void vfsreq_finish(VfsReq*, char __user *stored, long ret, int flags, Proc *handler); static inline void vfsreq_finish_short(VfsReq *req, long ret) { vfsreq_finish(req, (void __user *)ret, ret, 0, NULL); } /** Try to accept an enqueued request */ void vfsback_useraccept(VfsReq *); /** Decrements the "user" reference count. */ void vfsback_userdown(VfsBackend *); /** Decrements the "provider" reference count. */ void vfsback_provdown(VfsBackend *); void reqqueue_init(ReqQueue *q); void reqqueue_join(ReqQueue *q, VfsReq *req); VfsReq *reqqueue_pop(ReqQueue *q); /** If there are any pending read requests, and the ring buffer isn't empty, * fulfill them all with a single read. */ void reqqueue_ringreadall(ReqQueue *q, ring_t *r);