summaryrefslogtreecommitdiffstats
path: root/sys/compat/linux/linux_ioctl.c
diff options
context:
space:
mode:
authoralfred <alfred@FreeBSD.org>2002-01-13 11:58:06 +0000
committeralfred <alfred@FreeBSD.org>2002-01-13 11:58:06 +0000
commit844237b3960bfbf49070d6371a84f67f9e3366f6 (patch)
tree598e20df363e602313c7ad93de8f8c4b4240d61d /sys/compat/linux/linux_ioctl.c
parent8cd61193307ff459ae72eb7aa6a734eb5e3b427e (diff)
downloadFreeBSD-src-844237b3960bfbf49070d6371a84f67f9e3366f6.zip
FreeBSD-src-844237b3960bfbf49070d6371a84f67f9e3366f6.tar.gz
SMP Lock struct file, filedesc and the global file list.
Seigo Tanimura (tanimura) posted the initial delta. I've polished it quite a bit reducing the need for locking and adapting it for KSE. Locks: 1 mutex in each filedesc protects all the fields. protects "struct file" initialization, while a struct file is being changed from &badfileops -> &pipeops or something the filedesc should be locked. 1 mutex in each struct file protects the refcount fields. doesn't protect anything else. the flags used for garbage collection have been moved to f_gcflag which was the FILLER short, this doesn't need locking because the garbage collection is a single threaded container. could likely be made to use a pool mutex. 1 sx lock for the global filelist. struct file * fhold(struct file *fp); /* increments reference count on a file */ struct file * fhold_locked(struct file *fp); /* like fhold but expects file to locked */ struct file * ffind_hold(struct thread *, int fd); /* finds the struct file in thread, adds one reference and returns it unlocked */ struct file * ffind_lock(struct thread *, int fd); /* ffind_hold, but returns file locked */ I still have to smp-safe the fget cruft, I'll get to that asap.
Diffstat (limited to 'sys/compat/linux/linux_ioctl.c')
-rw-r--r--sys/compat/linux/linux_ioctl.c278
1 files changed, 184 insertions, 94 deletions
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
index f5ab820..baafb5b 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -105,19 +105,23 @@ static TAILQ_HEAD(, handler_element) handlers =
static int
linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
{
- struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd];
+ struct file *fp;
int error;
struct disklabel dl;
+ fp = ffind_hold(td, args->fd);
+ if (fp == NULL)
+ return (EBADF);
switch (args->cmd & 0xffff) {
case LINUX_BLKGETSIZE:
error = fo_ioctl(fp, DIOCGDINFO, (caddr_t)&dl, td);
+ fdrop(fp, td);
if (error)
return (error);
return (copyout(&(dl.d_secperunit), (caddr_t)args->arg,
sizeof(dl.d_secperunit)));
- break;
}
+ fdrop(fp, td);
return (ENOIOCTL);
}
@@ -548,66 +552,77 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
struct termios bios;
struct linux_termios lios;
struct linux_termio lio;
- struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd];
+ struct file *fp;
int error;
+ fp = ffind_hold(td, args->fd);
+ if (fp == NULL)
+ return (EBADF);
switch (args->cmd & 0xffff) {
case LINUX_TCGETS:
error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td);
if (error)
- return (error);
+ break;
bsd_to_linux_termios(&bios, &lios);
- return copyout(&lios, (caddr_t)args->arg, sizeof(lios));
+ error = copyout(&lios, (caddr_t)args->arg, sizeof(lios));
+ break;
case LINUX_TCSETS:
error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
if (error)
- return (error);
+ break;
linux_to_bsd_termios(&lios, &bios);
- return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td));
+ error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td));
+ break;
case LINUX_TCSETSW:
error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
if (error)
- return (error);
+ break;
linux_to_bsd_termios(&lios, &bios);
- return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td));
+ error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td));
+ break;
case LINUX_TCSETSF:
error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
if (error)
- return (error);
+ break;
linux_to_bsd_termios(&lios, &bios);
- return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td));
+ error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td));
+ break;
case LINUX_TCGETA:
error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td);
if (error)
- return (error);
+ break;
bsd_to_linux_termio(&bios, &lio);
- return (copyout(&lio, (caddr_t)args->arg, sizeof(lio)));
+ error = (copyout(&lio, (caddr_t)args->arg, sizeof(lio)));
+ break;
case LINUX_TCSETA:
error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
if (error)
- return (error);
+ break;
linux_to_bsd_termio(&lio, &bios);
- return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td));
+ error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td));
+ break;
case LINUX_TCSETAW:
error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
if (error)
- return (error);
+ break;
linux_to_bsd_termio(&lio, &bios);
- return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td));
+ error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td));
+ break;
case LINUX_TCSETAF:
error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
if (error)
- return (error);
+ break;
linux_to_bsd_termio(&lio, &bios);
- return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td));
+ error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td));
+ break;
/* LINUX_TCSBRK */
@@ -625,7 +640,8 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
struct write_args wr;
error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td);
if (error)
- return (error);
+ break;
+ fdrop(fp, td);
c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
c = bios.c_cc[c];
if (c != _POSIX_VDISABLE) {
@@ -637,10 +653,12 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
return (0);
}
default:
+ fdrop(fp, td);
return (EINVAL);
}
args->arg = 0;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
}
case LINUX_TCFLSH: {
@@ -656,97 +674,115 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
args->arg = FREAD | FWRITE;
break;
default:
+ fdrop(fp, td);
return (EINVAL);
}
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
}
case LINUX_TIOCEXCL:
args->cmd = TIOCEXCL;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_TIOCNXCL:
args->cmd = TIOCNXCL;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
/* LINUX_TIOCSCTTY */
case LINUX_TIOCGPGRP:
args->cmd = TIOCGPGRP;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_TIOCSPGRP:
args->cmd = TIOCSPGRP;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
/* LINUX_TIOCOUTQ */
/* LINUX_TIOCSTI */
case LINUX_TIOCGWINSZ:
args->cmd = TIOCGWINSZ;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_TIOCSWINSZ:
args->cmd = TIOCSWINSZ;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_TIOCMGET:
args->cmd = TIOCMGET;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_TIOCMBIS:
args->cmd = TIOCMBIS;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_TIOCMBIC:
args->cmd = TIOCMBIC;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_TIOCMSET:
args->cmd = TIOCMSET;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
/* TIOCGSOFTCAR */
/* TIOCSSOFTCAR */
case LINUX_FIONREAD: /* LINUX_TIOCINQ */
args->cmd = FIONREAD;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
/* LINUX_TIOCLINUX */
case LINUX_TIOCCONS:
args->cmd = TIOCCONS;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_TIOCGSERIAL: {
struct linux_serial_struct lss;
lss.type = LINUX_PORT_16550A;
lss.flags = 0;
lss.close_delay = 0;
- return copyout(&lss, (caddr_t)args->arg, sizeof(lss));
+ error = copyout(&lss, (caddr_t)args->arg, sizeof(lss));
+ break;
}
case LINUX_TIOCSSERIAL: {
struct linux_serial_struct lss;
error = copyin((caddr_t)args->arg, &lss, sizeof(lss));
if (error)
- return (error);
+ break;
/* XXX - It really helps to have an implementation that
* does nothing. NOT!
*/
- return (0);
+ error = 0;
+ break;
}
/* LINUX_TIOCPKT */
case LINUX_FIONBIO:
args->cmd = FIONBIO;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_TIOCNOTTY:
args->cmd = TIOCNOTTY;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_TIOCSETD: {
int line;
@@ -761,9 +797,11 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
line = PPPDISC;
break;
default:
+ fdrop(fp, td);
return (EINVAL);
}
- return (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td));
+ error = (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td));
+ break;
}
case LINUX_TIOCGETD: {
@@ -783,9 +821,11 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
linux_line = LINUX_N_PPP;
break;
default:
+ fdrop(fp, td);
return (EINVAL);
}
- return (copyout(&linux_line, (caddr_t)args->arg, sizeof(int)));
+ error = (copyout(&linux_line, (caddr_t)args->arg, sizeof(int)));
+ break;
}
/* LINUX_TCSBRKP */
@@ -793,15 +833,18 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
case LINUX_FIONCLEX:
args->cmd = FIONCLEX;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_FIOCLEX:
args->cmd = FIOCLEX;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_FIOASYNC:
args->cmd = FIOASYNC;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
/* LINUX_TIOCSERCONFIG */
/* LINUX_TIOCSERGWILD */
@@ -809,9 +852,13 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
/* LINUX_TIOCGLCKTRMIOS */
/* LINUX_TIOCSLCKTRMIOS */
+ default:
+ error = ENOIOCTL;
+ break;
}
- return (ENOIOCTL);
+ fdrop(fp, td);
+ return (error);
}
/*
@@ -1199,26 +1246,33 @@ bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp)
static int
linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
{
- struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd];
+ struct file *fp;
int error;
+ fp = ffind_hold(td, args->fd);
+ if (fp == NULL)
+ return (EBADF);
switch (args->cmd & 0xffff) {
case LINUX_CDROMPAUSE:
args->cmd = CDIOCPAUSE;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_CDROMRESUME:
args->cmd = CDIOCRESUME;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_CDROMPLAYMSF:
args->cmd = CDIOCPLAYMSF;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_CDROMPLAYTRKIND:
args->cmd = CDIOCPLAYTRACKS;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_CDROMREADTOCHDR: {
struct ioc_toc_header th;
@@ -1229,7 +1283,7 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
lth.cdth_trk1 = th.ending_track;
copyout(&lth, (caddr_t)args->arg, sizeof(lth));
}
- return (error);
+ break;
}
case LINUX_CDROMREADTOCENTRY: {
@@ -1247,20 +1301,23 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
&irtse.entry.addr, &lte.cdte_addr);
copyout(&lte, (caddr_t)args->arg, sizeof(lte));
}
- return (error);
+ break;
}
case LINUX_CDROMSTOP:
args->cmd = CDIOCSTOP;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_CDROMSTART:
args->cmd = CDIOCSTART;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_CDROMEJECT:
args->cmd = CDIOCEJECT;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
/* LINUX_CDROMVOLCTRL */
@@ -1278,11 +1335,11 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
bsdsc.data = bsdinfo;
error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, td);
if (error)
- return (error);
+ break;
error = copyin((caddr_t)args->arg, &sc,
sizeof(struct linux_cdrom_subchnl));
if (error)
- return (error);
+ break;
sc.cdsc_audiostatus = bsdinfo->header.audio_status;
sc.cdsc_adr = bsdinfo->what.position.addr_type;
sc.cdsc_ctrl = bsdinfo->what.position.control;
@@ -1294,7 +1351,7 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
bsdinfo->what.position.reladdr.lba);
error = copyout(&sc, (caddr_t)args->arg,
sizeof(struct linux_cdrom_subchnl));
- return (error);
+ break;
}
/* LINUX_CDROMREADMODE2 */
@@ -1306,7 +1363,8 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
case LINUX_CDROMRESET:
args->cmd = CDIOCRESET;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
/* LINUX_CDROMVOLREAD */
/* LINUX_CDROMREADRAW */
@@ -1337,18 +1395,19 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
error = copyin((caddr_t)args->arg, &lds, sizeof(l_dvd_struct));
if (error)
- return (error);
+ break;
error = linux_to_bsd_dvd_struct(&lds, &bds);
if (error)
- return (error);
+ break;
error = fo_ioctl(fp, DVDIOCREADSTRUCTURE, (caddr_t)&bds, td);
if (error)
- return (error);
+ break;
error = bsd_to_linux_dvd_struct(&bds, &lds);
if (error)
- return (error);
- return (copyout(&lds, (caddr_t)args->arg,
- sizeof(l_dvd_struct)));
+ break;
+ error = copyout(&lds, (caddr_t)args->arg,
+ sizeof(l_dvd_struct));
+ break;
}
/* LINUX_DVD_WRITE_STRUCT */
@@ -1361,10 +1420,10 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
error = copyin((caddr_t)args->arg, &lda,
sizeof(l_dvd_authinfo));
if (error)
- return (error);
+ break;
error = linux_to_bsd_dvd_authinfo(&lda, &bcode, &bda);
if (error)
- return (error);
+ break;
error = fo_ioctl(fp, bcode, (caddr_t)&bda, td);
if (error) {
if (lda.type == LINUX_DVD_HOST_SEND_KEY2) {
@@ -1372,22 +1431,27 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
copyout(&lda, (caddr_t)args->arg,
sizeof(l_dvd_authinfo));
}
- return (error);
+ break;
}
error = bsd_to_linux_dvd_authinfo(&bda, &lda);
if (error)
- return (error);
- return (copyout(&lda, (caddr_t)args->arg,
- sizeof(l_dvd_authinfo)));
+ break;
+ error = copyout(&lda, (caddr_t)args->arg,
+ sizeof(l_dvd_authinfo));
+ break;
}
/* LINUX_CDROM_SEND_PACKET */
/* LINUX_CDROM_NEXT_WRITABLE */
/* LINUX_CDROM_LAST_WRITTEN */
+ default:
+ error = ENOIOCTL;
+ break;
}
- return (ENOIOCTL);
+ fdrop(fp, td);
+ return (error);
}
/*
@@ -1639,37 +1703,48 @@ linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
static int
linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
{
- struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd];
+ struct file *fp;
+ int error;
+ fp = ffind_hold(td, args->fd);
+ if (fp == NULL)
+ return (EBADF);
switch (args->cmd & 0xffff) {
case LINUX_KIOCSOUND:
args->cmd = KIOCSOUND;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_KDMKTONE:
args->cmd = KDMKTONE;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_KDGETLED:
args->cmd = KDGETLED;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_KDSETLED:
args->cmd = KDSETLED;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_KDSETMODE:
args->cmd = KDSETMODE;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_KDGETMODE:
args->cmd = KDGETMODE;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_KDGKBMODE:
args->cmd = KDGKBMODE;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_KDSKBMODE: {
int kbdmode;
@@ -1684,18 +1759,22 @@ linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
kbdmode = K_RAW;
break;
default:
+ fdrop(fp, td);
return (EINVAL);
}
- return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, td));
+ error = (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, td));
+ break;
}
case LINUX_VT_OPENQRY:
args->cmd = VT_OPENQRY;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_VT_GETMODE:
args->cmd = VT_GETMODE;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_VT_SETMODE: {
struct vt_mode *mode;
@@ -1703,28 +1782,37 @@ linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
mode = (struct vt_mode *)args->arg;
if (!ISSIGVALID(mode->frsig) && ISSIGVALID(mode->acqsig))
mode->frsig = mode->acqsig;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
}
case LINUX_VT_GETSTATE:
args->cmd = VT_GETACTIVE;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_VT_RELDISP:
args->cmd = VT_RELDISP;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_VT_ACTIVATE:
args->cmd = VT_ACTIVATE;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
case LINUX_VT_WAITACTIVE:
args->cmd = VT_WAITACTIVE;
- return (ioctl(td, (struct ioctl_args *)args));
+ error = (ioctl(td, (struct ioctl_args *)args));
+ break;
+ default:
+ error = ENOIOCTL;
+ break;
}
- return (ENOIOCTL);
+ fdrop(fp, td);
+ return (error);
}
/*
@@ -2161,7 +2249,6 @@ linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args)
int
linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
{
- struct filedesc *fdp;
struct file *fp;
struct handler_element *he;
int error, cmd;
@@ -2172,12 +2259,13 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
(unsigned long)args->cmd);
#endif
- fdp = td->td_proc->p_fd;
- if ((unsigned)args->fd >= fdp->fd_nfiles)
+ fp = ffind_hold(td, args->fd);
+ if (fp == NULL)
return (EBADF);
- fp = fdp->fd_ofiles[args->fd];
- if (fp == NULL || (fp->f_flag & (FREAD|FWRITE)) == 0)
+ if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
+ fdrop(fp, td);
return (EBADF);
+ }
/* Iterate over the ioctl handlers */
cmd = args->cmd & 0xffff;
@@ -2185,9 +2273,11 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
if (cmd >= he->low && cmd <= he->high) {
error = (*he->func)(td, args);
if (error != ENOIOCTL)
+ fdrop(fp, td);
return (error);
}
}
+ fdrop(fp, td);
printf("linux: 'ioctl' fd=%d, cmd=0x%x ('%c',%d) not implemented\n",
args->fd, (int)(args->cmd & 0xffff),
OpenPOWER on IntegriCloud