smbd: get a valid file stat to disk_quotas
authorUri Simchoni <uri@samba.org>
Wed, 13 Jan 2016 22:09:36 +0000 (00:09 +0200)
committerJeremy Allison <jra@samba.org>
Fri, 12 Aug 2016 23:53:15 +0000 (01:53 +0200)
Most calls to disk_quotas originate at a state with an
open file descriptor. Pass the file's stat info down to
disk_quota, so that we can avoid extra stat's and the related
error handling.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=12145

Signed-off-by: Uri Simchoni <uri@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/modules/vfs_ceph.c
source3/modules/vfs_default.c
source3/smbd/dfree.c
source3/smbd/proto.h
source3/smbd/quotas.c
source3/smbd/reply.c
source3/smbd/trans2.c
source3/smbd/vfs.c

index 8e11dab852ecaf2e0185d670234563d30452725a..59e9b9cf9b3e8e5313a20823994fcacf9e4b4168 100644 (file)
@@ -847,9 +847,8 @@ static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_str
                "error %d. Falling back to slow manual allocation\n", errno));
 
        /* available disk space is enough or not? */
-       space_avail = get_dfree_info(fsp->conn,
-                                    fsp->fsp_name->base_name,
-                                    &bsize, &dfree, &dsize);
+       space_avail =
+           get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
        /* space_avail is 1k blocks */
        if (space_avail == (uint64_t)-1 ||
                        ((uint64_t)space_to_write/1024 > space_avail) ) {
index de5a4a3dd5571e76d88f064cb639c1a2c31a7d1f..5227e95e302978c6801a9332757e63b8a2dfa237 100644 (file)
@@ -1978,9 +1978,8 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
                "error %d. Falling back to slow manual allocation\n", errno));
 
        /* available disk space is enough or not? */
-       space_avail = get_dfree_info(fsp->conn,
-                                    fsp->fsp_name->base_name,
-                                    &bsize, &dfree, &dsize);
+       space_avail =
+           get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
        /* space_avail is 1k blocks */
        if (space_avail == (uint64_t)-1 ||
                        ((uint64_t)space_to_write/1024 > space_avail) ) {
index fc52e518a48ee615ce30f911a7e8660bb983e1f8..7e58daa45cf5d0bb642ed57e2a6c8e4a86b35007 100644 (file)
@@ -50,7 +50,7 @@ static void disk_norm(uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
  Return number of 1K blocks available on a path and total number.
 ****************************************************************************/
 
-uint64_t sys_disk_free(connection_struct *conn, const char *path,
+uint64_t sys_disk_free(connection_struct *conn, struct smb_filename *fname,
                       uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
        uint64_t dfree_retval;
@@ -59,6 +59,7 @@ uint64_t sys_disk_free(connection_struct *conn, const char *path,
        uint64_t dsize_q = 0;
        const char *dfree_command;
        static bool dfree_broken = false;
+       const char *path = fname->base_name;
 
        (*dfree) = (*dsize) = 0;
        (*bsize) = 512;
@@ -124,7 +125,7 @@ uint64_t sys_disk_free(connection_struct *conn, const char *path,
                return (uint64_t)-1;
        }
 
-       if (disk_quotas(conn, path, &bsize_q, &dfree_q, &dsize_q)) {
+       if (disk_quotas(conn, fname, &bsize_q, &dfree_q, &dsize_q)) {
                uint64_t min_bsize = MIN(*bsize, bsize_q);
 
                (*dfree) = (*dfree) * (*bsize) / min_bsize;
@@ -168,18 +169,15 @@ dfree_done:
  Potentially returned cached dfree info.
 ****************************************************************************/
 
-uint64_t get_dfree_info(connection_struct *conn,
-                       const char *path,
-                       uint64_t *bsize,
-                       uint64_t *dfree,
-                       uint64_t *dsize)
+uint64_t get_dfree_info(connection_struct *conn, struct smb_filename *fname,
+                       uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
        int dfree_cache_time = lp_dfree_cache_time(SNUM(conn));
        struct dfree_cached_info *dfc = conn->dfree_info;
        uint64_t dfree_ret;
 
        if (!dfree_cache_time) {
-               return sys_disk_free(conn, path, bsize, dfree, dsize);
+               return sys_disk_free(conn, fname, bsize, dfree, dsize);
        }
 
        if (dfc && (conn->lastused - dfc->last_dfree_time < dfree_cache_time)) {
@@ -190,7 +188,7 @@ uint64_t get_dfree_info(connection_struct *conn,
                return dfc->dfree_ret;
        }
 
-       dfree_ret = sys_disk_free(conn, path, bsize, dfree, dsize);
+       dfree_ret = sys_disk_free(conn, fname, bsize, dfree, dsize);
 
        if (dfree_ret == (uint64_t)-1) {
                /* Don't cache bad data. */
index 7ca546005beea615d2e487e098a12fbb0eca5c52..fb30a9e0eaa178c4bba6d038f7f39b56f0092398 100644 (file)
@@ -172,13 +172,10 @@ bool connections_snum_used(struct smbd_server_connection *unused, int snum);
 
 /* The following definitions come from smbd/dfree.c  */
 
-uint64_t sys_disk_free(connection_struct *conn, const char *path,
-                              uint64_t *bsize,uint64_t *dfree,uint64_t *dsize);
-uint64_t get_dfree_info(connection_struct *conn,
-                       const char *path,
-                       uint64_t *bsize,
-                       uint64_t *dfree,
-                       uint64_t *dsize);
+uint64_t sys_disk_free(connection_struct *conn, struct smb_filename *fname,
+                      uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
+uint64_t get_dfree_info(connection_struct *conn, struct smb_filename *fname,
+                       uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
 
 /* The following definitions come from smbd/dir.c  */
 
@@ -855,8 +852,8 @@ bool fork_echo_handler(struct smbXsrv_connection *xconn);
 
 /* The following definitions come from smbd/quotas.c  */
 
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-                uint64_t *dfree, uint64_t *dsize);
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+                uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
 
 /* The following definitions come from smbd/reply.c  */
 
index 9d3b9061e9b1eb840132696b51f83c391389a62f..f3a727c0ed14eff30184ed45e18d61a2afc4a6b3 100644 (file)
@@ -216,8 +216,8 @@ try to get the disk space from disk quotas (SunOS & Solaris2 version)
 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
 ****************************************************************************/
 
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-                uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+                uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
        uid_t euser_id;
        int ret;
@@ -230,14 +230,11 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
        SMB_STRUCT_STAT sbuf;
        SMB_DEV_T devno;
        bool found = false;
+       const char *path = fname->base_name;
 
        euser_id = geteuid();
 
-       if (sys_stat(path, &sbuf, false) == -1) {
-               return false;
-       }
-
-       devno = sbuf.st_ex_dev ;
+       devno = fname->st.st_ex_dev;
        DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
                path, (unsigned int)devno));
        if ((fd = fopen(MNTTAB, "r")) == NULL) {
@@ -362,15 +359,16 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 try to get the disk space from disk quotas - default version
 ****************************************************************************/
 
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-                uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+                uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
   int r;
   struct dqblk D;
   uid_t euser_id;
+  const char *path = fname->base_name;
 #if !defined(AIX)
   char dev_disk[256];
-  SMB_STRUCT_STAT S;
+  SMB_STRUCT_STAT S = fname->st;
 
   /* find the block device file */
 
@@ -463,8 +461,8 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 
 #else /* WITH_QUOTAS */
 
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-                uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+                uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
        (*bsize) = 512; /* This value should be ignored */
 
@@ -482,8 +480,8 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 /* wrapper to the new sys_quota interface
    this file should be removed later
    */
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-                uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+                uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
        int r;
        SMB_DISK_QUOTA D;
@@ -496,7 +494,8 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
         */
        ZERO_STRUCT(D);
        id.uid = -1;
-       r = SMB_VFS_GET_QUOTA(conn, path, SMB_USER_FS_QUOTA_TYPE, id, &D);
+       r = SMB_VFS_GET_QUOTA(conn, fname->base_name, SMB_USER_FS_QUOTA_TYPE,
+                             id, &D);
        if (r == -1 && errno != ENOSYS) {
                goto try_group_quota;
        }
@@ -507,7 +506,8 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
        ZERO_STRUCT(D);
        id.uid = geteuid();
 
-       r = SMB_VFS_GET_QUOTA(conn, path, SMB_USER_QUOTA_TYPE, id, &D);
+       r = SMB_VFS_GET_QUOTA(conn, fname->base_name, SMB_USER_QUOTA_TYPE, id,
+                             &D);
 
        if (r == -1) {
                goto try_group_quota;
@@ -543,7 +543,8 @@ try_group_quota:
         */
        ZERO_STRUCT(D);
        id.gid = -1;
-       r = SMB_VFS_GET_QUOTA(conn, path, SMB_GROUP_FS_QUOTA_TYPE, id, &D);
+       r = SMB_VFS_GET_QUOTA(conn, fname->base_name, SMB_GROUP_FS_QUOTA_TYPE,
+                             id, &D);
        if (r == -1 && errno != ENOSYS) {
                return false;
        }
@@ -554,7 +555,8 @@ try_group_quota:
        id.gid = getegid();
 
        ZERO_STRUCT(D);
-       r = SMB_VFS_GET_QUOTA(conn, path, SMB_GROUP_QUOTA_TYPE, id, &D);
+       r = SMB_VFS_GET_QUOTA(conn, fname->base_name, SMB_GROUP_QUOTA_TYPE, id,
+                             &D);
 
        if (r == -1) {
                return False;
index 0b7a4fbd32991b67ae9d8456ce38eefd0ca1cb5d..4f1ecb1ae8395e49a0afea88a872abc12540feaa 100644 (file)
@@ -1573,9 +1573,20 @@ void reply_dskattr(struct smb_request *req)
        connection_struct *conn = req->conn;
        uint64_t ret;
        uint64_t dfree,dsize,bsize;
+       struct smb_filename smb_fname;
        START_PROFILE(SMBdskattr);
 
-       ret = get_dfree_info(conn, ".", &bsize, &dfree, &dsize);
+       ZERO_STRUCT(smb_fname);
+       smb_fname.base_name = discard_const_p(char, ".");
+
+       if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
+               reply_nterror(req, map_nt_error_from_unix(errno));
+               DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
+               END_PROFILE(SMBdskattr);
+               return;
+       }
+
+       ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
        if (ret == (uint64_t)-1) {
                reply_nterror(req, map_nt_error_from_unix(errno));
                END_PROFILE(SMBdskattr);
index 9c0660b367488a61ec031d9387d37236d2baf4be..1775316330e2a45a07b5bf891d21a66a67dd672c 100644 (file)
@@ -3438,8 +3438,8 @@ NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn,
                {
                        uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
                        data_len = 18;
-                       df_ret = get_dfree_info(conn, filename, &bsize, &dfree,
-                                               &dsize);
+                       df_ret = get_dfree_info(conn, &smb_fname, &bsize,
+                                               &dfree, &dsize);
                        if (df_ret == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
@@ -3589,8 +3589,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
                {
                        uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
                        data_len = 24;
-                       df_ret = get_dfree_info(conn, filename, &bsize, &dfree,
-                                               &dsize);
+                       df_ret = get_dfree_info(conn, &smb_fname, &bsize,
+                                               &dfree, &dsize);
                        if (df_ret == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
@@ -3623,8 +3623,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                {
                        uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
                        data_len = 32;
-                       df_ret = get_dfree_info(conn, filename, &bsize, &dfree,
-                                               &dsize);
+                       df_ret = get_dfree_info(conn, &smb_fname, &bsize,
+                                               &dfree, &dsize);
                        if (df_ret == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
index 605f9ade70381f248c93e4a6eafe6f46728710f0..45562eedebe2a1973a89ce23bf368b7b428d4b82 100644 (file)
@@ -623,8 +623,8 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
 
        len -= fsp->fsp_name->st.st_ex_size;
        len /= 1024; /* Len is now number of 1k blocks needed. */
-       space_avail = get_dfree_info(conn, fsp->fsp_name->base_name,
-                                    &bsize, &dfree, &dsize);
+       space_avail =
+           get_dfree_info(conn, fsp->fsp_name, &bsize, &dfree, &dsize);
        if (space_avail == (uint64_t)-1) {
                return -1;
        }