[09/12] files: Add get_unused_fd() helper

Submitted by Kirill Tkhai on April 29, 2016, 2:37 p.m.

Details

Message ID 146194062850.9179.15238506378962818207.stgit@pro
State Rejected
Series "Support for packet's msg_name in receive queue of promiscous DGRAM sockets"
Headers show

Commit Message

Kirill Tkhai April 29, 2016, 2:37 p.m.
This function helps to find a fd, which is not occupied by restored
task and which won't be need by the task in the future.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 criu/cr-restore.c     |    2 -
 criu/files.c          |   99 +++++++++++++++++++++++++++++++++++++++++++++++++
 criu/include/files.h  |    2 +
 criu/include/pstree.h |    1 
 4 files changed, 103 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index 777c71d..9560254 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -108,7 +108,7 @@ 
 #define arch_export_unmap		__export_unmap
 #endif
 
-static struct pstree_item *current;
+struct pstree_item *current;
 
 static int restore_task_with_children(void *);
 static int sigreturn_restore(pid_t pid, CoreEntry *core);
diff --git a/criu/files.c b/criu/files.c
index fd5c61d..9ad640b 100644
--- a/criu/files.c
+++ b/criu/files.c
@@ -1149,6 +1149,105 @@  int prepare_fds(struct pstree_item *me)
 	return ret;
 }
 
+#define fle_entry(list) list_entry(list, struct fdinfo_list_entry, ps_list)
+/*
+ * Returns next range (*l, *r) above initial (*l). The search starts from
+ * fle, which is not necessary the first element.
+ */
+static void next_range(struct fdinfo_list_entry **fle, struct list_head *head, int *l, int *r)
+{
+	bool found = false;
+	int start = *l;
+
+	if (&(*fle)->ps_list != head) {
+		if ((*fle)->ps_list.prev != head)
+			*l = fle_entry((*fle)->ps_list.prev)->fe->fd;
+		else
+			*l = -1;
+
+		while (&(*fle)->ps_list != head) {
+			*r = (*fle)->fe->fd;
+			if (start + 1 < *r && *l + 1 < *r) {
+				found = true;
+				*l = max(start, *l);
+				break;
+			}
+			*l = *r;
+			*fle = fle_entry((*fle)->ps_list.next);
+		}
+		if (!found)
+			*r = INT_MAX;
+	} else if (!list_empty(head)) {
+		*l = fle_entry((*fle)->ps_list.prev)->fe->fd;
+		*l = max(*l, start);
+		*r = INT_MAX;
+	} else {
+		*l = start;
+		*r = INT_MAX;
+	}
+}
+
+int find_unused_fd(void)
+{
+	struct rst_info *ri = rsti(current);
+	struct fdinfo_list_entry *flea, *fleb, *flec, *fled;
+	int la, lb, lc, ld, ra, rb, rc, rd, i, ret = -1;
+
+	la = lb = lc = ld = -1;
+	ra = rb = rc = rd = INT_MAX;
+
+	flea = fle_entry(ri->fds.next);
+	fleb = fle_entry(ri->eventpoll.next);
+	flec = fle_entry(ri->tty_slaves.next);
+	fled = fle_entry(ri->tty_ctty.next);
+nexta:
+	next_range(&flea, &ri->fds, &la, &ra);
+	if (la == INT_MAX)
+		goto out;
+	lb = la;
+nextb:
+	next_range(&fleb, &ri->eventpoll, &lb, &rb);
+	if (lb == INT_MAX || lb >= ra) {
+		fleb = fle_entry(fleb->ps_list.prev);
+		la = ra;
+		goto nexta;
+	}
+
+	lc = lb;
+	rb = min(ra, rb);
+nextc:
+	next_range(&flec, &ri->tty_slaves, &lc, &rc);
+	if (lc == INT_MAX || lc >= rb) {
+		flec = fle_entry(flec->ps_list.prev);
+		lb = rb;
+		goto nextb;
+	}
+
+	ld = lc;
+	rc = min(rb, rc);
+nextd:
+	next_range(&fled, &ri->tty_ctty, &ld, &rd);
+	if (ld == INT_MAX || ld >= rc) {
+		fled = fle_entry(fled->ps_list.prev);
+		lc = rc;
+		goto nextc;
+	}
+
+	rd = min(rc, rd);
+
+	for (i = ld + 1; i < rd; i++) {
+		if (fcntl(i, F_GETFD) == -1 && errno == EBADF) {
+			ret = i;
+			goto out;
+		}
+	}
+
+	ld = rd;
+	goto nextd;
+out:
+	return ret;
+}
+
 static int fchroot(int fd)
 {
 	char fd_path[PSFDS];
diff --git a/criu/include/files.h b/criu/include/files.h
index 472cc45..6c5d579 100644
--- a/criu/include/files.h
+++ b/criu/include/files.h
@@ -160,9 +160,11 @@  extern int prepare_fd_pid(struct pstree_item *me);
 extern int prepare_ctl_tty(int pid, struct rst_info *rst_info, u32 ctl_tty_id);
 extern int prepare_shared_fdinfo(void);
 extern int get_filemap_fd(struct vma_area *);
+extern int find_unused_fd(void);
 extern int restore_fs(struct pstree_item *);
 extern int prepare_fs_pid(struct pstree_item *);
 extern int set_fd_flags(int fd, int flags);
+extern int get_unused_fd(void);
 
 extern int close_old_fds(void);
 #ifndef AT_EMPTY_PATH
diff --git a/criu/include/pstree.h b/criu/include/pstree.h
index 4bf6db7..f79a2ef 100644
--- a/criu/include/pstree.h
+++ b/criu/include/pstree.h
@@ -29,6 +29,7 @@  struct pstree_item {
 	TaskKobjIdsEntry	*ids;
 };
 
+struct pstree_item *current;
 struct rst_info;
 /* See alloc_pstree_item() for details */
 static inline struct rst_info *rsti(struct pstree_item *i)