mirror of
https://github.com/checkpoint-restore/criu
synced 2025-09-03 07:45:17 +00:00
files: Support dumping/restoring of completely unlinked files
Completely unlinked file is the one with n_link count being zero. Such files only allow to read their contents and carry with us. In order to dump this thing I introduce the "path remap" technology. For reg file a remapping entry is dumped which describes, that at restore stage before opening a regfile->path this path should be linked to some other name and then (after open) unlinked. For completely unlinked files the remap path would be a path to a "ghost" file, i.e. a file which is created only at the time of restore and which is removed completely at the end of it. Partially unlinked files (i.e. those having n_link != 0, but a path by which we see them in someone's fd is not accessible) should be handled in another way. Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
130
cr-dump.c
130
cr-dump.c
@@ -126,30 +126,142 @@ static int collect_fds(pid_t pid, int *fd, int *nr_fd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int path_accessible(char *path, const struct stat *ost)
|
/*
|
||||||
|
* Ghost files are those not visible from the FS. Dumping them is
|
||||||
|
* nasty and the only way we have -- just carry its contents with
|
||||||
|
* us. Any brave soul to implement link unlinked file back?
|
||||||
|
*/
|
||||||
|
struct ghost_file {
|
||||||
|
u32 dev;
|
||||||
|
u32 ino;
|
||||||
|
u32 id;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static u32 ghost_file_ids = 1;
|
||||||
|
static LIST_HEAD(ghost_files);
|
||||||
|
/*
|
||||||
|
* This constant is selected without any calculations. Just do not
|
||||||
|
* want to pick up too big files with us in the image.
|
||||||
|
*/
|
||||||
|
#define MAX_GHOST_FILE_SIZE (1 * 1024 * 1024)
|
||||||
|
|
||||||
|
static int dump_ghost_file(int _fd, u32 id, const struct stat *st)
|
||||||
|
{
|
||||||
|
int img, fd;
|
||||||
|
struct ghost_file_entry gfe;
|
||||||
|
char lpath[32];
|
||||||
|
|
||||||
|
pr_info("Dumping ghost file contents (id %x)\n", id);
|
||||||
|
|
||||||
|
img = open_image(CR_FD_GHOST_FILE, O_DUMP, id);
|
||||||
|
if (img < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reopen file locally since it may have no read
|
||||||
|
* permissions when drained
|
||||||
|
*/
|
||||||
|
snprintf(lpath, sizeof(lpath), "/proc/self/fd/%d", _fd);
|
||||||
|
fd = open(lpath, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
pr_perror("Can't open ghost original file");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfe.uid = st->st_uid;
|
||||||
|
gfe.gid = st->st_gid;
|
||||||
|
gfe.mode = st->st_mode;
|
||||||
|
|
||||||
|
if (write_img(img, &gfe))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (copy_file(fd, img, st->st_size))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
close(img);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dump_ghost_remap(char *path, const struct stat *st, int lfd, u32 id)
|
||||||
|
{
|
||||||
|
struct ghost_file *gf;
|
||||||
|
struct remap_file_path_entry rpe;
|
||||||
|
|
||||||
|
pr_info("Dumping ghost file for fd %d id %x\n", lfd, id);
|
||||||
|
|
||||||
|
if (st->st_size > MAX_GHOST_FILE_SIZE) {
|
||||||
|
pr_err("Can't dump ghost file %s of %lu size\n",
|
||||||
|
path, st->st_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry(gf, &ghost_files, list)
|
||||||
|
if ((gf->dev == st->st_dev) && (gf->ino == st->st_ino))
|
||||||
|
goto dump_entry;
|
||||||
|
|
||||||
|
gf = xmalloc(sizeof(*gf));
|
||||||
|
if (gf == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
gf->dev = st->st_dev;
|
||||||
|
gf->ino = st->st_ino;
|
||||||
|
gf->id = ghost_file_ids++;
|
||||||
|
list_add_tail(&gf->list, &ghost_files);
|
||||||
|
|
||||||
|
if (dump_ghost_file(lfd, gf->id, st))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
dump_entry:
|
||||||
|
rpe.orig_id = id;
|
||||||
|
rpe.remap_id = gf->id | REMAP_GHOST;
|
||||||
|
|
||||||
|
return write_img(fdset_fd(glob_fdset, CR_FD_REMAP_FPATH), &rpe);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_path_remap(char *path, const struct stat *ost, int lfd, u32 id)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct stat pst;
|
struct stat pst;
|
||||||
|
|
||||||
if (ost->st_nlink == 0) {
|
if (ost->st_nlink == 0)
|
||||||
pr_err("Unlinked file opened, can't dump\n");
|
/*
|
||||||
return 0;
|
* Unpleasant, but easy case. File is completely invisible
|
||||||
}
|
* from the FS. Just dump its contents and that's it. But
|
||||||
|
* be careful whether anybody still has any of its hardlinks
|
||||||
|
* also open.
|
||||||
|
*/
|
||||||
|
return dump_ghost_remap(path, ost, lfd, id);
|
||||||
|
|
||||||
ret = stat(path, &pst);
|
ret = stat(path, &pst);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
/*
|
||||||
|
* FIXME linked file, but path is not accessible (unless any
|
||||||
|
* other error occurred). We can create a temporary link to it
|
||||||
|
* uning linkat with AT_EMPTY_PATH flag and remap it to this
|
||||||
|
* name.
|
||||||
|
*/
|
||||||
pr_perror("Can't stat path");
|
pr_perror("Can't stat path");
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pst.st_ino != ost->st_ino) || (pst.st_dev != ost->st_dev)) {
|
if ((pst.st_ino != ost->st_ino) || (pst.st_dev != ost->st_dev)) {
|
||||||
|
/*
|
||||||
|
* FIXME linked file, but the name we see it by is reused
|
||||||
|
* by somebody else.
|
||||||
|
*/
|
||||||
pr_err("Unaccessible path opened %u:%u, need %u:%u\n",
|
pr_err("Unaccessible path opened %u:%u, need %u:%u\n",
|
||||||
(int)pst.st_dev, (int)pst.st_ino,
|
(int)pst.st_dev, (int)pst.st_ino,
|
||||||
(int)ost->st_dev, (int)ost->st_ino);
|
(int)ost->st_dev, (int)ost->st_ino);
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
/*
|
||||||
|
* File is linked and visible by the name it is opened by
|
||||||
|
* this task. Go ahead and dump it.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p)
|
static int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p)
|
||||||
@@ -170,7 +282,7 @@ static int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p)
|
|||||||
p->fd, lfd, big_buffer);
|
p->fd, lfd, big_buffer);
|
||||||
|
|
||||||
if (p->type == FDINFO_REG &&
|
if (p->type == FDINFO_REG &&
|
||||||
!path_accessible(big_buffer, &p->stat))
|
check_path_remap(big_buffer, &p->stat, lfd, id))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
rfe.len = len;
|
rfe.len = len;
|
||||||
|
@@ -900,6 +900,12 @@ out:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maybe rework ghosts to be auto-unlinkable?
|
||||||
|
*/
|
||||||
|
|
||||||
|
clear_ghost_files();
|
||||||
|
|
||||||
pr_info("Go on!!!\n");
|
pr_info("Go on!!!\n");
|
||||||
futex_set_and_wake(&task_entries->start, CR_STATE_COMPLETE);
|
futex_set_and_wake(&task_entries->start, CR_STATE_COMPLETE);
|
||||||
|
|
||||||
|
39
cr-show.c
39
cr-show.c
@@ -132,6 +132,45 @@ out:
|
|||||||
pr_img_tail(CR_FD_REG_FILES);
|
pr_img_tail(CR_FD_REG_FILES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline char *remap_id_type(u32 id)
|
||||||
|
{
|
||||||
|
if (id & REMAP_GHOST)
|
||||||
|
return "ghost";
|
||||||
|
else
|
||||||
|
return "real";
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_remap_files(int fd, struct cr_options *o)
|
||||||
|
{
|
||||||
|
struct remap_file_path_entry rfe;
|
||||||
|
|
||||||
|
pr_img_head(CR_FD_REMAP_FPATH);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = read_img_eof(fd, &rfe);
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pr_msg("%x -> %x (%s)\n", rfe.orig_id,
|
||||||
|
(rfe.remap_id & ~REMAP_GHOST),
|
||||||
|
remap_id_type(rfe.remap_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_img_tail(CR_FD_REMAP_FPATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_ghost_file(int fd, struct cr_options *o)
|
||||||
|
{
|
||||||
|
struct ghost_file_entry gfe;
|
||||||
|
|
||||||
|
pr_img_head(CR_FD_GHOST_FILE);
|
||||||
|
if (read_img(fd, &gfe) > 0)
|
||||||
|
pr_msg("uid %u god %u mode %x\n", gfe.uid, gfe.gid, gfe.mode);
|
||||||
|
pr_img_tail(CR_FD_GHOST_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
void show_pipes_data(int fd_pipes, struct cr_options *o)
|
void show_pipes_data(int fd_pipes, struct cr_options *o)
|
||||||
{
|
{
|
||||||
struct pipe_data_entry e;
|
struct pipe_data_entry e;
|
||||||
|
12
crtools.c
12
crtools.c
@@ -182,6 +182,18 @@ struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX] = {
|
|||||||
.magic = FS_MAGIC,
|
.magic = FS_MAGIC,
|
||||||
.show = show_fs,
|
.show = show_fs,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[CR_FD_REMAP_FPATH] = {
|
||||||
|
.fmt = FMT_FNAME_REMAP_FPATH,
|
||||||
|
.magic = REMAP_FPATH_MAGIC,
|
||||||
|
.show = show_remap_files,
|
||||||
|
},
|
||||||
|
|
||||||
|
[CR_FD_GHOST_FILE] = {
|
||||||
|
.fmt = FMT_FNAME_GHOST_FILE,
|
||||||
|
.magic = GHOST_FILE_MAGIC,
|
||||||
|
.show = show_ghost_file,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cr_fdset *alloc_cr_fdset(int nr)
|
static struct cr_fdset *alloc_cr_fdset(int nr)
|
||||||
|
137
files.c
137
files.c
@@ -81,6 +81,7 @@ struct fdinfo_list_entry *file_master(struct file_desc *d)
|
|||||||
|
|
||||||
struct reg_file_info {
|
struct reg_file_info {
|
||||||
struct reg_file_entry rfe;
|
struct reg_file_entry rfe;
|
||||||
|
char *remap_path;
|
||||||
char *path;
|
char *path;
|
||||||
struct file_desc d;
|
struct file_desc d;
|
||||||
};
|
};
|
||||||
@@ -151,6 +152,128 @@ static struct file_desc_ops reg_desc_ops = {
|
|||||||
.open = open_fe_fd,
|
.open = open_fe_fd,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ghost_file {
|
||||||
|
u32 id;
|
||||||
|
char *path;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static LIST_HEAD(ghost_files);
|
||||||
|
|
||||||
|
void clear_ghost_files(void)
|
||||||
|
{
|
||||||
|
struct ghost_file *gf;
|
||||||
|
|
||||||
|
pr_info("Unlinking ghosts\n");
|
||||||
|
|
||||||
|
list_for_each_entry(gf, &ghost_files, list) {
|
||||||
|
pr_info("\t`- %s\n", gf->path);
|
||||||
|
unlink(gf->path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_remap_ghost(struct reg_file_info *rfi,
|
||||||
|
struct remap_file_path_entry *rfe)
|
||||||
|
{
|
||||||
|
struct ghost_file *gf;
|
||||||
|
struct ghost_file_entry gfe;
|
||||||
|
int gfd, ifd;
|
||||||
|
|
||||||
|
list_for_each_entry(gf, &ghost_files, list)
|
||||||
|
if (gf->id == rfe->remap_id)
|
||||||
|
goto gf_found;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ghost not found. We will create one in the same dir
|
||||||
|
* as the very first client of it thus resolving any
|
||||||
|
* issues with cross-device links.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pr_info("Opening ghost file %x for %s\n", rfe->remap_id, rfi->path);
|
||||||
|
|
||||||
|
gf = xmalloc(sizeof(*gf));
|
||||||
|
if (!gf)
|
||||||
|
return -1;
|
||||||
|
gf->path = xmalloc(PATH_MAX);
|
||||||
|
if (!gf->path)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ifd = open_image_ro(CR_FD_GHOST_FILE, rfe->remap_id);
|
||||||
|
if (ifd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (read_img(ifd, &gfe) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
sprintf(gf->path, "%s.cr.%x.ghost", rfi->path, rfe->remap_id);
|
||||||
|
gfd = open(gf->path, O_WRONLY | O_CREAT | O_EXCL, gfe.mode);
|
||||||
|
if (gfd < 0) {
|
||||||
|
pr_perror("Can't open ghost file");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fchown(gfd, gfe.uid, gfe.gid) < 0) {
|
||||||
|
pr_perror("Can't reset user/group on ghost %x\n", rfe->remap_id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_file(ifd, gfd, 0) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
close(ifd);
|
||||||
|
close(gfd);
|
||||||
|
|
||||||
|
gf->id = rfe->remap_id;
|
||||||
|
list_add_tail(&gf->list, &ghost_files);
|
||||||
|
gf_found:
|
||||||
|
rfi->remap_path = gf->path;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int collect_remaps(void)
|
||||||
|
{
|
||||||
|
int fd, ret = 0;
|
||||||
|
|
||||||
|
fd = open_image_ro(CR_FD_REMAP_FPATH);
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct remap_file_path_entry rfe;
|
||||||
|
struct file_desc *fdesc;
|
||||||
|
struct reg_file_info *rfi;
|
||||||
|
|
||||||
|
ret = read_img_eof(fd, &rfe);
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
if (!(rfe.remap_id & REMAP_GHOST)) {
|
||||||
|
pr_err("Non ghost remap not supported @%x\n",
|
||||||
|
rfe.orig_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdesc = find_file_desc_raw(FDINFO_REG, rfe.orig_id);
|
||||||
|
if (fdesc == NULL) {
|
||||||
|
pr_err("Remap for non existing file %x\n",
|
||||||
|
rfe.orig_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rfe.remap_id &= ~REMAP_GHOST;
|
||||||
|
rfi = container_of(fdesc, struct reg_file_info, d);
|
||||||
|
pr_info("Configuring remap %x -> %x\n", rfi->rfe.id, rfe.remap_id);
|
||||||
|
ret = open_remap_ghost(rfi, &rfe);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int collect_reg_files(void)
|
int collect_reg_files(void)
|
||||||
{
|
{
|
||||||
struct reg_file_info *rfi = NULL;
|
struct reg_file_info *rfi = NULL;
|
||||||
@@ -183,6 +306,7 @@ int collect_reg_files(void)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
rfi->remap_path = NULL;
|
||||||
rfi->path[len] = '\0';
|
rfi->path[len] = '\0';
|
||||||
|
|
||||||
pr_info("Collected [%s] ID %x\n", rfi->path, rfi->rfe.id);
|
pr_info("Collected [%s] ID %x\n", rfi->path, rfi->rfe.id);
|
||||||
@@ -196,7 +320,8 @@ int collect_reg_files(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
return ret;
|
|
||||||
|
return collect_remaps();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int collect_fd(int pid, struct fdinfo_entry *e)
|
static int collect_fd(int pid, struct fdinfo_entry *e)
|
||||||
@@ -269,12 +394,22 @@ static int open_fe_fd(struct file_desc *d)
|
|||||||
|
|
||||||
rfi = container_of(d, struct reg_file_info, d);
|
rfi = container_of(d, struct reg_file_info, d);
|
||||||
|
|
||||||
|
if (rfi->remap_path)
|
||||||
|
if (link(rfi->remap_path, rfi->path) < 0) {
|
||||||
|
pr_perror("Can't link %s -> %s\n",
|
||||||
|
rfi->remap_path, rfi->path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
tmp = open(rfi->path, rfi->rfe.flags);
|
tmp = open(rfi->path, rfi->rfe.flags);
|
||||||
if (tmp < 0) {
|
if (tmp < 0) {
|
||||||
pr_perror("Can't open file %s", rfi->path);
|
pr_perror("Can't open file %s", rfi->path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rfi->remap_path)
|
||||||
|
unlink(rfi->path);
|
||||||
|
|
||||||
lseek(tmp, rfi->rfe.pos, SEEK_SET);
|
lseek(tmp, rfi->rfe.pos, SEEK_SET);
|
||||||
|
|
||||||
if (restore_fown(tmp, &rfi->rfe.fown))
|
if (restore_fown(tmp, &rfi->rfe.fown))
|
||||||
|
@@ -44,6 +44,7 @@ enum {
|
|||||||
|
|
||||||
CR_FD_PSTREE,
|
CR_FD_PSTREE,
|
||||||
CR_FD_SHMEM_PAGES,
|
CR_FD_SHMEM_PAGES,
|
||||||
|
CR_FD_GHOST_FILE,
|
||||||
|
|
||||||
_CR_FD_GLOB_FROM,
|
_CR_FD_GLOB_FROM,
|
||||||
CR_FD_SK_QUEUES,
|
CR_FD_SK_QUEUES,
|
||||||
@@ -52,6 +53,7 @@ enum {
|
|||||||
CR_FD_UNIXSK,
|
CR_FD_UNIXSK,
|
||||||
CR_FD_PIPES,
|
CR_FD_PIPES,
|
||||||
CR_FD_PIPES_DATA,
|
CR_FD_PIPES_DATA,
|
||||||
|
CR_FD_REMAP_FPATH,
|
||||||
_CR_FD_GLOB_TO,
|
_CR_FD_GLOB_TO,
|
||||||
|
|
||||||
CR_FD_MAX
|
CR_FD_MAX
|
||||||
@@ -94,6 +96,8 @@ void show_sigacts(int fd_sigacts, struct cr_options *o);
|
|||||||
void show_itimers(int fd, struct cr_options *o);
|
void show_itimers(int fd, struct cr_options *o);
|
||||||
void show_creds(int fd, struct cr_options *o);
|
void show_creds(int fd, struct cr_options *o);
|
||||||
void show_fs(int fd, struct cr_options *o);
|
void show_fs(int fd, struct cr_options *o);
|
||||||
|
void show_remap_files(int fd, struct cr_options *o);
|
||||||
|
void show_ghost_file(int fd, struct cr_options *o);
|
||||||
void show_fown_cont(fown_t *fown);
|
void show_fown_cont(fown_t *fown);
|
||||||
|
|
||||||
extern void print_data(unsigned long addr, unsigned char *data, size_t size);
|
extern void print_data(unsigned long addr, unsigned char *data, size_t size);
|
||||||
@@ -121,6 +125,8 @@ extern struct cr_fd_desc_tmpl fdset_template[CR_FD_MAX];
|
|||||||
#define FMT_FNAME_IPCNS_SEM "ipcns-sem-%d.img"
|
#define FMT_FNAME_IPCNS_SEM "ipcns-sem-%d.img"
|
||||||
#define FMT_FNAME_SK_QUEUES "sk-queues.img"
|
#define FMT_FNAME_SK_QUEUES "sk-queues.img"
|
||||||
#define FMT_FNAME_FS "fs-%d.img"
|
#define FMT_FNAME_FS "fs-%d.img"
|
||||||
|
#define FMT_FNAME_REMAP_FPATH "remap-fpath.img"
|
||||||
|
#define FMT_FNAME_GHOST_FILE "ghost-file-%x.img"
|
||||||
|
|
||||||
extern int open_image_dir(void);
|
extern int open_image_dir(void);
|
||||||
extern void close_image_dir(void);
|
extern void close_image_dir(void);
|
||||||
|
@@ -73,4 +73,6 @@ struct file_desc;
|
|||||||
extern int collect_pipes(void);
|
extern int collect_pipes(void);
|
||||||
extern void mark_pipe_master(void);
|
extern void mark_pipe_master(void);
|
||||||
|
|
||||||
|
void clear_ghost_files(void);
|
||||||
|
|
||||||
#endif /* FILES_H_ */
|
#endif /* FILES_H_ */
|
||||||
|
@@ -30,6 +30,8 @@
|
|||||||
#define REG_FILES_MAGIC 0x50363636 /* Belgorod */
|
#define REG_FILES_MAGIC 0x50363636 /* Belgorod */
|
||||||
#define FS_MAGIC 0x51403912 /* Voronezh */
|
#define FS_MAGIC 0x51403912 /* Voronezh */
|
||||||
#define MM_MAGIC 0x57492820 /* Pskov */
|
#define MM_MAGIC 0x57492820 /* Pskov */
|
||||||
|
#define REMAP_FPATH_MAGIC 0x59133954 /* Vologda */
|
||||||
|
#define GHOST_FILE_MAGIC 0x52583605 /* Oryol */
|
||||||
|
|
||||||
#define PIPEFS_MAGIC 0x50495045
|
#define PIPEFS_MAGIC 0x50495045
|
||||||
|
|
||||||
@@ -64,6 +66,23 @@ struct reg_file_entry {
|
|||||||
u8 name[0];
|
u8 name[0];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct remap_file_path_entry {
|
||||||
|
u32 orig_id;
|
||||||
|
u32 remap_id;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Top bit set in the tgt id means we've remapped
|
||||||
|
* to a ghost file.
|
||||||
|
*/
|
||||||
|
#define REMAP_GHOST (1 << 31)
|
||||||
|
|
||||||
|
struct ghost_file_entry {
|
||||||
|
u32 uid;
|
||||||
|
u32 gid;
|
||||||
|
u32 mode;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
struct fdinfo_entry {
|
struct fdinfo_entry {
|
||||||
u32 fd;
|
u32 fd;
|
||||||
u8 type;
|
u8 type;
|
||||||
|
Reference in New Issue
Block a user