AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
remove.c
Go to the documentation of this file.
1
9
10#include <ext2.h>
11#include <core/time.h>
12#include <ds/bitmap.h>
13#include <fs/vcache.h>
14
21static uint32_t free_tree(struct ext2 *desc, struct ext2_inode *inode, uint32_t block, int depth, size_t from)
22{
23 size_t bs = desc->bs, p = bs / 4, span = 1;
24
25 if (!block)
26 return 0;
27
28 if (depth) {
29 uint32_t *table = kmalloc(bs, &M_BUFFER, 0);
30
31 for (int i = 1; i < depth; ++i)
32 span *= p;
33
34 /* a table that can't be read stays, and what's under it too (its
35 * pointers aren't known, so nothing under it can be freed) */
36 if (!table || ext2_block_read(desc, block, table)) {
37 kfree(table);
38 return block;
39 }
40
41 for (size_t i = from / span; i < p; ++i)
42 table[i] = free_tree(desc, inode, table[i], depth - 1, i == from / span ? from % span : 0);
43
44 /* the first part of the tree stays */
45 if (from) {
46 ext2_block_write(desc, block, table);
47 kfree(table);
48 return block;
49 }
50
51 kfree(table);
52 }
53
54 if (ext2_block_free(desc, block))
55 return block;
56
57 inode->blocks -= bs / 512;
58 return 0;
59}
60
69void ext2_blocks_free(struct ext2 *desc, struct ext2_inode *inode, size_t from)
70{
71 size_t p = desc->bs / 4, base = EXT2_DIRECT_POINTERS;
72
73 /* a fast symbolic link keeps its target in the block pointers, and a
74 * device node its number: they have no blocks */
75 if ((S_ISLNK(inode->mode) && !inode->blocks) ||
76 S_ISCHR(inode->mode) || S_ISBLK(inode->mode))
77 return;
78
79 for (size_t i = from; i < EXT2_DIRECT_POINTERS; ++i)
80 inode->direct_pointer[i] = free_tree(desc, inode, inode->direct_pointer[i], 0, 0);
81
83 free_tree(desc, inode, inode->singly_indirect_pointer, 1, from > base ? from - base : 0);
84 base += p;
86 free_tree(desc, inode, inode->doubly_indirect_pointer, 2, from > base ? from - base : 0);
87 base += p * p;
89 free_tree(desc, inode, inode->triply_indirect_pointer, 3, from > base ? from - base : 0);
90}
91
94static void ext2_inode_free(struct ext2 *desc, ino_t ino, int dir)
95{
96 uint32_t group = (ino - 1) / desc->superblock->ginodes;
97 uint32_t index = (ino - 1) % desc->superblock->ginodes;
98 uint32_t *buf = kmalloc(desc->bs, &M_BUFFER, 0);
99 struct bitmap bm = {.map = buf, .max_idx = desc->superblock->ginodes};
100
101 if (!buf)
102 return;
103
104 if (ext2_block_read(desc, desc->groups[group].imap, buf)) {
105 kfree(buf);
106 return;
107 }
108
109 bitmap_clear(&bm, index);
110 int err = ext2_block_write(desc, desc->groups[group].imap, buf);
111 kfree(buf);
112
113 if (err)
114 return;
115
116 desc->groups[group].free_inodes++;
117 if (dir)
118 desc->groups[group].directories_count--;
120
121 desc->superblock->free_inodes++;
123}
124
131void ext2_inode_discard(struct ext2 *desc, ino_t ino)
132{
133 struct ext2_inode inode;
134 struct timespec ts;
135
136 if (ext2_inode_read(desc, ino, &inode))
137 return;
138
139 ext2_blocks_free(desc, &inode, 0);
140
141 gettime(&ts);
142 inode.nlink = 0;
143 inode.size = 0;
144 inode.dtime = ts.tv_sec;
145
146 /* unless the inode could be written as deleted, it stays used */
147 if (!ext2_inode_write(desc, ino, &inode))
148 ext2_inode_free(desc, ino, S_ISDIR(inode.mode));
149}
150
159{
160 struct ext2 *desc = vnode->p;
161
162 /* it was unlinked while it was open */
163 if (!vnode->nlink) {
165 vcache_remove(desc->vcache, vnode);
167 kfree(vnode);
168 }
169
170 return 0;
171}
172
179static int dentry_update(struct vnode *dir, const char *name,
180 void (*fn)(struct ext2_dentry *d, struct ext2_dentry *prev, void *arg),
181 void *arg, ino_t *ino)
182{
183 struct ext2 *desc = dir->p;
184 struct ext2_inode dir_inode;
185 size_t bs = desc->bs, len = strlen(name);
186 int err;
187
188 if ((err = ext2_inode_read(desc, dir->ino, &dir_inode)))
189 return err;
190
191 char *buf = kmalloc(bs, &M_BUFFER, 0);
192
193 if (!buf)
194 return -ENOMEM;
195
196 err = -ENOENT;
197
198 for (size_t i = 0; i < dir_inode.size / bs && err == -ENOENT; ++i) {
199 struct ext2_dentry *d = (struct ext2_dentry *) buf, *prev = NULL;
200 int r;
201
202 if ((r = ext2_inode_block_read(desc, &dir_inode, i, buf))) {
203 err = r;
204 break;
205 }
206
207 while ((char *) d < buf + bs && d->size) {
208 if (d->ino && d->length == len && !memcmp(d->name, name, len)) {
209 *ino = d->ino;
210 fn(d, prev, arg);
211 err = ext2_inode_block_write(desc, &dir_inode, dir->ino, i, buf);
212 break;
213 }
214
215 prev = d;
216 d = (struct ext2_dentry *) ((char *) d + d->size);
217 }
218 }
219
220 kfree(buf);
221 return err;
222}
223
226static void dentry_remove(struct ext2_dentry *d, struct ext2_dentry *prev, void *arg)
227{
228 if (prev)
229 prev->size += d->size;
230 else
231 d->ino = 0;
232}
233
235static void dentry_set_ino(struct ext2_dentry *d, struct ext2_dentry *prev, void *arg)
236{
237 d->ino = *(ino_t *) arg;
238}
239
249int ext2_vunlink(struct vnode *dir, const char *fn, struct uio *uio)
250{
251 struct ext2 *desc = dir->p;
252 struct vnode *vnode = NULL;
253 struct timespec ts;
254 ino_t ino = 0;
255 int err;
256
257 if ((err = dentry_update(dir, fn, dentry_remove, NULL, &ino)))
258 return err;
259
260 if ((err = ext2_inode_build(desc, ino, &vnode)))
261 return err;
262
263 gettime(&ts);
264
265 if (S_ISDIR(vnode->mode)) {
266 /* a directory loses its . link, and the parent the link of its
267 * .. */
268 vnode->nlink = 0;
269 dir->nlink--;
270 } else {
271 vnode->nlink--;
272 }
273
274 dir->mtime = dir->ctime = ts;
275 ext2_inode_sync(dir);
276
277 vnode->ctime = ts;
279
280 /* if nothing has it open, release it now */
281 if (!vnode->ref) {
282 vnode->ref = 1;
284 }
285
286 return 0;
287}
288
298int ext2_vlink(struct vnode *dir, const char *fn, struct vnode *vnode, struct uio *uio)
299{
300 struct ext2 *desc = dir->p;
301 struct ext2_inode dir_inode;
302 struct timespec ts;
303 int err;
304
305 if ((err = ext2_inode_read(desc, dir->ino, &dir_inode)))
306 return err;
307
308 ino_t ino;
309
310 if (!(err = ext2_dentry_find(desc, &dir_inode, fn, &ino)))
311 return -EEXIST;
312
313 if (err != -ENOENT)
314 return err;
315
316 if ((err = ext2_dentry_create(dir, fn, vnode->ino, vnode->mode)))
317 return err;
318
319 gettime(&ts);
320 vnode->nlink++;
321 vnode->ctime = ts;
322 return ext2_inode_sync(vnode);
323}
324
337int ext2_vrename(struct vnode *odir, const char *ofn, struct vnode *ndir, const char *nfn, struct uio *uio)
338{
339 struct ext2 *desc = odir->p;
340 struct ext2_inode inode;
341 struct vnode *vnode = NULL;
342 struct timespec ts;
343 int err;
344
345 if ((err = ext2_inode_read(desc, odir->ino, &inode)))
346 return err;
347
348 ino_t ino, other, dummy;
349
350 if ((err = ext2_dentry_find(desc, &inode, ofn, &ino)))
351 return err;
352
353 if ((err = ext2_inode_build(desc, ino, &vnode)))
354 return err;
355
356 /* remove the entry it replaces, if there's one (the VFS checked its
357 * type) */
358 if ((err = ext2_inode_read(desc, ndir->ino, &inode)))
359 return err;
360
361 if (!(err = ext2_dentry_find(desc, &inode, nfn, &other)))
362 err = ext2_vunlink(ndir, nfn, uio);
363
364 if (err && err != -ENOENT)
365 return err;
366
367 if ((err = ext2_dentry_create(ndir, nfn, ino, vnode->mode)))
368 return err;
369
370 if ((err = dentry_update(odir, ofn, dentry_remove, NULL, &dummy)))
371 return err;
372
373 gettime(&ts);
374
375 /* a directory's .. now points to its new parent */
376 if (S_ISDIR(vnode->mode) && odir != ndir) {
377 ino_t parent = ndir->ino;
378
379 if ((err = dentry_update(vnode, "..", dentry_set_ino, &parent, &dummy)))
380 return err;
381
382 odir->nlink--;
383 ndir->nlink++;
384 }
385
386 odir->mtime = odir->ctime = ts;
387 ndir->mtime = ndir->ctime = ts;
388 vnode->ctime = ts;
389
390 ext2_inode_sync(odir);
391 if (ndir != odir)
392 ext2_inode_sync(ndir);
393
394 return ext2_inode_sync(vnode);
395}
int vfs_close(struct vnode *vnode)
Drops a reference to a vnode.
Definition close.c:18
int ext2_block_free(struct ext2 *desc, uint32_t block)
Frees a block: its bit is cleared in its group's block bitmap, and the free counts go up.
Definition block.c:145
int ext2_block_write(struct ext2 *desc, uint32_t number, void *buf)
Writes a block to the disk.
Definition block.c:62
int ext2_bgd_table_rewrite(struct ext2 *desc)
Writes the block group descriptor table back to the disk, after a change to a group's counts.
Definition block.c:34
int ext2_block_read(struct ext2 *desc, uint32_t number, void *buf)
Reads a block from the disk.
Definition block.c:49
int ext2_dentry_create(struct vnode *dir, const char *name, ino_t ino, mode_t mode)
Adds an entry to a directory.
Definition dentry.c:87
int ext2_dentry_find(struct ext2 *desc, struct ext2_inode *inode, const char *name, ino_t *ino)
Finds the inode number of a name in a directory.
Definition dentry.c:20
int ext2_inode_build(struct ext2 *desc, ino_t ino, struct vnode **ref_inode)
Gets the vnode of an inode: the cached one if it's in use, or a new one made from the inode on the di...
Definition ext2.c:29
int ext2_inode_sync(struct vnode *inode)
Writes a vnode's attributes back to its inode on the disk.
Definition ext2.c:93
void ext2_blocks_free(struct ext2 *desc, struct ext2_inode *inode, size_t from)
Frees a file's blocks, from a block on, when the file is truncated or removed.
Definition remove.c:69
int ext2_close(struct vnode *vnode)
Releases a vnode when its last reference goes.
Definition remove.c:158
#define EXT2_DIRECT_POINTERS
Definition ext2.h:165
int ext2_inode_read(struct ext2 *desc, ino_t inode, struct ext2_inode *ref)
Reads an inode from the disk.
Definition inode.c:33
int ext2_vlink(struct vnode *dir, const char *fn, struct vnode *vnode, struct uio *uio)
Adds an entry for an existing file (a hard link) to a directory.
Definition remove.c:298
int ext2_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 (the VFS checked ...
Definition remove.c:337
void ext2_inode_discard(struct ext2 *desc, ino_t ino)
Frees an inode that has no links left, and the blocks it uses.
Definition remove.c:131
int ext2_inode_block_read(struct ext2 *desc, struct ext2_inode *inode, size_t idx, void *buf)
Reads a block of a file.
Definition inode.c:144
int ext2_inode_write(struct ext2 *desc, ino_t inode, struct ext2_inode *i)
Writes an inode to the disk.
Definition inode.c:51
int ext2_superblock_rewrite(struct ext2 *desc)
Writes the in-memory copy of the superblock back to the disk, after a change to its counts of free bl...
Definition super.c:14
int ext2_vunlink(struct vnode *dir, const char *fn, struct uio *uio)
Removes an entry from a directory, and drops a link to its file.
Definition remove.c:249
int ext2_inode_block_write(struct ext2 *desc, struct ext2_inode *inode, uint32_t inode_nr, size_t idx, void *buf)
Writes a block of a file, allocating it and the indirect blocks above it if they don't exist yet.
Definition inode.c:235
void vnode_pages_free(struct vnode *vnode)
Frees a vnode's vm object and its cached pages, when the vnode itself is freed.
Definition vm_object.c:172
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
int memcmp(const void *a, const void *b, size_t n)
Compares n bytes.
Definition libc.c:51
static blk_t free_tree(struct minix *desc, blk_t zone, int depth, size_t from)
Frees the zones of the tree at zone (a data zone at depth 0, or an indirect zone depth levels above t...
Definition inode.c:281
static uint64_t * table(paddr_t paddr)
Returns a page table, through the direct map.
Definition pmap.c:72
static void dentry_set_ino(struct ext2_dentry *d, struct ext2_dentry *prev, void *arg)
Points an entry to another inode, the one arg points to.
Definition remove.c:235
static void dentry_remove(struct ext2_dentry *d, struct ext2_dentry *prev, void *arg)
Removes an entry: the previous entry takes its space, or, for the first entry of a block,...
Definition remove.c:226
static void ext2_inode_free(struct ext2 *desc, ino_t ino, int dir)
Marks an inode free in its group's inode bitmap, and counts it as free.
Definition remove.c:94
static int dentry_update(struct vnode *dir, const char *name, void(*fn)(struct ext2_dentry *d, struct ext2_dentry *prev, void *arg), void *arg, ino_t *ino)
Finds the entry name of directory dir, calls fn on it, and writes its block back.
Definition remove.c:179
#define NULL
Definition stddef.h:27
unsigned int uint32_t
Definition stddef.h:22
A bitmap: its blocks, and its last bit's index.
Definition bitmap.h:17
A directory entry, as it is on the disk.
Definition ext2.h:142
uint16_t size
entry total size
Definition ext2.h:146
uint8_t name[0]
the name follows (not NUL-terminated)
Definition ext2.h:152
uint32_t ino
inode number
Definition ext2.h:144
uint8_t length
name length
Definition ext2.h:148
uint16_t free_inodes
number of unallocated inodes
Definition ext2.h:108
uint16_t directories_count
Definition ext2.h:109
uint32_t imap
inodes bitmap
Definition ext2.h:102
An inode, as it is on the disk.
Definition ext2.h:114
uint16_t nlink
Definition ext2.h:123
uint32_t blocks
Definition ext2.h:124
uint32_t size
Definition ext2.h:117
uint32_t doubly_indirect_pointer
Definition ext2.h:130
uint32_t direct_pointer[12]
Definition ext2.h:128
uint32_t triply_indirect_pointer
Definition ext2.h:131
uint16_t mode
Definition ext2.h:115
uint32_t dtime
Definition ext2.h:121
uint32_t singly_indirect_pointer
Definition ext2.h:129
uint32_t ginodes
number of inodes per block group
Definition ext2.h:56
uint32_t free_inodes
number of unallocated inodes
Definition ext2.h:44
A mounted ext2 filesystem.
Definition ext2.h:168
struct ext2_superblock * superblock
Definition ext2.h:170
struct ext2_group * groups
Definition ext2.h:171
struct vcache * vcache
its vnodes in use, by inode number
Definition ext2.h:187
size_t bs
the block size
Definition ext2.h:177
time_t tv_sec
Definition types.h:31
Who does a filesystem operation: where its paths start, and its credentials and umask.
Definition vfs.h:60
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 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
_time_t mtime
Definition vfs.h:124
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
uintptr_t ino_t
Definition types.h:23
int vcache_remove(struct vcache *vcache, struct vnode *vnode)
Takes a vnode out of a cache.
Definition vcache.c:56