mirror of
https://github.com/samba-team/samba.git
synced 2025-03-27 22:50:26 +03:00
s3:vfs_gpfs: Report disk space and usage on GPFS share according to quotas
When a client requests the information about free space and space used, adjust the reported values according to quotas in the GPFS file system: - Retrieve quotas for the current user, current group and fileset for the top level of the share. - If the soft block quota grace time has expired, report disk as full. - If a hard block quota has been exceeded, report disk as full. - If none of the hard block quotas been exceeded, report share size and free space according to the lowest limits found in the quotas. - If no applicable hard block quota has been set, report the information from the statfs call. This feature is disabled by default and has to be enabled by setting the option gpfs:dfreequota.
This commit is contained in:
parent
a9cfd80d87
commit
62616784ae
@ -221,6 +221,53 @@
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
||||
<term>gpfs:dfreequota = [ yes | no ]</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Adjust reporting of the size and free space of a share
|
||||
according to quotas. If this setting is "yes", a
|
||||
request for size and free space will also evaluate the
|
||||
following quotas:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>The user quota of the user requesting
|
||||
the data.</para></listitem>
|
||||
<listitem><para>The group quota of the primary group
|
||||
of the user.</para></listitem>
|
||||
<listitem><para>The fileset quota for the fileset
|
||||
containing the top level directory of the share.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
If any of the soft or hard quota limits has been
|
||||
reached, the free space will be reported as 0. If a
|
||||
quota is in place, but the limits have not been
|
||||
reached, the free space will be reported according to
|
||||
the space left in the quota. If more than one quota
|
||||
applies the free space will be reported as the smallest
|
||||
space left in those quotas. The size of the share
|
||||
will be reported according to the quota usage. If more
|
||||
than one quota applies, the smallest size will be
|
||||
reported for the share size according to these quotas.
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<command>yes</command> - include the quotas
|
||||
when reporting the share size and free space
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<command>no(default)</command> - do not include quotas,
|
||||
simply report the size and free space of the file system
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
||||
<term>nfs4:mode = [ simple | special ]</term>
|
||||
<listitem>
|
||||
<para>
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "nfs4_acls.h"
|
||||
#include "vfs_gpfs.h"
|
||||
#include "system/filesys.h"
|
||||
#include "auth.h"
|
||||
|
||||
struct gpfs_config_data {
|
||||
bool sharemodes;
|
||||
@ -42,6 +43,7 @@ struct gpfs_config_data {
|
||||
bool winattr;
|
||||
bool ftruncate;
|
||||
bool getrealfilename;
|
||||
bool dfreequota;
|
||||
};
|
||||
|
||||
|
||||
@ -1385,6 +1387,9 @@ int vfs_gpfs_connect(struct vfs_handle_struct *handle, const char *service,
|
||||
config->getrealfilename = lp_parm_bool(SNUM(handle->conn), "gpfs",
|
||||
"getrealfilename", true);
|
||||
|
||||
config->dfreequota = lp_parm_bool(SNUM(handle->conn), "gpfs",
|
||||
"dfreequota", false);
|
||||
|
||||
SMB_VFS_HANDLE_SET_DATA(handle, config,
|
||||
NULL, struct gpfs_config_data,
|
||||
return -1);
|
||||
@ -1392,6 +1397,129 @@ int vfs_gpfs_connect(struct vfs_handle_struct *handle, const char *service,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfs_gpfs_get_quotas(const char *path, uid_t uid, gid_t gid,
|
||||
int *fset_id,
|
||||
struct gpfs_quotaInfo *qi_user,
|
||||
struct gpfs_quotaInfo *qi_group,
|
||||
struct gpfs_quotaInfo *qi_fset)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = get_gpfs_fset_id(path, fset_id);
|
||||
if (err) {
|
||||
DEBUG(0, ("Get fset id failed, errno %d.\n", errno));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = get_gpfs_quota(path, GPFS_USRQUOTA, uid, qi_user);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = get_gpfs_quota(path, GPFS_GRPQUOTA, gid, qi_group);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = get_gpfs_quota(path, GPFS_FILESETQUOTA, *fset_id, qi_fset);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vfs_gpfs_disk_free_quota(struct gpfs_quotaInfo qi, time_t cur_time,
|
||||
uint64_t *dfree, uint64_t *dsize)
|
||||
{
|
||||
uint64_t usage, limit;
|
||||
|
||||
/*
|
||||
* The quota reporting is done in units of 1024 byte blocks, but
|
||||
* sys_fsusage uses units of 512 byte blocks, adjust the block number
|
||||
* accordingly. Also filter possibly negative usage counts from gpfs.
|
||||
*/
|
||||
usage = qi.blockUsage < 0 ? 0 : (uint64_t)qi.blockUsage * 2;
|
||||
limit = (uint64_t)qi.blockHardLimit * 2;
|
||||
|
||||
/*
|
||||
* When the grace time for the exceeded soft block quota has been
|
||||
* exceeded, the soft block quota becomes an additional hard limit.
|
||||
*/
|
||||
if (qi.blockGraceTime && cur_time > qi.blockGraceTime) {
|
||||
/* report disk as full */
|
||||
*dfree = 0;
|
||||
*dsize = MIN(*dsize, usage);
|
||||
}
|
||||
|
||||
if (!qi.blockHardLimit)
|
||||
return;
|
||||
|
||||
if (usage >= limit) {
|
||||
/* report disk as full */
|
||||
*dfree = 0;
|
||||
*dsize = MIN(*dsize, usage);
|
||||
|
||||
} else {
|
||||
/* limit has not been reached, determine "free space" */
|
||||
*dfree = MIN(*dfree, limit - usage);
|
||||
*dsize = MIN(*dsize, limit);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t vfs_gpfs_disk_free(vfs_handle_struct *handle, const char *path,
|
||||
bool small_query, uint64_t *bsize,
|
||||
uint64_t *dfree, uint64_t *dsize)
|
||||
{
|
||||
struct security_unix_token *utok;
|
||||
struct gpfs_quotaInfo qi_user, qi_group, qi_fset;
|
||||
struct gpfs_config_data *config;
|
||||
int err, fset_id;
|
||||
time_t cur_time;
|
||||
|
||||
SMB_VFS_HANDLE_GET_DATA(handle, config, struct gpfs_config_data,
|
||||
return (uint64_t)-1);
|
||||
if (!config->dfreequota) {
|
||||
return SMB_VFS_NEXT_DISK_FREE(handle, path, small_query,
|
||||
bsize, dfree, dsize);
|
||||
}
|
||||
|
||||
err = sys_fsusage(path, dfree, dsize);
|
||||
if (err) {
|
||||
DEBUG (0, ("Could not get fs usage, errno %d\n", errno));
|
||||
return SMB_VFS_NEXT_DISK_FREE(handle, path, small_query,
|
||||
bsize, dfree, dsize);
|
||||
}
|
||||
|
||||
/* sys_fsusage returns units of 512 bytes */
|
||||
*bsize = 512;
|
||||
|
||||
DEBUG(10, ("fs dfree %llu, dsize %llu\n",
|
||||
(unsigned long long)*dfree, (unsigned long long)*dsize));
|
||||
|
||||
utok = handle->conn->session_info->unix_token;
|
||||
err = vfs_gpfs_get_quotas(path, utok->uid, utok->gid, &fset_id,
|
||||
&qi_user, &qi_group, &qi_fset);
|
||||
if (err) {
|
||||
return SMB_VFS_NEXT_DISK_FREE(handle, path, small_query,
|
||||
bsize, dfree, dsize);
|
||||
}
|
||||
|
||||
cur_time = time(NULL);
|
||||
|
||||
/* Adjust free space and size according to quota limits. */
|
||||
vfs_gpfs_disk_free_quota(qi_user, cur_time, dfree, dsize);
|
||||
vfs_gpfs_disk_free_quota(qi_group, cur_time, dfree, dsize);
|
||||
|
||||
/* Id 0 indicates the default quota, not an actual quota */
|
||||
if (fset_id != 0) {
|
||||
vfs_gpfs_disk_free_quota(qi_fset, cur_time, dfree, dsize);
|
||||
}
|
||||
|
||||
disk_norm(small_query, bsize, dfree, dsize);
|
||||
return *dfree;
|
||||
}
|
||||
|
||||
static uint32_t vfs_gpfs_capabilities(struct vfs_handle_struct *handle,
|
||||
enum timestamp_set_resolution *p_ts_res)
|
||||
{
|
||||
@ -1429,6 +1557,7 @@ static int vfs_gpfs_open(struct vfs_handle_struct *handle,
|
||||
|
||||
static struct vfs_fn_pointers vfs_gpfs_fns = {
|
||||
.connect_fn = vfs_gpfs_connect,
|
||||
.disk_free_fn = vfs_gpfs_disk_free,
|
||||
.fs_capabilities_fn = vfs_gpfs_capabilities,
|
||||
.kernel_flock_fn = vfs_gpfs_kernel_flock,
|
||||
.linux_setlease_fn = vfs_gpfs_setlease,
|
||||
|
Loading…
x
Reference in New Issue
Block a user