]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
lib: Streamline finding a file's block device for quota code
authorVolker Lendecke <vl@samba.org>
Mon, 26 Jan 2026 13:01:05 +0000 (14:01 +0100)
committerAnoop C S <anoopcs@samba.org>
Sun, 15 Feb 2026 10:42:34 +0000 (10:42 +0000)
Use /proc/self/mountinfo to find the block device a file is mounted on for
quotactl purposes.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Anoop C S <anoopcs@samba.org>
source3/include/proto.h
source3/lib/sysquotas.c
source3/modules/vfs_default.c

index ca659235697d33c6f00bdc24d633426b8ecad2b4..776c8898fc3e16b89a1757342f62ddc09f6b9ea2 100644 (file)
@@ -142,8 +142,16 @@ int smbrunsecret(const char *cmd, const char *secret);
 
 /* The following definitions come from lib/sysquotas.c  */
 
-int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
-int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp);
+int sys_get_quota(dev_t dev,
+                 const char *path,
+                 enum SMB_QUOTA_TYPE qtype,
+                 unid_t id,
+                 SMB_DISK_QUOTA *dp);
+int sys_set_quota(dev_t dev,
+                 const char *path,
+                 enum SMB_QUOTA_TYPE qtype,
+                 unid_t id,
+                 SMB_DISK_QUOTA *dp);
 
 /* The following definitions come from lib/sysquotas_*.c  */
 
index 648d028c7d815b1399175c0f0e97d6a96d58e98f..619456db3955ff85a1c4e381a354840b6c2792d2 100644 (file)
 
 #endif /* NO_QUOTACTL_USED */
 
+static bool sys_dev_to_bdev(TALLOC_CTX *mem_ctx,
+                           dev_t dev,
+                           char **mntpath,
+                           char **bdev,
+                           char **fs)
+{
+       static bool have_proc_self_mountinfo = true;
+       FILE *f = NULL;
+       char *line = NULL;
+       size_t len = 0;
+       ssize_t nread;
+       bool ret = false;
+
+       if (!have_proc_self_mountinfo) {
+               /*
+                * try only once
+                */
+               return false;
+       }
+
+       /*
+        * /proc/self/mountinfo gives us all we need without stat()ing
+        * every mountpoint.
+        */
+
+       f = fopen("/proc/self/mountinfo", "r");
+       if (f == NULL) {
+               have_proc_self_mountinfo = false;
+               return false;
+       }
+
+       while ((nread = getline(&line, &len, f)) != -1) {
+               unsigned long major, minor;
+               char **entry = NULL;
+               size_t entrylen;
+               int num;
+
+               entry = str_list_make(mem_ctx, line, " ");
+               if (entry == NULL) {
+                       break;
+               }
+
+               entrylen = str_list_length((const char *const *)entry);
+               if (entrylen < 11) {
+                       TALLOC_FREE(entry);
+                       continue;
+               }
+
+               num = sscanf(entry[2], "%lu:%lu", &major, &minor);
+               if (num != 2) {
+                       TALLOC_FREE(entry);
+                       continue;
+               }
+
+               if (makedev(major, minor) != dev) {
+                       TALLOC_FREE(entry);
+                       continue;
+               }
+
+               *mntpath = talloc_move(mem_ctx, &entry[4]);
+               *bdev = talloc_move(mem_ctx, &entry[9]);
+               *fs = talloc_move(mem_ctx, &entry[8]);
+               TALLOC_FREE(entry);
+               ret = true;
+
+               break;
+       }
+
+       SAFE_FREE(line);
+
+       if (f != NULL) {
+               fclose(f);
+               f = NULL;
+       }
+
+       return ret;
+}
+
 #if defined(HAVE_MNTENT) && defined(HAVE_REALPATH)
 static int sys_path_to_bdev(TALLOC_CTX *mem_ctx,
                            const char *path,
@@ -425,8 +503,13 @@ static int command_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t
        return -1;
 }
 
-int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+int sys_get_quota(dev_t dev,
+                 const char *path,
+                 enum SMB_QUOTA_TYPE qtype,
+                 unid_t id,
+                 SMB_DISK_QUOTA *dp)
 {
+       bool ok;
        int ret = -1;
        int i;
        bool ready = False;
@@ -443,10 +526,14 @@ int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DI
                return -1;
        }
 
-       ret = sys_path_to_bdev(talloc_tos(), path, &mntpath, &bdev, &fs);
-       if (ret != 0) {
-               DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
-               return ret;
+       ok = sys_dev_to_bdev(talloc_tos(), dev, &mntpath, &bdev, &fs);
+       if (!ok) {
+               ret = sys_path_to_bdev(
+                       talloc_tos(), path, &mntpath, &bdev, &fs);
+               if (ret != 0) {
+                       DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
+                       return ret;
+               }
        }
 
        errno = 0;
@@ -486,8 +573,13 @@ int sys_get_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DI
        return ret;
 }
 
-int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
+int sys_set_quota(dev_t dev,
+                 const char *path,
+                 enum SMB_QUOTA_TYPE qtype,
+                 unid_t id,
+                 SMB_DISK_QUOTA *dp)
 {
+       bool ok;
        int ret = -1;
        int i;
        bool ready = False;
@@ -506,10 +598,14 @@ int sys_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DI
                return -1;
        }
 
-       ret = sys_path_to_bdev(talloc_tos(), path, &mntpath, &bdev, &fs);
-       if (ret != 0) {
-               DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
-               return ret;
+       ok = sys_dev_to_bdev(talloc_tos(), dev, &mntpath, &bdev, &fs);
+       if (!ok) {
+               ret = sys_path_to_bdev(
+                       talloc_tos(), path, &mntpath, &bdev, &fs);
+               if (ret != 0) {
+                       DEBUG(0,("sys_path_to_bdev() failed for path [%s]!\n",path));
+                       return ret;
+               }
        }
 
        errno = 0;
index d17462d6f6764c1b8c497e0c7cf4f016deccc065..21fab6c5d31560bb1358e5cbd0ac948b5d70f213 100644 (file)
@@ -130,7 +130,8 @@ static int vfswrap_get_quota(struct vfs_handle_struct *handle,
        int result;
 
        START_PROFILE_X(SNUM(handle->conn), syscall_get_quota);
-       result = sys_get_quota(smb_fname->base_name, qtype, id, qt);
+       result = sys_get_quota(
+               smb_fname->st.st_ex_dev, smb_fname->base_name, qtype, id, qt);
        END_PROFILE_X(syscall_get_quota);
        return result;
 #else
@@ -150,7 +151,8 @@ static int vfswrap_set_quota(struct vfs_handle_struct *handle,
        int result;
 
        START_PROFILE_X(SNUM(handle->conn), syscall_set_quota);
-       result = sys_set_quota(smb_fname->base_name, qtype, id, qt);
+       result = sys_set_quota(
+               smb_fname->st.st_ex_dev, smb_fname->base_name, qtype, id, qt);
        END_PROFILE_X(syscall_set_quota);
        return result;
 #else