The branch, master has been updated via 8718c7b s3:vfs_gpfs: fix some compiler warnings via 0a37ca5 s3:vfs_gpfs: remove fallback to linux_setlease via a551ee5 s3:vfs_gpfs: correct use of profiling macros via 0a89609 s3:vfs_gpfs: Implement fallocate callback for GPFS via 6261678 s3:vfs_gpfs: Report disk space and usage on GPFS share according to quotas via a9cfd80 s3:vfs_gpfs: add GPFS api calls for quota and free space reporting via 4262eb4 s3:vfs_gpfs: Export disk_norm function via 80cb6e8 s3:client correct a wording from ffe884c s3: Fix smbd -i
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 8718c7b88de993cef66c2a26ff1addd52b30b05c Author: Christian Ambach <a...@samba.org> Date: Thu Mar 22 18:12:07 2012 +0100 s3:vfs_gpfs: fix some compiler warnings Autobuild-User: Christian Ambach <a...@samba.org> Autobuild-Date: Thu Mar 22 20:14:34 CET 2012 on sn-devel-104 commit 0a37ca5210c8591fc12a6560d3c5fc3ccdeceede Author: Christian Ambach <a...@samba.org> Date: Thu Mar 22 18:11:47 2012 +0100 s3:vfs_gpfs: remove fallback to linux_setlease if setting the lease in GPFS failed, there is not much sense in trying to set a lease just locally that would not inform us of openers on other cluster nodes commit a551ee5f222264d26e8eb02ecaf90b828433bab8 Author: Christian Ambach <a...@samba.org> Date: Thu Mar 22 18:00:17 2012 +0100 s3:vfs_gpfs: correct use of profiling macros under certain conditions START_PROFILE could have been called, but no END_PROFILE commit 0a896094c61fa1eec7dbb5bb35485747cdc1549d Author: Christof Schmitt <christof.schm...@us.ibm.com> Date: Thu Mar 8 13:57:12 2012 -0800 s3:vfs_gpfs: Implement fallocate callback for GPFS GPFS provides the gpfs_prealloc call. Implement the fallocate callback with mode VFS_FALLOCATE_EXTEND_SIZE using this call. There is no support for VFS_FALLOCATE_KEEP_SIZE, so report this mode as not available. commit 62616784ae5460bfd8f68ccfe596f80f55727b87 Author: Christof Schmitt <christof.schm...@us.ibm.com> Date: Fri Mar 2 14:26:24 2012 -0700 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. commit a9cfd80d8722f9af7fc18ea70115a6b1b1033168 Author: Christof Schmitt <christof.schm...@us.ibm.com> Date: Fri Mar 2 14:26:19 2012 -0700 s3:vfs_gpfs: add GPFS api calls for quota and free space reporting Add the GPFS api calls for reporting the quotas and free space: - get_gpfs_quota for querying a quota - get_gpfs_fset_id for mapping a path to a fileset id commit 4262eb401fac0a6f9f0f76bff390041ad6600536 Author: Christof Schmitt <christof.schm...@us.ibm.com> Date: Fri Mar 2 14:26:10 2012 -0700 s3:vfs_gpfs: Export disk_norm function vfs modules implementing the disk_free callback need access to the function disk_norm for normalizing the data if the parameter small query is true. commit 80cb6e84de0fa5c713bf1ba4c5866cdb1aea15f5 Author: Christian Ambach <a...@samba.org> Date: Thu Mar 22 16:49:30 2012 +0100 s3:client correct a wording ----------------------------------------------------------------------- Summary of changes: docs-xml/manpages-3/vfs_gpfs.8.xml | 72 ++++++++++++++ source3/client/client.c | 2 +- source3/modules/gpfs.c | 88 +++++++++++++++++ source3/modules/vfs_gpfs.c | 189 +++++++++++++++++++++++++++++++++--- source3/modules/vfs_gpfs.h | 7 +- source3/smbd/dfree.c | 2 +- source3/smbd/proto.h | 1 + 7 files changed, 346 insertions(+), 15 deletions(-) Changeset truncated at 500 lines: diff --git a/docs-xml/manpages-3/vfs_gpfs.8.xml b/docs-xml/manpages-3/vfs_gpfs.8.xml index 2107b74..4ea8c4d 100644 --- a/docs-xml/manpages-3/vfs_gpfs.8.xml +++ b/docs-xml/manpages-3/vfs_gpfs.8.xml @@ -221,6 +221,78 @@ </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>gpfs:prealloc = [ yes | no ]</term> + <listitem> + <para> + If set to yes the gpfs_prealloc function will be used in the + fallocate callback when appropriate. If set to no gpfs_prealloc + will not be used. In both cases the system and libc calls are + avoided. + </para> + + <itemizedlist> + <listitem><para> + <command>yes (default)</command> - Use gpfs_prealloc for the + fallocate callback. + </para></listitem> + <listitem><para> + <command>no</command> - Do not use gpfs_prealloc for the + fallocate callback. + </para></listitem> + </itemizedlist> + </listitem> + + </varlistentry> + + <varlistentry> + <term>nfs4:mode = [ simple | special ]</term> <listitem> <para> diff --git a/source3/client/client.c b/source3/client/client.c index 9ace7e4..87ec3a9 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -4617,7 +4617,7 @@ static struct { {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}}, {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}}, {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}}, - {"notify",cmd_notify,"<file>Get notified by dir changes",{COMPL_REMOTE,COMPL_NONE}}, + {"notify",cmd_notify,"<file>Get notified of dir changes",{COMPL_REMOTE,COMPL_NONE}}, {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}}, {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}}, {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}}, diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c index 5ce2381..2cbf0b5 100644 --- a/source3/modules/gpfs.c +++ b/source3/modules/gpfs.c @@ -22,6 +22,7 @@ #include "smbd/smbd.h" #include "libcli/security/security.h" +#include "gpfs_fcntl.h" #include "gpfs_gpl.h" #include "vfs_gpfs.h" @@ -34,8 +35,12 @@ static int (*gpfs_get_realfilename_path_fn)(char *pathname, char *filenamep, static int (*gpfs_set_winattrs_path_fn)(char *pathname, int flags, struct gpfs_winattr *attrs); static int (*gpfs_get_winattrs_path_fn)(char *pathname, struct gpfs_winattr *attrs); static int (*gpfs_get_winattrs_fn)(int fd, struct gpfs_winattr *attrs); +static int (*gpfs_prealloc_fn)(int fd, gpfs_off64_t startOffset, gpfs_off64_t bytesToPrealloc); static int (*gpfs_ftruncate_fn)(int fd, gpfs_off64_t length); static int (*gpfs_lib_init_fn)(int flags); +static int (*gpfs_quotactl_fn)(char *pathname, int cmd, int id, void *bufferP); +static int (*gpfs_fcntl_fn)(gpfs_file_t fileDesc, void *fcntlArgP); +static int (*gpfs_getfilesetid_fn)(char *pathname, char *name, int *idP); bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, uint32 share_access) @@ -173,6 +178,16 @@ int smbd_fget_gpfs_winattrs(int fd, struct gpfs_winattr *attrs) return gpfs_get_winattrs_fn(fd, attrs); } +int smbd_gpfs_prealloc(int fd, gpfs_off64_t start, gpfs_off64_t bytes) +{ + if (gpfs_prealloc_fn == NULL) { + errno = ENOSYS; + return -1; + } + + return gpfs_prealloc_fn(fd, start, bytes); +} + int set_gpfs_winattrs(char *pathname,int flags,struct gpfs_winattr *attrs) { if (gpfs_set_winattrs_path_fn == NULL) { @@ -184,6 +199,75 @@ int set_gpfs_winattrs(char *pathname,int flags,struct gpfs_winattr *attrs) return gpfs_set_winattrs_path_fn(pathname,flags, attrs); } +int get_gpfs_quota(const char *pathname, int type, int id, + struct gpfs_quotaInfo *qi) +{ + int ret; + + if (!gpfs_quotactl_fn) { + errno = ENOSYS; + return -1; + } + + ZERO_STRUCTP(qi); + ret = gpfs_quotactl_fn(discard_const_p(char, pathname), + GPFS_QCMD(Q_GETQUOTA, type), id, qi); + + if (ret) { + if (errno == GPFS_E_NO_QUOTA_INST) { + DEBUG(10, ("Quotas disabled on GPFS filesystem.\n")); + } else { + DEBUG(0, ("Get quota failed, type %d, id, %d, " + "errno %d.\n", type, id, errno)); + } + + return ret; + } + + DEBUG(10, ("quota type %d, id %d, blk u:%lld h:%lld s:%lld gt:%u\n", + type, id, qi->blockUsage, qi->blockHardLimit, + qi->blockSoftLimit, qi->blockGraceTime)); + + return ret; +} + +int get_gpfs_fset_id(const char *pathname, int *fset_id) +{ + int err, fd, errno_fcntl; + + struct { + gpfsFcntlHeader_t hdr; + gpfsGetFilesetName_t fsn; + } arg; + + if (!gpfs_fcntl_fn || !gpfs_getfilesetid_fn) { + errno = ENOSYS; + return -1; + } + + arg.hdr.totalLength = sizeof(arg); + arg.hdr.fcntlVersion = GPFS_FCNTL_CURRENT_VERSION; + arg.hdr.fcntlReserved = 0; + arg.fsn.structLen = sizeof(arg.fsn); + arg.fsn.structType = GPFS_FCNTL_GET_FILESETNAME; + + fd = open(pathname, O_RDONLY); + if (fd == -1) + return fd; + + err = gpfs_fcntl_fn(fd, &arg); + errno_fcntl = errno; + close(fd); + + if (err) { + errno = errno_fcntl; + return err; + } + + return gpfs_getfilesetid_fn(discard_const_p(char, pathname), + arg.fsn.buffer, fset_id); +} + void smbd_gpfs_lib_init() { if (gpfs_lib_init_fn) { @@ -256,8 +340,12 @@ void init_gpfs(void) init_gpfs_function(&gpfs_get_winattrs_path_fn,"gpfs_get_winattrs_path"); init_gpfs_function(&gpfs_set_winattrs_path_fn,"gpfs_set_winattrs_path"); init_gpfs_function(&gpfs_get_winattrs_fn,"gpfs_get_winattrs"); + init_gpfs_function(&gpfs_prealloc_fn, "gpfs_prealloc"); init_gpfs_function(&gpfs_ftruncate_fn, "gpfs_ftruncate"); init_gpfs_function(&gpfs_lib_init_fn,"gpfs_lib_init"); + init_gpfs_function(&gpfs_quotactl_fn, "gpfs_quotactl"); + init_gpfs_function(&gpfs_fcntl_fn, "gpfs_fcntl"); + init_gpfs_function(&gpfs_getfilesetid_fn, "gpfs_getfilesetid"); return; } diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 6a9d3d5..fce1b28 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -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,8 @@ struct gpfs_config_data { bool winattr; bool ftruncate; bool getrealfilename; + bool dfreequota; + bool prealloc; }; @@ -50,6 +53,7 @@ static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, { struct gpfs_config_data *config; + int ret = 0; SMB_VFS_HANDLE_GET_DATA(handle, config, struct gpfs_config_data, @@ -61,12 +65,12 @@ static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, if (config->sharemodes && !set_gpfs_sharemode(fsp, access_mask, fsp->share_access)) { - return -1; + ret = -1; } END_PROFILE(syscall_kernel_flock); - return 0; + return ret; } static int vfs_gpfs_close(vfs_handle_struct *handle, files_struct *fsp) @@ -95,21 +99,15 @@ static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, struct gpfs_config_data, return -1); - START_PROFILE(syscall_linux_setlease); - if (linux_set_lease_sighandler(fsp->fh->fd) == -1) return -1; + START_PROFILE(syscall_linux_setlease); + if (config->leases) { ret = set_gpfs_lease(fsp->fh->fd,leasetype); } - if (ret < 0) { - /* This must have come from GPFS not being available */ - /* or some other error, hence call the default */ - ret = linux_setlease(fsp->fh->fd, leasetype); - } - END_PROFILE(syscall_linux_setlease); return ret; @@ -1261,6 +1259,42 @@ static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle, } +static int vfs_gpfs_fallocate(struct vfs_handle_struct *handle, + struct files_struct *fsp, enum vfs_fallocate_mode mode, + SMB_OFF_T offset, SMB_OFF_T len) +{ + int ret; + struct gpfs_config_data *config; + + SMB_VFS_HANDLE_GET_DATA(handle, config, + struct gpfs_config_data, + return -1); + + if (!config->prealloc) { + /* you should better not run fallocate() on GPFS at all */ + errno = ENOTSUP; + return -1; + } + + if (mode == VFS_FALLOCATE_KEEP_SIZE) { + DEBUG(10, ("Unsupported VFS_FALLOCATE_KEEP_SIZE\n")); + errno = ENOTSUP; + return -1; + } + + ret = smbd_gpfs_prealloc(fsp->fh->fd, offset, len); + + if (ret == -1 && errno != ENOSYS) { + DEBUG(0, ("GPFS prealloc failed: %s\n", strerror(errno))); + } else if (ret == -1 && errno == ENOSYS) { + DEBUG(10, ("GPFS prealloc not supported.\n")); + } else { + DEBUG(10, ("GPFS prealloc succeeded.\n")); + } + + return ret; +} + static int vfs_gpfs_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T len) { @@ -1343,8 +1377,8 @@ static ssize_t vfs_gpfs_sendfile(vfs_handle_struct *handle, int tofd, return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n); } -int vfs_gpfs_connect(struct vfs_handle_struct *handle, const char *service, - const char *user) +static int vfs_gpfs_connect(struct vfs_handle_struct *handle, + const char *service, const char *user) { struct gpfs_config_data *config; int ret; @@ -1385,6 +1419,12 @@ 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); + + config->prealloc = lp_parm_bool(SNUM(handle->conn), "gpfs", + "prealloc", true); + SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct gpfs_config_data, return -1); @@ -1392,6 +1432,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 +1592,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, -- Samba Shared Repository