summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 ff956ec2c..60add299d 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 531dd44f2..be9800b30 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 63c28b8cf..75476cef8 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 5e4216dec..9767ad043 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 e44aca1d0..db2deaca2 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 d9783f2e0..13c026bcf 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 c794813cf..6aee69715 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 1fb959c3a..9c6a1c67a 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 1af80b93c..5a09ea0d3 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);
}