From: Waldemar Kozaczuk <jwkozac...@gmail.com>
Committer: Waldemar Kozaczuk <jwkozac...@gmail.com>
Branch: master
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 <jwkozac...@gmail.com>
---
diff --git a/fs/ramfs/ramfs.h b/fs/ramfs/ramfs.h
--- a/fs/ramfs/ramfs.h
+++ b/fs/ramfs/ramfs.h
@@ -59,6 +59,8 @@ struct ramfs_node {
struct timespec rn_mtime;
int rn_mode;
bool rn_owns_buf;
+ int rn_ref_count;
+ bool rn_removed;
};
struct ramfs_node *ramfs_allocate_node(const char *name, int type);
diff --git a/fs/ramfs/ramfs_vnops.cc b/fs/ramfs/ramfs_vnops.cc
--- a/fs/ramfs/ramfs_vnops.cc
+++ b/fs/ramfs/ramfs_vnops.cc
@@ -95,13 +95,19 @@ ramfs_allocate_node(const char *name, int type)
set_times_to_now(&(np->rn_ctime), &(np->rn_atime), &(np->rn_mtime));
np->rn_owns_buf = true;
+ np->rn_ref_count = 0;
+ np->rn_removed = false;
return np;
}
void
ramfs_free_node(struct ramfs_node *np)
{
+ if (!np->rn_removed || np->rn_ref_count > 0) {
+ return;
+ }
+
if (np->rn_buf != NULL && np->rn_owns_buf)
free(np->rn_buf);
@@ -159,7 +165,11 @@ ramfs_remove_node(struct ramfs_node *dnp, struct
ramfs_node *np)
}
prev->rn_next = np->rn_next;
}
- ramfs_free_node(np);
+
+ np->rn_removed = true;
+ if (np->rn_ref_count <= 0) {
+ ramfs_free_node(np);
+ }
set_times_to_now(&(dnp->rn_mtime), &(dnp->rn_ctime));
@@ -522,6 +532,9 @@ ramfs_rename(struct vnode *dvp1, struct vnode *vp1,
char *name1,
np->rn_buf = old_np->rn_buf;
np->rn_size = old_np->rn_size;
np->rn_bufsize = old_np->rn_bufsize;
+ np->rn_owns_buf = old_np->rn_owns_buf;
+ np->rn_ref_count = old_np->rn_ref_count;
+ np->rn_removed = old_np->rn_removed;
old_np->rn_buf = NULL;
}
/* Remove source file */
@@ -629,8 +642,27 @@ ramfs_setattr(struct vnode *vnode, struct vattr *attr)
{
return 0;
}
-#define ramfs_open ((vnop_open_t)vop_nullop)
-#define ramfs_close ((vnop_close_t)vop_nullop)
+int ramfs_open(struct file *fp)
+{
+ struct vnode *vp = file_dentry(fp)->d_vnode;
+ struct ramfs_node *np = (ramfs_node *) vp->v_data;
+ np->rn_ref_count++;
+ return 0;
+}
+
+int ramfs_close(struct vnode *dvp, struct file *file)
+{
+ struct vnode *vp = file_dentry(file)->d_vnode;
+ struct ramfs_node *np = (ramfs_node *) vp->v_data;
+ np->rn_ref_count--;
+
+ if (np->rn_removed && np->rn_ref_count <= 0) {
+ ramfs_free_node(np);
+ }
+
+ return 0;
+}
+
#define ramfs_seek ((vnop_seek_t)vop_nullop)
#define ramfs_ioctl ((vnop_ioctl_t)vop_einval)
#define ramfs_fsync ((vnop_fsync_t)vop_nullop)
diff --git a/tests/tst-mmap-file.cc b/tests/tst-mmap-file.cc
--- a/tests/tst-mmap-file.cc
+++ b/tests/tst-mmap-file.cc
@@ -14,6 +14,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
+#include <assert.h>
static int tests = 0, fails = 0;
@@ -81,6 +82,34 @@ static int check_mapping(void *addr, size_t size,
unsigned flags, int fd,
return 0;
}
+static int test_mmap_with_file_removed()
+{
+ char file_template[30];
+ snprintf(file_template, sizeof(file_template) /
sizeof(char), "%s/mmap-file-deleted.XXXXXX", "/tmp");
+
+ auto fd1 = mkstemp(file_template);
+ assert(fd1 != -1);
+
+ assert(unlink(file_template) >= 0);
+ size_t buf_size = 131072;
+ assert(ftruncate(fd1, buf_size) >= 0);
+
+ auto buf = (char *) mmap(NULL, buf_size, PROT_READ|PROT_WRITE,
MAP_PRIVATE, fd1, 0);
+ assert(buf != MAP_FAILED);
+
+ auto fd2 = open(file_template, O_RDWR);
+ close(fd2);
+
+ auto urandom = fopen("/dev/urandom", "rb");
+ assert(urandom != NULL);
+ assert(fread(buf, 1, buf_size, urandom) == buf_size);
+
+ close(fd1);
+ report(munmap(buf,buf_size) == 0, "test_mmap_with_file_removed
succeeded");
+
+ return 0;
+}
+
int main(int argc, char *argv[])
{
auto fd = open("/tmp/mmap-file-test", O_CREAT|O_TRUNC|O_RDWR, 0666);
@@ -143,6 +172,8 @@ int main(int argc, char *argv[])
report(munmap(b, 4096) == 0, "munmap temporary mapping");
report(close(fd) == 0, "close again");
+ test_mmap_with_file_removed();
+
// TODO: map an append-only file with prot asking for PROT_WRITE, mmap
should return EACCES.
// TODO: map a file under a fs mounted with the flag NO_EXEC and prot
asked for PROT_EXEC (expect EPERM).
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/osv-dev/000000000000949852058c18147f%40google.com.
For more options, visit https://groups.google.com/d/optout.