/* Install a given filp in a given files_struct, with CLOEXEC set. * Safe for files != current->files. * Mostly cut-and-paste from linux-2.6.0/fs/fcntl.c:locate_fd() */ int cr_dup_other(struct files_struct *files, struct file *filp) { unsigned int newfd; unsigned int start; unsigned int max_fds; int error; cr_fdtable_t *fdt; spin_lock(&files->file_lock); repeat: fdt = cr_fdtable(files); start = CR_NEXT_FD(files, fdt); newfd = start; max_fds = CR_MAX_FDS(fdt); if (start < max_fds) { newfd = find_next_zero_bit(CR_OPEN_FDS_BITS(fdt), max_fds, start); } /* XXX: Really shouldn't be using current here. * However, I haven't bothered to figure out the locking * requirements for using anything else. * XXX: Probably could just pass the limit in. * XXX: Later kernels push this into expand_files() */ error = -EMFILE; if (newfd >= CR_RLIM(current)[RLIMIT_NOFILE].rlim_cur) { goto out; } error = expand_files(files, newfd); if (error < 0) { goto out; } else if (error) { /* grew - search again (also reacquires fdt) */ goto repeat; } CR_NEXT_FD(files, fdt) = newfd + 1; /* Claim */ cr_set_open_fd(newfd, fdt); cr_set_close_on_exec(newfd, fdt); /* Install */ get_file(filp); rcu_assign_pointer(fdt->fd[newfd], filp); error = newfd; out: spin_unlock(&files->file_lock); return error; }
/* * cr_fd_claim * * Atomically checks and claims an fd * * returns < 0 on conflict w/ an existing fd */ int cr_fd_claim(int fd) { cr_fdtable_t *fdt; int retval; /* Mark the fd in use */ spin_lock(¤t->files->file_lock); fdt = cr_fdtable(current->files); if (FD_ISSET(fd, fdt->open_fds)) { retval = -EBUSY; } else { retval = 0; FD_SET(fd, fdt->open_fds); FD_CLR(fd, fdt->close_on_exec); } spin_unlock(¤t->files->file_lock); return retval; }
/* * cr_fd_claim * * Atomically checks and claims an fd * * returns < 0 on conflict w/ an existing fd */ int cr_fd_claim(int fd) { cr_fdtable_t *fdt; int retval; /* Mark the fd in use */ spin_lock(¤t->files->file_lock); fdt = cr_fdtable(current->files); if (cr_read_open_fd(fd, fdt)) { retval = -EBUSY; } else { retval = 0; cr_set_open_fd(fd, fdt); cr_clear_close_on_exec(fd, fdt); } spin_unlock(¤t->files->file_lock); return retval; }