diff --git a/files.c b/files.c index 2bffcbae7..8193d59e7 100644 --- a/files.c +++ b/files.c @@ -83,6 +83,39 @@ static inline struct file_desc *find_file_desc(FdinfoEntry *fe) return find_file_desc_raw(fe->type, fe->id); } +/* + * A file may be shared between several file descriptors. E.g + * when doing a fork() every fd of a forker and respective fds + * of the child have such. Another way of getting shared files + * is by dup()-ing them or sending them via unix sockets in + * SCM_RIGHTS message. + * + * We restore this type of things in 3 steps (states[] below) + * + * 1. Prepare step. + * Select which task will create the file (open() one, or + * call any other syscall for than (socket, pipe, etc.). All + * the others, that share one, create unix sockets under the + * respective file descriptor (transport socket). + * 2. Open step. + * The one who creates the file (the 'master') creates one, + * then creates one more unix socket (transport) and sends the + * created file over this socket to the other recepients. + * 3. Receive step. + * Those, who wait for the file to appear, receive one via + * the transport socket, then close the socket and dup() the + * received file descriptor into its place. + * + * There's the 4th step in the states[] array -- the post_open + * one. This one is not about file-sharing resolving, but about + * doing something with a file using it's 'desired' fd. The + * thing is that while going the 3-step process above, the file + * may appear in variuos places in the task's fd table, and if + * we want to do something with it's _final_ descriptor value, + * we should wait for it to appear there. So the post_open is + * called when the file is finally set into its place. + */ + struct fdinfo_list_entry *file_master(struct file_desc *d) { if (list_empty(&d->fd_info_head)) { @@ -110,6 +143,14 @@ void show_saved_files(void) } } +/* + * The gen_id thing is used to optimize the comparison of shared files. + * If two files have different gen_ids, then they are different for sure. + * If it matches, we don't know it and have to call sys_kcmp(). + * + * The kcmp-ids.c engine does this trick, see comments in it for more info. + */ + static u32 make_gen_id(const struct fd_parms *p) { return ((u32)p->stat.st_dev) ^ ((u32)p->stat.st_ino) ^ ((u32)p->pos); diff --git a/include/files.h b/include/files.h index 1d195b749..5b65bd7bf 100644 --- a/include/files.h +++ b/include/files.h @@ -90,7 +90,7 @@ struct file_desc_ops { int (*post_open)(struct file_desc *d, int fd); /* * Report whether the fd in question wants a transport socket - * in it instead of a real file. + * in it instead of a real file. See file_master for details. */ int (*want_transport)(FdinfoEntry *fe, struct file_desc *d); /* @@ -101,7 +101,7 @@ struct file_desc_ops { }; struct file_desc { - u32 id; /* File descriptor id, unique */ + u32 id; /* File id, unique */ struct hlist_node hash; /* Descriptor hashing and lookup */ struct list_head fd_info_head; /* Chain of fdinfo_list_entry-s with same ID and type but different pids */ struct file_desc_ops *ops; /* Associated operations */