Skip to content

Commit 2e45b33

Browse files
committed
Make RAMFS not to free file data when file is still opened
Even though it is valid to delete a file its data (i-node) should not be deleted until all file descriptors are closed. This patch fixes the bug in file deletion logic in RAMFS to make sure that file node does not get deleted until all file descriptors are closed. Fixes #1035 Signed-off-by: Waldemar Kozaczuk <[email protected]>
1 parent 1e22a86 commit 2e45b33

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

fs/ramfs/ramfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ struct ramfs_node {
5959
struct timespec rn_mtime;
6060
int rn_mode;
6161
bool rn_owns_buf;
62+
int rn_ref_count;
63+
bool rn_removed;
6264
};
6365

6466
struct ramfs_node *ramfs_allocate_node(const char *name, int type);

fs/ramfs/ramfs_vnops.cc

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,19 @@ ramfs_allocate_node(const char *name, int type)
9595

9696
set_times_to_now(&(np->rn_ctime), &(np->rn_atime), &(np->rn_mtime));
9797
np->rn_owns_buf = true;
98+
np->rn_ref_count = 0;
99+
np->rn_removed = false;
98100

99101
return np;
100102
}
101103

102104
void
103105
ramfs_free_node(struct ramfs_node *np)
104106
{
107+
if (!np->rn_removed || np->rn_ref_count > 0) {
108+
return;
109+
}
110+
105111
if (np->rn_buf != NULL && np->rn_owns_buf)
106112
free(np->rn_buf);
107113

@@ -159,7 +165,11 @@ ramfs_remove_node(struct ramfs_node *dnp, struct ramfs_node *np)
159165
}
160166
prev->rn_next = np->rn_next;
161167
}
162-
ramfs_free_node(np);
168+
169+
np->rn_removed = true;
170+
if (np->rn_ref_count <= 0) {
171+
ramfs_free_node(np);
172+
}
163173

164174
set_times_to_now(&(dnp->rn_mtime), &(dnp->rn_ctime));
165175

@@ -522,6 +532,9 @@ ramfs_rename(struct vnode *dvp1, struct vnode *vp1, char *name1,
522532
np->rn_buf = old_np->rn_buf;
523533
np->rn_size = old_np->rn_size;
524534
np->rn_bufsize = old_np->rn_bufsize;
535+
np->rn_owns_buf = old_np->rn_owns_buf;
536+
np->rn_ref_count = old_np->rn_ref_count;
537+
np->rn_removed = old_np->rn_removed;
525538
old_np->rn_buf = NULL;
526539
}
527540
/* Remove source file */
@@ -629,8 +642,27 @@ ramfs_setattr(struct vnode *vnode, struct vattr *attr) {
629642
return 0;
630643
}
631644

632-
#define ramfs_open ((vnop_open_t)vop_nullop)
633-
#define ramfs_close ((vnop_close_t)vop_nullop)
645+
int ramfs_open(struct file *fp)
646+
{
647+
struct vnode *vp = file_dentry(fp)->d_vnode;
648+
struct ramfs_node *np = (ramfs_node *) vp->v_data;
649+
np->rn_ref_count++;
650+
return 0;
651+
}
652+
653+
int ramfs_close(struct vnode *dvp, struct file *file)
654+
{
655+
struct vnode *vp = file_dentry(file)->d_vnode;
656+
struct ramfs_node *np = (ramfs_node *) vp->v_data;
657+
np->rn_ref_count--;
658+
659+
if (np->rn_removed && np->rn_ref_count <= 0) {
660+
ramfs_free_node(np);
661+
}
662+
663+
return 0;
664+
}
665+
634666
#define ramfs_seek ((vnop_seek_t)vop_nullop)
635667
#define ramfs_ioctl ((vnop_ioctl_t)vop_einval)
636668
#define ramfs_fsync ((vnop_fsync_t)vop_nullop)

tests/tst-mmap-file.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <fcntl.h>
1515
#include <stdio.h>
1616
#include <errno.h>
17+
#include <assert.h>
1718

1819
static int tests = 0, fails = 0;
1920

@@ -81,6 +82,34 @@ static int check_mapping(void *addr, size_t size, unsigned flags, int fd,
8182
return 0;
8283
}
8384

85+
static int test_mmap_with_file_removed()
86+
{
87+
char file_template[30];
88+
snprintf(file_template, sizeof(file_template) / sizeof(char), "%s/mmap-file-deleted.XXXXXX", "/tmp");
89+
90+
auto fd1 = mkstemp(file_template);
91+
assert(fd1 != -1);
92+
93+
assert(unlink(file_template) >= 0);
94+
size_t buf_size = 131072;
95+
assert(ftruncate(fd1, buf_size) >= 0);
96+
97+
auto buf = (char *) mmap(NULL, buf_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd1, 0);
98+
assert(buf != MAP_FAILED);
99+
100+
auto fd2 = open(file_template, O_RDWR);
101+
close(fd2);
102+
103+
auto urandom = fopen("/dev/urandom", "rb");
104+
assert(urandom != NULL);
105+
assert(fread(buf, 1, buf_size, urandom) == buf_size);
106+
107+
close(fd1);
108+
report(munmap(buf,buf_size) == 0, "test_mmap_with_file_removed succeeded");
109+
110+
return 0;
111+
}
112+
84113
int main(int argc, char *argv[])
85114
{
86115
auto fd = open("/tmp/mmap-file-test", O_CREAT|O_TRUNC|O_RDWR, 0666);
@@ -143,6 +172,8 @@ int main(int argc, char *argv[])
143172
report(munmap(b, 4096) == 0, "munmap temporary mapping");
144173
report(close(fd) == 0, "close again");
145174

175+
test_mmap_with_file_removed();
176+
146177
// TODO: map an append-only file with prot asking for PROT_WRITE, mmap should return EACCES.
147178
// TODO: map a file under a fs mounted with the flag NO_EXEC and prot asked for PROT_EXEC (expect EPERM).
148179

0 commit comments

Comments
 (0)