features/snapview-client: handle readdir requests differently for samba

* For samba export, the entry point is also added to the readdir response.

Change-Id: I825c017e0f16db1f1890bb56e086f36e6558a1c2
BUG: 1168875
Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
Reviewed-on: http://review.gluster.org/9218
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
This commit is contained in:
Raghavendra Bhat 2014-11-28 18:08:53 +05:30 committed by Vijay Bellur
parent ad1ed80060
commit 7cfa31434e
7 changed files with 722 additions and 9 deletions

View File

@ -248,4 +248,52 @@ world) can be changed using the below command.
*gluster volume set <volname> snapshot-directory <new-name>*
3) Accessing from windows:
The glusterfs volumes can be made accessible by windows via samba. (the
glusterfs plugin for samba helps achieve this, without having to re-export
a fuse mounted glusterfs volume). The snapshots of a glusterfs volume can
also be viewed in the windows explorer.
There are 2 ways:
* Give the path of the entry point directory
(\\<hostname>\<samba-share>\<directory>\<entry-point path>) in the run command
window
* Go to the samba share via windows explorer. Make hidden files and folders
visible so that in the root of the samba share a folder icon for the entry point
can be seen.
NOTE: From the explorer, snapshot world can be entered via entry point only from
the root of the samba share. If snapshots have to be seen from subfolders, then
the path should be provided in the run command window.
For snapshots to be accessible from windows, below 2 options can be used.
A) The glusterfs plugin for samba should give the option "snapdir-entry-path"
while starting. The option is an indication to glusterfs, that samba is loading
it and the value of the option should be the path that is being used as the
share for windows.
Ex: Say, there is a glusterfs volume and a directory called "export" from the
root of the volume is being used as the samba share, then samba has to load
glusterfs with this option as well.
ret = glfs_set_xlator_option(fs, "*-snapview-client",
"snapdir-entry-path", "/export");
The xlator option "snapdir-entry-path" is not exposed via volume set options,
cannot be changed from CLI. Its an option that has to be provded at the time of
mounting glusterfs or when samba loads glusterfs.
B) The accessibility of snapshots via root of the samba share from windows
is configurable. By default it is turned off. It is a volume set option which can
be changed via CLI.
gluster volume set <volname> features.show-snapshot-directory "on/off". By
default it is off.
Only when both the above options have been provided (i.e snapdir-entry-path
contains a valid unix path that is exported and show-snapshot-directory option
is set to true), snapshots can accessed via windows explorer.
If only 1st option (i.e. snapdir-entry-path) is set via samba and 2nd option
(i.e. show-snapshot-directory) is off, then snapshots can be accessed from
windows via the run command window, but not via the explorer.
--------------------------------------------------------------------------------------

96
tests/bugs/bug-1168875.t Normal file
View File

@ -0,0 +1,96 @@
#!/bin/bash
. $(dirname $0)/../include.rc
. $(dirname $0)/../volume.rc
. $(dirname $0)/../snapshot.rc
. $(dirname $0)/../fileio.rc
. $(dirname $0)/../nfs.rc
cleanup;
function check_entry_point_exists ()
{
local entry_point=$1;
local _path=$2;
ls -a $_path | grep $entry_point;
if [ $? -eq 0 ]; then
echo 'Y';
else
echo 'N';
fi
}
TEST init_n_bricks 3;
TEST setup_lvm 3;
TEST glusterd;
TEST pidof glusterd;
TEST $CLI volume create $V0 $H0:$L1 $H0:$L2 $H0:$L3;
TEST $CLI volume start $V0;
TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 --xlator-option *-snapview-client.snapdir-entry-path=/dir $M0;
TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 $N0;
for i in {1..10} ; do echo "file" > $M0/file$i ; done
for i in {11..20} ; do echo "file" > $M0/file$i ; done
mkdir $M0/dir;
for i in {1..10} ; do echo "file" > $M0/dir/file$i ; done
mkdir $M0/dir1;
mkdir $M0/dir2;
for i in {1..10} ; do echo "foo" > $M0/dir1/foo$i ; done
for i in {1..10} ; do echo "foo" > $M0/dir2/foo$i ; done
for i in {11..20} ; do echo "foo" > $M0/dir1/foo$i ; done
for i in {11..20} ; do echo "foo" > $M0/dir2/foo$i ; done
TEST $CLI snapshot create snap1 $V0;
TEST $CLI snapshot activate snap1;
TEST $CLI volume set $V0 features.uss enable;
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Y' check_if_snapd_exist
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists .snaps $M0/dir
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists .snaps $N0/dir
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists .snaps $M0/dir1
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists .snaps $N0/dir1
TEST $CLI volume set $V0 features.show-snapshot-directory enable;
EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $M0/dir
EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $N0/dir
EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $M0/dir1
EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $N0/dir1
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Y' check_entry_point_exists ".snaps" $M0/dir
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists ".snaps" $N0/dir
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists ".snaps" $M0/dir1
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists ".snaps" $N0/dir1
TEST $CLI volume set $V0 features.show-snapshot-directory disable;
EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $M0/dir
EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $N0/dir
EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $M0/dir1
EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $N0/dir1
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists ".snaps" $M0/dir
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists ".snaps" $N0/dir
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists ".snaps" $M0/dir1
EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'N' check_entry_point_exists ".snaps" $N0/dir1
cleanup;

View File

@ -17,6 +17,7 @@ enum svc_mem_types {
gf_svc_mt_svc_private_t = gf_common_mt_end + 1,
gf_svc_mt_svc_local_t,
gf_svc_mt_svc_inode_t,
gf_svc_mt_svc_fd_t,
gf_svc_mt_end
};

View File

@ -1,4 +1,4 @@
/*
/*
Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
@ -23,6 +23,10 @@ svc_local_free (svc_local_t *local)
{
if (local) {
loc_wipe (&local->loc);
if (local->fd)
fd_unref (local->fd);
if (local->xdata)
dict_unref (local->xdata);
mem_put (local);
}
}
@ -115,6 +119,150 @@ out:
return ret;
}
svc_fd_t *
svc_fd_new (void)
{
svc_fd_t *svc_fd = NULL;
svc_fd = GF_CALLOC (1, sizeof (*svc_fd), gf_svc_mt_svc_fd_t);
return svc_fd;
}
svc_fd_t *
__svc_fd_ctx_get (xlator_t *this, fd_t *fd)
{
svc_fd_t *svc_fd = NULL;
uint64_t value = 0;
int ret = -1;
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
GF_VALIDATE_OR_GOTO (this->name, fd, out);
ret = __fd_ctx_get (fd, this, &value);
if (ret)
return NULL;
svc_fd = (svc_fd_t *) ((long) value);
out:
return svc_fd;
}
svc_fd_t *
svc_fd_ctx_get (xlator_t *this, fd_t *fd)
{
svc_fd_t *svc_fd = NULL;
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
GF_VALIDATE_OR_GOTO (this->name, fd, out);
LOCK (&fd->lock);
{
svc_fd = __svc_fd_ctx_get (this, fd);
}
UNLOCK (&fd->lock);
out:
return svc_fd;
}
int
__svc_fd_ctx_set (xlator_t *this, fd_t *fd, svc_fd_t *svc_fd)
{
uint64_t value = 0;
int ret = -1;
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
GF_VALIDATE_OR_GOTO (this->name, fd, out);
GF_VALIDATE_OR_GOTO (this->name, svc_fd, out);
value = (uint64_t)(long) svc_fd;
ret = __fd_ctx_set (fd, this, value);
out:
return ret;
}
int32_t
svc_fd_ctx_set (xlator_t *this, fd_t *fd, svc_fd_t *svc_fd)
{
int32_t ret = -1;
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
GF_VALIDATE_OR_GOTO (this->name, fd, out);
GF_VALIDATE_OR_GOTO (this->name, svc_fd, out);
LOCK (&fd->lock);
{
ret = __svc_fd_ctx_set (this, fd, svc_fd);
}
UNLOCK (&fd->lock);
out:
return ret;
}
svc_fd_t *
__svc_fd_ctx_get_or_new (xlator_t *this, fd_t *fd)
{
svc_fd_t *svc_fd = NULL;
int ret = -1;
inode_t *inode = NULL;
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
GF_VALIDATE_OR_GOTO (this->name, fd, out);
inode = fd->inode;
svc_fd = __svc_fd_ctx_get (this, fd);
if (svc_fd) {
ret = 0;
goto out;
}
svc_fd = svc_fd_new ();
if (!svc_fd) {
gf_log (this->name, GF_LOG_ERROR, "failed to allocate new fd "
"context for gfid %s", uuid_utoa (inode->gfid));
goto out;
}
ret = __svc_fd_ctx_set (this, fd, svc_fd);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, "failed to set fd context "
"for gfid %s", uuid_utoa (inode->gfid));
ret = -1;
}
out:
if (ret) {
GF_FREE (svc_fd);
svc_fd = NULL;
}
return svc_fd;
}
svc_fd_t *
svc_fd_ctx_get_or_new (xlator_t *this, fd_t *fd)
{
svc_fd_t *svc_fd = NULL;
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
GF_VALIDATE_OR_GOTO (this->name, fd, out);
LOCK (&fd->lock);
{
svc_fd = __svc_fd_ctx_get_or_new (this, fd);
}
UNLOCK (&fd->lock);
out:
return svc_fd;
}
int32_t
svc_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, inode_t *inode,
@ -337,7 +485,7 @@ svc_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc,
out:
if (wind)
STACK_WIND (frame, svc_lookup_cbk,
subvolume, subvolume->fops->lookup, loc, xdata);
subvolume, subvolume->fops->lookup, loc, xdata);
else
SVC_STACK_UNWIND (lookup, frame, op_ret, op_errno, NULL,
NULL, NULL, NULL);
@ -413,6 +561,63 @@ out:
return ret;
}
int32_t
svc_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata)
{
svc_fd_t *svc_fd = NULL;
svc_local_t *local = NULL;
svc_private_t *priv = NULL;
gf_boolean_t special_dir = _gf_false;
char path[PATH_MAX] = {0, };
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
GF_VALIDATE_OR_GOTO (this->name, this->private, out);
if (op_ret)
goto out;
priv = this->private;
local = frame->local;
if (local->subvolume == FIRST_CHILD (this) && priv->special_dir
&& strcmp (priv->special_dir, "")) {
if (!__is_root_gfid (fd->inode->gfid))
snprintf (path, sizeof (path), "%s/.",
priv->special_dir);
else
snprintf (path, sizeof (path), "/.");
if (!strcmp (local->loc.path, priv->special_dir) ||
!strcmp (local->loc.path, path)) {
gf_log_callingfn (this->name, GF_LOG_DEBUG,
"got opendir on special "
"directory %s (%s)", path,
uuid_utoa (fd->inode->gfid));
special_dir = _gf_true;
}
}
if (special_dir) {
svc_fd = svc_fd_ctx_get_or_new (this, fd);
if (!svc_fd) {
gf_log (this->name, GF_LOG_ERROR,
"fd context not found for %s",
uuid_utoa (fd->inode->gfid));
goto out;
}
svc_fd->last_offset = -1;
svc_fd->special_dir = special_dir;
}
out:
STACK_UNWIND_STRICT (opendir, frame, op_ret, op_errno, fd, xdata);
return 0;
}
/* If the inode represents a directory which is actually
present in a snapshot, then opendir on that directory
should be sent to the snap-view-server which opens
@ -433,6 +638,7 @@ svc_opendir (call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd,
int op_ret = -1;
int op_errno = EINVAL;
gf_boolean_t wind = _gf_false;
svc_local_t *local = NULL;
GF_VALIDATE_OR_GOTO ("svc", this, out);
GF_VALIDATE_OR_GOTO (this->name, frame, out);
@ -440,11 +646,24 @@ svc_opendir (call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd,
GF_VALIDATE_OR_GOTO (this->name, loc->inode, out);
GF_VALIDATE_OR_GOTO (this->name, fd, out);
local = mem_get0 (this->local_pool);
if (!local) {
gf_log (this->name, GF_LOG_ERROR, "failed to allocate memory "
"for local (path: %s, gfid: %s)", loc->path,
uuid_utoa (fd->inode->gfid));
op_errno = ENOMEM;
goto out;
}
SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret,
loc->inode, subvolume, out);
STACK_WIND_TAIL (frame, subvolume, subvolume->fops->opendir, loc, fd,
xdata);
loc_copy (&local->loc, loc);
local->subvolume = subvolume;
frame->local = local;
STACK_WIND (frame, svc_opendir_cbk, subvolume, subvolume->fops->opendir,
loc, fd, xdata);
wind = _gf_true;
@ -586,6 +805,7 @@ svc_getxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, const char *name,
ret = dict_set_dynstr_with_alloc (dict,
(char *)name,
priv->path);
if (ret) {
op_errno = ENOMEM;
dict_unref (dict);
@ -612,6 +832,9 @@ out:
SVC_STACK_UNWIND (getxattr, frame, op_ret, op_errno,
dict, NULL);
if (dict)
dict_unref (dict);
return 0;
}
@ -1264,12 +1487,29 @@ svc_readdir (call_frame_t *frame, xlator_t *this, fd_t *fd,
int op_ret = -1;
int op_errno = EINVAL;
gf_boolean_t wind = _gf_false;
svc_fd_t *svc_fd = NULL;
gf_dirent_t entries;
INIT_LIST_HEAD (&entries);
GF_VALIDATE_OR_GOTO ("svc", this, out);
GF_VALIDATE_OR_GOTO (this->name, frame, out);
GF_VALIDATE_OR_GOTO (this->name, fd, out);
GF_VALIDATE_OR_GOTO (this->name, fd->inode, out);
svc_fd = svc_fd_ctx_get_or_new (this, fd);
if (!svc_fd)
gf_log (this->name, GF_LOG_ERROR, "failed to get the fd "
"context for the inode %s",
uuid_utoa (fd->inode->gfid));
else {
if (svc_fd->entry_point_handled && off == svc_fd->last_offset) {
op_ret = 0;
op_errno = ENOENT;
goto out;
}
}
SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret,
fd->inode, subvolume, out);
@ -1280,11 +1520,211 @@ svc_readdir (call_frame_t *frame, xlator_t *this, fd_t *fd,
out:
if (!wind)
SVC_STACK_UNWIND (readdir, frame, op_ret, op_errno, NULL,
SVC_STACK_UNWIND (readdir, frame, op_ret, op_errno, &entries,
NULL);
gf_dirent_free (&entries);
return 0;
}
/*
* This lookup if mainly for supporting USS for windows.
* Since the dentry for the entry-point directory is not sent in
* the readdir response, from windows explorer, there is no way
* to access the snapshots. If the explicit path of the entry-point
* directory is mentioned in the address bar, then windows sends
* readdir on the parent directory and compares if the entry point
* directory's name is there in readdir response. If it is not there
* then access to snapshot world is denied. And windows users cannot
* access snapshots via samba.
* So, to handle this a new option called special-directory is created,
* which if set, snapview-client will send the entry-point's dentry
* in readdirp o/p for the special directory, so that it will be
* visible from windows explorer.
* But to send that virtual entry, the following mechanism is used.
* 1) Check if readdir from posix is over.
* 2) If so, then send a lookup on entry point directory to snap daemon
* (this is needed because in readdirp inodes are linked, so we need to
* maintain 1:1 mapping between inodes (gfids) from snapview server to
* snapview client).
* 3) Once successful lookup response received, send a new entry to
* windows.
*/
int32_t
svc_readdirp_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, inode_t *inode,
struct iatt *buf, dict_t *xdata,
struct iatt *postparent)
{
gf_dirent_t entries;
gf_dirent_t *entry = NULL;
svc_private_t *private = NULL;
svc_fd_t *svc_fd = NULL;
svc_local_t *local = NULL;
int inode_type = -1;
int ret = -1;
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
GF_VALIDATE_OR_GOTO (this->name, this->private, out);
private = this->private;
INIT_LIST_HEAD (&entries.list);
local = frame->local;
if (op_ret) {
op_ret = 0;
op_errno = ENOENT;
goto out;
}
svc_fd = svc_fd_ctx_get (this, local->fd);
if (!svc_fd) {
gf_log (this->name, GF_LOG_ERROR, "failed to get the fd "
"context for the inode %s",
uuid_utoa (local->fd->inode->gfid));
op_ret = 0;
op_errno = ENOENT;
goto out;
}
entry = gf_dirent_for_name (private->path);
if (!entry) {
gf_log (this->name, GF_LOG_ERROR, "failed to allocate memory "
"for the entry %s", private->path);
op_ret = 0;
op_errno = ENOMEM;
goto out;
}
entry->inode = inode_ref (inode);
entry->d_off = svc_fd->last_offset + 22;
entry->d_ino = buf->ia_ino;
entry->d_type = DT_DIR;
entry->d_stat = *buf;
inode_type = VIRTUAL_INODE;
ret = svc_inode_ctx_set (this, entry->inode, inode_type);
if (ret)
gf_log (this->name, GF_LOG_ERROR, "failed to set the inode "
"context");
list_add_tail (&entry->list, &entries.list);
op_ret = 1;
svc_fd->last_offset = entry->d_off;
svc_fd->entry_point_handled = _gf_true;
out:
SVC_STACK_UNWIND (readdirp, frame, op_ret, op_errno, &entries,
local->xdata);
gf_dirent_free (&entries);
return 0;
}
gf_boolean_t
svc_readdir_on_special_dir (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
gf_dirent_t *entries, dict_t *xdata)
{
svc_local_t *local = NULL;
svc_private_t *private = NULL;
inode_t *inode = NULL;
fd_t *fd = NULL;
char *path = NULL;
loc_t *loc = NULL;
dict_t *tmp_xdata = NULL;
int ret = -1;
gf_boolean_t unwind = _gf_true;
svc_fd_t *svc_fd = NULL;
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
GF_VALIDATE_OR_GOTO (this->name, this->private, out);
private = this->private;
local = frame->local;
loc = &local->loc;
fd = local->fd;
svc_fd = svc_fd_ctx_get (this, fd);
if (!svc_fd) {
gf_log (this->name, GF_LOG_ERROR, "failed to get the fd "
"context for the inode %s",
uuid_utoa (fd->inode->gfid));
goto out;
}
/*
* check if its end of readdir operation from posix, if special_dir
* option is set, if readdir is done on special directory and if
* readdirp is from normal regular graph.
*/
if (!private->show_entry_point)
goto out;
if (op_ret == 0 && op_errno == ENOENT && private->special_dir &&
strcmp (private->special_dir, "") && svc_fd->special_dir &&
local->subvolume == FIRST_CHILD (this)) {
inode = inode_grep (fd->inode->table, fd->inode,
private->path);
if (!inode) {
inode = inode_new (fd->inode->table);
if (!inode) {
gf_log (this->name, GF_LOG_ERROR, "failed to "
"allocate new inode");
goto out;
}
}
uuid_copy (local->loc.pargfid, fd->inode->gfid);
uuid_copy (local->loc.gfid, inode->gfid);
if (uuid_is_null (inode->gfid))
ret = inode_path (fd->inode, private->path, &path);
else
ret = inode_path (inode, NULL, &path);
if (ret < 0)
goto out;
loc->path = gf_strdup (path);
if (loc->path) {
if (!loc->name ||
(loc->name && !strcmp (loc->name, ""))) {
loc->name = strrchr (loc->path, '/');
if (loc->name)
loc->name++;
}
}
loc->inode = inode;
loc->parent = inode_ref (fd->inode);
tmp_xdata = dict_new ();
if (!tmp_xdata)
goto out;
ret = dict_set_str (tmp_xdata, "entry-point", "true");
if (ret) {
gf_log (this->name, GF_LOG_ERROR, "failed to set dict");
goto out;
}
local->cookie = cookie;
local->xdata = dict_ref (xdata);
STACK_WIND (frame, svc_readdirp_lookup_cbk,
SECOND_CHILD (this),
SECOND_CHILD (this)->fops->lookup, loc, tmp_xdata);
unwind = _gf_false;
}
out:
if (tmp_xdata)
dict_unref (tmp_xdata);
GF_FREE (path);
return unwind;
}
int32_t
svc_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
@ -1295,12 +1735,22 @@ svc_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
gf_boolean_t real = _gf_true;
int inode_type = -1;
int ret = -1;
svc_fd_t *svc_fd = NULL;
gf_boolean_t unwind = _gf_true;
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
if (op_ret < 0)
goto out;
local = frame->local;
frame->local = NULL;
svc_fd = svc_fd_ctx_get (this, local->fd);
if (!svc_fd) {
gf_log (this->name, GF_LOG_WARNING, "failed to get the fd "
"context for the gfid %s",
uuid_utoa (local->fd->inode->gfid));
}
if (local->subvolume == FIRST_CHILD (this))
real = _gf_true;
@ -1320,11 +1770,16 @@ svc_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
if (ret)
gf_log (this->name, GF_LOG_ERROR, "failed to set inode "
"context");
svc_fd->last_offset = entry->d_off;
}
unwind = svc_readdir_on_special_dir (frame, cookie, this, op_ret,
op_errno, entries, xdata);
out:
SVC_STACK_UNWIND (readdirp, frame, op_ret, op_errno, entries, xdata);
if (unwind)
SVC_STACK_UNWIND (readdirp, frame, op_ret, op_errno, entries,
xdata);
return 0;
}
@ -1341,6 +1796,10 @@ svc_readdirp (call_frame_t *frame, xlator_t *this, fd_t *fd,
int op_ret = -1;
int op_errno = EINVAL;
gf_boolean_t wind = _gf_false;
svc_fd_t *svc_fd = NULL;
gf_dirent_t entries;
INIT_LIST_HEAD (&entries.list);
GF_VALIDATE_OR_GOTO ("svc", this, out);
GF_VALIDATE_OR_GOTO (this->name, frame, out);
@ -1350,13 +1809,37 @@ svc_readdirp (call_frame_t *frame, xlator_t *this, fd_t *fd,
local = mem_get0 (this->local_pool);
if (!local) {
gf_log (this->name, GF_LOG_ERROR, "failed to allocate local");
op_errno = ENOMEM;
goto out;
}
/*
* This is mainly for samba shares (or windows clients). As part of
* readdirp on the directory used as samba share, the entry point
* directory would have been added at the end. So when a new readdirp
* request comes, we have to check if the entry point has been handled
* or not in readdirp. That information and the offset used for it
* is remembered in fd context. If it has been handled, then simply
* unwind indication end of readdir operation.
*/
svc_fd = svc_fd_ctx_get_or_new (this, fd);
if (!svc_fd)
gf_log (this->name, GF_LOG_ERROR, "failed to get the fd "
"context for the inode %s",
uuid_utoa (fd->inode->gfid));
else {
if (svc_fd->entry_point_handled && off == svc_fd->last_offset) {
op_ret = 0;
op_errno = ENOENT;
goto out;
}
}
SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret,
fd->inode, subvolume, out);
local->subvolume = subvolume;
local->fd = fd_ref (fd);
frame->local = local;
STACK_WIND (frame, svc_readdirp_cbk, subvolume,
@ -1366,7 +1849,10 @@ svc_readdirp (call_frame_t *frame, xlator_t *this, fd_t *fd,
out:
if (!wind)
SVC_STACK_UNWIND (readdirp, frame, op_ret, op_errno, NULL, NULL);
SVC_STACK_UNWIND (readdirp, frame, op_ret, op_errno, &entries,
NULL);
gf_dirent_free (&entries);
return 0;
}
@ -1575,6 +2061,29 @@ out:
return 0;
}
int32_t
svc_releasedir (xlator_t *this, fd_t *fd)
{
svc_fd_t *sfd = NULL;
uint64_t tmp_pfd = 0;
int ret = 0;
GF_VALIDATE_OR_GOTO ("snapview-client", this, out);
GF_VALIDATE_OR_GOTO (this->name, fd, out);
ret = fd_ctx_del (fd, this, &tmp_pfd);
if (ret < 0) {
gf_log (this->name, GF_LOG_DEBUG,
"pfd from fd=%p is NULL", fd);
goto out;
}
GF_FREE (sfd);
out:
return 0;
}
int32_t
svc_forget (xlator_t *this, inode_t *inode)
{
@ -1603,6 +2112,8 @@ reconfigure (xlator_t *this, dict_t *options)
priv = this->private;
GF_OPTION_RECONF ("snapshot-directory", priv->path, options, str, out);
GF_OPTION_RECONF ("show-snapshot-directory", priv->show_entry_point,
options, bool, out);
out:
return 0;
@ -1665,6 +2176,18 @@ init (xlator_t *this)
goto out;
GF_OPTION_INIT ("snapshot-directory", private->path, str, out);
GF_OPTION_INIT ("snapdir-entry-path", private->special_dir, str,
out);
GF_OPTION_INIT ("show-snapshot-directory", private->show_entry_point,
bool, out);
if (strstr (private->special_dir, private->path)) {
gf_log (this->name, GF_LOG_ERROR, "entry point directory "
"cannot be part of the special directory");
GF_FREE (private->special_dir);
private->special_dir = NULL;
goto out;
}
this->private = private;
this->local_pool = mem_pool_new (svc_local_t, 128);
@ -1698,6 +2221,7 @@ fini (xlator_t *this)
this->private = NULL;
GF_FREE (priv->path);
GF_FREE (priv->special_dir);
GF_FREE (priv);
return;
@ -1757,6 +2281,7 @@ struct xlator_fops fops = {
struct xlator_cbks cbks = {
.forget = svc_forget,
.releasedir = svc_releasedir,
};
struct volume_options options[] = {
@ -1764,5 +2289,20 @@ struct volume_options options[] = {
.type = GF_OPTION_TYPE_STR,
.default_value = ".snaps",
},
{ .key = {"snapdir-entry-path"},
.type = GF_OPTION_TYPE_STR,
.description = "An option to set the path of a directory on which "
"when readdir comes, dentry for the snapshot-directory"
" should be created and added in the readdir response",
.default_value = "",
},
{ .key = {"show-snapshot-directory"},
.type = GF_OPTION_TYPE_BOOL,
.description = "If this option is set, and the option "
"\"snapdir-entry-path\" is set (which is set by samba "
"vfs plugin for glusterfs, then send the entry point "
"when readdir comes on the snapdir-entry-path",
.default_value = "off",
},
{ .key = {NULL} },
};

View File

@ -25,6 +25,9 @@
struct __svc_local {
loc_t loc;
xlator_t *subvolume;
fd_t *fd;
void *cookie;
dict_t *xdata;
};
typedef struct __svc_local svc_local_t;
@ -81,10 +84,19 @@ svc_local_free (svc_local_t *local);
} while (0);
struct svc_private {
char *path; //might be helpful for samba
char *path;
char *special_dir; /* needed for samba */
gf_boolean_t show_entry_point;
};
typedef struct svc_private svc_private_t;
struct svc_fd {
off_t last_offset;
gf_boolean_t entry_point_handled;
gf_boolean_t special_dir;
};
typedef struct svc_fd svc_fd_t;
typedef enum {
NORMAL_INODE = 1,
VIRTUAL_INODE
@ -107,4 +119,8 @@ svc_inode_ctx_set (xlator_t *this, inode_t *inode, int inode_type);
void
svc_local_free (svc_local_t *local);
gf_boolean_t
svc_readdir_on_special_dir (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
gf_dirent_t *entries, dict_t *xdata);
#endif /* __SNAP_VIEW_CLIENT_H__ */

View File

@ -1062,6 +1062,8 @@ svs_releasedir (xlator_t *this, fd_t *fd)
uuid_utoa (fd->inode->gfid));
}
GF_FREE (sfd);
out:
return 0;
}
@ -1132,6 +1134,7 @@ svs_release (xlator_t *this, fd_t *fd)
}
}
GF_FREE (sfd);
out:
return 0;
}

View File

@ -1152,6 +1152,15 @@ struct volopt_map_entry glusterd_volopt_map[] = {
.description = "Entry point directory for entering snapshot world"
},
{ .key = "features.show-snapshot-directory",
.voltype = "features/snapview-client",
.op_version = GD_OP_VERSION_3_6_0,
.value = "off",
.flags = OPT_FLAG_CLIENT_OPT | OPT_FLAG_XLATOR_OPT,
.description = "show entry point in readdir output of "
"snapdir-entry-path which is set by samba"
},
#ifdef HAVE_LIB_Z
/* Compressor-decompressor xlator options
* defaults used from xlator/features/compress/src/cdc.h