1
0
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:
Christof Schmitt 2012-03-02 14:26:24 -07:00 committed by Christian Ambach
parent a9cfd80d87
commit 62616784ae
2 changed files with 176 additions and 0 deletions

View File

@ -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>

View File

@ -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,