[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