summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaghavendra G <raghavendra@gluster.com>2012-02-08 15:06:30 +0530
committerVijay Bellur <vijay@gluster.com>2012-02-21 01:05:14 -0800
commit7197111677619da96c80572a09331d6e28c1015b (patch)
tree4ebe916f4aa9b4bd34ab23a1c6ec145fd60c3b27
parent6d19136de7af9135dd23662f18c3ee544a2888da (diff)
fuse-bridge: Handle graph-switch.
The purpose of this patch is to let protocol/client know when its transports can be disconnected, without application running on gluster mount noticing any effects of graph switch. In order to do this, we migrate all fds and blocked locks to new graph. Once this migration is complete and there are no in-transit frames as viewed by fuse-bridge, we send a PARENT_DOWN event to its children. protocol/client on receiving this event, can disconnect up its transports. Change-Id: Idcea4bc43e23fb077ac16538b61335ebad84ba16 BUG: 767862 Reviewed-on: http://review.gluster.com/2734 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Vijay Bellur <vijay@gluster.com>
-rw-r--r--libglusterfs/src/fd.c97
-rw-r--r--libglusterfs/src/fd.h11
-rw-r--r--libglusterfs/src/glusterfs.h1
-rw-r--r--libglusterfs/src/xlator.h2
-rw-r--r--xlators/mount/fuse/src/fuse-bridge.c482
-rw-r--r--xlators/mount/fuse/src/fuse-bridge.h40
-rw-r--r--xlators/mount/fuse/src/fuse-helpers.c36
-rw-r--r--xlators/mount/fuse/src/fuse-mem-types.h1
-rw-r--r--xlators/mount/fuse/src/fuse-resolve.c38
9 files changed, 631 insertions, 77 deletions
diff --git a/libglusterfs/src/fd.c b/libglusterfs/src/fd.c
index ff956ec2cff..60add299dd7 100644
--- a/libglusterfs/src/fd.c
+++ b/libglusterfs/src/fd.c
@@ -168,6 +168,50 @@ gf_fd_fdtable_get_all_fds (fdtable_t *fdtable, uint32_t *count)
}
+fdentry_t *
+__gf_fd_fdtable_copy_all_fds (fdtable_t *fdtable, uint32_t *count)
+{
+ fdentry_t *fdentries = NULL;
+ size_t cpy = 0;
+
+ if (count == NULL) {
+ gf_log_callingfn ("fd", GF_LOG_WARNING, "!count");
+ goto out;
+ }
+
+ fdentries = GF_CALLOC (fdtable->max_fds, sizeof (fdentry_t),
+ gf_common_mt_fdentry_t);
+ if (fdentries == NULL) {
+ goto out;
+ }
+
+ *count = fdtable->max_fds;
+
+ cpy = fdtable->max_fds * sizeof (fdentry_t);
+ memcpy ((void *)fdentries, (void *)fdtable->fdentries, cpy);
+
+out:
+ return fdentries;
+}
+
+
+fdentry_t *
+gf_fd_fdtable_copy_all_fds (fdtable_t *fdtable, uint32_t *count)
+{
+ fdentry_t *entries = NULL;
+
+ if (fdtable) {
+ pthread_mutex_lock (&fdtable->lock);
+ {
+ entries = __gf_fd_fdtable_copy_all_fds (fdtable, count);
+ }
+ pthread_mutex_unlock (&fdtable->lock);
+ }
+
+ return entries;
+}
+
+
void
gf_fd_fdtable_destroy (fdtable_t *fdtable)
{
@@ -309,6 +353,54 @@ unlock_out:
}
+inline void
+gf_fdptr_put (fdtable_t *fdtable, fd_t *fd)
+{
+ fdentry_t *fde = NULL;
+ int32_t i = 0;
+
+ if ((fdtable == NULL) || (fd == NULL)) {
+ gf_log_callingfn ("fd", GF_LOG_ERROR, "invalid argument");
+ return;
+ }
+
+ pthread_mutex_lock (&fdtable->lock);
+ {
+ for (i = 0; i < fdtable->max_fds; i++) {
+ if (fdtable->fdentries[i].fd == fd) {
+ fde = &fdtable->fdentries[i];
+ break;
+ }
+ }
+
+ if (fde == NULL) {
+ gf_log_callingfn ("fd", GF_LOG_WARNING,
+ "fd (%p) is not present in fdtable", fd);
+ goto unlock_out;
+ }
+
+ /* If the entry is not allocated, put operation must return
+ * without doing anything.
+ * This has the potential of masking out any bugs in a user of
+ * fd that ends up calling gf_fd_put twice for the same fd or
+ * for an unallocated fd, but it is a price we have to pay for
+ * ensuring sanity of our fd-table.
+ */
+ if (fde->next_free != GF_FDENTRY_ALLOCATED)
+ goto unlock_out;
+ fde->fd = NULL;
+ fde->next_free = fdtable->first_free;
+ fdtable->first_free = i;
+ }
+unlock_out:
+ pthread_mutex_unlock (&fdtable->lock);
+
+ if ((fd != NULL) && (fde != NULL)) {
+ fd_unref (fd);
+ }
+}
+
+
fd_t *
gf_fd_fdptr_get (fdtable_t *fdtable, int64_t fd)
{
@@ -401,7 +493,7 @@ fd_destroy (fd_t *fd)
goto out;
if (IA_ISDIR (fd->inode->ia_type)) {
- for (i = 0; i < fd->xl_count; i++) {
+ for (i = 0; i < fd->xl_count; i++) {
if (fd->_ctx[i].key) {
xl = fd->_ctx[i].xl_key;
old_THIS = THIS;
@@ -464,6 +556,7 @@ fd_unref (fd_t *fd)
fd_t *
__fd_bind (fd_t *fd)
{
+ list_del_init (&fd->inode_list);
list_add (&fd->inode_list, &fd->inode->fd_list);
return fd;
@@ -502,7 +595,7 @@ __fd_create (inode_t *inode, uint64_t pid)
if (!fd)
goto out;
- fd->xl_count = inode->table->xl->graph->xl_count + 1;
+ fd->xl_count = 3 * inode->table->xl->graph->xl_count + 1;
fd->_ctx = GF_CALLOC (1, (sizeof (struct _fd_ctx) * fd->xl_count),
gf_common_mt_fd_ctx);
diff --git a/libglusterfs/src/fd.h b/libglusterfs/src/fd.h
index 531dd44f2a2..be9800b3001 100644
--- a/libglusterfs/src/fd.h
+++ b/libglusterfs/src/fd.h
@@ -154,6 +154,8 @@ fd_list_empty (struct _inode *inode);
fd_t *
fd_bind (fd_t *fd);
+fd_t *
+__fd_bind (fd_t *fd);
int
fd_ctx_set (fd_t *fd, xlator_t *xlator, uint64_t value);
@@ -184,4 +186,13 @@ __fd_ref (fd_t *fd);
void
fd_ctx_dump (fd_t *fd, char *prefix);
+fdentry_t *
+gf_fd_fdtable_copy_all_fds (fdtable_t *fdtable, uint32_t *count);
+
+fdentry_t *
+__gf_fd_fdtable_copy_all_fds (fdtable_t *fdtable, uint32_t *count);
+
+void
+gf_fdptr_put (fdtable_t *fdtable, fd_t *fd);
+
#endif /* _FD_H */
diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h
index 63c28b8cf81..75476cef801 100644
--- a/libglusterfs/src/glusterfs.h
+++ b/libglusterfs/src/glusterfs.h
@@ -388,6 +388,7 @@ typedef enum {
GF_EVENT_TRANSLATOR_OP,
GF_EVENT_AUTH_FAILED,
GF_EVENT_VOLUME_DEFRAG,
+ GF_EVENT_PARENT_DOWN,
GF_EVENT_MAXVAL,
} glusterfs_event_t;
diff --git a/libglusterfs/src/xlator.h b/libglusterfs/src/xlator.h
index 5e4216deca5..9767ad04391 100644
--- a/libglusterfs/src/xlator.h
+++ b/libglusterfs/src/xlator.h
@@ -828,6 +828,8 @@ struct _xlator {
char init_succeeded;
void *private;
struct mem_acct mem_acct;
+ uint64_t winds;
+ char switched;
};
#define xlator_has_parent(xl) (xl->parents != NULL)
diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c
index e44aca1d0c1..db2deaca29c 100644
--- a/xlators/mount/fuse/src/fuse-bridge.c
+++ b/xlators/mount/fuse/src/fuse-bridge.c
@@ -205,11 +205,11 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
inode_t *inode, struct iatt *buf)
{
- fuse_state_t *state = NULL;
- fuse_in_header_t *finh = NULL;
- struct fuse_entry_out feo = {0, };
- fuse_private_t *priv = NULL;
- inode_t *linked_inode = NULL;
+ fuse_state_t *state = NULL;
+ fuse_in_header_t *finh = NULL;
+ struct fuse_entry_out feo = {0, };
+ fuse_private_t *priv = NULL;
+ inode_t *linked_inode = NULL;
priv = this->private;
state = frame->root->state;
@@ -630,11 +630,11 @@ static int
fuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, fd_t *fd)
{
- fuse_state_t *state = NULL;
- fuse_in_header_t *finh = NULL;
- fuse_private_t *priv = NULL;
- int32_t ret = 0;
- struct fuse_open_out foo = {0, };
+ fuse_state_t *state = NULL;
+ fuse_in_header_t *finh = NULL;
+ fuse_private_t *priv = NULL;
+ int32_t ret = 0;
+ struct fuse_open_out foo = {0, };
priv = this->private;
state = frame->root->state;
@@ -677,12 +677,10 @@ fuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
goto err;
}
- fd_ref (fd);
-
if (send_fuse_obj (this, finh, &foo) == ENOENT) {
gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
"open(%s) got EINTR", state->loc.path);
- fd_unref (fd);
+ gf_fd_put (priv->fdtable, state->fd_no);
goto out;
}
@@ -695,6 +693,7 @@ fuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
strerror (op_errno));
send_fuse_err (this, finh, op_errno);
+ gf_fd_put (priv->fdtable, state->fd_no);
}
out:
free_fuse_state (state);
@@ -1141,6 +1140,11 @@ fuse_mknod_resume (fuse_state_t *state)
return;
}
+ if (state->resolve.op_errno == ENOENT) {
+ state->resolve.op_ret = 0;
+ state->resolve.op_errno = 0;
+ }
+
if (state->loc.inode) {
gf_log (state->this->name, GF_LOG_DEBUG, "inode already present");
inode_unref (state->loc.inode);
@@ -1236,6 +1240,11 @@ fuse_mkdir_resume (fuse_state_t *state)
return;
}
+ if (state->resolve.op_errno == ENOENT) {
+ state->resolve.op_ret = 0;
+ state->resolve.op_errno = 0;
+ }
+
if (state->loc.inode) {
gf_log (state->this->name, GF_LOG_DEBUG, "inode already present");
inode_unref (state->loc.inode);
@@ -1399,6 +1408,11 @@ fuse_symlink_resume (fuse_state_t *state)
return;
}
+ if (state->resolve.op_errno == ENOENT) {
+ state->resolve.op_ret = 0;
+ state->resolve.op_errno = 0;
+ }
+
if (state->loc.inode) {
gf_log (state->this->name, GF_LOG_DEBUG, "inode already present");
inode_unref (state->loc.inode);
@@ -1516,6 +1530,9 @@ fuse_rename_resume (fuse_state_t *state)
return;
}
+ state->resolve.op_ret = 0;
+ state->resolve2.op_ret = 0;
+
gf_log ("glusterfs-fuse", GF_LOG_TRACE,
"%"PRIu64": RENAME `%s (%s)' -> `%s (%s)'",
state->finh->unique, state->loc.path, loc_uuid,
@@ -1558,6 +1575,9 @@ fuse_link_resume (fuse_state_t *state)
return;
}
+ state->resolve.op_ret = 0;
+ state->resolve2.op_ret = 0;
+
if (state->loc.inode) {
inode_unref (state->loc.inode);
state->loc.inode = NULL;
@@ -1599,14 +1619,14 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
fd_t *fd, inode_t *inode, struct iatt *buf,
struct iatt *preparent, struct iatt *postparent)
{
- fuse_state_t *state = NULL;
- fuse_in_header_t *finh = NULL;
- fuse_private_t *priv = NULL;
- struct fuse_out_header fouh = {0, };
- struct fuse_entry_out feo = {0, };
- struct fuse_open_out foo = {0, };
- struct iovec iov_out[3];
- inode_t *linked_inode = NULL;
+ fuse_state_t *state = NULL;
+ fuse_in_header_t *finh = NULL;
+ fuse_private_t *priv = NULL;
+ struct fuse_out_header fouh = {0, };
+ struct fuse_entry_out feo = {0, };
+ struct fuse_open_out foo = {0, };
+ struct iovec iov_out[3];
+ inode_t *linked_inode = NULL;
state = frame->root->state;
priv = this->private;
@@ -1645,8 +1665,6 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
inode_unref (linked_inode);
- fd_ref (fd);
-
feo.nodeid = inode_to_fuse_nodeid (linked_inode);
feo.entry_valid = calc_timeout_sec (priv->entry_timeout);
@@ -1671,7 +1689,7 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
"create(%s) got EINTR", state->loc.path);
inode_forget (inode, 1);
- fd_unref (fd);
+ gf_fd_put (priv->fdtable, state->fd_no);
goto out;
}
@@ -1681,6 +1699,7 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
"%"PRIu64": %s => -1 (%s)", finh->unique,
state->loc.path, strerror (op_errno));
send_fuse_err (this, finh, op_errno);
+ gf_fd_put (priv->fdtable, state->fd_no);
}
out:
free_fuse_state (state);
@@ -1693,7 +1712,8 @@ out:
void
fuse_create_resume (fuse_state_t *state)
{
- fd_t *fd = NULL;
+ fd_t *fd = NULL;
+ fuse_private_t *priv = NULL;
if (!state->loc.parent) {
gf_log ("glusterfs-fuse", GF_LOG_WARNING,
@@ -1705,15 +1725,26 @@ fuse_create_resume (fuse_state_t *state)
return;
}
+ if (state->resolve.op_errno == ENOENT) {
+ state->resolve.op_ret = 0;
+ state->resolve.op_errno = 0;
+ }
+
if (state->loc.inode) {
- gf_log (state->this->name, GF_LOG_DEBUG, "inode already present");
+ gf_log (state->this->name, GF_LOG_DEBUG,
+ "inode already present");
inode_unref (state->loc.inode);
}
state->loc.inode = inode_new (state->loc.parent->table);
fd = fd_create (state->loc.inode, state->finh->pid);
- state->fd = fd;
+
+ priv = state->this->private;
+
+ state->fd_no = gf_fd_unused_get (priv->fdtable, fd);
+
+ state->fd = fd_ref (fd);
fd->flags = state->flags;
gf_log ("glusterfs-fuse", GF_LOG_TRACE,
@@ -1799,7 +1830,8 @@ fuse_create (xlator_t *this, fuse_in_header_t *finh, void *msg)
void
fuse_open_resume (fuse_state_t *state)
{
- fd_t *fd = NULL;
+ fd_t *fd = NULL;
+ fuse_private_t *priv = NULL;
if (!state->loc.inode) {
gf_log ("glusterfs-fuse", GF_LOG_ERROR,
@@ -1820,7 +1852,10 @@ fuse_open_resume (fuse_state_t *state)
return;
}
- state->fd = fd;
+ priv = state->this->private;
+
+ state->fd_no = gf_fd_unused_get (priv->fdtable, fd);
+ state->fd = fd_ref (fd);
fd->flags = state->flags;
gf_log ("glusterfs-fuse", GF_LOG_TRACE,
@@ -2084,18 +2119,21 @@ fuse_flush (xlator_t *this, fuse_in_header_t *finh, void *msg)
static void
fuse_release (xlator_t *this, fuse_in_header_t *finh, void *msg)
{
- struct fuse_release_in *fri = msg;
- fd_t *new_fd = NULL;
- fd_t *fd = NULL;
- uint64_t val = 0;
- int ret = 0;
- fuse_state_t *state = NULL;
- fuse_fd_ctx_t *fdctx = NULL;
+ struct fuse_release_in *fri = msg;
+ fd_t *new_fd = NULL;
+ fd_t *fd = NULL;
+ uint64_t val = 0;
+ int ret = 0;
+ fuse_state_t *state = NULL;
+ fuse_fd_ctx_t *fdctx = NULL;
+ fuse_private_t *priv = NULL;
GET_STATE (this, finh, state);
fd = FH_TO_FD (fri->fh);
state->fd = fd;
+ priv = this->private;
+
gf_log ("glusterfs-fuse", GF_LOG_TRACE,
"%"PRIu64": RELEASE %p", finh->unique, state->fd);
@@ -2113,6 +2151,10 @@ fuse_release (xlator_t *this, fuse_in_header_t *finh, void *msg)
}
fd_unref (fd);
+ state->fd = NULL;
+
+ gf_fdptr_put (priv->fdtable, fd);
+
send_fuse_err (this, finh, 0);
free_fuse_state (state);
@@ -2156,7 +2198,10 @@ fuse_fsync (xlator_t *this, fuse_in_header_t *finh, void *msg)
void
fuse_opendir_resume (fuse_state_t *state)
{
- fd_t *fd = NULL;
+ fd_t *fd = NULL;
+ fuse_private_t *priv = NULL;
+
+ priv = state->this->private;
if (!state->loc.inode) {
gf_log ("glusterfs-fuse", GF_LOG_WARNING,
@@ -2168,7 +2213,8 @@ fuse_opendir_resume (fuse_state_t *state)
}
fd = fd_create (state->loc.inode, state->finh->pid);
- state->fd = fd;
+ state->fd = fd_ref (fd);
+ state->fd_no = gf_fd_unused_get (priv->fdtable, fd);
gf_log ("glusterfs-fuse", GF_LOG_TRACE,
"%"PRIu64": OPENDIR %s", state->finh->unique,
@@ -2331,16 +2377,19 @@ fuse_readdir (xlator_t *this, fuse_in_header_t *finh, void *msg)
static void
fuse_releasedir (xlator_t *this, fuse_in_header_t *finh, void *msg)
{
- struct fuse_release_in *fri = msg;
- fd_t *new_fd = NULL;
- uint64_t val = 0;
- int ret = 0;
- fuse_state_t *state = NULL;
- fuse_fd_ctx_t *fdctx = NULL;
+ struct fuse_release_in *fri = msg;
+ fd_t *new_fd = NULL;
+ uint64_t val = 0;
+ int ret = 0;
+ fuse_state_t *state = NULL;
+ fuse_fd_ctx_t *fdctx = NULL;
+ fuse_private_t *priv = NULL;
GET_STATE (this, finh, state);
state->fd = FH_TO_FD (fri->fh);
+ priv = this->private;
+
gf_log ("glusterfs-fuse", GF_LOG_TRACE,
"%"PRIu64": RELEASEDIR %p", finh->unique, state->fd);
@@ -2360,6 +2409,10 @@ fuse_releasedir (xlator_t *this, fuse_in_header_t *finh, void *msg)
fd_unref (state->fd);
+ gf_fdptr_put (priv->fdtable, state->fd);
+
+ state->fd = NULL;
+
send_fuse_err (this, finh, 0);
free_fuse_state (state);
@@ -3409,11 +3462,321 @@ fuse_first_lookup (xlator_t *this)
int
+fuse_nameless_lookup (xlator_t *xl, uuid_t gfid, loc_t *loc)
+{
+ int ret = -1;
+ dict_t *xattr_req = NULL;
+ struct iatt iatt = {0, };
+
+ if ((loc == NULL) || (xl == NULL)) {
+ goto out;
+ }
+
+ if (loc->inode == NULL) {
+ loc->inode = inode_new (xl->itable);
+ if (loc->inode == NULL) {
+ goto out;
+ }
+ }
+
+ uuid_copy (loc->gfid, gfid);
+
+ xattr_req = dict_new ();
+ if (xattr_req == NULL) {
+ goto out;
+ }
+
+ ret = syncop_lookup (xl, loc, xattr_req, &iatt, NULL, NULL);
+ if (ret < 0) {
+ goto out;
+ }
+
+ inode_link (loc->inode, NULL, NULL, &iatt);
+
+ ret = 0;
+out:
+ if (xattr_req != NULL) {
+ dict_unref (xattr_req);
+ }
+
+ return ret;
+}
+
+
+int
+fuse_migrate_fd (xlator_t *this, fd_t *fd, xlator_t *old_subvol,
+ xlator_t *new_subvol)
+{
+ int ret = -1;
+ loc_t loc = {0, };
+ char create_in_progress = 0;
+ inode_t *old_inode = NULL;
+
+ /* could've used pthread_cond_wait, but that requires a cond variable to
+ * be mainted for each fd and that is a bit too much overhead.
+ */
+ do {
+ LOCK (&fd->inode->lock);
+ {
+ if (uuid_is_null (fd->inode->gfid)) {
+ create_in_progress = 1;
+ } else {
+ create_in_progress = 0;
+ }
+ }
+ UNLOCK (&fd->inode->lock);
+
+ if (create_in_progress) {
+ gf_log ("glusterfs-fuse", GF_LOG_INFO,
+ "create call on fd (%p) is in progress, "
+ "hence waiting", fd);
+ sleep (1);
+ }
+
+ } while (create_in_progress);
+
+ if (fd->inode->table->xl == old_subvol) {
+ ret = syncop_fsync (old_subvol, fd);
+ if (ret < 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_WARNING,
+ "syncop_fsync failed (%s)", strerror (errno));
+ }
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "fd (%p) was not "
+ "migrated during previous graph switch", fd);
+ }
+
+ loc.path = "";
+ loc.name = NULL;
+
+ ret = fuse_nameless_lookup (new_subvol, fd->inode->gfid, &loc);
+ if (ret < 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_WARNING,
+ "name-less lookup of gfid (%s) failed (%s)",
+ uuid_utoa (fd->inode->gfid), strerror (errno));
+ goto out;
+ }
+
+ old_inode = fd->inode;
+
+ inode_ref (loc.inode);
+
+ LOCK (&fd->inode->lock);
+ {
+ list_del_init (&fd->inode_list);
+ }
+ UNLOCK (&fd->inode->lock);
+
+ LOCK (&fd->lock);
+ {
+ fd->inode = loc.inode;
+ }
+ UNLOCK (&fd->lock);
+
+ if (IA_ISDIR (fd->inode->ia_type)) {
+ ret = syncop_opendir (new_subvol, &loc, fd);
+ } else {
+ ret = syncop_open (new_subvol, &loc, fd->flags, fd);
+ }
+
+ if (ret < 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_WARNING,
+ "open on gfid (%s) failed (%s)",
+ uuid_utoa (fd->inode->gfid), strerror (errno));
+ goto out;
+ }
+
+ fd_bind (fd);
+
+ ret = 0;
+out:
+ if (loc.inode != NULL) {
+ inode_unref (loc.inode);
+ }
+
+ if (old_inode != NULL) {
+ inode_unref (old_inode);
+ }
+
+ return ret;
+}
+
+
+int
+fuse_handle_opened_fds (xlator_t *this, xlator_t *old_subvol,
+ xlator_t *new_subvol)
+{
+ fuse_private_t *priv = NULL;
+ fdentry_t *fdentries = NULL;
+ uint32_t count = 0;
+ fdtable_t *fdtable = NULL;
+ int i = 0;
+ fd_t *fd = NULL;
+
+ priv = this->private;
+
+ fdtable = priv->fdtable;
+
+ fdentries = gf_fd_fdtable_copy_all_fds (fdtable, &count);
+ if (fdentries != NULL) {
+ for (i = 0; i < count; i++) {
+ fd = fdentries[i].fd;
+ if (fd != NULL) {
+ fuse_migrate_fd (this, fd, old_subvol,
+ new_subvol);
+ }
+ }
+
+ GF_FREE (fdentries);
+ }
+
+ return 0;
+}
+
+
+static int
+fuse_handle_blocked_locks (xlator_t *this, xlator_t *old_subvol,
+ xlator_t *new_subvol)
+{
+ return 0;
+}
+
+
+static int
+fuse_graph_switch_task (void *data)
+{
+ fuse_graph_switch_args_t *args = NULL;
+
+ args = data;
+ if (args == NULL) {
+ goto out;
+ }
+
+ /* don't change the order of handling open fds and blocked locks, since
+ * the act of opening files also reacquires granted locks in new graph.
+ */
+ fuse_handle_opened_fds (args->this, args->old_subvol, args->new_subvol);
+
+ fuse_handle_blocked_locks (args->this, args->old_subvol,
+ args->new_subvol);
+
+ pthread_mutex_lock (&args->lock);
+ {
+ args->complete = 1;
+ pthread_cond_broadcast (&args->cond);
+ }
+ pthread_mutex_unlock (&args->lock);
+out:
+ return 0;
+}
+
+
+fuse_graph_switch_args_t *
+fuse_graph_switch_args_alloc (void)
+{
+ fuse_graph_switch_args_t *args = NULL;
+
+ args = GF_CALLOC (1, sizeof (*args), gf_fuse_mt_graph_switch_args_t);
+ if (args == NULL) {
+ goto out;
+ }
+
+ pthread_cond_init (&args->cond, NULL);
+ pthread_mutex_init (&args->lock, NULL);
+
+out:
+ return args;
+}
+
+
+void
+fuse_graph_switch_args_destroy (fuse_graph_switch_args_t *args)
+{
+ if (args == NULL) {
+ goto out;
+ }
+
+ pthread_cond_destroy (&args->cond);
+ pthread_mutex_destroy (&args->lock);
+
+ GF_FREE (args);
+out:
+ return;
+}
+
+
+static int
+fuse_graph_switch_complete (int ret, call_frame_t *frame, void *data)
+{
+ return 0;
+}
+
+
+int
+fuse_handle_graph_switch (xlator_t *this, xlator_t *old_subvol,
+ xlator_t *new_subvol)
+{
+ call_frame_t *frame = NULL;
+ int32_t ret = -1;
+ fuse_graph_switch_args_t *args = NULL;
+
+ frame = create_frame (this, this->ctx->pool);
+ if (frame == NULL) {
+ goto out;
+ }
+
+ args = fuse_graph_switch_args_alloc ();
+ if (args == NULL) {
+ goto out;
+ }
+
+ args->this = this;
+ args->old_subvol = old_subvol;
+ args->new_subvol = new_subvol;
+
+ ret = synctask_new (this->ctx->env, fuse_graph_switch_task,
+ fuse_graph_switch_complete, frame, args);
+ if (ret == -1) {
+ gf_log (this->name, GF_LOG_WARNING, "starting sync-task to "
+ "handle graph switch failed");
+ goto out;
+ }
+
+ pthread_mutex_lock (&args->lock);
+ {
+ while (!args->complete) {
+ ret = pthread_cond_wait (&args->cond, &args->lock);
+ if (ret != 0) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "cond_wait failed ret:%d errno:%d", ret,
+ errno);
+ }
+ }
+ }
+ pthread_mutex_unlock (&args->lock);
+
+ ret = 0;
+out:
+ if (args != NULL) {
+ fuse_graph_switch_args_destroy (args);
+ }
+
+ if (frame != NULL) {
+ STACK_DESTROY (frame->root);
+ }
+
+ return ret;
+}
+
+
+int
fuse_graph_sync (xlator_t *this)
{
- fuse_private_t *priv = NULL;
- int need_first_lookup = 0;
- int ret = 0;
+ fuse_private_t *priv = NULL;
+ int need_first_lookup = 0;
+ int ret = 0;
+ xlator_t *old_subvol = NULL, *new_subvol = NULL;
+ uint64_t winds_on_old_subvol = 0;
priv = this->private;
@@ -3422,7 +3785,8 @@ fuse_graph_sync (xlator_t *this)
if (!priv->next_graph)
goto unlock;
- priv->active_subvol = priv->next_graph->top;
+ old_subvol = priv->active_subvol;
+ new_subvol = priv->active_subvol = priv->next_graph->top;
priv->next_graph = NULL;
need_first_lookup = 1;
@@ -3444,6 +3808,22 @@ unlock:
fuse_first_lookup (this);
}
+ if ((old_subvol != NULL) && (new_subvol != NULL)) {
+ fuse_handle_graph_switch (this, old_subvol, new_subvol);
+
+ pthread_mutex_lock (&priv->sync_mutex);
+ {
+ old_subvol->switched = 1;
+ winds_on_old_subvol = old_subvol->winds;
+ }
+ pthread_mutex_unlock (&priv->sync_mutex);
+
+ if (winds_on_old_subvol == 0) {
+ xlator_notify (old_subvol, GF_EVENT_PARENT_DOWN,
+ old_subvol, NULL);
+ }
+ }
+
return 0;
}
@@ -4068,6 +4448,12 @@ init (xlator_t *this_xl)
if (!fsname)
fsname = "glusterfs";
+ priv->fdtable = gf_fd_fdtable_alloc ();
+ if (priv->fdtable == NULL) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR, "Out of memory");
+ goto cleanup_exit;
+ }
+
gf_asprintf (&mnt_args, "%s%sallow_other,max_read=131072",
priv->read_only ? "ro," : "",
priv->acl ? "" : "default_permissions,");
diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h
index d9783f2e054..13c026bcff7 100644
--- a/xlators/mount/fuse/src/fuse-bridge.h
+++ b/xlators/mount/fuse/src/fuse-bridge.h
@@ -54,6 +54,7 @@
#include "list.h"
#include "dict.h"
+#include "syncop.h"
#if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__)
#define FUSE_OP_HIGH (FUSE_POLL + 1)
@@ -109,6 +110,7 @@ struct fuse_private {
unsigned uid_map_root;
gf_boolean_t acl;
gf_boolean_t read_only;
+ fdtable_t *fdtable;
/* For fuse-reverse-validation */
int revchan_in;
@@ -117,6 +119,16 @@ struct fuse_private {
};
typedef struct fuse_private fuse_private_t;
+struct fuse_graph_switch_args {
+ xlator_t *this;
+ xlator_t *old_subvol;
+ xlator_t *new_subvol;
+ pthread_cond_t cond;
+ pthread_mutex_t lock;
+ char complete;
+};
+typedef struct fuse_graph_switch_args fuse_graph_switch_args_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) + \
@@ -131,6 +143,7 @@ typedef struct fuse_private fuse_private_t;
do { \
call_frame_t *frame = NULL; \
xlator_t *xl = NULL; \
+ int32_t op_ret = 0, op_errno = 0; \
\
frame = get_call_frame_for_req (state); \
if (!frame) { \
@@ -140,7 +153,7 @@ typedef struct fuse_private fuse_private_t;
* better than trying to go on with a NULL \
* frame ... \
*/ \
- gf_log ("glusterfs-fuse", \
+ gf_log_callingfn ("glusterfs-fuse", \
GF_LOG_ERROR, \
"FUSE message" \
" unique %"PRIu64" opcode %d:" \
@@ -159,9 +172,27 @@ typedef struct fuse_private fuse_private_t;
\
xl = state->active_subvol; \
if (!xl) { \
- gf_log ("glusterfs-fuse", GF_LOG_ERROR, \
- "xl is NULL"); \
- send_fuse_err (state->this, state->finh, ENOENT); \
+ gf_log_callingfn ("glusterfs-fuse", GF_LOG_ERROR, \
+ "xl is NULL"); \
+ op_errno = ENOENT; \
+ op_ret = -1; \
+ } else if (state->resolve.op_ret < 0) { \
+ op_errno = state->resolve.op_errno; \
+ op_ret = -1; \
+/* gf_log_callingfn ("glusterfs-fuse", GF_LOG_WARNING, \
+ "resolve failed (%s)", \
+ strerror (op_errno)); */ \
+ } else if (state->resolve2.op_ret < 0) { \
+ op_errno = state->resolve2.op_errno; \
+ op_ret = -1; \
+ /* gf_log_callingfn ("glusterfs-fuse", GF_LOG_WARNING, \
+ "resolve of second entity " \
+ "failed (%s)", \
+ strerror (op_errno)); */ \
+ } \
+ \
+ if (op_ret < 0) { \
+ send_fuse_err (state->this, state->finh, op_errno); \
free_fuse_state (state); \
STACK_DESTROY (frame->root); \
} else { \
@@ -293,6 +324,7 @@ typedef struct {
uuid_t gfid;
uint32_t io_flags;
+ int32_t fd_no;
} fuse_state_t;
typedef struct fuse_fd_ctx {
diff --git a/xlators/mount/fuse/src/fuse-helpers.c b/xlators/mount/fuse/src/fuse-helpers.c
index c794813cf3c..6aee697158c 100644
--- a/xlators/mount/fuse/src/fuse-helpers.c
+++ b/xlators/mount/fuse/src/fuse-helpers.c
@@ -57,6 +57,15 @@ fuse_resolve_wipe (fuse_resolve_t *resolve)
void
free_fuse_state (fuse_state_t *state)
{
+ xlator_t *this = NULL;
+ fuse_private_t *priv = NULL;
+ uint64_t winds = 0;
+ char switched = 0;
+
+ this = state->this;
+
+ priv = this->private;
+
loc_wipe (&state->loc);
loc_wipe (&state->loc2);
@@ -81,6 +90,18 @@ free_fuse_state (fuse_state_t *state)
fuse_resolve_wipe (&state->resolve);
fuse_resolve_wipe (&state->resolve2);
+ pthread_mutex_lock (&priv->sync_mutex);
+ {
+ winds = --state->active_subvol->winds;
+ switched = state->active_subvol->switched;
+ }
+ pthread_mutex_unlock (&priv->sync_mutex);
+
+ if ((winds == 0) && (switched)) {
+ xlator_notify (state->active_subvol, GF_EVENT_PARENT_DOWN,
+ state->active_subvol, NULL);
+ }
+
#ifdef DEBUG
memset (state, 0x90, sizeof (*state));
#endif
@@ -92,8 +113,9 @@ free_fuse_state (fuse_state_t *state)
fuse_state_t *
get_fuse_state (xlator_t *this, fuse_in_header_t *finh)
{
- fuse_state_t *state = NULL;
- xlator_t *active_subvol = NULL;
+ fuse_state_t *state = NULL;
+ xlator_t *active_subvol = NULL;
+ fuse_private_t *priv = NULL;
state = (void *)GF_CALLOC (1, sizeof (*state),
gf_fuse_mt_fuse_state_t);
@@ -101,7 +123,15 @@ get_fuse_state (xlator_t *this, fuse_in_header_t *finh)
return NULL;
state->this = THIS;
- active_subvol = fuse_active_subvol (state->this);
+ priv = this->private;
+
+ pthread_mutex_lock (&priv->sync_mutex);
+ {
+ active_subvol = fuse_active_subvol (state->this);
+ active_subvol->winds++;
+ }
+ pthread_mutex_unlock (&priv->sync_mutex);
+
state->active_subvol = active_subvol;
state->itable = active_subvol->itable;
diff --git a/xlators/mount/fuse/src/fuse-mem-types.h b/xlators/mount/fuse/src/fuse-mem-types.h
index 1fb959c3a44..9c6a1c67a7a 100644
--- a/xlators/mount/fuse/src/fuse-mem-types.h
+++ b/xlators/mount/fuse/src/fuse-mem-types.h
@@ -30,6 +30,7 @@ enum gf_fuse_mem_types_ {
gf_fuse_mt_iov_base,
gf_fuse_mt_fuse_state_t,
gf_fuse_mt_fd_ctx_t,
+ gf_fuse_mt_graph_switch_args_t,
gf_fuse_mt_end
};
#endif
diff --git a/xlators/mount/fuse/src/fuse-resolve.c b/xlators/mount/fuse/src/fuse-resolve.c
index 1af80b93c57..5a09ea0d3e9 100644
--- a/xlators/mount/fuse/src/fuse-resolve.c
+++ b/xlators/mount/fuse/src/fuse-resolve.c
@@ -80,11 +80,13 @@ fuse_resolve_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
STACK_DESTROY (frame->root);
if (op_ret == -1) {
- gf_log (this->name, ((op_errno == ENOENT) ? GF_LOG_DEBUG :
- GF_LOG_WARNING),
+ gf_log (this->name, (op_errno == ENOENT)
+ ? GF_LOG_DEBUG : GF_LOG_WARNING,
"%s/%s: failed to resolve (%s)",
uuid_utoa (resolve_loc->pargfid), resolve_loc->name,
strerror (op_errno));
+ resolve->op_ret = -1;
+ resolve->op_errno = op_errno;
goto out;
}
@@ -141,12 +143,14 @@ fuse_resolve_gfid_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
STACK_DESTROY (frame->root);
if (op_ret == -1) {
- gf_log (this->name, ((op_errno == ENOENT) ? GF_LOG_DEBUG :
- GF_LOG_WARNING),
+ gf_log (this->name, (op_errno == ENOENT)
+ ? GF_LOG_DEBUG : GF_LOG_WARNING,
"%s: failed to resolve (%s)",
uuid_utoa (resolve->resolve_loc.gfid),
strerror (op_errno));
loc_wipe (&resolve->resolve_loc);
+ resolve->op_ret = -1;
+ resolve->op_errno = op_errno;
goto out;
}
@@ -163,6 +167,7 @@ fuse_resolve_gfid_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
}
loc_now->parent = link_inode;
+ uuid_copy (loc_now->pargfid, link_inode->gfid);
fuse_resolve_entry (state);
@@ -237,13 +242,12 @@ fuse_resolve_parent_simple (fuse_state_t *state)
parent = inode_find (state->itable, resolve->pargfid);
if (!parent) {
- resolve->op_ret = -1;
- resolve->op_errno = ENOENT;
/* non decisive result - parent missing */
return 1;
}
loc->parent = parent;
+ uuid_copy (loc->pargfid, resolve->pargfid);
inode = inode_grep (state->itable, parent, loc->name);
if (inode) {
@@ -261,9 +265,6 @@ int
fuse_resolve_parent (fuse_state_t *state)
{
int ret = 0;
- loc_t *loc = NULL;
-
- loc = state->loc_now;
ret = fuse_resolve_parent_simple (state);
if (ret > 0) {
@@ -302,9 +303,6 @@ fuse_resolve_inode_simple (fuse_state_t *state)
if (inode)
goto found;
- resolve->op_ret = -1;
- resolve->op_errno = ENOENT;
-
return 1;
found:
loc->inode = inode;
@@ -316,9 +314,6 @@ int
fuse_resolve_inode (fuse_state_t *state)
{
int ret = 0;
- loc_t *loc = NULL;
-
- loc = state->loc_now;
ret = fuse_resolve_inode_simple (state);
@@ -344,7 +339,14 @@ fuse_resolve_fd (fuse_state_t *state)
fd = resolve->fd;
active_subvol = fd->inode->table->xl;
- state->active_subvol = active_subvol;
+ if (state->active_subvol != active_subvol) {
+ resolve->op_ret = -1;
+ resolve->op_errno = EBADF;
+ gf_log ("fuse-resolve", GF_LOG_WARNING, "migration of fd (%p) "
+ "did not complete, failing fop with EBADF", fd);
+ }
+
+ /* state->active_subvol = active_subvol; */
fuse_resolve_continue (state);
@@ -434,10 +436,6 @@ fuse_resolve (fuse_state_t *state)
fuse_resolve_inode (state);
} else {
-
- resolve->op_ret = 0;
- resolve->op_errno = EINVAL;
-
fuse_resolve_all (state);
}