AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
tmpfs.c
Go to the documentation of this file.
1
9
10#include <core/system.h>
11#include <core/module.h>
12#include <core/string.h>
13#include <core/panic.h>
14#include <core/time.h>
15
16#include <mm/mm.h>
17
18#include <fs/vfs.h>
19#include <fs/iobuf.h>
20#include <fs/pseudofs.h>
21#include <fs/tmpfs.h>
22#include <fs/posix.h>
23
24#include <aquila/errno.h>
25#include <aquila/dirent.h>
26
28static int tmpfs_vget(struct vnode *super, ino_t ino, struct vnode **vnode)
29{
30 /* the vnode is always in memory */
31 struct vnode *node = (struct vnode *) ino;
32 if (vnode) *vnode = node;
33
34 return 0;
35}
36
38static int tmpfs_close(struct vnode *vnode)
39{
40 if (!vnode->ref && !vnode->nlink) {
41 kfree(vnode->p);
43 }
44
45 return 0;
46}
47
49static ssize_t tmpfs_read(struct vnode *node, off_t offset, struct iobuf *io)
50{
51 if (offset < 0)
52 return -EINVAL;
53
54 if ((size_t) offset >= node->size)
55 return 0;
56
57 return iobuf_out(io, (char *) node->p + offset, node->size - offset);
58}
59
61static ssize_t tmpfs_write(struct vnode *node, off_t offset, struct iobuf *io)
62{
63 size_t size = io->resid, old_size = node->size;
64
65 if (offset < 0)
66 return -EINVAL;
67
68 if (((size_t) offset + size) > node->size) { /* a bigger buffer */
69 size_t sz = (size_t) offset + size;
70
71 /* zeroed, so that a gap between the old size and the offset
72 * reads as zeros */
73 void *new = kmalloc(sz, &M_BUFFER, M_ZERO);
74 if (!new)
75 return -ENOMEM;
76
77 if (node->p)
78 memcpy(new, node->p, node->size);
79 kfree(node->p);
80 node->p = new;
81 node->size = sz;
82 }
83
84 ssize_t r = iobuf_in(io, (char *) node->p + offset, size);
85 size_t done = r > 0 ? r : 0;
86
87 /* if a fault stopped the copy, the file ends where the data does */
88 if (done < size)
89 node->size = MAX(old_size, (size_t) offset + done);
90
91 return r;
92}
93
95static int tmpfs_trunc(struct vnode *vnode, off_t len)
96{
97 if (!vnode || len < 0)
98 return -EINVAL;
99
100 if ((size_t) len == vnode->size)
101 return 0;
102
103 if (len == 0) {
104 kfree(vnode->p);
105 vnode->p = NULL;
106 vnode->size = 0;
107 return 0;
108 }
109
110 size_t sz = MIN((size_t) len, vnode->size);
111 char *buf = kmalloc(len, &M_BUFFER, 0);
112
113 /* with no memory, the file stays as it was */
114 if (!buf)
115 return -ENOMEM;
116
117 memcpy(buf, vnode->p, sz);
118
119 if ((size_t) len > vnode->size)
120 memset(buf + vnode->size, 0, len - vnode->size);
121
122 kfree(vnode->p);
123 vnode->p = buf;
124 vnode->size = len;
125 return 0;
126}
127
128/* File operations */
129
131static int tmpfs_file_can_read(struct file *file, size_t size)
132{
133 if ((size_t) file->offset + size < file->vnode->size)
134 return 1;
135
136 return 0;
137}
138
140static int tmpfs_file_can_write(struct file *file __unused, size_t size __unused)
141{
142 return 1;
143}
144
146static int tmpfs_file_eof(struct file *file)
147{
148 return (size_t) file->offset == file->vnode->size;
149}
150
152static int tmpfs_init()
153{
154 return vfs_install(&tmpfs);
155}
156
160static int tmpfs_mount(struct vnode *dir, int flags __unused, void *data __unused)
161{
162 /* a new root directory */
163 struct vnode *tmpfs_root = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);
164 if (!tmpfs_root) return -ENOMEM;
165
166 uint32_t mode = 0777;
167
168 struct mdata {
169 char *dev;
170 char *opt;
171 } *mdata = data;
172
173 if (mdata && mdata->opt) {
174 char **tokens = tokenize(mdata->opt, ',');
175 for (char **token_p = tokens; token_p && *token_p; ++token_p) {
176 char *token = *token_p;
177 if (!strncmp(token, "mode=", 5)) { /* an octal number */
178 char *t = token + 5;
179 mode = 0;
180 while (*t) {
181 mode <<= 3;
182 mode |= (*t++ - '0');
183 }
184 }
185 }
186
187 free_tokens(tokens);
188 }
189
190 tmpfs_root->ino = (vino_t) tmpfs_root;
191 tmpfs_root->mode = S_IFDIR | mode;
192 tmpfs_root->size = 0;
193 tmpfs_root->nlink = 2;
194 tmpfs_root->fs = &tmpfs;
195 tmpfs_root->p = NULL;
196 tmpfs_root->ref = 1;
197
198 struct timespec ts;
199 gettime(&ts);
200
201 tmpfs_root->ctime = ts;
202 tmpfs_root->atime = ts;
203 tmpfs_root->mtime = ts;
204
205 /* something is mounted there already: the new root goes */
206 int err = vfs_bind(dir, tmpfs_root);
207
208 if (err)
209 kfree(tmpfs_root);
210
211 return err;
212}
213
214struct fs tmpfs = {
215 .name = "tmpfs",
216 .nodev = 1,
217 .init = tmpfs_init,
218 .mount = tmpfs_mount,
219
220 .vops = {
221 .read = tmpfs_read,
222 .write = tmpfs_write,
223 .close = tmpfs_close,
224 .trunc = tmpfs_trunc,
225
226 .readdir = pseudofs_readdir,
227 .finddir = pseudofs_finddir,
228
229 .vmknod = pseudofs_vmknod,
230 .vunlink = pseudofs_vunlink,
231 .vlink = pseudofs_vlink,
232 .vrename = pseudofs_vrename,
233 .setattr = pseudofs_setattr,
234 .vget = tmpfs_vget,
235 },
236
237 .fops = {
238 .open = posix_file_open,
239 .close = posix_file_close,
240 .read = posix_file_read,
241 .write = posix_file_write,
242 .ioctl = posix_file_ioctl,
243 .lseek = posix_file_lseek,
244 .readdir = posix_file_readdir,
245 .trunc = posix_file_trunc,
246
247 .can_read = tmpfs_file_can_read,
248 .can_write = tmpfs_file_can_write,
249 .eof = tmpfs_file_eof,
250 },
251};
252
#define MIN(a, b)
Definition system.h:11
#define MAX(a, b)
Definition system.h:10
ssize_t iobuf_out(struct iobuf *io, const void *src, size_t n)
Copies bytes from the kernel into the iobuf's buffer, and moves past them.
Definition iobuf.c:115
ssize_t iobuf_in(struct iobuf *io, void *dst, size_t n)
Copies bytes from the iobuf's buffer into the kernel, and moves past them.
Definition iobuf.c:135
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
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
off_t posix_file_lseek(struct file *file, off_t offset, int whence)
Moves an open file's offset: to offset (SEEK_SET), by offset from where it is (SEEK_CUR),...
Definition lseek.c:22
#define MODULE_INIT(name, i, f)
Definition module.h:10
int posix_file_open(struct file *file)
Finishes opening a file: with O_TRUNC, a regular file is truncated to 0 bytes.
Definition open.c:17
int posix_file_close(struct file *file)
Closes an open file by dropping its reference to its vnode.
Definition close.c:15
int posix_file_ioctl(struct file *file, int request, void *argp)
Passes an ioctl() request on to the file's vnode (a device's, or its filesystem's).
Definition ioctl.c:19
ssize_t posix_file_read(struct file *file, struct iobuf *io)
Reads from an open file at its offset, and moves the offset past what was read.
Definition read.c:29
ssize_t posix_file_readdir(struct file *file, struct dirent *dirent)
Reads the directory entry at an open directory's offset, and moves the offset past it.
Definition readdir.c:22
int posix_file_trunc(struct file *file, off_t len)
Truncates (or extends) an open file to a new length.
Definition trunc.c:16
ssize_t posix_file_write(struct file *file, struct iobuf *io)
Writes to an open file at its offset, and moves the offset past what was written.
Definition write.c:25
int pseudofs_setattr(struct vnode *vnode)
Stores a vnode's attributes: there's nothing to do, since they only live in the vnode.
Definition pseudofs.c:306
int pseudofs_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)
Makes a node in a directory: a new vnode, owned by the caller, and an entry for it.
Definition pseudofs.c:49
int pseudofs_finddir(struct vnode *dir, const char *name, struct dirent *dirent)
Finds the entry of a directory that has a name.
Definition pseudofs.c:367
int pseudofs_vlink(struct vnode *dir, const char *fn, struct vnode *vnode, struct uio *uio)
Adds an entry for an existing vnode (a hard link) to a directory.
Definition pseudofs.c:211
int pseudofs_close(struct vnode *vnode)
Frees a vnode that has no names or references left, and its cached pages.
Definition pseudofs.c:397
int pseudofs_vunlink(struct vnode *vnode, const char *fn, struct uio *uio)
Removes an entry from a directory.
Definition pseudofs.c:186
ssize_t pseudofs_readdir(struct vnode *dir, off_t offset, struct dirent *dirent)
Reads a directory's entry at an offset.
Definition pseudofs.c:320
int pseudofs_vrename(struct vnode *odir, const char *ofn, struct vnode *ndir, const char *nfn, struct uio *uio)
Renames an entry, possibly to another directory, replacing an entry at the new name.
Definition pseudofs.c:250
#define NULL
Definition stddef.h:27
unsigned int uint32_t
Definition stddef.h:22
__SIZE_TYPE__ size_t
Definition stddef.h:7
A device driver: its operations, any of which may be NULL.
Definition dev.h:28
An open file (POSIX's "open file description", fs/file.c).
Definition vfs.h:157
off_t offset
Definition vfs.h:163
A filesystem type.
Definition vfs.h:98
An iobuf.
Definition iobuf.h:35
size_t resid
Definition iobuf.h:38
A file in memory (a vnode): what its inode says, and the kernel's own state.
Definition vfs.h:113
ino_t ino
Definition vfs.h:114
_time_t atime
Definition vfs.h:123
_time_t ctime
Definition vfs.h:125
size_t ref
how many references there are to it
Definition vfs.h:133
nlink_t nlink
Definition vfs.h:121
struct fs * fs
Definition vfs.h:127
_time_t mtime
Definition vfs.h:124
size_t size
Definition vfs.h:115
void * p
the filesystem's own data
Definition vfs.h:130
mode_t mode
Definition vfs.h:118
int gettime(struct timespec *ts)
Reads the wall clock (CLOCK_REALTIME).
Definition time.c:29
static ssize_t tmpfs_read(struct vnode *node, off_t offset, struct iobuf *io)
Reads a file's data from its buffer.
Definition tmpfs.c:49
static int tmpfs_file_can_read(struct file *file, size_t size)
Says whether size bytes can be read from the file's offset.
Definition tmpfs.c:131
static int tmpfs_file_can_write(struct file *file, size_t size)
Says that a write can always go on: tmpfs has no size limit yet.
Definition tmpfs.c:140
struct fs tmpfs
Definition tmpfs.c:214
static ssize_t tmpfs_write(struct vnode *node, off_t offset, struct iobuf *io)
Writes a file's data into its buffer, which grows to hold it.
Definition tmpfs.c:61
static int tmpfs_init()
Installs tmpfs at boot.
Definition tmpfs.c:152
static int tmpfs_mount(struct vnode *dir, int flags, void *data)
Mounts a new, empty tmpfs on a directory.
Definition tmpfs.c:160
static int tmpfs_close(struct vnode *vnode)
Frees a vnode that has neither references nor names left.
Definition tmpfs.c:38
static int tmpfs_vget(struct vnode *super, ino_t ino, struct vnode **vnode)
Gets a vnode by its inode number, which is its address.
Definition tmpfs.c:28
static int tmpfs_file_eof(struct file *file)
Says whether the file's offset is at its end.
Definition tmpfs.c:146
static int tmpfs_trunc(struct vnode *vnode, off_t len)
Changes a file's length: its buffer is cut, or grows with zeros.
Definition tmpfs.c:95
uintptr_t ino_t
Definition types.h:23
uintptr_t vino_t
Definition types.h:14
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10
int vfs_bind(struct vnode *dir, struct vnode *root)
Mounts a filesystem on a directory: a lookup that reaches dir goes on in root instead.
Definition vfs.c:53
int vfs_install(struct fs *fs)
Installs a filesystem, so that it can be mounted by name.
Definition vfs.c:85