s3:vfs_fileid: always add the 'nolock' behavior via file_id.extid
authorStefan Metzmacher <metze@samba.org>
Wed, 29 Jun 2022 14:47:50 +0000 (16:47 +0200)
committerRalph Boehme <slow@samba.org>
Tue, 5 Jul 2022 15:09:35 +0000 (15:09 +0000)
file_id.extid was filled with getpid() by 'fsname_norootdir_ext'.

However instead of forcing the existing 'hostname' algorithm for the 'nolock'
case, we'll now generate file_id.extid also based the hostname, vnn
and for 'fsname_norootdir_ext' also the pid.

This simplifies further changes and gives us the ability to generate stable
results for file_id.{devid,inode} based on the main algorithm. This is important
as we have a push_file_id_16() helper function used in places to generate a
stable identifier of the file that is also client visible and might be stored on
stable storage (acl_tdb, xattr_tdb). While the file_id.extid is only used
internally in volatile databases.

Review with: git show --patience

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/modules/vfs_fileid.c

index 7f235aaddb4926378579884576836ce45c5d6d87..ff1432c8457cd16c6138c55df17b797069857415 100644 (file)
@@ -51,6 +51,7 @@ struct fileid_handle_data {
        unsigned num_mount_entries;
        struct fileid_mount_entry *mount_entries;
        struct {
+               uint64_t extid;
                size_t num_inodes;
                struct fileid_nolock_inode *inodes;
        } nolock;
@@ -330,37 +331,38 @@ static int fileid_add_nolock_inode(struct fileid_handle_data *data,
        return 0;
 }
 
-/* a device mapping using a fsname for files and hostname for dirs */
-static struct file_id fileid_mapping_fsname_nodirs(
-       struct fileid_handle_data *data,
-       const SMB_STRUCT_STAT *sbuf)
+static uint64_t fileid_mapping_nolock_extid(uint64_t max_slots)
 {
-       if (S_ISDIR(sbuf->st_ex_mode)) {
-               return fileid_mapping_hostname(data, sbuf);
+       char buf[8+4+HOST_NAME_MAX+1] = { 0, };
+       uint64_t slot = 0;
+       uint64_t id;
+       int rc;
+
+       if (max_slots > 1) {
+               slot = getpid() % max_slots;
        }
 
-       return fileid_mapping_fsname(data, sbuf);
-}
+       PUSH_LE_U64(buf, 0, slot);
+       PUSH_LE_U32(buf, 8, get_my_vnn());
 
-static struct file_id fileid_mapping_fsname_norootdir(
-       struct fileid_handle_data *data,
-       const SMB_STRUCT_STAT *sbuf)
-{
-       if (fileid_is_nolock_inode(data, sbuf)) {
-               return fileid_mapping_hostname(data, sbuf);
+       rc = gethostname(&buf[12], HOST_NAME_MAX+1);
+       if (rc != 0) {
+               DBG_ERR("gethostname failed\n");
+               return UINT64_MAX;
        }
 
-       return fileid_mapping_fsname(data, sbuf);
+       id = fileid_uint64_hash((uint8_t *)buf, ARRAY_SIZE(buf));
+
+       return id;
 }
 
-static struct file_id fileid_mapping_fsname_norootdir_ext(
+/* a device mapping using a fsname for files and hostname for dirs */
+static struct file_id fileid_mapping_fsname_nodirs(
        struct fileid_handle_data *data,
        const SMB_STRUCT_STAT *sbuf)
 {
-       if (fileid_is_nolock_inode(data, sbuf)) {
-               struct file_id id = fileid_mapping_hostname(data, sbuf);
-               id.extid = getpid();
-               return id;
+       if (S_ISDIR(sbuf->st_ex_mode)) {
+               return fileid_mapping_hostname(data, sbuf);
        }
 
        return fileid_mapping_fsname(data, sbuf);
@@ -469,6 +471,7 @@ static int fileid_connect(struct vfs_handle_struct *handle,
        const char **mntdir_deny_list = NULL;
        const char **mntdir_allow_list = NULL;
        ino_t nolockinode;
+       uint64_t max_slots = 0;
        bool rootdir_nolock = false;
        int saved_errno;
        int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
@@ -506,11 +509,12 @@ static int fileid_connect(struct vfs_handle_struct *handle,
        } else if (strcmp("hostname", algorithm) == 0) {
                data->mapping_fn = fileid_mapping_hostname;
        } else if (strcmp("fsname_norootdir", algorithm) == 0) {
-               data->mapping_fn = fileid_mapping_fsname_norootdir;
+               data->mapping_fn = fileid_mapping_fsname;
                rootdir_nolock = true;
        } else if (strcmp("fsname_norootdir_ext", algorithm) == 0) {
-               data->mapping_fn = fileid_mapping_fsname_norootdir_ext;
+               data->mapping_fn = fileid_mapping_fsname;
                rootdir_nolock = true;
+               max_slots = UINT64_MAX;
        } else if (strcmp("next_module", algorithm) == 0) {
                data->mapping_fn        = fileid_mapping_next_module;
        } else {
@@ -571,6 +575,10 @@ static int fileid_connect(struct vfs_handle_struct *handle,
                }
        }
 
+       max_slots = MAX(max_slots, 1);
+
+       data->nolock.extid = fileid_mapping_nolock_extid(max_slots);
+
        nolockinode = lp_parm_ulong(SNUM(handle->conn), "fileid", "nolockinode", 0);
        if (nolockinode != 0) {
                SMB_STRUCT_STAT tmpsbuf = { .st_ex_ino = nolockinode, };
@@ -636,6 +644,9 @@ static struct file_id fileid_file_id_create(struct vfs_handle_struct *handle,
                                return id);
 
        id = data->mapping_fn(data, sbuf);
+       if (id.extid == 0 && fileid_is_nolock_inode(data, sbuf)) {
+               id.extid = data->nolock.extid;
+       }
 
        DBG_DEBUG("Returning dev [%jx] inode [%jx] extid [%jx]\n",
                  (uintmax_t)id.devid, (uintmax_t)id.inode, (uintmax_t)id.extid);