From 1d38ec6ce40279d7e8ef2b5a9bd59a2d289eca23 Mon Sep 17 00:00:00 2001 From: Amar Tumballi Date: Thu, 24 Nov 2011 15:42:55 +0530 Subject: fuse: bring in the reverse invalidation Thanks to Csaba Henk for the patch Currently one can invalidate the inodes using 'setxattr()' with key 'inode-invalidate' (and any value). This can be further extended to do a purge of inode table itself. Change-Id: I165d5d585ed808b9e463ac0aad859ec64568c7a2 BUG: 762277 Signed-off-by: Amar Tumballi Reviewed-on: http://review.gluster.com/324 Tested-by: Gluster Build System Reviewed-by: Anand Avati --- xlators/mount/fuse/src/fuse-bridge.c | 139 +++++++++++++++++++++++++++++++++-- xlators/mount/fuse/src/fuse-bridge.h | 11 +++ 2 files changed, 145 insertions(+), 5 deletions(-) (limited to 'xlators/mount/fuse') diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index ae3dd4c0b..7e66668a3 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -145,6 +145,54 @@ send_fuse_data (xlator_t *this, fuse_in_header_t *finh, void *data, size_t size) #define send_fuse_obj(this, finh, obj) \ send_fuse_data (this, finh, obj, sizeof (*(obj))) + +static void +fuse_invalidate (xlator_t *this, uint64_t fuse_ino) +{ + struct fuse_out_header *fouh = NULL; + struct fuse_notify_inval_entry_out *fnieo = NULL; + fuse_private_t *priv = NULL; + dentry_t *dentry = NULL; + inode_t *inode = NULL; + size_t nlen = 0; + int rv = 0; + + char inval_buf[INVAL_BUF_SIZE] = {0,}; + + fouh = (struct fuse_out_header *)inval_buf; + fnieo = (struct fuse_notify_inval_entry_out *)(fouh + 1); + + priv = this->private; + if (priv->revchan_out == -1) + return; + + fouh->unique = 0; + fouh->error = FUSE_NOTIFY_INVAL_ENTRY; + + inode = fuse_ino_to_inode (fuse_ino, this); + + list_for_each_entry (dentry, &inode->dentry_list, inode_list) { + nlen = strlen (dentry->name); + fouh->len = sizeof (*fouh) + sizeof (*fnieo) + nlen + 1; + fnieo->parent = inode_to_fuse_nodeid (dentry->parent); + + fnieo->namelen = nlen; + strcpy (inval_buf + sizeof (*fouh) + sizeof (*fnieo), dentry->name); + + rv = write (priv->revchan_out, inval_buf, fouh->len); + if (rv != fouh->len) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "kernel notification daemon defunct"); + + close (priv->fd); + break; + } + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, "INVALIDATE entry: " + "%"PRIu64"/%s", fnieo->parent, dentry->name); + } +} + int send_fuse_err (xlator_t *this, fuse_in_header_t *finh, int error) { @@ -355,6 +403,10 @@ fuse_forget (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": FORGET %"PRIu64"/%"PRIu64, + finh->unique, finh->nodeid, ffi->nlookup); + fuse_inode = fuse_ino_to_inode (finh->nodeid, this); inode_forget (fuse_inode, ffi->nlookup); @@ -2512,6 +2564,15 @@ fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } + if (!strcmp ("inode-invalidate", name)) { + gf_log ("fuse", GF_LOG_TRACE, + "got request to invalidate %"PRIu64, finh->nodeid); + send_fuse_err (this, finh, 0); + fuse_invalidate (this, finh->nodeid); + GF_FREE (finh); + return; + } + GET_STATE (this, finh, state); state->size = fsi->size; ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL); @@ -3031,14 +3092,52 @@ fuse_setlk (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } +static void * +notify_kernel_loop (void *data) +{ + xlator_t *this = NULL; + fuse_private_t *priv = NULL; + struct fuse_out_header *fouh = NULL; + int rv = 0; + + char inval_buf[INVAL_BUF_SIZE] = {0,}; + + this = data; + priv = this->private; + + for (;;) { + rv = read (priv->revchan_in, inval_buf, sizeof (*fouh)); + if (rv != sizeof (*fouh)) + break; + fouh = (struct fuse_out_header *)inval_buf; + rv = read (priv->revchan_in, inval_buf + sizeof (*fouh), + fouh->len - sizeof (*fouh)); + if (rv != fouh->len - sizeof (*fouh)) + break; + rv = write (priv->fd, inval_buf, fouh->len); + if (rv != fouh->len && !(rv == -1 && errno == ENOENT)) + break; + } + + close (priv->revchan_in); + close (priv->revchan_out); + + gf_log ("glusterfs-fuse", GF_LOG_INFO, + "kernel notifier loop terminated"); + + return NULL; +} + + static void fuse_init (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_init_in *fini = msg; - - struct fuse_init_out fino; - fuse_private_t *priv = NULL; - int ret; + struct fuse_init_in *fini = msg; + struct fuse_init_out fino = {0,}; + fuse_private_t *priv = NULL; + int ret = 0; + int pfd[2] = {0,}; + pthread_t messenger; priv = this->private; @@ -3075,6 +3174,31 @@ fuse_init (xlator_t *this, fuse_in_header_t *finh, void *msg) priv->direct_io_mode = 0; fino.flags |= FUSE_BIG_WRITES; } + + /* Used for 'reverse invalidation of inode' */ + if (fini->minor >= 12) { + if (pipe(pfd) == -1) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "cannot create pipe pair (%s)", + strerror(errno)); + + close (priv->fd); + goto out; + } + priv->revchan_in = pfd[0]; + priv->revchan_out = pfd[1]; + ret = pthread_create (&messenger, NULL, notify_kernel_loop, + this); + if (ret != 0) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "failed to start messenger daemon (%s)", + strerror(errno)); + + close (priv->fd); + goto out; + } + priv->reverse_fuse_thread_started = _gf_true; + } if (fini->minor >= 13) { /* these values seemed to work fine during testing */ @@ -3418,6 +3542,7 @@ fuse_thread_proc (void *data) return NULL; } + int32_t fuse_itable_dump (xlator_t *this) { @@ -3468,6 +3593,8 @@ fuse_priv_dump (xlator_t *this) (int)private->init_recvd); gf_proc_dump_write("strict_volfile_check", "%d", (int)private->strict_volfile_check); + gf_proc_dump_write("reverse_thread_started", "%d", + (int)private->reverse_fuse_thread_started); return 0; } @@ -3717,6 +3844,8 @@ init (xlator_t *this_xl) this_xl->private = (void *) priv; priv->mount_point = NULL; priv->fd = -1; + priv->revchan_in = -1; + priv->revchan_out = -1; /* get options from option dictionary */ ret = dict_get_str (options, ZR_MOUNTPOINT_OPT, &value_string); diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h index b7ca9b08e..39b54f6fe 100644 --- a/xlators/mount/fuse/src/fuse-bridge.h +++ b/xlators/mount/fuse/src/fuse-bridge.h @@ -109,9 +109,20 @@ struct fuse_private { unsigned uid_map_root; gf_boolean_t acl; gf_boolean_t read_only; + + /* For fuse-reverse-validation */ + int revchan_in; + int revchan_out; + gf_boolean_t reverse_fuse_thread_started; }; typedef struct fuse_private fuse_private_t; +#define INVAL_BUF_SIZE (sizeof (struct fuse_out_header) + \ + max (sizeof (struct fuse_notify_inval_inode_out), \ + sizeof (struct fuse_notify_inval_entry_out) + \ + NAME_MAX + 1)) + + #define _FH_TO_FD(fh) ((fd_t *)(uintptr_t)(fh)) #define FH_TO_FD(fh) ((_FH_TO_FD (fh))?(fd_ref (_FH_TO_FD (fh))):((fd_t *) 0)) -- cgit