AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
flock.c
Go to the documentation of this file.
1
7
8#include <core/system.h>
9#include <fs/vfs.h>
10#include <net/socket.h>
11#include <sys/sched.h>
12#include <ds/queue.h>
13
14#include <aquila/fcntl.h>
15#include <aquila/errno.h>
16
17MALLOC_DEFINE(M_FILE_LOCK, "file-lock", "flock() lock");
18
20struct file_lock {
21 struct vnode *vnode; /* the file it locks */
22 int type; /* LOCK_SH, LOCK_EX, or 0 while not locked */
23};
24
25/* the locks held, and the threads waiting for one to be released */
26static struct queue locks = {0};
27static struct waitq waiters = {0};
28
31static int lock_conflicts(struct file_lock *lock, int type)
32{
33 queue_for (node, &locks) {
34 struct file_lock *held = node->value;
35
36 if (held != lock && held->vnode == lock->vnode &&
37 (type == LOCK_EX || held->type == LOCK_EX))
38 return 1;
39 }
40
41 return 0;
42}
43
45static void lock_unlock(struct file_lock *lock)
46{
47 if (!lock->type)
48 return;
49
50 queue_remove(&locks, lock);
51 lock->type = 0;
53}
54
67int vfs_file_flock(struct file *file, int op)
68{
69 int type = op & ~LOCK_NB;
70
71 if (type != LOCK_SH && type != LOCK_EX && type != LOCK_UN)
72 return -EINVAL;
73
74 if (file->flags & FILE_SOCKET)
75 return -EINVAL;
76
77 struct file_lock *lock = file->lock;
78
79 if (type == LOCK_UN) {
80 if (lock)
81 lock_unlock(lock);
82 return 0;
83 }
84
85 if (!lock) {
86 lock = kmalloc(sizeof(*lock), &M_FILE_LOCK, M_ZERO);
87 if (!lock) return -ENOMEM;
88
89 lock->vnode = file->vnode;
90 file->lock = lock;
91 }
92
93 while (lock_conflicts(lock, type)) {
94 if (op & LOCK_NB)
95 return -EWOULDBLOCK;
96
97 int err = waitq_sleep(&waiters);
98
99 if (err)
100 return err;
101 }
102
103 if (!lock->type)
104 enqueue(&locks, lock);
105
106 /* changing an exclusive lock to a shared one may let others in */
107 if (lock->type == LOCK_EX && type == LOCK_SH)
109
110 lock->type = type;
111 return 0;
112}
113
120{
121 struct file_lock *lock = file->lock;
122
123 if (!lock)
124 return;
125
126 file->lock = NULL;
127 lock_unlock(lock);
128 kfree(lock);
129}
int vfs_file_flock(struct file *file, int op)
Takes, changes or releases an open file's lock.
Definition flock.c:67
static struct waitq waiters
Definition flock.c:27
static struct queue locks
Definition flock.c:26
void vfs_file_lock_release(struct file *file)
Releases an open file's lock when the file is closed.
Definition flock.c:119
static int lock_conflicts(struct file_lock *lock, int type)
Says whether taking a lock of type conflicts with a lock that another open file holds on the same fil...
Definition flock.c:31
static void lock_unlock(struct file_lock *lock)
Releases a lock, and wakes up the threads waiting for one.
Definition flock.c:45
#define MALLOC_DEFINE(type, _name, _desc)
Definition kvmem.h:30
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
#define M_ZERO
Definition kvmem.h:26
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
#define queue_for(n, q)
Definition queue.h:37
#define FILE_SOCKET
Definition socket.h:70
#define NULL
Definition stddef.h:27
An open file's lock.
Definition flock.c:20
struct vnode * vnode
Definition flock.c:21
int type
Definition flock.c:22
An open file (POSIX's "open file description", fs/file.c).
Definition vfs.h:157
struct file_lock * lock
Definition vfs.h:167
int flags
Definition vfs.h:164
A queue.
Definition queue.h:29
Definition waitq.h:19
void waitq_wakeup(struct waitq *waitq)
Wakes up every thread sleeping on a wait queue, and every thread polling it.
Definition waitq.c:178
int waitq_sleep(struct waitq *waitq)
Puts the current thread to sleep on a wait queue until it is woken up.
Definition waitq.c:50