[PATCH]: vmsplice2 update
authorJens Axboe <axboe@suse.de>
Wed, 3 May 2006 08:23:31 +0000 (10:23 +0200)
committerJens Axboe <axboe@suse.de>
Wed, 3 May 2006 08:23:31 +0000 (10:23 +0200)
vmsplice2.c

index 448ba9396afd556c83f4ddeb6645aa7442441c76..a273496c97f9ec4342fe6a4de518cf2d8a00fca0 100644 (file)
 
 #define PAGE_SIZE      4096
 #define PAGE_MASK      (PAGE_SIZE - 1)
-#define ALIGN(buf)     (void *) (((unsigned long) (buf) + PAGE_MASK) & ~PAGE_MASK)
 
 static int alloc_stack;
 static int cross_page;
+static int force_align;
+static int full_page;
+static int gift;
 
 int do_vmsplice(int fd, struct iovec *iov, unsigned long nr_vecs)
 {
@@ -34,7 +36,7 @@ int do_vmsplice(int fd, struct iovec *iov, unsigned long nr_vecs)
                if (poll(&pfd, 1, -1) < 0)
                        return error("poll");
 
-               written = vmsplice(fd, iov, nr_vecs, 0);
+               written = vmsplice(fd, iov, nr_vecs, gift ? SPLICE_F_GIFT : 0);
 
                if (written <= 0)
                        return error("vmsplice");
@@ -60,7 +62,7 @@ int do_vmsplice(int fd, struct iovec *iov, unsigned long nr_vecs)
 
 static int usage(char *name)
 {
-       fprintf(stderr, "%s [-s(tack)] [-c(ross page)]| ...\n", name);
+       fprintf(stderr, "%s [-s(tack)] [-c(ross page)] [-a(lign)] [-f(ull page)] [-g(ift)] | ...\n", name);
        return 1;
 }
 
@@ -68,7 +70,7 @@ static int parse_options(int argc, char *argv[])
 {
        int c, index = 1;
 
-       while ((c = getopt(argc, argv, "sc")) != -1) {
+       while ((c = getopt(argc, argv, "scafg")) != -1) {
                switch (c) {
                case 's':
                        alloc_stack = 1;
@@ -78,64 +80,115 @@ static int parse_options(int argc, char *argv[])
                        cross_page = 1;
                        index++;
                        break;
+               case 'a':
+                       force_align = 1;
+                       index++;
+                       break;
+               case 'f':
+                       full_page = 1;
+                       index++;
+                       break;
+               case 'g':
+                       gift = 1;
+                       index++;
+                       break;
                default:
                        return -1;
                }
        }
 
-       if (alloc_stack && cross_page)
-               fprintf(stderr, "Stack alloc and cross page are mutually exclusive\n");
+       if (cross_page && force_align) {
+               fprintf(stderr, "Can't get both aligning and cross page spanning\n");
+               return -1;
+       }
 
        return index;
 }
 
+#define ASIZE  (3 * PAGE_SIZE)
 #define S1     "header header header header header header header header "
 #define S2     "body body body body body body body body body body body "
 #define S3     "footer footer footer footer footer footer footer footer"
 
+static void check_address(void *addr, void *start, void *end, int len,char *msg)
+{
+       if (addr < start || (addr + len - 1) > end)
+               fprintf(stderr, "%s: bad: %p < %p < %p false\n", msg, start, addr, end);
+}
+
 int main(int argc, char *argv[])
 {
        struct iovec vecs[3];
+       char stack1[ASIZE], stack2[ASIZE], stack3[ASIZE];
+       char *h_s, *h_e, *b_s, *b_e, *f_s, *f_e;
        char *h, *b, *f;
+       int i;
+
+       if (check_output_pipe())
+               return usage(argv[0]);
 
        if (parse_options(argc, argv) < 0)
                return usage(argv[0]);
 
        if (alloc_stack) {
-               h = S1;
-               b = S2;
-               f = S3;
+               h = stack1;
+               b = stack2;
+               f = stack3;
        } else {
+               h = malloc(ASIZE);
+               b = malloc(ASIZE);
+               f = malloc(ASIZE);
+       }
+
+       memset(h, 0, ASIZE);
+       memset(b, 0, ASIZE);
+       memset(f, 0, ASIZE);
+
+       h_s = h;
+       h_e = h_s + 2 * PAGE_SIZE - 1;
+       b_s = b;
+       b_e = b_s + 2 * PAGE_SIZE - 1;
+       f_s = f;
+       f_e = f_s + 2 * PAGE_SIZE - 1;
+
+       if (force_align || cross_page) {
+               /* align forward to start of 2nd page */
+               unsigned long off;
+
+               off = PAGE_SIZE - ((unsigned long) h & PAGE_MASK);
+               h += off;
+               off = PAGE_SIZE - ((unsigned long) b & PAGE_MASK);
+               b += off;
+               off = PAGE_SIZE - ((unsigned long) f & PAGE_MASK);
+               f += off;
                if (cross_page) {
-                       void *ptr;
-
-                       ptr = ALIGN(malloc(3 * PAGE_SIZE));
-                       h = ptr + PAGE_SIZE - (strlen(S1) / 2);
-                       strcpy(h, S1);
-
-                       ptr = ALIGN(malloc(3 * PAGE_SIZE));
-                       b = ptr + PAGE_SIZE - (strlen(S2) / 2);
-                       strcpy(b, S2);
-
-                       ptr = ALIGN(malloc(3 * PAGE_SIZE));
-                       f = ptr + PAGE_SIZE - (strlen(S3) / 2);
-                       strcpy(f, S3);
-               } else {
-                       h = strdup(S1);
-                       b = strdup(S2);
-                       f = strdup(S3);
+                       /* this puts half the string in both pages */
+                       h -= strlen(S1) / 2;
+                       b -= strlen(S2) / 2;
+                       f -= strlen(S3) / 2;
                }
        }
 
+       strcpy(h, S1);
+       strcpy(b, S2);
+       strcpy(f, S3);
+
        vecs[0].iov_base = h;
        vecs[1].iov_base = b;
        vecs[2].iov_base = f;
-       vecs[0].iov_len = strlen(vecs[0].iov_base);
-       vecs[1].iov_len = strlen(vecs[1].iov_base);
-       vecs[2].iov_len = strlen(vecs[2].iov_base);
-               
-       if (check_output_pipe())
-               return usage(argv[0]);
+       if (!full_page) {
+               vecs[0].iov_len = strlen(vecs[0].iov_base);
+               vecs[1].iov_len = strlen(vecs[1].iov_base);
+               vecs[2].iov_len = strlen(vecs[2].iov_base);
+       } else {
+               vecs[0].iov_len = PAGE_SIZE;
+               vecs[1].iov_len = PAGE_SIZE;
+               vecs[2].iov_len = PAGE_SIZE;
+       }
+
+       check_address(h, h_s, h_e, vecs[0].iov_len, "header");
+       check_address(b, b_s, b_e, vecs[1].iov_len, "body");
+       check_address(f, f_s, f_e, vecs[2].iov_len, "footer");
 
        return do_vmsplice(STDOUT_FILENO, vecs, 3);
 }