dht,posix: support for case discovery

This is support for discovering a filename in a given directory
which has a case insensitive match of a given name. It is implemented
as a virtual extended attribute on the directory where the required
filename is specified in the key.

E.g:

  sh# getfattr -e "text" -n user.glusterfs.get_real_filename:FiLe-B /mnt/samba/patchy
  getfattr: Removing leading '/' from absolute path names
  # file: mnt/samba/patchy
  user.glusterfs.get_real_filename:FiLe-B="file-b"

In reality, there can be multiple "answers" as the backend filesystem is
case sensitive and there can be multiple files which can strcasecamp()
successfully. In this case we pick the first matched file from the first
responding server.

If a matching file does not exist, we return ENOENT (and NOT ENODATA).
This way the caller can differentiate between "unsupported" glusterfs
API and file not existing.

This API is used by Samba VFS to perform efficient discovery of the real
filename without doing a full scan at the Samba level.

Change-Id: I53054c4067cba69e585fd0bbce004495bc6e39e8
BUG: 953694
Signed-off-by: Anand Avati <avati@redhat.com>
Reviewed-on: http://review.gluster.org/4941
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Tested-by: Gluster Build System <jenkins@build.gluster.com>
This commit is contained in:
Anand Avati 2013-05-02 08:00:22 -07:00 committed by Vijay Bellur
parent 9b645be90f
commit 05aaec645a
3 changed files with 140 additions and 0 deletions

View File

@ -83,6 +83,7 @@
#define GF_XATTR_NODE_UUID_KEY "trusted.glusterfs.node-uuid"
#define GF_XATTR_VOL_ID_KEY "trusted.glusterfs.volume-id"
#define GF_XATTR_LOCKINFO_KEY "trusted.glusterfs.lockinfo"
#define GF_XATTR_GET_REAL_FILENAME_KEY "user.glusterfs.get_real_filename:"
#define GF_READDIR_SKIP_DIRS "readdir-filter-directories"

View File

@ -2026,6 +2026,71 @@ dht_getxattr_unwind (call_frame_t *frame,
}
int
dht_getxattr_get_real_filename_cbk (call_frame_t *frame, void *cookie,
xlator_t *this, int op_ret, int op_errno,
dict_t *xattr, dict_t *xdata)
{
int this_call_cnt = 0;
dht_local_t *local = NULL;
dht_conf_t *conf = NULL;
conf = this->private;
local = frame->local;
if (op_ret != -1) {
if (local->xattr)
dict_unref (local->xattr);
local->xattr = dict_ref (xattr);
if (local->xattr_req)
dict_unref (local->xattr_req);
local->xattr_req = dict_ref (xdata);
}
this_call_cnt = dht_frame_return (frame);
if (is_last_call (this_call_cnt)) {
DHT_STACK_UNWIND (getxattr, frame, local->op_ret, op_errno,
local->xattr, local->xattr_req);
}
return 0;
}
int
dht_getxattr_get_real_filename (call_frame_t *frame, xlator_t *this,
loc_t *loc, const char *key, dict_t *xdata)
{
dht_conf_t *conf = NULL;
dht_local_t *local = NULL;
int i = 0;
dht_layout_t *layout = NULL;
int cnt = 0;
xlator_t *subvol = NULL;
conf = this->private;
local = frame->local;
layout = local->layout;
cnt = local->call_cnt = layout->cnt;
local->op_ret = -1;
local->op_errno = ENODATA;
for (i = 0; i < cnt; i++) {
subvol = layout->list[i].xlator;
STACK_WIND (frame, dht_getxattr_get_real_filename_cbk,
subvol, subvol->fops->getxattr,
loc, key, xdata);
}
return 0;
}
int
dht_getxattr (call_frame_t *frame, xlator_t *this,
loc_t *loc, const char *key, dict_t *xdata)
@ -2075,6 +2140,14 @@ dht_getxattr (call_frame_t *frame, xlator_t *this,
}
}
if (key &&
(strncmp (key, GF_XATTR_GET_REAL_FILENAME_KEY,
strlen (GF_XATTR_GET_REAL_FILENAME_KEY)) == 0)
&& DHT_IS_DIR(layout)) {
dht_getxattr_get_real_filename (frame, this, loc, key, xdata);
return 0;
}
/* for file use cached subvolume (obviously!): see if {}
* below
* for directory:

View File

@ -2439,6 +2439,53 @@ out:
return 0;
}
int
posix_xattr_get_real_filename (call_frame_t *frame, xlator_t *this, loc_t *loc,
const char *key, dict_t *dict, dict_t *xdata)
{
char *real_path = NULL;
struct dirent *dirent = NULL;
DIR *fd = NULL;
const char *fname = NULL;
char *found = NULL;
int ret = -1;
int op_ret = -1;
MAKE_INODE_HANDLE (real_path, this, loc, NULL);
fd = opendir (real_path);
if (!fd)
return -errno;
fname = key + strlen (GF_XATTR_GET_REAL_FILENAME_KEY);
while ((dirent = readdir (fd))) {
if (strcasecmp (dirent->d_name, fname) == 0) {
found = gf_strdup (dirent->d_name);
if (!found) {
closedir (fd);
return -ENOMEM;
}
break;
}
}
closedir (fd);
if (!found)
return -ENOENT;
ret = dict_set_dynstr (dict, (char *)key, found);
if (ret) {
GF_FREE (found);
return -ENOMEM;
}
ret = strlen (found) + 1;
return ret;
}
/**
* posix_getxattr - this function returns a dictionary with all the
* key:value pair present as xattr. used for
@ -2493,9 +2540,28 @@ posix_getxattr (call_frame_t *frame, xlator_t *this,
dict = dict_new ();
if (!dict) {
op_errno = ENOMEM;
goto out;
}
if (loc->inode && name &&
(strncmp (name, GF_XATTR_GET_REAL_FILENAME_KEY,
strlen (GF_XATTR_GET_REAL_FILENAME_KEY)) == 0)) {
ret = posix_xattr_get_real_filename (frame, this, loc,
name, dict, xdata);
if (ret < 0) {
op_ret = -1;
op_errno = -ret;
gf_log (this->name, GF_LOG_WARNING,
"Failed to get rea filename (%s, %s): %s",
loc->path, name, strerror (op_errno));
goto out;
}
size = ret;
goto done;
}
if (loc->inode && name && !strcmp (name, GLUSTERFS_OPEN_FD_COUNT)) {
if (!list_empty (&loc->inode->fd_list)) {
ret = dict_set_uint32 (dict, (char *)name, 1);