s3:vfs_gpfs: Implement fallocate callback for GPFS
authorChristof Schmitt <christof.schmitt@us.ibm.com>
Thu, 8 Mar 2012 21:57:12 +0000 (13:57 -0800)
committerChristian Ambach <ambi@samba.org>
Thu, 22 Mar 2012 17:41:22 +0000 (18:41 +0100)
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.

docs-xml/manpages-3/vfs_gpfs.8.xml
source3/modules/gpfs.c
source3/modules/vfs_gpfs.c
source3/modules/vfs_gpfs.h

index 398dcff..4ea8c4d 100644 (file)
                </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>
index f17c6bb..2cbf0b5 100644 (file)
@@ -35,6 +35,7 @@ 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);
@@ -177,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) {
@@ -329,6 +340,7 @@ 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");
index 9597999..65cd33a 100644 (file)
@@ -44,6 +44,7 @@ struct gpfs_config_data {
        bool ftruncate;
        bool getrealfilename;
        bool dfreequota;
+       bool prealloc;
 };
 
 
@@ -1263,6 +1264,42 @@ static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
 
 }
 
+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)
 {
@@ -1390,6 +1427,9 @@ int vfs_gpfs_connect(struct vfs_handle_struct *handle, const char *service,
        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);
@@ -1582,6 +1622,7 @@ static struct vfs_fn_pointers vfs_gpfs_fns = {
        .is_offline_fn = vfs_gpfs_is_offline,
        .aio_force_fn = vfs_gpfs_aio_force,
        .sendfile_fn = vfs_gpfs_sendfile,
+       .fallocate_fn = vfs_gpfs_fallocate,
        .open_fn = vfs_gpfs_open,
        .ftruncate_fn = vfs_gpfs_ftruncate
 };
index 4a9528a..dfa4d43 100644 (file)
@@ -33,6 +33,7 @@ int smbd_gpfs_get_realfilename_path(char *pathname, char *filenamep,
 int smbd_fget_gpfs_winattrs(int fd, struct gpfs_winattr *attrs);
 int get_gpfs_winattrs(char * pathname,struct gpfs_winattr *attrs);
 int set_gpfs_winattrs(char * pathname,int flags,struct gpfs_winattr *attrs);
+int smbd_gpfs_prealloc(int fd, gpfs_off64_t start, gpfs_off64_t bytes);
 int smbd_gpfs_ftruncate(int fd, gpfs_off64_t length);
 int get_gpfs_quota(const char *pathname, int type, int id,
                   struct gpfs_quotaInfo *qi);