1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00

s3:vfs_fileid: maintain an array of nolock inodes

This way 'fsname_norootdir[_ext]' is not overwritten by
'fileid:nolockinode' and both can work independently.

It will also allow us to add more nolock inodes under
other conditions in the following changes.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
This commit is contained in:
Stefan Metzmacher 2022-06-29 16:31:22 +02:00 committed by Ralph Boehme
parent 3ec4dddb54
commit 2668700f1e

View File

@ -35,6 +35,11 @@ struct fileid_mount_entry {
uint64_t devid; uint64_t devid;
}; };
struct fileid_nolock_inode {
dev_t dev;
ino_t ino;
};
struct fileid_handle_data { struct fileid_handle_data {
struct file_id (*mapping_fn)(struct fileid_handle_data *data, struct file_id (*mapping_fn)(struct fileid_handle_data *data,
const SMB_STRUCT_STAT *sbuf); const SMB_STRUCT_STAT *sbuf);
@ -44,7 +49,10 @@ struct fileid_handle_data {
char **mntdir_allow_list; char **mntdir_allow_list;
unsigned num_mount_entries; unsigned num_mount_entries;
struct fileid_mount_entry *mount_entries; struct fileid_mount_entry *mount_entries;
ino_t nolockinode; struct {
size_t num_inodes;
struct fileid_nolock_inode *inodes;
} nolock;
}; };
/* check if a mount entry is allowed based on fstype and mount directory */ /* check if a mount entry is allowed based on fstype and mount directory */
@ -264,15 +272,61 @@ static struct file_id fileid_mapping_hostname(struct fileid_handle_data *data,
static bool fileid_is_nolock_inode(struct fileid_handle_data *data, static bool fileid_is_nolock_inode(struct fileid_handle_data *data,
const SMB_STRUCT_STAT *sbuf) const SMB_STRUCT_STAT *sbuf)
{ {
if (data->nolockinode == 0) { size_t i;
return false;
/*
* We could make this a binary search over an sorted array,
* but for now we keep things simple.
*/
for (i=0; i < data->nolock.num_inodes; i++) {
if (data->nolock.inodes[i].ino != sbuf->st_ex_ino) {
continue;
}
if (data->nolock.inodes[i].dev == 0) {
/*
* legacy "fileid:nolockinode"
* handling ignoring dev
*/
return true;
}
if (data->nolock.inodes[i].dev != sbuf->st_ex_dev) {
continue;
}
return true;
} }
if (sbuf->st_ex_ino != data->nolockinode) { return false;
return false; }
static int fileid_add_nolock_inode(struct fileid_handle_data *data,
const SMB_STRUCT_STAT *sbuf)
{
bool exists = fileid_is_nolock_inode(data, sbuf);
struct fileid_nolock_inode *inodes = NULL;
if (exists) {
return 0;
} }
return true; inodes = talloc_realloc(data, data->nolock.inodes,
struct fileid_nolock_inode,
data->nolock.num_inodes + 1);
if (inodes == NULL) {
return -1;
}
inodes[data->nolock.num_inodes] = (struct fileid_nolock_inode) {
.dev = sbuf->st_ex_dev,
.ino = sbuf->st_ex_ino,
};
data->nolock.inodes = inodes;
data->nolock.num_inodes += 1;
return 0;
} }
/* a device mapping using a fsname for files and hostname for dirs */ /* a device mapping using a fsname for files and hostname for dirs */
@ -349,31 +403,51 @@ static struct file_id fileid_mapping_fsid(struct fileid_handle_data *data,
} }
static int get_connectpath_ino(struct vfs_handle_struct *handle, static int get_connectpath_ino(struct vfs_handle_struct *handle,
ino_t *ino) const char *path,
SMB_STRUCT_STAT *psbuf)
{ {
TALLOC_CTX *frame = talloc_stackframe();
struct smb_filename *fname = NULL; struct smb_filename *fname = NULL;
const char *fullpath = NULL;
int ret; int ret;
fname = synthetic_smb_fname(talloc_tos(), if (path[0] == '/') {
handle->conn->connectpath, fullpath = path;
} else {
fullpath = talloc_asprintf(frame,
"%s/%s",
handle->conn->connectpath,
path);
if (fullpath == NULL) {
DBG_ERR("talloc_asprintf() failed\n");
TALLOC_FREE(frame);
return -1;
}
}
fname = synthetic_smb_fname(frame,
fullpath,
NULL, NULL,
NULL, NULL,
0, 0,
0); 0);
if (fname == NULL) { if (fname == NULL) {
DBG_ERR("synthetic_smb_fname failed\n"); DBG_ERR("synthetic_smb_fname(%s) failed - %s\n",
fullpath, strerror(errno));
TALLOC_FREE(frame);
return -1; return -1;
} }
ret = SMB_VFS_NEXT_STAT(handle, fname); ret = SMB_VFS_NEXT_STAT(handle, fname);
if (ret != 0) { if (ret != 0) {
DBG_ERR("stat failed for %s with %s\n", DBG_ERR("stat failed for %s with %s\n",
handle->conn->connectpath, strerror(errno)); fullpath, strerror(errno));
TALLOC_FREE(fname); TALLOC_FREE(frame);
return -1; return -1;
} }
*ino = fname->st.st_ex_ino; *psbuf = fname->st;
TALLOC_FREE(fname);
TALLOC_FREE(frame);
return 0; return 0;
} }
@ -387,6 +461,8 @@ static int fileid_connect(struct vfs_handle_struct *handle,
const char **fstype_allow_list = NULL; const char **fstype_allow_list = NULL;
const char **mntdir_deny_list = NULL; const char **mntdir_deny_list = NULL;
const char **mntdir_allow_list = NULL; const char **mntdir_allow_list = NULL;
ino_t nolockinode;
bool rootdir_nolock = false;
int saved_errno; int saved_errno;
int ret = SMB_VFS_NEXT_CONNECT(handle, service, user); int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
@ -403,8 +479,6 @@ static int fileid_connect(struct vfs_handle_struct *handle,
return -1; return -1;
} }
data->nolockinode = 0;
/* /*
* "fileid:mapping" is only here as fallback for old setups * "fileid:mapping" is only here as fallback for old setups
* "fileid:algorithm" is the option new setups should use * "fileid:algorithm" is the option new setups should use
@ -425,24 +499,10 @@ static int fileid_connect(struct vfs_handle_struct *handle,
data->mapping_fn = fileid_mapping_hostname; data->mapping_fn = fileid_mapping_hostname;
} else if (strcmp("fsname_norootdir", algorithm) == 0) { } else if (strcmp("fsname_norootdir", algorithm) == 0) {
data->mapping_fn = fileid_mapping_fsname_norootdir; data->mapping_fn = fileid_mapping_fsname_norootdir;
rootdir_nolock = true;
ret = get_connectpath_ino(handle, &data->nolockinode);
if (ret != 0) {
saved_errno = errno;
SMB_VFS_NEXT_DISCONNECT(handle);
errno = saved_errno;
return -1;
}
} else if (strcmp("fsname_norootdir_ext", algorithm) == 0) { } else if (strcmp("fsname_norootdir_ext", algorithm) == 0) {
data->mapping_fn = fileid_mapping_fsname_norootdir_ext; data->mapping_fn = fileid_mapping_fsname_norootdir_ext;
rootdir_nolock = true;
ret = get_connectpath_ino(handle, &data->nolockinode);
if (ret != 0) {
saved_errno = errno;
SMB_VFS_NEXT_DISCONNECT(handle);
errno = saved_errno;
return -1;
}
} else { } else {
SMB_VFS_NEXT_DISCONNECT(handle); SMB_VFS_NEXT_DISCONNECT(handle);
DEBUG(0,("fileid_connect(): unknown algorithm[%s]\n", algorithm)); DEBUG(0,("fileid_connect(): unknown algorithm[%s]\n", algorithm));
@ -501,15 +561,45 @@ static int fileid_connect(struct vfs_handle_struct *handle,
} }
} }
data->nolockinode = lp_parm_ulong(SNUM(handle->conn), "fileid", nolockinode = lp_parm_ulong(SNUM(handle->conn), "fileid", "nolockinode", 0);
"nolockinode", data->nolockinode); if (nolockinode != 0) {
SMB_STRUCT_STAT tmpsbuf = { .st_ex_ino = nolockinode, };
ret = fileid_add_nolock_inode(data, &tmpsbuf);
if (ret != 0) {
saved_errno = errno;
SMB_VFS_NEXT_DISCONNECT(handle);
errno = saved_errno;
return -1;
}
}
if (rootdir_nolock) {
SMB_STRUCT_STAT rootdirsbuf;
ret = get_connectpath_ino(handle, ".", &rootdirsbuf);
if (ret != 0) {
saved_errno = errno;
SMB_VFS_NEXT_DISCONNECT(handle);
errno = saved_errno;
return -1;
}
ret = fileid_add_nolock_inode(data, &rootdirsbuf);
if (ret != 0) {
saved_errno = errno;
SMB_VFS_NEXT_DISCONNECT(handle);
errno = saved_errno;
return -1;
}
}
SMB_VFS_HANDLE_SET_DATA(handle, data, NULL, SMB_VFS_HANDLE_SET_DATA(handle, data, NULL,
struct fileid_handle_data, struct fileid_handle_data,
return -1); return -1);
DBG_DEBUG("connect to service[%s] with algorithm[%s] nolockinode %lli\n", DBG_DEBUG("connect to service[%s] with algorithm[%s] nolock.inodes %zu\n",
service, algorithm, (long long) data->nolockinode); service, algorithm, data->nolock.num_inodes);
return 0; return 0;
} }