From d448a75ec700b70fa23a2bfb50e11a2080ea7013 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 1 Jul 2012 08:55:16 +0400 Subject: [PATCH] pipe/fifo: Fix and cleanup data restore Make it in two stages. First -- collect pipe data into hash without checking for pipe/fifo existance. Next -- when pipe/fifo gets restored walk the hash and search where the pipe data is. Signed-off-by: Pavel Emelyanov --- fifo.c | 62 +++++++++++++--------------------------------- include/pipes.h | 13 +++++++++- pipes.c | 66 ++++++++++++++++++++++++++++++------------------- 3 files changed, 69 insertions(+), 72 deletions(-) diff --git a/fifo.c b/fifo.c index e476853f2..993bf6e15 100644 --- a/fifo.c +++ b/fifo.c @@ -73,6 +73,8 @@ int dump_fifo(struct fd_parms *p, int lfd, const struct cr_fdset *set) return do_dump_gen_file(p, lfd, &fifo_ops, set); } +static struct pipe_data_rst *pd_hash_fifo[PIPE_DATA_HASH_SIZE]; + static int do_open_fifo(struct reg_file_info *rfi, void *arg) { struct fifo_info *info = arg; @@ -96,13 +98,12 @@ static int do_open_fifo(struct reg_file_info *rfi, void *arg) goto out; } - if (info->restore_data) { - if (restore_pipe_data(CR_FD_FIFO_DATA, fake_fifo, info->fe->id, - info->bytes, info->off)) { + if (info->restore_data) + if (restore_pipe_data(CR_FD_FIFO_DATA, fake_fifo, + info->fe->pipe_id, pd_hash_fifo)) { close(new_fifo); new_fifo = -1; } - } out: close(fake_fifo); @@ -121,44 +122,9 @@ static struct file_desc_ops fifo_desc_ops = { .open = open_fifo_fd, }; -static int handle_fifo_data(void) -{ - int img, ret; - - img = open_image_ro(CR_FD_FIFO_DATA); - if (img < 0) - return -1; - - while (1) { - struct pipe_data_entry pde; - struct fifo_info *info; - - ret = read_img_eof(img, &pde); - if (ret <= 0) - break; - - list_for_each_entry(info, &fifo_head, list) { - if (info->fe->pipe_id != pde.pipe_id || - info->restore_data) - continue; - - info->off = lseek(img, 0, SEEK_CUR) + pde.off; - info->bytes = pde.bytes; - - lseek(img, pde.bytes + pde.off, SEEK_CUR); - - info->restore_data = true; - break; - } - } - - close(img); - return ret; -} - int collect_fifo(void) { - struct fifo_info *info = NULL; + struct fifo_info *info = NULL, *f; int img, ret; img = open_image_ro(CR_FD_FIFO); @@ -183,15 +149,21 @@ int collect_fifo(void) info->fe->id, info->fe->pipe_id); file_desc_add(&info->d, info->fe->id, &fifo_desc_ops); - list_add(&info->list, &fifo_head); - } - if (!ret) - ret = handle_fifo_data(); + /* check who will restore the fifo data */ + list_for_each_entry(f, &fifo_head, list) + if (f->fe->pipe_id == info->fe->pipe_id) + break; + + if (&f->list == &fifo_head) { + list_add(&info->list, &fifo_head); + info->restore_data = true; + } + } xfree(info ? info->fe : NULL); xfree(info); close(img); - return ret; + return collect_pipe_data(CR_FD_FIFO_DATA, pd_hash_fifo); } diff --git a/include/pipes.h b/include/pipes.h index 0d7b71225..655440f88 100644 --- a/include/pipes.h +++ b/include/pipes.h @@ -14,6 +14,17 @@ struct pipe_data_dump { }; extern int dump_one_pipe_data(struct pipe_data_dump *pd, int lfd, const struct fd_parms *p); -extern int restore_pipe_data(int img_type, int pfd, u32 id, int bytes, off_t off); + +struct pipe_data_rst { + struct pipe_data_entry pde; + struct pipe_data_rst *next; +}; + +#define PIPE_DATA_HASH_BITS 5 +#define PIPE_DATA_HASH_SIZE (1 << PIPE_DATA_HASH_BITS) +#define PIPE_DATA_HASH_MASK (PIPE_DATA_HASH_SIZE - 1) + +extern int collect_pipe_data(int img_type, struct pipe_data_rst **hash); +extern int restore_pipe_data(int img_type, int pfd, u32 id, struct pipe_data_rst **hash); #endif diff --git a/pipes.c b/pipes.c index 47882d56f..e0b986040 100644 --- a/pipes.c +++ b/pipes.c @@ -39,34 +39,37 @@ static void show_saved_pipe_fds(struct pipe_info *pi) pr_info(" `- FD %d pid %d\n", fle->fe->fd, fle->pid); } -static int handle_pipes_data(void) +int collect_pipe_data(int img_type, struct pipe_data_rst **hash) { int fd, ret; - fd = open_image_ro(CR_FD_PIPES_DATA); + fd = open_image_ro(img_type); if (fd < 0) return -1; while (1) { - struct pipe_info *pi; - struct pipe_data_entry pde; + struct pipe_data_rst *r; + u32 off; - ret = read_img_eof(fd, &pde); + ret = -1; + r = xmalloc(sizeof(*r)); + if (!r) + break; + + ret = read_img_eof(fd, &r->pde); if (ret <= 0) break; - list_for_each_entry(pi, &pipes, list) { - if (pi->pe.pipe_id != pde.pipe_id) - continue; - if (!pi->create) - continue; + off = r->pde.off + lseek(fd, 0, SEEK_CUR); + lseek(fd, r->pde.bytes + r->pde.off, SEEK_CUR); + r->pde.off = off; - pi->off = lseek(fd, 0, SEEK_CUR) + pde.off; - pi->bytes = pde.bytes; + ret = r->pde.pipe_id & PIPE_DATA_HASH_MASK; + r->next = hash[ret]; + hash[ret] = r; - lseek(fd, pde.bytes + pde.off, SEEK_CUR); - break; - } + pr_info("Collected pipe data for %#x (chain %u)\n", + r->pde.pipe_id, ret); } close(fd); @@ -117,24 +120,33 @@ void mark_pipe_master(void) } list_splice(&head, &pipes); - - handle_pipes_data(); } -int restore_pipe_data(int img_type, int pfd, u32 id, int bytes, off_t off) +static struct pipe_data_rst *pd_hash_pipes[PIPE_DATA_HASH_SIZE]; + +int restore_pipe_data(int img_type, int pfd, u32 id, struct pipe_data_rst **hash) { int img, size = 0, ret; + struct pipe_data_rst *pd; + + for (pd = hash[id & PIPE_DATA_HASH_MASK]; pd != NULL; pd = pd->next) + if (pd->pde.pipe_id == id) + break; + + if (!pd) { /* no data for this pipe */ + pr_info("No data for pipe %#x\n", id); + return 0; + } img = open_image_ro(img_type); if (img < 0) return -1; - lseek(img, off, SEEK_SET); + pr_info("\t\tSplicing data size=%u off=%u\n", pd->pde.bytes, pd->pde.off); + lseek(img, pd->pde.off, SEEK_SET); - pr_info("\t\tSplicing data size=%d off=%ld\n", bytes, off); - - while (size != bytes) { - ret = splice(img, NULL, pfd, NULL, bytes - size, 0); + while (size != pd->pde.bytes) { + ret = splice(img, NULL, pfd, NULL, pd->pde.bytes - size, 0); if (ret < 0) { pr_perror("%#x: Error splicing data", id); goto err; @@ -142,7 +154,7 @@ int restore_pipe_data(int img_type, int pfd, u32 id, int bytes, off_t off) if (ret == 0) { pr_err("%#x: Wanted to restore %d bytes, but got %d\n", - id, bytes, size); + id, pd->pde.bytes, size); ret = -1; goto err; } @@ -207,7 +219,8 @@ static int open_pipe(struct file_desc *d) return -1; } - ret = restore_pipe_data(CR_FD_PIPES_DATA, pfd[1], pi->pe.id, pi->bytes, pi->off); + ret = restore_pipe_data(CR_FD_PIPES_DATA, pfd[1], + pi->pe.pipe_id, pd_hash_pipes); if (ret) return -1; @@ -295,7 +308,8 @@ int collect_pipes(void) xfree(pi); close(fd); - return ret; + + return collect_pipe_data(CR_FD_PIPES_DATA, pd_hash_pipes); } int dump_one_pipe_data(struct pipe_data_dump *pd, int lfd, const struct fd_parms *p)