Add fdallocn function and use it when passing fds over unix socket.

This gets rid of "unp_externalize fdalloc failed" panic.

Reviewed by:	pjd
MFC after:	1 week
This commit is contained in:
Mateusz Guzik 2013-04-14 17:08:34 +00:00
parent fb69d3e351
commit db8f33fd32
3 changed files with 38 additions and 12 deletions

View File

@ -1581,6 +1581,34 @@ fdalloc(struct thread *td, int minfd, int *result)
return (0);
}
/*
* Allocate n file descriptors for the process.
*/
int
fdallocn(struct thread *td, int minfd, int *fds, int n)
{
struct proc *p = td->td_proc;
struct filedesc *fdp = p->p_fd;
int i;
FILEDESC_XLOCK_ASSERT(fdp);
if (!fdavail(td, n))
return (EMFILE);
for (i = 0; i < n; i++)
if (fdalloc(td, 0, &fds[i]) != 0)
break;
if (i < n) {
for (i--; i >= 0; i--)
fdunused(fdp, fds[i]);
return (EMFILE);
}
return (0);
}
/*
* Check to see whether n user file descriptors are available to the process
* p.

View File

@ -1706,7 +1706,6 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags)
void *data;
socklen_t clen = control->m_len, datalen;
int error, newfds;
int f;
u_int newlen;
UNP_LINK_UNLOCK_ASSERT();
@ -1732,13 +1731,6 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags)
goto next;
}
FILEDESC_XLOCK(fdesc);
/* if the new FD's will not fit free them. */
if (!fdavail(td, newfds)) {
FILEDESC_XUNLOCK(fdesc);
error = EMSGSIZE;
unp_freerights(fdep, newfds);
goto next;
}
/*
* Now change each pointer to an fd in the global
@ -1758,17 +1750,22 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags)
fdp = (int *)
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
if (fdallocn(td, 0, fdp, newfds) != 0) {
FILEDESC_XUNLOCK(td->td_proc->p_fd);
error = EMSGSIZE;
unp_freerights(fdep, newfds);
m_freem(*controlp);
*controlp = NULL;
goto next;
}
for (i = 0; i < newfds; i++, fdp++) {
if (fdalloc(td, 0, &f))
panic("unp_externalize fdalloc failed");
fde = &fdesc->fd_ofiles[f];
fde = &fdesc->fd_ofiles[*fdp];
fde->fde_file = fdep[0]->fde_file;
filecaps_move(&fdep[0]->fde_caps,
&fde->fde_caps);
if ((flags & MSG_CMSG_CLOEXEC) != 0)
fde->fde_flags |= UF_EXCLOSE;
unp_externalize_fp(fde->fde_file);
*fdp = f;
}
FILEDESC_XUNLOCK(fdesc);
free(fdep[0], M_FILECAPS);

View File

@ -150,6 +150,7 @@ int falloc_noinstall(struct thread *td, struct file **resultfp);
int finstall(struct thread *td, struct file *fp, int *resultfp, int flags,
struct filecaps *fcaps);
int fdalloc(struct thread *td, int minfd, int *result);
int fdallocn(struct thread *td, int minfd, int *fds, int n);
int fdavail(struct thread *td, int n);
int fdcheckstd(struct thread *td);
void fdclose(struct filedesc *fdp, struct file *fp, int idx, struct thread *td);