From cbf7881f016d25ec0fbccc3db8463d066f5ef5e7 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 08:48:10 +0200 Subject: [PATCH 01/18] main: load_dir updates the node last layer Signed-off-by: Giuseppe Scrivano --- main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 45c3505..11da83a 100644 --- a/main.c +++ b/main.c @@ -1149,7 +1149,10 @@ make_ovl_node (const char *path, struct ovl_layer *layer, const char *name, ino_ continue; if (fstat (fd, &st) == 0) - ret->ino = st.st_ino; + { + ret->ino = st.st_ino; + ret->last_layer = it; + } s = safe_read_xattr (&val, fd, PRIVILEGED_ORIGIN_XATTR, PATH_MAX); if (s > 0) @@ -1322,6 +1325,7 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char child = hash_lookup (n->children, &key); if (child) { + child->last_layer = it; if (child->whiteout && it == upper_layer) { hash_delete (n->children, child); @@ -1386,13 +1390,13 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char } else { - child = make_ovl_node (node_path, it, dent->d_name, 0, dirp, n, lo->fast_ino_check); if (child == NULL) { errno = ENOMEM; return NULL; } + child->last_layer = it; } } From 64e493e7e4647e6e349d968c6aa52fc55be6208e Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 09:18:30 +0200 Subject: [PATCH 02/18] main: create_directory does unlink only on ENOTDIR Signed-off-by: Giuseppe Scrivano --- main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index 11da83a..5198bf5 100644 --- a/main.c +++ b/main.c @@ -2194,11 +2194,11 @@ create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct goto out; } - unlinkat (dirfd, name, 0); - ret = renameat (lo->workdir_fd, wd_tmp_file_name, dirfd, name); if (ret < 0) { + if (errno == ENOTDIR) + unlinkat (dirfd, name, 0); if (errno == ENOENT && parent) { ret = create_node_directory (lo, parent); From f3d66013b39a280c95054d1d4406dda1856fb451 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 10:03:21 +0200 Subject: [PATCH 03/18] main: drop present_lowerdir attribute use last_layer instead. Signed-off-by: Giuseppe Scrivano --- main.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/main.c b/main.c index 5198bf5..aa0ae46 100644 --- a/main.c +++ b/main.c @@ -213,7 +213,6 @@ struct ovl_node ino_t ino; size_t name_hash; - unsigned int present_lowerdir : 1; unsigned int do_unlink : 1; unsigned int do_rmdir : 1; unsigned int hidden : 1; @@ -1326,18 +1325,15 @@ load_dir (struct ovl_data *lo, struct ovl_node *n, struct ovl_layer *layer, char if (child) { child->last_layer = it; - if (child->whiteout && it == upper_layer) + if (!child->whiteout || it != upper_layer) + continue; + else { hash_delete (n->children, child); node_free (child); child = NULL; } - else - { - if (it->low) - child->present_lowerdir = 1; - continue; - } + if (lo->fast_ino_check) continue; } @@ -1573,8 +1569,7 @@ do_lookup_file (struct ovl_data *lo, fuse_ino_t parent, const char *name) if (node) { node->ino = st.st_ino; - if (it->low) - node->present_lowerdir = 1; + node->last_layer = it; continue; } @@ -1617,11 +1612,9 @@ insert_node: errno = ENOMEM; return NULL; } - if (node->last_layer) - break; + if (pnode && pnode->last_layer == it) break; - if (lo->fast_ino_check) break; } @@ -3499,7 +3492,7 @@ ovl_rename_exchange (fuse_req_t req, fuse_ino_t parent, const char *name, return; } - if (node->layer != get_upper_layer (lo) || node->present_lowerdir) + if (node->layer != get_upper_layer (lo) || node->last_layer != get_upper_layer (lo)) { fuse_reply_err (req, EXDEV); return; @@ -3539,7 +3532,7 @@ ovl_rename_exchange (fuse_req_t req, fuse_ino_t parent, const char *name, errno = ENOENT; goto error; } - if (node_dirp (node) && destnode->present_lowerdir) + if (node_dirp (node) && destnode->last_layer != get_upper_layer (lo)) { fuse_reply_err (req, EXDEV); return; @@ -3631,7 +3624,7 @@ ovl_rename_direct (fuse_req_t req, fuse_ino_t parent, const char *name, return; } - if (node->layer != get_upper_layer (lo) || node->present_lowerdir) + if (node->layer != get_upper_layer (lo) || node->last_layer != get_upper_layer (lo)) { fuse_reply_err (req, EXDEV); return; From 98aeb52ac228256e1f8861cbecc09bbbd6e31736 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 09:48:16 +0200 Subject: [PATCH 04/18] main, mkdir: do not lookup lower layers if not needed if the parent directory is only on the upper layer, there is no need to look for the ino in the lower layers. Signed-off-by: Giuseppe Scrivano --- main.c | 52 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/main.c b/main.c index aa0ae46..c1205cf 100644 --- a/main.c +++ b/main.c @@ -2144,7 +2144,7 @@ static int create_node_directory (struct ovl_data *lo, struct ovl_node *src); static int create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct timespec *times, - struct ovl_node *parent, int xattr_sfd, uid_t uid, gid_t gid, mode_t mode) + struct ovl_node *parent, int xattr_sfd, uid_t uid, gid_t gid, mode_t mode, struct stat *st_out) { int ret; cleanup_close int dfd = -1; @@ -2187,6 +2187,13 @@ create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct goto out; } + if (st_out) + { + ret = fstat (dfd, st_out); + if (ret < 0) + goto out; + } + ret = renameat (lo->workdir_fd, wd_tmp_file_name, dirfd, name); if (ret < 0) { @@ -2233,7 +2240,7 @@ create_node_directory (struct ovl_data *lo, struct ovl_node *src) times[0] = st.st_atim; times[1] = st.st_mtim; - ret = create_directory (lo, get_upper_layer (lo)->fd, src->path, times, src->parent, sfd, st.st_uid, st.st_gid, st.st_mode); + ret = create_directory (lo, get_upper_layer (lo)->fd, src->path, times, src->parent, sfd, st.st_uid, st.st_gid, st.st_mode, NULL); if (ret == 0) { src->layer = get_upper_layer (lo); @@ -4021,14 +4028,17 @@ ovl_mknod (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev static void ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) { - cleanup_lock int l = enter_big_lock (); - struct ovl_node *node; + const struct fuse_ctx *ctx = fuse_req_ctx (req); struct ovl_data *lo = ovl_data (req); + struct fuse_entry_param e; + bool parent_upperdir_only; struct ovl_node *pnode; + struct ovl_node *node; + struct stat st; + ino_t ino = 0; int ret = 0; char *path; - struct fuse_entry_param e; - const struct fuse_ctx *ctx = fuse_req_ctx (req); + cleanup_lock int l = enter_big_lock (); if (ovl_debug (req)) fprintf (stderr, "ovl_mkdir(ino=%" PRIu64 ", name=%s, mode=%d)\n", @@ -4054,6 +4064,9 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) fuse_reply_err (req, errno); return; } + + parent_upperdir_only = pnode->last_layer == get_upper_layer (lo); + ret = asprintf (&path, "%s/%s", pnode->path, name); if (ret < 0) { @@ -4062,14 +4075,19 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) } ret = create_directory (lo, get_upper_layer (lo)->fd, path, NULL, pnode, -1, - get_uid (lo, ctx->uid), get_gid (lo, ctx->gid), mode & ~ctx->umask); + get_uid (lo, ctx->uid), get_gid (lo, ctx->gid), mode & ~ctx->umask, + parent_upperdir_only ? &st : NULL); if (ret < 0) { fuse_reply_err (req, errno); return; } - node = make_ovl_node (path, get_upper_layer (lo), name, 0, true, pnode, lo->fast_ino_check); + /* if the parent is on the upper layer, it doesn't need to lookup the ino in the lower layers. */ + if (parent_upperdir_only) + ino = st.st_ino; + + node = make_ovl_node (path, get_upper_layer (lo), name, ino, true, pnode, lo->fast_ino_check); if (node == NULL) { fuse_reply_err (req, ENOMEM); @@ -4082,11 +4100,21 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) fuse_reply_err (req, ENOMEM); return; } - ret = hide_all (lo, node); - if (ret < 0) + + if (parent_upperdir_only) { - fuse_reply_err (req, errno); - return; + node->last_layer = pnode->last_layer; + node->loaded = 1; + node->no_security_capability = 1; + } + else + { + ret = hide_all (lo, node); + if (ret < 0) + { + fuse_reply_err (req, errno); + return; + } } if (delete_whiteout (lo, -1, pnode, name) < 0) From 605e17fbf726b7b1c57f155b9b9c11de8a9b7d17 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 10:21:29 +0200 Subject: [PATCH 05/18] main: rpl_stat can reuse existing struct stat Signed-off-by: Giuseppe Scrivano --- main.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/main.c b/main.c index c1205cf..4f56e1f 100644 --- a/main.c +++ b/main.c @@ -851,12 +851,14 @@ get_gid (struct ovl_data *data, gid_t id) } static int -rpl_stat (fuse_req_t req, struct ovl_node *node, int fd, const char *path, struct stat *st) +rpl_stat (fuse_req_t req, struct ovl_node *node, int fd, const char *path, struct stat *st_in, struct stat *st) { - int ret; + int ret = 0; struct ovl_data *data = ovl_data (req); - if (fd >= 0) + if (st_in) + memcpy (st, st_in, sizeof (* st)); + else if (fd >= 0) ret = fstat (fd, st); else if (path != NULL) ret = stat (path, st); @@ -1653,7 +1655,7 @@ ovl_lookup (fuse_req_t req, fuse_ino_t parent, const char *name) return; } - err = rpl_stat (req, node, -1, NULL, &e.attr); + err = rpl_stat (req, node, -1, NULL, NULL, &e.attr); if (err) { fuse_reply_err (req, errno); @@ -1873,7 +1875,7 @@ ovl_do_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, if (node == NULL || node->whiteout || node->hidden) continue; - ret = rpl_stat (req, node, -1, NULL, &st); + ret = rpl_stat (req, node, -1, NULL, NULL, &st); if (ret < 0) { fuse_reply_err (req, errno); @@ -2564,6 +2566,7 @@ do_rm (fuse_req_t req, fuse_ino_t parent, const char *name, bool dirp) struct ovl_data *lo = ovl_data (req); struct ovl_node *pnode; int ret = 0; + size_t whiteouts = 0; struct ovl_node key, *rm; node = do_lookup_file (lo, parent, name); @@ -2585,7 +2588,7 @@ do_rm (fuse_req_t req, fuse_ino_t parent, const char *name, bool dirp) return; } - c = count_dir_entries (node, NULL); + c = count_dir_entries (node, &whiteouts); if (c) { fuse_reply_err (req, ENOTEMPTY); @@ -2601,10 +2604,13 @@ do_rm (fuse_req_t req, fuse_ino_t parent, const char *name, bool dirp) node->do_unlink = 1; else { - if (empty_dir (lo, node) < 0) + if (whiteouts > 0) { - fuse_reply_err (req, errno); - return; + if (empty_dir (lo, node) < 0) + { + fuse_reply_err (req, errno); + return; + } } node->do_rmdir = 1; @@ -2977,7 +2983,7 @@ do_getattr (fuse_req_t req, struct fuse_entry_param *e, struct ovl_node *node, i memset (e, 0, sizeof (*e)); - err = rpl_stat (req, node, fd, path, &e->attr); + err = rpl_stat (req, node, fd, path, NULL, &e->attr); if (err < 0) return err; @@ -3351,7 +3357,7 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn memset (&e, 0, sizeof (e)); - ret = rpl_stat (req, node, -1, NULL, &e.attr); + ret = rpl_stat (req, node, -1, NULL, NULL, &e.attr); if (ret) { fuse_reply_err (req, errno); @@ -3455,7 +3461,7 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na memset (&e, 0, sizeof (e)); - ret = rpl_stat (req, node, -1, NULL, &e.attr); + ret = rpl_stat (req, node, -1, NULL, NULL, &e.attr); if (ret) { fuse_reply_err (req, errno); @@ -4011,7 +4017,7 @@ ovl_mknod (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev memset (&e, 0, sizeof (e)); - ret = rpl_stat (req, node, -1, NULL, &e.attr); + ret = rpl_stat (req, node, -1, NULL, NULL, &e.attr); if (ret) { fuse_reply_err (req, errno); @@ -4125,7 +4131,7 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) memset (&e, 0, sizeof (e)); - ret = rpl_stat (req, node, -1, NULL, &e.attr); + ret = rpl_stat (req, node, -1, NULL, NULL, &e.attr); if (ret) { fuse_reply_err (req, errno); From c5bfc0ba875dfbead661a8968115f668e07c47a8 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 11:09:58 +0200 Subject: [PATCH 06/18] main: use malloc instead of calloc the memory will be overwritten. Signed-off-by: Giuseppe Scrivano --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 4f56e1f..927c76e 100644 --- a/main.c +++ b/main.c @@ -1857,7 +1857,7 @@ ovl_do_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, char *p; cleanup_free char *buffer = NULL; - buffer = calloc (size, 1); + buffer = malloc (size); if (buffer == NULL) { fuse_reply_err (req, ENOMEM); From 1545d4bf842c15d72c45156baf4e486c7c2cf0e1 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 10:21:44 +0200 Subject: [PATCH 07/18] main, mkdir: reuse stat when possible Signed-off-by: Giuseppe Scrivano --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 927c76e..f60cf2d 100644 --- a/main.c +++ b/main.c @@ -4131,7 +4131,7 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) memset (&e, 0, sizeof (e)); - ret = rpl_stat (req, node, -1, NULL, NULL, &e.attr); + ret = rpl_stat (req, node, -1, NULL, parent_upperdir_only ? &st : NULL, &e.attr); if (ret) { fuse_reply_err (req, errno); From 551638090f81592d284c6d6c8738b1497e400169 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 10:45:17 +0200 Subject: [PATCH 08/18] main: cache inode st_mode Signed-off-by: Giuseppe Scrivano --- main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index f60cf2d..d3ff677 100644 --- a/main.c +++ b/main.c @@ -210,8 +210,9 @@ struct ovl_node int lookups; int hidden_dirfd; int nlinks; - ino_t ino; + mode_t mode; size_t name_hash; + ino_t ino; unsigned int do_unlink : 1; unsigned int do_rmdir : 1; @@ -883,6 +884,7 @@ rpl_stat (fuse_req_t req, struct ovl_node *node, int fd, const char *path, struc st->st_nlink++; } node->nlinks = st->st_nlink; + node->mode = st->st_mode; } return ret; From 1237d05c1aa364ca814843daf77d3859fc93d522 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 10:54:13 +0200 Subject: [PATCH 09/18] main, readdir: use only st_mode and st_ino Signed-off-by: Giuseppe Scrivano --- main.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/main.c b/main.c index d3ff677..f6ac614 100644 --- a/main.c +++ b/main.c @@ -1870,20 +1870,14 @@ ovl_do_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, { int ret; size_t entsize; - struct stat st; const char *name; struct ovl_node *node = d->tbl[offset]; + struct fuse_entry_param e; + struct stat *st = &e.attr; if (node == NULL || node->whiteout || node->hidden) continue; - ret = rpl_stat (req, node, -1, NULL, NULL, &st); - if (ret < 0) - { - fuse_reply_err (req, errno); - return; - } - if (offset == 0) name = "."; else if (offset == 1) @@ -1896,17 +1890,28 @@ ovl_do_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, } if (!plus) - entsize = fuse_add_direntry (req, p, remaining, name, &st, offset + 1); + { + /* From the 'stbuf' argument the st_ino field and bits 12-15 of the + * st_mode field are used. The other fields are ignored. + */ + st->st_ino = node->ino; + st->st_mode = node->mode; + + entsize = fuse_add_direntry (req, p, remaining, name, st, offset + 1); + } else { - struct fuse_entry_param e; - memset (&e, 0, sizeof (e)); + ret = rpl_stat (req, node, -1, NULL, NULL, st); + if (ret < 0) + { + fuse_reply_err (req, errno); + return; + } + e.attr_timeout = get_timeout (lo); e.entry_timeout = get_timeout (lo); e.ino = NODE_TO_INODE (node); - memcpy (&e.attr, &st, sizeof (st)); - entsize = fuse_add_direntry_plus (req, p, remaining, name, &e, offset + 1); if (entsize <= remaining) { From c2d45f78432179182b2a16a70f4e76e613611b2f Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 11:01:22 +0200 Subject: [PATCH 10/18] main, access: use the cached mode Signed-off-by: Giuseppe Scrivano --- main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index f6ac614..d0a7798 100644 --- a/main.c +++ b/main.c @@ -2118,8 +2118,10 @@ ovl_access (fuse_req_t req, fuse_ino_t ino, int mask) fprintf (stderr, "ovl_access(ino=%" PRIu64 ", mask=%d)\n", ino, mask); - ret = faccessat (node_dirfd (n), n->path, mask, AT_SYMLINK_NOFOLLOW); - fuse_reply_err (req, ret < 0 ? errno : 0); + if (mask & n->mode == mask) + fuse_reply_err (req, 0); + else + fuse_reply_err (req, EPERM); } static int From a4ebbc8361229e02c5866c1118ad7107fd56a02e Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 12:28:18 +0200 Subject: [PATCH 11/18] main: give hint on debugging being disabled Signed-off-by: Giuseppe Scrivano --- main.c | 66 ++++++++++++++++++++++++++++----------------------------- utils.h | 3 +++ 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/main.c b/main.c index d0a7798..c1bea1b 100644 --- a/main.c +++ b/main.c @@ -961,7 +961,7 @@ ovl_forget (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) { cleanup_lock int l = enter_big_lock (); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_forget(ino=%" PRIu64 ", nlookup=%lu)\n", ino, nlookup); do_forget (ino, nlookup); @@ -974,7 +974,7 @@ ovl_forget_multi (fuse_req_t req, size_t count, struct fuse_forget_data *forgets size_t i; cleanup_lock int l = enter_big_lock (); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_forget_multi(count=%zu, forgets=%p)\n", count, forgets); @@ -1641,7 +1641,7 @@ ovl_lookup (fuse_req_t req, fuse_ino_t parent, const char *name) struct ovl_data *lo = ovl_data (req); struct ovl_node *node; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_lookup(parent=%" PRIu64 ", name=%s)\n", parent, name); @@ -1696,7 +1696,7 @@ ovl_opendir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) struct ovl_dirp *d = calloc (1, sizeof (struct ovl_dirp)); cleanup_lock int l = enter_big_lock (); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_opendir(ino=%" PRIu64 ")\n", ino); if (d == NULL) @@ -1935,7 +1935,7 @@ ovl_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info *fi) { cleanup_lock int l = enter_big_lock (); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_readdir(ino=%" PRIu64 ", size=%zu, offset=%llo)\n", ino, size, offset); ovl_do_readdir (req, ino, size, offset, fi, 0); } @@ -1945,7 +1945,7 @@ ovl_readdirplus (fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info *fi) { cleanup_lock int l = enter_big_lock (); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_readdirplus(ino=%" PRIu64 ", size=%zu, offset=%llo)\n", ino, size, offset); ovl_do_readdir (req, ino, size, offset, fi, 1); } @@ -1957,7 +1957,7 @@ ovl_releasedir (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) size_t s; struct ovl_dirp *d = ovl_dirp (fi); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_releasedir(ino=%" PRIu64 ")\n", ino); for (s = 2; s < d->tbl_size; s++) @@ -1983,7 +1983,7 @@ ovl_listxattr (fuse_req_t req, fuse_ino_t ino, size_t size) char path[PATH_MAX]; int ret; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_listxattr(ino=%" PRIu64 ", size=%zu)\n", ino, size); if (lo->disable_xattrs) @@ -2045,7 +2045,7 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) bool is_security_capability = false; int ret; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_getxattr(ino=%" PRIu64 ", name=%s, size=%zu)\n", ino, name, size); if (lo->disable_xattrs) @@ -2114,7 +2114,7 @@ ovl_access (fuse_req_t req, fuse_ino_t ino, int mask) struct ovl_data *lo = ovl_data (req); struct ovl_node *n = do_lookup_file (lo, ino, NULL); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_access(ino=%" PRIu64 ", mask=%d)\n", ino, mask); @@ -2672,7 +2672,7 @@ static void ovl_unlink (fuse_req_t req, fuse_ino_t parent, const char *name) { cleanup_lock int l = enter_big_lock (); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_unlink(parent=%" PRIu64 ", name=%s)\n", parent, name); do_rm (req, parent, name, false); @@ -2682,7 +2682,7 @@ static void ovl_rmdir (fuse_req_t req, fuse_ino_t parent, const char *name) { cleanup_lock int l = enter_big_lock (); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_rmdir(parent=%" PRIu64 ", name=%s)\n", parent, name); do_rm (req, parent, name, true); @@ -2700,7 +2700,7 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t ino, const char *name, char path[PATH_MAX]; int ret; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_setxattr(ino=%" PRIu64 "s, name=%s, value=%s, size=%zu, flags=%d)\n", ino, name, value, size, flags); @@ -2766,7 +2766,7 @@ ovl_removexattr (fuse_req_t req, fuse_ino_t ino, const char *name) char path[PATH_MAX]; int ret; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_removexattr(ino=%" PRIu64 "s, name=%s)\n", ino, name); node = do_lookup_file (lo, ino, NULL); @@ -2938,7 +2938,7 @@ ovl_read (fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info *fi) { struct fuse_bufvec buf = FUSE_BUFVEC_INIT (size); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_read(ino=%" PRIu64 ", size=%zd, " "off=%lu)\n", ino, size, (unsigned long) offset); buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; @@ -2959,7 +2959,7 @@ ovl_write_buf (fuse_req_t req, fuse_ino_t ino, out_buf.buf[0].fd = fi->fh; out_buf.buf[0].pos = off; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_write_buf(ino=%" PRIu64 ", size=%zd, off=%lu, fd=%d)\n", ino, out_buf.buf[0].size, (unsigned long) off, (int) fi->fh); @@ -2977,7 +2977,7 @@ ovl_release (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) int ret; (void) ino; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_release(ino=%" PRIu64 ")\n", ino); ret = close (fi->fh); @@ -3013,7 +3013,7 @@ ovl_create (fuse_req_t req, fuse_ino_t parent, const char *name, struct ovl_data *lo = ovl_data (req); struct ovl_node *node; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_create(parent=%" PRIu64 ", name=%s)\n", parent, name); @@ -3046,7 +3046,7 @@ ovl_open (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) cleanup_lock int l = enter_big_lock (); cleanup_close int fd = -1; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_open(ino=%" PRIu64 "s)\n", ino); fd = ovl_do_open (req, ino, NULL, fi->flags, 0700); @@ -3070,7 +3070,7 @@ ovl_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) struct ovl_node *node; struct fuse_entry_param e; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_getattr(ino=%" PRIu64 "s)\n", ino); node = do_lookup_file (lo, ino, NULL); @@ -3104,7 +3104,7 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru int fd; char proc_path[PATH_MAX]; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_setattr(ino=%" PRIu64 "s, to_set=%d)\n", ino, to_set); node = do_lookup_file (lo, ino, NULL); @@ -3259,7 +3259,7 @@ ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newn struct fuse_entry_param e; char wd_tmp_file_name[32]; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_link(ino=%" PRIu64 "s, newparent=%" PRIu64 "s, newname=%s)\n", ino, newparent, newname); node = do_lookup_file (lo, ino, NULL); @@ -3392,7 +3392,7 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na const struct fuse_ctx *ctx = fuse_req_ctx (req); char wd_tmp_file_name[32]; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_symlink(link=%s, ino=%" PRIu64 "s, name=%s)\n", link, parent, name); pnode = do_lookup_file (lo, parent, NULL); @@ -3817,7 +3817,7 @@ ovl_rename (fuse_req_t req, fuse_ino_t parent, const char *name, unsigned int flags) { cleanup_lock int l = enter_big_lock (); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_rename(ino=%" PRIu64 "s, name=%s , ino=%" PRIu64 "s, name=%s)\n", parent, name, newparent, newname); if (flags & RENAME_EXCHANGE) @@ -3833,7 +3833,7 @@ ovl_statfs (fuse_req_t req, fuse_ino_t ino) struct statvfs sfs; struct ovl_data *lo = ovl_data (req); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_statfs(ino=%" PRIu64 "s)\n", ino); ret = fstatvfs (get_upper_layer (lo)->fd, &sfs); @@ -3855,7 +3855,7 @@ ovl_readlink (fuse_req_t req, fuse_ino_t ino) size_t current_size; int ret = 0; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_readlink(ino=%" PRIu64 "s)\n", ino); node = do_lookup_file (lo, ino, NULL); @@ -3949,7 +3949,7 @@ ovl_mknod (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev const struct fuse_ctx *ctx = fuse_req_ctx (req); char wd_tmp_file_name[32]; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_mknod(ino=%" PRIu64 ", name=%s, mode=%d, rdev=%lu)\n", parent, name, mode, rdev); @@ -4055,7 +4055,7 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) char *path; cleanup_lock int l = enter_big_lock (); - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_mkdir(ino=%" PRIu64 ", name=%s, mode=%d)\n", parent, name, mode); @@ -4208,7 +4208,7 @@ do_fsync (fuse_req_t req, fuse_ino_t ino, int datasync, int fd) static void ovl_fsync (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_fsync(ino=%" PRIu64 ", datasync=%d, fi=%p)\n", ino, datasync, fi); @@ -4218,7 +4218,7 @@ ovl_fsync (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info * static void ovl_fsyncdir (fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_fsyncdir(ino=%" PRIu64 ", datasync=%d, fi=%p)\n", ino, datasync, fi); @@ -4243,7 +4243,7 @@ ovl_ioctl (fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, return; } - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_ioctl(ino=%" PRIu64 ", cmd=%d, arg=%p, fi=%p, flags=%d, buf=%p, in_bufsz=%zu, out_bufsz=%zu)\n", ino, cmd, arg, fi, flags, in_buf, in_bufsz, out_bufsz); @@ -4306,7 +4306,7 @@ ovl_fallocate (fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t len struct ovl_node *node; int ret; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_fallocate(ino=%" PRIu64 ", mode=%d, offset=%llo, length=%llu, fi=%p)\n", ino, mode, offset, length, fi); @@ -4348,7 +4348,7 @@ ovl_copy_file_range (fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fus cleanup_close int fd = -1; ssize_t ret; - if (ovl_debug (req)) + if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_copy_file_range(ino_in=%" PRIu64 ", off_in=%llo, fi_in=%p), ino_out=%" PRIu64 ", off_out=%llo, fi_out=%p, size=%zu, flags=%d)\n", ino_in, off_in, fi_in, ino_out, off_out, fi_out, len, flags); diff --git a/utils.h b/utils.h index ce11cd9..3a383ef 100644 --- a/utils.h +++ b/utils.h @@ -54,4 +54,7 @@ cleanup_dirp (DIR **p) # define cleanup_close __attribute__((cleanup (cleanup_closep))) # define cleanup_dir __attribute__((cleanup (cleanup_dirp))) +# define LIKELY(x) __builtin_expect((x),1) +# define UNLIKELY(x) __builtin_expect((x),0) + #endif From c99226b70b74d464121b5101442e0da799e9a3dd Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 11:04:54 +0200 Subject: [PATCH 12/18] main: skip RENAME_WHITEOUT if we cannot use mknod Signed-off-by: Giuseppe Scrivano --- main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.c b/main.c index c1bea1b..e8c2f54 100644 --- a/main.c +++ b/main.c @@ -766,8 +766,8 @@ hide_node (struct ovl_data *lo, struct ovl_node *node, bool unlink_src) if (unlink_src) { /* If the atomic rename+mknod failed, then fallback into doing it in two steps. */ - if (syscall (SYS_renameat2, node_dirfd (node), node->path, lo->workdir_fd, - newpath, RENAME_WHITEOUT) < 0) + if (!can_mknod || syscall (SYS_renameat2, node_dirfd (node), node->path, lo->workdir_fd, + newpath, RENAME_WHITEOUT) < 0) { if (node->parent) { From 87deb1d4585129adc222a778c978f08936368784 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 12:00:23 +0200 Subject: [PATCH 13/18] main: assume workdir is empty on startup Signed-off-by: Giuseppe Scrivano --- main.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/main.c b/main.c index e8c2f54..c0ed756 100644 --- a/main.c +++ b/main.c @@ -759,10 +759,6 @@ hide_node (struct ovl_data *lo, struct ovl_node *node, bool unlink_src) assert (node->layer == get_upper_layer (lo)); - /* Might be leftover from a previous run. */ - unlinkat (lo->workdir_fd, newpath, 0); - unlinkat (lo->workdir_fd, newpath, AT_REMOVEDIR); - if (unlink_src) { /* If the atomic rename+mknod failed, then fallback into doing it in two steps. */ From fcfd937a3d7db6e969a08f6ce1e691c87de01871 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 11:59:56 +0200 Subject: [PATCH 14/18] main, unlink: do not create a whiteout if not necessary if the parent dir is on the upper layer only, there is no need to create a whiteout file. Signed-off-by: Giuseppe Scrivano --- main.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/main.c b/main.c index c0ed756..88ab123 100644 --- a/main.c +++ b/main.c @@ -761,30 +761,39 @@ hide_node (struct ovl_data *lo, struct ovl_node *node, bool unlink_src) if (unlink_src) { - /* If the atomic rename+mknod failed, then fallback into doing it in two steps. */ - if (!can_mknod || syscall (SYS_renameat2, node_dirfd (node), node->path, lo->workdir_fd, - newpath, RENAME_WHITEOUT) < 0) + bool moved = false; + bool whiteout_created = false; + bool needs_whiteout; + + needs_whiteout = node->parent && node->parent->last_layer != get_upper_layer (lo); + + if (needs_whiteout) { - if (node->parent) + /* If the atomic rename+mknod failed, then fallback into doing it in two steps. */ + if (can_mknod && syscall (SYS_renameat2, node_dirfd (node), node->path, lo->workdir_fd, newpath, RENAME_WHITEOUT) == 0) { - /* If we are here, it means we have no permissions to use mknod. Also - since the file is not yet moved, creating a whiteout would fail on - the mknodat call. */ - if (create_whiteout (lo, node->parent, node->name, true, false) < 0) - return -1; + whiteout_created = true; + moved = true; } - if (renameat (node_dirfd (node), node->path, lo->workdir_fd, newpath) < 0) + + if (!whiteout_created) { if (node->parent) { - char whpath[PATH_MAX]; - - strconcat3 (whpath, PATH_MAX, node->parent->path, "/.wh.", node->name); - unlinkat (get_upper_layer (lo)->fd, whpath, 0); + /* If we are here, it means we have no permissions to use mknod. Also + since the file is not yet moved, creating a whiteout would fail on + the mknodat call. */ + if (create_whiteout (lo, node->parent, node->name, true, false) < 0) + return -1; } - return -1; } } + + if (!moved) + { + if (renameat (node_dirfd (node), node->path, lo->workdir_fd, newpath) < 0) + return -1; + } } else { From 16517708373b3592fb148cd01e142d0192d80da8 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 13:55:23 +0200 Subject: [PATCH 15/18] main: accept atime/noatime Signed-off-by: Giuseppe Scrivano --- main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.c b/main.c index 88ab123..863775c 100644 --- a/main.c +++ b/main.c @@ -4481,6 +4481,10 @@ fuse_opt_proc (void *data, const char *arg, int key, struct fuse_args *outargs) return 1; if (strcmp (arg, "noexec") == 0) return 1; + if (strcmp (arg, "atime") == 0) + return 1; + if (strcmp (arg, "noatime") == 0) + return 1; if (strcmp (arg, "splice_write") == 0) return 1; if (strcmp (arg, "splice_read") == 0) From c174cef9f3748ddaf3038e31338b60856b3fddf4 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 12:39:00 +0200 Subject: [PATCH 16/18] main, mkdir: delete whiteout only if necessary Signed-off-by: Giuseppe Scrivano --- main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 863775c..e123692 100644 --- a/main.c +++ b/main.c @@ -4058,6 +4058,7 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) ino_t ino = 0; int ret = 0; char *path; + bool need_delete_whiteout = true; cleanup_lock int l = enter_big_lock (); if (UNLIKELY (ovl_debug (req))) @@ -4085,6 +4086,9 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) return; } + if (pnode->loaded && node == NULL) + need_delete_whiteout = false; + parent_upperdir_only = pnode->last_layer == get_upper_layer (lo); ret = asprintf (&path, "%s/%s", pnode->path, name); @@ -4137,7 +4141,7 @@ ovl_mkdir (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) } } - if (delete_whiteout (lo, -1, pnode, name) < 0) + if (need_delete_whiteout && delete_whiteout (lo, -1, pnode, name) < 0) { fuse_reply_err (req, errno); return; From 99206771b5950346a178fd061cbe61978364223c Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 12:58:03 +0200 Subject: [PATCH 17/18] main, symlink: skip delete whiteout if not needed Signed-off-by: Giuseppe Scrivano --- main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index e123692..45b45f1 100644 --- a/main.c +++ b/main.c @@ -3396,6 +3396,7 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na struct fuse_entry_param e; const struct fuse_ctx *ctx = fuse_req_ctx (req); char wd_tmp_file_name[32]; + bool need_delete_whiteout = true; if (UNLIKELY (ovl_debug (req))) fprintf (stderr, "ovl_symlink(link=%s, ino=%" PRIu64 "s, name=%s)\n", link, parent, name); @@ -3421,6 +3422,9 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na return; } + if (pnode->loaded && node == NULL) + need_delete_whiteout = false; + sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ()); unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); @@ -3438,7 +3442,7 @@ ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *na return; } - if (delete_whiteout (lo, -1, pnode, name) < 0) + if (need_delete_whiteout && delete_whiteout (lo, -1, pnode, name) < 0) { unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); fuse_reply_err (req, errno); From 1395753e1a17da68f35ab05b805878b9da0972b1 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 23 Jul 2019 14:13:56 +0200 Subject: [PATCH 18/18] main, fsync: if fsync is disabled return ENOSYS Signed-off-by: Giuseppe Scrivano --- main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.c b/main.c index 45b45f1..884de1e 100644 --- a/main.c +++ b/main.c @@ -4180,7 +4180,7 @@ do_fsync (fuse_req_t req, fuse_ino_t ino, int datasync, int fd) if (!lo->fsync) { - fuse_reply_err (req, 0); + fuse_reply_err (req, ENOSYS); return; }