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:
parent
ad1ed80060
commit
7cfa31434e
@ -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
96
tests/bugs/bug-1168875.t
Normal 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;
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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} },
|
||||
};
|
||||
|
@ -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__ */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user