[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha6-889-g85eccea

Tim Prouty tprouty at samba.org
Sat Feb 14 06:05:48 GMT 2009


The branch, master has been updated
       via  85eccea0b435e4b3c6fb4da6f0a7ea6e9b28b070 (commit)
       via  c05eb1a835ddf0165f72f218d6e1940a02ded37e (commit)
      from  add9b4afb14d3426d1f3bf5b8e7c86926f462578 (commit)

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


- Log -----------------------------------------------------------------
commit 85eccea0b435e4b3c6fb4da6f0a7ea6e9b28b070
Author: Tim Prouty <tprouty at samba.org>
Date:   Fri Feb 13 21:36:42 2009 -0800

    s3 OneFS: Add recvfile implementation

commit c05eb1a835ddf0165f72f218d6e1940a02ded37e
Author: Tim Prouty <tprouty at samba.org>
Date:   Thu Feb 12 17:30:58 2009 -0800

    s3 vfs: Fix SMB_VFS_RECVFILE/SENDFILE macros

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

Summary of changes:
 source3/include/vfs_macros.h   |    8 +-
 source3/modules/onefs.h        |    3 +
 source3/modules/onefs_system.c |  181 ++++++++++++++++++++++++++++++++++++++++
 source3/modules/vfs_onefs.c    |   14 +++
 4 files changed, 202 insertions(+), 4 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h
index dcef63d..3af6123 100644
--- a/source3/include/vfs_macros.h
+++ b/source3/include/vfs_macros.h
@@ -56,8 +56,8 @@
 #define SMB_VFS_WRITE(fsp, data, n) ((fsp)->conn->vfs.ops.write((fsp)->conn->vfs.handles.write, (fsp), (data), (n)))
 #define SMB_VFS_PWRITE(fsp, data, n, off) ((fsp)->conn->vfs.ops.pwrite((fsp)->conn->vfs.handles.pwrite, (fsp), (data), (n), (off)))
 #define SMB_VFS_LSEEK(fsp, offset, whence) ((fsp)->conn->vfs.ops.lseek((fsp)->conn->vfs.handles.lseek, (fsp), (offset), (whence)))
-#define SMB_VFS_SENDFILE(tofd, fromfsp, header, offset, count) ((fsp)->conn->vfs.ops.sendfile((fsp)->conn->vfs.handles.sendfile, (tofd), (fromfsp), (header), (offset), (count)))
-#define SMB_VFS_RECVFILE(fromfd, tofsp, offset, count) ((fsp)->conn->vfs.ops.recvfile((fsp)->conn->vfs.handles.recvfile, (fromfd), (tofsp), (offset), (count)))
+#define SMB_VFS_SENDFILE(tofd, fromfsp, header, offset, count) ((fromfsp)->conn->vfs.ops.sendfile((fromfsp)->conn->vfs.handles.sendfile, (tofd), (fromfsp), (header), (offset), (count)))
+#define SMB_VFS_RECVFILE(fromfd, tofsp, offset, count) ((tofsp)->conn->vfs.ops.recvfile((tofsp)->conn->vfs.handles.recvfile, (fromfd), (tofsp), (offset), (count)))
 #define SMB_VFS_RENAME(conn, old, new) ((conn)->vfs.ops.rename((conn)->vfs.handles.rename, (old), (new)))
 #define SMB_VFS_FSYNC(fsp) ((fsp)->conn->vfs.ops.fsync((fsp)->conn->vfs.handles.fsync, (fsp)))
 #define SMB_VFS_STAT(conn, fname, sbuf) ((conn)->vfs.ops.stat((conn)->vfs.handles.stat, (fname), (sbuf)))
@@ -188,8 +188,8 @@
 #define SMB_VFS_OPAQUE_WRITE(fsp, data, n) ((fsp)->conn->vfs_opaque.ops.write((fsp)->conn->vfs_opaque.handles.write, (fsp), (data), (n)))
 #define SMB_VFS_OPAQUE_PWRITE(fsp, data, n, off) ((fsp)->conn->vfs_opaque.ops.pwrite((fsp)->conn->vfs_opaque.handles.pwrite, (fsp), (data), (n), (off)))
 #define SMB_VFS_OPAQUE_LSEEK(fsp, offset, whence) ((fsp)->conn->vfs_opaque.ops.lseek((fsp)->conn->vfs_opaque.handles.lseek, (fsp), (offset), (whence)))
-#define SMB_VFS_OPAQUE_SENDFILE(tofd, fromfsp, header, offset, count) ((fsp)->conn->vfs_opaque.ops.sendfile((fsp)->conn->vfs_opaque.handles.sendfile, (tofd), (fromfsp), (header), (offset), (count)))
-#define SMB_VFS_OPAQUE_RECVFILE(fromfd, tofsp, offset, count) ((fsp)->conn->vfs_opaque.ops.recvfile((fsp)->conn->vfs_opaque.handles.recvfile, (fromfd), (tofsp), (offset), (count)))
+#define SMB_VFS_OPAQUE_SENDFILE(tofd, fromfsp, header, offset, count) ((fromfsp)->conn->vfs_opaque.ops.sendfile((fromfsp)->conn->vfs_opaque.handles.sendfile, (tofd), (fromfsp), (header), (offset), (count)))
+#define SMB_VFS_OPAQUE_RECVFILE(fromfd, tofsp, offset, count) ((tofsp)->conn->vfs_opaque.ops.recvfile((tofsp)->conn->vfs_opaque.handles.recvfile, (fromfd), (tofsp), (offset), (count)))
 #define SMB_VFS_OPAQUE_RENAME(conn, old, new) ((conn)->vfs_opaque.ops.rename((conn)->vfs_opaque.handles.rename, (old), (new)))
 #define SMB_VFS_OPAQUE_FSYNC(fsp) ((fsp)->conn->vfs_opaque.ops.fsync((fsp)->conn->vfs_opaque.handles.fsync, (fsp)))
 #define SMB_VFS_OPAQUE_STAT(conn, fname, sbuf) ((conn)->vfs_opaque.ops.stat((conn)->vfs_opaque.handles.stat, (fname), (sbuf)))
diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h
index 5719496..126b756 100644
--- a/source3/modules/onefs.h
+++ b/source3/modules/onefs.h
@@ -234,4 +234,7 @@ int onefs_sys_create_file(connection_struct *conn,
 			  uint32_t ntfs_flags,
 			  int *granted_oplock);
 
+ssize_t onefs_sys_recvfile(int fromfd, int tofd, SMB_OFF_T offset,
+			   size_t count);
+
 #endif /* _ONEFS_H */
diff --git a/source3/modules/onefs_system.c b/source3/modules/onefs_system.c
index acc38fb..b17cfe9 100644
--- a/source3/modules/onefs_system.c
+++ b/source3/modules/onefs_system.c
@@ -163,3 +163,184 @@ int onefs_sys_create_file(connection_struct *conn,
 
 	return ret_fd;
 }
+
+/**
+ * Only talloc the spill buffer once (reallocing when necessary).
+ */
+static char *get_spill_buffer(size_t new_count)
+{
+	static int cur_count = 0;
+	static char *spill_buffer = NULL;
+
+	/* If a sufficiently sized buffer exists, just return. */
+	if (new_count <= cur_count) {
+		SMB_ASSERT(spill_buffer);
+		return spill_buffer;
+	}
+
+	/* Allocate the first time. */
+	if (cur_count == 0) {
+		SMB_ASSERT(!spill_buffer);
+		spill_buffer = talloc_array(NULL, char, new_count);
+		if (spill_buffer) {
+			cur_count = new_count;
+		}
+		return spill_buffer;
+	}
+
+	/* A buffer exists, but it's not big enough, so realloc. */
+	SMB_ASSERT(spill_buffer);
+	spill_buffer = talloc_realloc(NULL, spill_buffer, char, new_count);
+	if (spill_buffer) {
+		cur_count = new_count;
+	}
+	return spill_buffer;
+}
+
+/**
+ * recvfile does zero-copy writes given an fd to write to, and a socket with
+ * some data to write.  If recvfile read more than it was able to write, it
+ * spills the data into a buffer.  After first reading any additional data
+ * from the socket into the buffer, the spill buffer is then written with a
+ * standard pwrite.
+ */
+ssize_t onefs_sys_recvfile(int fromfd, int tofd, SMB_OFF_T offset,
+			   size_t count)
+{
+	char *spill_buffer = NULL;
+	bool socket_drained = false;
+	int ret;
+	off_t total_rbytes = 0;
+	off_t total_wbytes = 0;
+	off_t rbytes;
+	off_t wbytes;
+
+	DEBUG(10,("onefs_recvfile: from = %d, to = %d, offset=%llu, count = "
+		  "%lu\n", fromfd, tofd, offset, count));
+
+	if (count == 0) {
+		return 0;
+	}
+
+	/*
+	 * Setup up a buffer for recvfile to spill data that has been read
+	 * from the socket but not written.
+	 */
+	spill_buffer = get_spill_buffer(count);
+	if (spill_buffer == NULL) {
+		ret = -1;
+		goto out;
+	}
+
+	/*
+	 * Keep trying recvfile until:
+	 *  - There is no data left to read on the socket, or
+	 *  - bytes read != bytes written, or
+	 *  - An error is returned that isn't EINTR/EAGAIN
+	 */
+	do {
+		/* Keep track of bytes read/written for recvfile */
+		rbytes = 0;
+		wbytes = 0;
+
+		DEBUG(10, ("calling recvfile loop, offset + total_wbytes = "
+			   "%llu, count - total_rbytes = %llu\n",
+			   offset + total_wbytes, count - total_rbytes));
+
+		ret = recvfile(tofd, fromfd, offset + total_wbytes,
+			       count - total_wbytes, &rbytes, &wbytes, 0,
+			       spill_buffer);
+
+		DEBUG(10, ("recvfile ret = %d, errno = %d, rbytes = %llu, "
+			   "wbytes = %llu\n", ret, ret >= 0 ? 0 : errno,
+			   rbytes, wbytes));
+
+		/* Update our progress so far */
+		total_rbytes += rbytes;
+		total_wbytes += wbytes;
+
+	} while ((count - total_rbytes) && (rbytes == wbytes) &&
+		 (ret == -1 && (errno == EINTR || errno == EAGAIN)));
+
+	DEBUG(10, ("total_rbytes = %llu, total_wbytes = %llu\n",
+		   total_rbytes, total_wbytes));
+
+	/* Log if recvfile didn't write everything it read. */
+	if (total_rbytes != total_wbytes) {
+		DEBUG(0, ("partial recvfile: total_rbytes=%llu but "
+			  "total_wbytes=%llu, diff = %llu\n", total_rbytes,
+			  total_wbytes, total_rbytes - total_wbytes));
+		SMB_ASSERT(total_rbytes > total_wbytes);
+	}
+
+	/*
+	 * If there is still data on the socket, read it off.
+	 */
+	while (total_rbytes < count) {
+
+		DEBUG(0, ("shallow recvfile, reading %llu\n",
+			  count - total_rbytes));
+
+		/*
+		 * Read the remaining data into the spill buffer.  recvfile
+		 * may already have some data in the spill buffer, so start
+		 * filling the buffer at total_rbytes - total_wbytes.
+		 */
+		ret = sys_read(fromfd,
+			       spill_buffer + (total_rbytes - total_wbytes),
+			       count - total_rbytes);
+
+		if (ret == -1) {
+			DEBUG(0, ("shallow recvfile read failed: %s\n",
+				  strerror(errno)));
+			/* Socket is dead, so treat as if it were drained. */
+			socket_drained = true;
+			goto out;
+		}
+
+		/* Data was read so update the rbytes */
+		total_rbytes += ret;
+	}
+
+	if (total_rbytes != count) {
+		smb_panic("Unread recvfile data still on the socket!");
+	}
+
+	/*
+	 * Now write any spilled data + the extra data read off the socket.
+	 */
+	while (total_wbytes < count) {
+
+		DEBUG(0, ("partial recvfile, writing %llu\n", count - total_wbytes));
+
+		ret = sys_pwrite(tofd, spill_buffer, count - total_wbytes,
+				 offset + total_wbytes);
+
+		if (ret == -1) {
+			DEBUG(0, ("partial recvfile write failed: %s\n",
+				  strerror(errno)));
+			goto out;
+		}
+
+		/* Data was written so update the wbytes */
+		total_wbytes += ret;
+	}
+
+	/* Success! */
+	ret = total_wbytes;
+
+out:
+	/* Make sure we always try to drain the socket. */
+	if (!socket_drained && count - total_rbytes) {
+		int saved_errno = errno;
+
+		if (drain_socket(fromfd, count - total_rbytes) !=
+		    count - total_rbytes) {
+			/* Socket is dead! */
+			DEBUG(0, ("drain socket failed: %d\n", errno));
+		}
+		errno = saved_errno;
+	}
+
+	return ret;
+}
diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c
index 123139f..fe0dfc9 100644
--- a/source3/modules/vfs_onefs.c
+++ b/source3/modules/vfs_onefs.c
@@ -153,6 +153,18 @@ static int onefs_open(vfs_handle_struct *handle, const char *fname,
 	return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
 }
 
+static ssize_t onefs_recvfile(vfs_handle_struct *handle, int fromfd,
+			      files_struct *tofsp, SMB_OFF_T offset,
+			      size_t count)
+{
+	ssize_t result;
+
+	START_PROFILE_BYTES(syscall_recvfile, count);
+	result = onefs_sys_recvfile(fromfd, tofsp->fh->fd, offset, count);
+	END_PROFILE(syscall_recvfile);
+	return result;
+}
+
 static uint64_t onefs_get_alloc_size(struct vfs_handle_struct *handle,
 				     files_struct *fsp,
 				     const SMB_STRUCT_STAT *sbuf)
@@ -309,6 +321,8 @@ static vfs_op_tuple onefs_ops[] = {
 	 SMB_VFS_LAYER_OPAQUE},
 	{SMB_VFS_OP(onefs_close), SMB_VFS_OP_CLOSE,
 	 SMB_VFS_LAYER_TRANSPARENT},
+	{SMB_VFS_OP(onefs_recvfile), SMB_VFS_OP_RECVFILE,
+	 SMB_VFS_LAYER_OPAQUE},
 	{SMB_VFS_OP(onefs_rename), SMB_VFS_OP_RENAME,
 	 SMB_VFS_LAYER_TRANSPARENT},
 	{SMB_VFS_OP(onefs_stat), SMB_VFS_OP_STAT,


-- 
Samba Shared Repository


More information about the samba-cvs mailing list