#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
+#include <sys/sendfile.h>
#include "blktrace.h"
#include "barrier.h"
#define RELAYFS_TYPE 0xF0B4A981
-#define S_OPTS "d:a:A:r:o:kw:Vb:n:D:lh:p:"
+#define S_OPTS "d:a:A:r:o:kw:Vb:n:D:lh:p:s"
static struct option l_opts[] = {
{
.name = "dev",
.flag = NULL,
.val = 'p'
},
+ {
+ .name = "sendfile",
+ .has_arg = no_argument,
+ .flag = NULL,
+ .val = 's'
+ },
{
.name = NULL,
}
void *buf;
unsigned int len;
unsigned int max_len;
+ off_t offset;
};
#define FIFO_SIZE (1024) /* should be plenty big! */
FILE *ofile;
char *ofile_buffer;
+ off_t ofile_offset;
int ofile_stdout;
int ofile_mmap;
static char hostname[MAXHOSTNAMELEN];
static int net_port = TRACE_NET_PORT;
static int net_mode = 0;
+static int net_sendfile;
static int net_in_fd = -1;
static int net_out_fd = -1;
return -1;
}
+static int get_subbuf_sendfile(struct thread_information *tip,
+ unsigned int maxlen)
+{
+ struct tip_subbuf *ts = malloc(sizeof(*ts));
+ struct stat sb;
+
+ ts->buf = malloc(buf_size);
+ ts->max_len = maxlen;
+ ts->buf = NULL;
+
+ if (fstat(tip->fd, &sb) < 0) {
+ perror("trace stat");
+ return 1;
+ }
+
+ ts->len = sb.st_size - tip->ofile_offset;
+ ts->max_len = ts->len;
+ ts->offset = tip->ofile_offset;
+ tip->ofile_offset += ts->len;
+ return subbuf_fifo_queue(tip, ts);
+}
+
/*
* Use the copy approach for pipes and network
*/
return 0;
}
-static int flush_subbuf_net(struct thread_information *tip,
- struct tip_subbuf *ts)
+static int net_send_header(struct thread_information *tip, unsigned int len)
{
struct blktrace_net_hdr hdr;
strcpy(hdr.buts_name, tip->device->buts_name);
hdr.cpu = tip->cpu;
hdr.max_cpus = ncpus;
- hdr.len = ts->len;
+ hdr.len = len;
- if (write_data_net(net_out_fd, &hdr, sizeof(hdr)))
- return 1;
+ return write_data_net(net_out_fd, &hdr, sizeof(hdr));
+}
+static int flush_subbuf_net(struct thread_information *tip,
+ struct tip_subbuf *ts)
+{
+ if (net_send_header(tip, ts->len))
+ return 1;
if (write_data_net(net_out_fd, ts->buf, ts->len))
return 1;
return 0;
}
+static int flush_subbuf_sendfile(struct thread_information *tip,
+ struct tip_subbuf *ts)
+{
+ if (net_send_header(tip, ts->len))
+ return 1;
+ if (sendfile(net_out_fd, tip->fd, &ts->offset, ts->len) < 0) {
+ perror("sendfile");
+ return 1;
+ }
+
+ free(ts);
+ return 0;
+}
+
static int write_data(struct thread_information *tip, void *buf,
unsigned int buf_len)
{
/*
* setup ops
*/
- if (tip->ofile_mmap && net_mode != Net_client)
- tip->get_subbuf = mmap_subbuf;
- else
- tip->get_subbuf = get_subbuf;
+ if (net_mode == Net_client) {
+ if (net_sendfile) {
+ tip->get_subbuf = get_subbuf_sendfile;
+ tip->flush_subbuf = flush_subbuf_sendfile;
+ } else {
+ tip->get_subbuf = get_subbuf;
+ tip->flush_subbuf = flush_subbuf_net;
+ }
+ } else {
+ if (tip->ofile_mmap)
+ tip->get_subbuf = mmap_subbuf;
+ else
+ tip->get_subbuf = get_subbuf;
- if (net_mode == Net_client)
- tip->flush_subbuf = flush_subbuf_net;
- else
tip->flush_subbuf = flush_subbuf_file;
-
+ }
+
if (net_mode == Net_server)
tip->read_data = read_data_net;
else
case 'p':
net_port = atoi(optarg);
break;
+ case 's':
+ net_sendfile = 1;
+ break;
default:
show_usage(argv[0]);
return 1;