[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha6-714-g11f60a6

Steven Danneman sdanneman at samba.org
Tue Feb 10 07:59:57 GMT 2009


The branch, master has been updated
       via  11f60a62a1d7633e9a8ec62da18ed9ababa694df (commit)
       via  6272f4c2f453c509b8a3893d4c2ac5fc356b348d (commit)
       via  25d345eb39c69b2b42a966846ae893b068de40a4 (commit)
       via  af0e199b31ea4132e369508d72888757887b3327 (commit)
      from  9a7491e83177ba32e30f29e1b84b8b8be9888953 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 11f60a62a1d7633e9a8ec62da18ed9ababa694df
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Mon Jan 26 20:14:32 2009 -0800

    s3: OneFS bulk directory enumeration support
    
    OneFS provides the bulk directory enumeration syscall readdirplus().  This
    syscall has the same semantics as the NFSv3 READDIRPLUS command, returning
    a batch of directory entries with prefetched stat information via one
    syscall.
    
    This commit wraps the readdirplus() call in the existing POSIX
    readdir/seekdir VFS interface.  By default a batch of 128 directory entries
    are optimistically read from the kernel into a global cache, and fed to
    iterative calls of VFS_OP_READDIR.
    
    The global buffers could be avoided in the future by hanging connection
    specific buffers off the conn struct.
    
    Added new parameter "onefs:use readdirplus" which toggles usage of this
    code on or off.

commit 6272f4c2f453c509b8a3893d4c2ac5fc356b348d
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Mon Feb 2 21:37:51 2009 -0800

    s3: Added SMB_VFS_INIT_SEARCH_OP to initialize data at the beginning of SMB search requests.
    
    By default this VFS call is a NOOP, but the onefs vfs module takes advantage
    of it to initialize direntry search caches at the beginning of each
    TRANS2_FIND_FIRST, TRANS2_FIND_NEXT, SMBffirst, SMBsearch, and SMBunique

commit 25d345eb39c69b2b42a966846ae893b068de40a4
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Thu Jan 22 20:18:56 2009 -0800

    Pass stat buffer down through all levels of VFS_READDIR wrappers
    
    * VFS_OP_READDIR can now provide stat information, take advantage of it
      if it's available
    * is_visible_file(): optimistically expect the provided stat buffer is
      already valid
    * dptr_ReadDirName(): refactor code for easier readability, functionality
      is the same

commit af0e199b31ea4132e369508d72888757887b3327
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Thu Jan 22 20:14:38 2009 -0800

    Add an optional SMB_STRUCT_SMB parameter to VFS_OP_READDIR
    
    * this allows VFS implementations that prefetch stat information on
      readdir to return it through one VFS call
    * backwards compatibility is maintained by passing in NULL
    * if the system readdir doesn't return stat info, the stat struct is
      set to invalid

-----------------------------------------------------------------------

Summary of changes:
 source3/Makefile.in                 |    2 +-
 source3/include/proto.h             |    6 +-
 source3/include/vfs.h               |   15 +-
 source3/include/vfs_macros.h        |   11 +-
 source3/modules/onefs.h             |   46 ++-
 source3/modules/onefs_dir.c         |  636 +++++++++++++++++++++++++++++++++++
 source3/modules/onefs_streams.c     |    2 +-
 source3/modules/vfs_cap.c           |    2 +-
 source3/modules/vfs_catia.c         |    5 +-
 source3/modules/vfs_default.c       |   16 +-
 source3/modules/vfs_full_audit.c    |   21 +-
 source3/modules/vfs_onefs.c         |   24 ++-
 source3/modules/vfs_shadow_copy.c   |    4 +-
 source3/modules/vfs_shadow_copy2.c  |    2 +-
 source3/modules/vfs_streams_depot.c |    2 +-
 source3/smbd/dir.c                  |  180 ++++++-----
 source3/smbd/filename.c             |    2 +-
 source3/smbd/msdfs.c                |    4 +-
 source3/smbd/reply.c                |   24 +-
 source3/smbd/trans2.c               |   12 +-
 source3/smbd/vfs.c                  |    4 +-
 source3/torture/cmd_vfs.c           |   35 ++-
 22 files changed, 912 insertions(+), 143 deletions(-)
 create mode 100644 source3/modules/onefs_dir.c


Changeset truncated at 500 lines:

diff --git a/source3/Makefile.in b/source3/Makefile.in
index 2049953..6e453c9 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -664,7 +664,7 @@ VFS_ACL_XATTR_OBJ = modules/vfs_acl_xattr.o
 VFS_ACL_TDB_OBJ = modules/vfs_acl_tdb.o
 VFS_SMB_TRAFFIC_ANALYZER_OBJ = modules/vfs_smb_traffic_analyzer.o
 VFS_ONEFS_OBJ = modules/vfs_onefs.o modules/onefs_acl.o modules/onefs_system.o \
-		modules/onefs_open.o modules/onefs_streams.o
+		modules/onefs_open.o modules/onefs_streams.o modules/onefs_dir.c
 PERFCOUNT_ONEFS_OBJ = modules/perfcount_onefs.o
 
 PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 1566a01..849bed3 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -6495,6 +6495,7 @@ const char *dptr_ReadDirName(TALLOC_CTX *ctx,
 			SMB_STRUCT_STAT *pst);
 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst);
 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset);
+void dptr_init_search_op(struct dptr_struct *dptr);
 bool dptr_fill(char *buf1,unsigned int key);
 struct dptr_struct *dptr_fetch(char *buf,int *num);
 struct dptr_struct *dptr_fetch_lanman2(int dptr_num);
@@ -6512,7 +6513,8 @@ bool get_dir_entry(TALLOC_CTX *ctx,
 bool is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, bool use_veto);
 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
 			const char *name, const char *mask, uint32 attr);
-const char *ReadDirName(struct smb_Dir *dirp, long *poffset);
+const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
+			SMB_STRUCT_STAT *sbuf);
 void RewindDir(struct smb_Dir *dirp, long *poffset);
 void SeekDir(struct smb_Dir *dirp, long offset);
 long TellDir(struct smb_Dir *dirp);
@@ -7356,7 +7358,7 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len);
 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len);
 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len);
 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n);
-char *vfs_readdirname(connection_struct *conn, void *p);
+char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf);
 int vfs_ChDir(connection_struct *conn, const char *path);
 char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn);
 NTSTATUS check_reduced_name(connection_struct *conn, const char *fname);
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index 228f090..f944c89 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -113,6 +113,8 @@
 /* Leave at 25 - not yet released. Add create_file call. -- tprouty. */
 /* Leave at 25 - not yet released. Add create time to ntimes. -- tstecher. */
 /* Leave at 25 - not yet released. Add get_alloc_size call. -- tprouty. */
+/* Leave at 25 - not yet released. Add SMB_STRUCT_STAT to readdir. - sdann */
+/* Leave at 25 - not yet released. Add init_search_op call. - sdann */
 
 #define SMB_VFS_INTERFACE_VERSION 25
 
@@ -143,14 +145,14 @@ struct smb_file_time;
 
 /*
     Available VFS operations. These values must be in sync with vfs_ops struct
-    (struct vfs_fn_pointers and struct vfs_handle_pointers inside of struct vfs_ops). 
+    (struct vfs_fn_pointers and struct vfs_handle_pointers inside of struct vfs_ops).
     In particular, if new operations are added to vfs_ops, appropriate constants
     should be added to vfs_op_type so that order of them kept same as in vfs_ops.
 */
 
 typedef enum _vfs_op_type {
 	SMB_VFS_OP_NOOP = -1,
-	
+
 	/* Disk operations */
 
 	SMB_VFS_OP_CONNECT = 0,
@@ -172,6 +174,7 @@ typedef enum _vfs_op_type {
 	SMB_VFS_OP_MKDIR,
 	SMB_VFS_OP_RMDIR,
 	SMB_VFS_OP_CLOSEDIR,
+	SMB_VFS_OP_INIT_SEARCH_OP,
 
 	/* File operations */
 
@@ -249,7 +252,7 @@ typedef enum _vfs_op_type {
 	SMB_VFS_OP_SYS_ACL_FREE_TEXT,
 	SMB_VFS_OP_SYS_ACL_FREE_ACL,
 	SMB_VFS_OP_SYS_ACL_FREE_QUALIFIER,
-	
+
 	/* EA operations. */
 	SMB_VFS_OP_GETXATTR,
 	SMB_VFS_OP_LGETXATTR,
@@ -303,13 +306,16 @@ struct vfs_ops {
 		/* Directory operations */
 
 		SMB_STRUCT_DIR *(*opendir)(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attributes);
-		SMB_STRUCT_DIRENT *(*readdir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp);
+		SMB_STRUCT_DIRENT *(*readdir)(struct vfs_handle_struct *handle,
+					      SMB_STRUCT_DIR *dirp,
+					      SMB_STRUCT_STAT *sbuf);
 		void (*seekdir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, long offset);
 		long (*telldir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp);
 		void (*rewind_dir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp);
 		int (*mkdir)(struct vfs_handle_struct *handle, const char *path, mode_t mode);
 		int (*rmdir)(struct vfs_handle_struct *handle, const char *path);
 		int (*closedir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dir);
+		void (*init_search_op)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp);
 
 		/* File operations */
 
@@ -481,6 +487,7 @@ struct vfs_ops {
 		struct vfs_handle_struct *mkdir;
 		struct vfs_handle_struct *rmdir;
 		struct vfs_handle_struct *closedir;
+		struct vfs_handle_struct *init_search_op;
 
 		/* File operations */
 
diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h
index e7a9cfd..e57cbd2 100644
--- a/source3/include/vfs_macros.h
+++ b/source3/include/vfs_macros.h
@@ -38,13 +38,14 @@
 
 /* Directory operations */
 #define SMB_VFS_OPENDIR(conn, fname, mask, attr) ((conn)->vfs.ops.opendir((conn)->vfs.handles.opendir, (fname), (mask), (attr)))
-#define SMB_VFS_READDIR(conn, dirp) ((conn)->vfs.ops.readdir((conn)->vfs.handles.readdir, (dirp)))
+#define SMB_VFS_READDIR(conn, dirp, sbuf) ((conn)->vfs.ops.readdir((conn)->vfs.handles.readdir, (dirp), (sbuf)))
 #define SMB_VFS_SEEKDIR(conn, dirp, offset) ((conn)->vfs.ops.seekdir((conn)->vfs.handles.seekdir, (dirp), (offset)))
 #define SMB_VFS_TELLDIR(conn, dirp) ((conn)->vfs.ops.telldir((conn)->vfs.handles.telldir, (dirp)))
 #define SMB_VFS_REWINDDIR(conn, dirp) ((conn)->vfs.ops.rewind_dir((conn)->vfs.handles.rewind_dir, (dirp)))
 #define SMB_VFS_MKDIR(conn, path, mode) ((conn)->vfs.ops.mkdir((conn)->vfs.handles.mkdir,(path), (mode)))
 #define SMB_VFS_RMDIR(conn, path) ((conn)->vfs.ops.rmdir((conn)->vfs.handles.rmdir, (path)))
 #define SMB_VFS_CLOSEDIR(conn, dir) ((conn)->vfs.ops.closedir((conn)->vfs.handles.closedir, dir))
+#define SMB_VFS_INIT_SEARCH_OP(conn, dirp) ((conn)->vfs.ops.init_search_op((conn)->vfs.handles.init_search_op, (dirp)))
 
 /* File operations */
 #define SMB_VFS_OPEN(conn, fname, fsp, flags, mode) (((conn)->vfs.ops.open)((conn)->vfs.handles.open, (fname), (fsp), (flags), (mode)))
@@ -166,13 +167,14 @@
 
 /* Directory operations */
 #define SMB_VFS_OPAQUE_OPENDIR(conn, fname, mask, attr) ((conn)->vfs_opaque.ops.opendir((conn)->vfs_opaque.handles.opendir, (fname), (mask), (attr)))
-#define SMB_VFS_OPAQUE_READDIR(conn, dirp) ((conn)->vfs_opaque.ops.readdir((conn)->vfs_opaque.handles.readdir, (dirp)))
+#define SMB_VFS_OPAQUE_READDIR(conn, dirp, sbuf) ((conn)->vfs_opaque.ops.readdir((conn)->vfs_opaque.handles.readdir, (dirp), (sbuf)))
 #define SMB_VFS_OPAQUE_SEEKDIR(conn, dirp, offset) ((conn)->vfs_opaque.ops.seekdir((conn)->vfs_opaque.handles.seekdir, (dirp), (offset)))
 #define SMB_VFS_OPAQUE_TELLDIR(conn, dirp) ((conn)->vfs_opaque.ops.telldir((conn)->vfs_opaque.handles.telldir, (dirp)))
 #define SMB_VFS_OPAQUE_REWINDDIR(conn, dirp) ((conn)->vfs_opaque.ops.rewind_dir((conn)->vfs_opaque.handles.rewind_dir, (dirp)))
 #define SMB_VFS_OPAQUE_MKDIR(conn, path, mode) ((conn)->vfs_opaque.ops.mkdir((conn)->vfs_opaque.handles.mkdir,(path), (mode)))
 #define SMB_VFS_OPAQUE_RMDIR(conn, path) ((conn)->vfs_opaque.ops.rmdir((conn)->vfs_opaque.handles.rmdir, (path)))
 #define SMB_VFS_OPAQUE_CLOSEDIR(conn, dir) ((conn)->vfs_opaque.ops.closedir((conn)->vfs_opaque.handles.closedir, dir))
+#define SMB_VFS_OPAQUE_INIT_SEARCH_OP(conn, dirp) ((conn)->vfs_opaque.ops.init_search_op((conn)->vfs_opaque.handles.init_search_op, (dirp)))
 
 /* File operations */
 #define SMB_VFS_OPAQUE_OPEN(conn, fname, fsp, flags, mode) (((conn)->vfs_opaque.ops.open)((conn)->vfs_opaque.handles.open, (fname), (fsp), (flags), (mode)))
@@ -294,14 +296,15 @@
 
 /* Directory operations */
 #define SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr) ((handle)->vfs_next.ops.opendir((handle)->vfs_next.handles.opendir, (fname), (mask), (attr)))
-#define SMB_VFS_NEXT_READDIR(handle, dirp) ((handle)->vfs_next.ops.readdir((handle)->vfs_next.handles.readdir, (dirp)))
+#define SMB_VFS_NEXT_READDIR(handle, dirp, sbuf) ((handle)->vfs_next.ops.readdir((handle)->vfs_next.handles.readdir, (dirp), (sbuf)))
 #define SMB_VFS_NEXT_SEEKDIR(handle, dirp, offset) ((handle)->vfs_next.ops.seekdir((handle)->vfs_next.handles.seekdir, (dirp), (offset)))
 #define SMB_VFS_NEXT_TELLDIR(handle, dirp) ((handle)->vfs_next.ops.telldir((handle)->vfs_next.handles.telldir, (dirp)))
 #define SMB_VFS_NEXT_REWINDDIR(handle, dirp) ((handle)->vfs_next.ops.rewind_dir((handle)->vfs_next.handles.rewind_dir, (dirp)))
-#define SMB_VFS_NEXT_DIR(handle, dirp) ((handle)->vfs_next.ops.readdir((handle)->vfs_next.handles.readdir, (dirp)))
+#define SMB_VFS_NEXT_DIR(handle, dirp, sbuf) ((handle)->vfs_next.ops.readdir((handle)->vfs_next.handles.readdir, (dirp), (sbuf)))
 #define SMB_VFS_NEXT_MKDIR(handle, path, mode) ((handle)->vfs_next.ops.mkdir((handle)->vfs_next.handles.mkdir,(path), (mode)))
 #define SMB_VFS_NEXT_RMDIR(handle, path) ((handle)->vfs_next.ops.rmdir((handle)->vfs_next.handles.rmdir, (path)))
 #define SMB_VFS_NEXT_CLOSEDIR(handle, dir) ((handle)->vfs_next.ops.closedir((handle)->vfs_next.handles.closedir, dir))
+#define SMB_VFS_NEXT_INIT_SEARCH_OP(handle, dirp) ((handle)->vfs_next.ops.init_search_op((handle)->vfs_next.handles.init_search_op, (dirp)))
 
 /* File operations */
 #define SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode) (((handle)->vfs_next.ops.open)((handle)->vfs_next.handles.open, (fname), (fsp), (flags), (mode)))
diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h
index c8f19f4..72be682 100644
--- a/source3/modules/onefs.h
+++ b/source3/modules/onefs.h
@@ -41,26 +41,28 @@ enum onefs_acl_wire_format
 #define PARM_ONEFS_TYPE "onefs"
 #define PARM_ACL_WIRE_FORMAT "acl wire format"
 #define PARM_ACL_WIRE_FORMAT_DEFAULT ACL_FORMAT_WINDOWS_SD
-#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE "simple file sharing compatibility mode"
-#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT false
+#define PARM_ATIME_NOW		"atime now files"
+#define PARM_ATIME_STATIC	"atime static files"
+#define PARM_ATIME_SLOP		"atime now slop"
 #define PARM_CREATOR_OWNER_GETS_FULL_CONTROL "creator owner gets full control"
 #define PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT true
+#define PARM_CTIME_NOW		"ctime now files"
+#define PARM_CTIME_SLOP		"ctime now slop"
+#define PARM_IGNORE_SACL "ignore sacl"
+#define PARM_IGNORE_SACL_DEFAULT false
+#define PARM_MTIME_NOW		"mtime now files"
+#define PARM_MTIME_STATIC	"mtime static files"
+#define PARM_MTIME_SLOP		"mtime now slop"
+#define PARM_USE_READDIRPLUS "use readdirplus"
+#define PARM_USE_READDIRPLUS_DEFAULT true
+#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE "simple file sharing compatibility mode"
+#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT false
 #define PARM_UNMAPPABLE_SIDS_DENY_EVERYONE "unmappable sids deny everyone"
 #define PARM_UNMAPPABLE_SIDS_DENY_EVERYONE_DEFAULT false
 #define PARM_UNMAPPABLE_SIDS_IGNORE "ignore unmappable sids"
 #define PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT false
 #define PARM_UNMAPPABLE_SIDS_IGNORE_LIST "unmappable sids ignore list"
 #define PARM_UNMAPPABLE_SIDS_IGNORE_LIST_DEFAULT NULL
-#define PARM_IGNORE_SACL "ignore sacl"
-#define PARM_IGNORE_SACL_DEFAULT false
-#define PARM_ATIME_NOW		"atime now files"
-#define PARM_ATIME_SLOP		"atime now slop"
-#define PARM_CTIME_NOW		"ctime now files"
-#define PARM_CTIME_SLOP		"ctime now slop"
-#define PARM_MTIME_NOW		"mtime now files"
-#define PARM_MTIME_SLOP		"mtime now slop"
-#define PARM_MTIME_STATIC	"mtime static files"
-#define PARM_ATIME_STATIC	"atime static files"
 
 #define IS_CTIME_NOW_PATH(conn,cfg,path)  ((conn) && is_in_path((path),\
 	(cfg)->ctime_now_list,(conn)->case_sensitive))
@@ -81,7 +83,6 @@ enum onefs_acl_wire_format
 
 #define ONEFS_VFS_CONFIG_FAKETIMESTAMPS	0x00000001
 
-
 struct onefs_vfs_config
 {
 	int32 init_flags;
@@ -113,6 +114,25 @@ struct onefs_vfs_config
 /*
  * vfs interface handlers
  */
+SMB_STRUCT_DIR *onefs_opendir(struct vfs_handle_struct *handle,
+			      const char *fname, const char *mask,
+			      uint32 attributes);
+
+SMB_STRUCT_DIRENT *onefs_readdir(struct vfs_handle_struct *handle,
+				 SMB_STRUCT_DIR *dirp, SMB_STRUCT_STAT *sbuf);
+
+void onefs_seekdir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp,
+		   long offset);
+
+long onefs_telldir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp);
+
+void onefs_rewinddir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp);
+
+int onefs_closedir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dir);
+
+void onefs_init_search_op(struct vfs_handle_struct *handle,
+			  SMB_STRUCT_DIR *dirp);
+
 NTSTATUS onefs_create_file(vfs_handle_struct *handle,
 			   struct smb_request *req,
 			   uint16_t root_dir_fid,
diff --git a/source3/modules/onefs_dir.c b/source3/modules/onefs_dir.c
new file mode 100644
index 0000000..3c1a836
--- /dev/null
+++ b/source3/modules/onefs_dir.c
@@ -0,0 +1,636 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Support for OneFS bulk directory enumeration API
+ *
+ * Copyright (C) Steven Danneman, 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "onefs.h"
+
+#include <ifs/ifs_syscalls.h>
+
+/* The OneFS filesystem provides a readdirplus() syscall, equivalent to the
+ * NFSv3 PDU, which retrieves bulk directory listings with stat information
+ * in a single syscall.
+ *
+ * This file hides this bulk interface underneath Samba's very POSIX like
+ * opendir/readdir/telldir VFS interface.  This is done to provide a
+ * significant performance improvement when listing the contents of large
+ * directories, which also require file meta information. ie a typical
+ * Windows Explorer request.
+ */
+
+#define RDP_RESUME_KEY_START 0x1
+
+#define RDP_BATCH_SIZE 128
+#define RDP_DIRENTRIES_SIZE ((size_t)(RDP_BATCH_SIZE * sizeof(struct dirent)))
+
+static char *rdp_direntries = NULL;
+static SMB_STRUCT_STAT *rdp_stats = NULL;
+static uint64_t *rdp_cookies = NULL;
+
+struct rdp_dir_state {
+	struct rdp_dir_state *next, *prev;
+	SMB_STRUCT_DIR *dirp;
+	char *direntries_cursor; /* cursor to current direntry in the cache */
+	size_t stat_count;	 /* number of entries stored in the cache */
+	size_t stat_cursor;	 /* cursor to current stat in the cache */
+	uint64_t resume_cookie;  /* last cookie returned from the cache */
+	long location;		 /* absolute location of direnty in DIR */
+};
+
+static struct rdp_dir_state *dirstatelist = NULL;
+
+SMB_STRUCT_DIR *rdp_last_dirp = NULL;
+
+/**
+ * Given a DIR pointer, return our internal state.
+ *
+ * This function also tells us whether the given DIR is the same as we saw
+ * during the last call.  Because we use a single globally allocated buffer
+ * for readdirplus entries we must check every call into this API to see if
+ * it's for the same directory listing, or a new one. If it's the same we can
+ * maintain our current cached entries, otherwise we must go to the kernel.
+ *
+ * @return 0 on success, 1 on failure
+ */
+static int
+rdp_retrieve_dir_state(SMB_STRUCT_DIR *dirp, struct rdp_dir_state **dir_state,
+		       bool *same_as_last)
+{
+	struct rdp_dir_state *dsp;
+
+	/* Is this directory the same as the last call */
+	*same_as_last = (dirp == rdp_last_dirp);
+
+	for(dsp = dirstatelist; dsp; dsp = dsp->next)
+		if (dsp->dirp == dirp) {
+			*dir_state = dsp;
+			return 0;
+		}
+
+	/* Couldn't find existing dir_state for the given directory
+	 * pointer. */
+	return 1;
+}
+
+/**
+ * Initialize the global readdirplus buffers.
+ *
+ * These same buffers are used for all calls into readdirplus.
+ *
+ * @return 0 on success, errno value on failure
+ */
+static int
+rdp_init(struct rdp_dir_state *dsp)
+{
+	/* Unfortunately, there is no good way to free these buffers.  If we
+	 * allocated and freed for every DIR handle performance would be
+	 * adversely affected.  For now these buffers will be leaked and only
+	 * freed when the smbd process dies. */
+	if (!rdp_direntries) {
+		rdp_direntries = SMB_MALLOC(RDP_DIRENTRIES_SIZE);
+		if (!rdp_direntries)
+			return ENOMEM;
+	}
+
+	if (!rdp_stats) {
+		rdp_stats =
+		    SMB_MALLOC(RDP_BATCH_SIZE * sizeof(SMB_STRUCT_STAT));
+		if (!rdp_stats)
+			return ENOMEM;
+	}
+
+	if (!rdp_cookies) {
+		rdp_cookies = SMB_MALLOC(RDP_BATCH_SIZE * sizeof(uint64_t));
+		if (!rdp_cookies)
+			return ENOMEM;
+	}
+
+	dsp->direntries_cursor = rdp_direntries + RDP_DIRENTRIES_SIZE;
+	dsp->stat_count = RDP_BATCH_SIZE;
+	dsp->stat_cursor = RDP_BATCH_SIZE;
+	dsp->resume_cookie = RDP_RESUME_KEY_START;
+	dsp->location = 0;
+
+	return 0;
+}
+
+/**
+ * Call into readdirplus() to refill our global dirent cache.
+ *
+ * This function also resets all cursors back to the beginning of the cache.
+ * All stat buffers are retrieved by following symlinks.
+ *
+ * @return number of entries retrieved, -1 on error
+ */
+static int
+rdp_fill_cache(struct rdp_dir_state *dsp)
+{
+	int nread, dirfd;
+
+	dirfd = dirfd(dsp->dirp);
+	if (dirfd < 0) {
+		DEBUG(1, ("Could not retrieve fd for DIR\n"));
+		return -1;
+	}
+
+	/* Resize the stat_count to grab as many entries as possible */
+	dsp->stat_count = RDP_BATCH_SIZE;
+
+	DEBUG(9, ("Calling readdirplus() with DIR %p, dirfd: %d, "
+		 "resume_cookie 0x%llx, location %u, size_to_read: %zu, "
+		 "direntries_size: %zu, stat_count: %u\n",
+		 dsp->dirp, dirfd, dsp->resume_cookie, dsp->location,
+		 RDP_BATCH_SIZE, RDP_DIRENTRIES_SIZE, dsp->stat_count));
+
+	nread = readdirplus(dirfd,
+			    RDP_FOLLOW,
+			    &dsp->resume_cookie,
+			    RDP_BATCH_SIZE,
+			    rdp_direntries,
+			    RDP_DIRENTRIES_SIZE,
+			    &dsp->stat_count,
+			    rdp_stats,
+			    rdp_cookies);
+	if (nread < 0) {
+		DEBUG(1, ("Error calling readdirplus(): %s\n",
+			 strerror(errno)));
+		return -1;
+	}
+
+	DEBUG(9, ("readdirplus() returned %u entries from DIR %p\n",
+		 dsp->stat_count, dsp->dirp));
+
+	dsp->direntries_cursor = rdp_direntries;
+	dsp->stat_cursor = 0;
+
+	return nread;
+}
+
+/**
+ * Open a directory for enumeration.
+ *
+ * Create a state struct to track the state of this directory for the life
+ * of this open.
+ *
+ * @param[in] handle vfs handle given in most VFS calls
+ * @param[in] fname filename of the directory to open
+ * @param[in] mask unused
+ * @param[in] attr unused
+ *
+ * @return DIR pointer, NULL if directory does not exist, NULL on error
+ */
+SMB_STRUCT_DIR *
+onefs_opendir(vfs_handle_struct *handle, const char *fname, const char *mask,
+	      uint32 attr)
+{
+	int ret = 0;
+	SMB_STRUCT_DIR *ret_dirp;
+	struct rdp_dir_state *dsp = NULL;
+
+	/* Fallback to default system routines if readdirplus is disabled */
+	if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
+	    PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT))
+	{
+		return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
+	}
+
+	/* Create a struct dir_state */
+	dsp = SMB_MALLOC_P(struct rdp_dir_state);
+	if (!dsp) {
+		DEBUG(0, ("Error allocating struct rdp_dir_state.\n"));
+		return NULL;
+	}
+
+	/* Open the directory */
+	ret_dirp = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
+	if (!ret_dirp) {
+		DEBUG(3, ("Unable to open directory: %s\n", fname));
+		return NULL;
+	}
+
+	/* Initialize the dir_state structure and add it to the list */
+	ret = rdp_init(dsp);
+	if (ret) {
+		DEBUG(0, ("Error initializing readdirplus() buffers: %s\n",
+		    strerror(ret)));
+		return NULL;
+	}
+
+	/* Set the SMB_STRUCT_DIR in the dsp */
+	dsp->dirp = ret_dirp;
+
+	DLIST_ADD(dirstatelist, dsp);
+
+	DEBUG(9, ("Opened handle on directory: \"%s\", DIR %p\n",
+		 fname, dsp->dirp));
+
+	return ret_dirp;
+}


-- 
Samba Shared Repository


More information about the samba-cvs mailing list