Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3147c531 authored by Marcin Slusarz's avatar Marcin Slusarz Committed by Jens Axboe
Browse files

cdrom: split mmc_ioctl to lower stack usage



Checkstack output:

Before:
mmc_ioctl:                  584

After:
mmc_ioctl_dvd_read_struct:  280
mmc_ioctl_cdrom_subchannel: 152
mmc_ioctl_cdrom_read_data:  120
mmc_ioctl_cdrom_volume:     104
mmc_ioctl_cdrom_read_audio: 104
(mmc_ioctl is inlined into cdrom_ioctl - 104 bytes)

Signed-off-by: default avatarMarcin Slusarz <marcin.slusarz@gmail.com>
Cc: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 2b91bafc
Loading
Loading
Loading
Loading
+329 −241
Original line number Diff line number Diff line
@@ -2787,25 +2787,15 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
	return cdo->generic_packet(cdi, &cgc);
}

static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
		     unsigned long arg)
static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi,
					void __user *arg,
					struct packet_command *cgc,
					int cmd)
{
	struct cdrom_device_ops *cdo = cdi->ops;
	struct packet_command cgc;
	struct request_sense sense;
	unsigned char buffer[32];
	int ret = 0;

	memset(&cgc, 0, sizeof(cgc));

	/* build a unified command and queue it through
	   cdo->generic_packet() */
	switch (cmd) {
	case CDROMREADRAW:
	case CDROMREADMODE1:
	case CDROMREADMODE2: {
	struct cdrom_msf msf;
	int blocksize = 0, format = 0, lba;
	int ret;

	switch (cmd) {
	case CDROMREADRAW:
@@ -2824,33 +2814,40 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
	/* FIXME: we need upper bound checking, too!! */
	if (lba < 0)
		return -EINVAL;
		cgc.buffer = kmalloc(blocksize, GFP_KERNEL);
		if (cgc.buffer == NULL)

	cgc->buffer = kmalloc(blocksize, GFP_KERNEL);
	if (cgc->buffer == NULL)
		return -ENOMEM;

	memset(&sense, 0, sizeof(sense));
		cgc.sense = &sense;
		cgc.data_direction = CGC_DATA_READ;
		ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize);
		if (ret && sense.sense_key==0x05 && sense.asc==0x20 && sense.ascq==0x00) {
	cgc->sense = &sense;
	cgc->data_direction = CGC_DATA_READ;
	ret = cdrom_read_block(cdi, cgc, lba, 1, format, blocksize);
	if (ret && sense.sense_key == 0x05 &&
		   sense.asc == 0x20 &&
		   sense.ascq == 0x00) {
		/*
		 * SCSI-II devices are not required to support
		 * READ_CD, so let's try switching block size
		 */
		/* FIXME: switch back again... */
			if ((ret = cdrom_switch_blocksize(cdi, blocksize))) {
				kfree(cgc.buffer);
				return ret;
			}
			cgc.sense = NULL;
			ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1);
		ret = cdrom_switch_blocksize(cdi, blocksize);
		if (ret)
			goto out;
		cgc->sense = NULL;
		ret = cdrom_read_cd(cdi, cgc, lba, blocksize, 1);
		ret |= cdrom_switch_blocksize(cdi, blocksize);
	}
		if (!ret && copy_to_user((char __user *)arg, cgc.buffer, blocksize))
	if (!ret && copy_to_user(arg, cgc->buffer, blocksize))
		ret = -EFAULT;
		kfree(cgc.buffer);
out:
	kfree(cgc->buffer);
	return ret;
}
	case CDROMREADAUDIO: {

static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi,
					void __user *arg)
{
	struct cdrom_read_audio ra;
	int lba;

@@ -2871,7 +2868,11 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,

	return cdrom_read_cdda(cdi, ra.buf, lba, ra.nframes);
}
	case CDROMSUBCHNL: {

static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi,
					void __user *arg)
{
	int ret;
	struct cdrom_subchnl q;
	u_char requested, back;
	IOCTL_IN(arg, struct cdrom_subchnl, q);
@@ -2880,7 +2881,8 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
	      (requested == CDROM_LBA)))
		return -EINVAL;
	q.cdsc_format = CDROM_MSF;
		if ((ret = cdrom_read_subchannel(cdi, &q, 0)))
	ret = cdrom_read_subchannel(cdi, &q, 0);
	if (ret)
		return ret;
	back = q.cdsc_format; /* local copy */
	sanitize_format(&q.cdsc_absaddr, &back, requested);
@@ -2889,47 +2891,64 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
	/* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
	return 0;
}
	case CDROMPLAYMSF: {

static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi,
					void __user *arg,
					struct packet_command *cgc)
{
	struct cdrom_device_ops *cdo = cdi->ops;
	struct cdrom_msf msf;
	cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
	IOCTL_IN(arg, struct cdrom_msf, msf);
		cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
		cgc.cmd[3] = msf.cdmsf_min0;
		cgc.cmd[4] = msf.cdmsf_sec0;
		cgc.cmd[5] = msf.cdmsf_frame0;
		cgc.cmd[6] = msf.cdmsf_min1;
		cgc.cmd[7] = msf.cdmsf_sec1;
		cgc.cmd[8] = msf.cdmsf_frame1;
		cgc.data_direction = CGC_DATA_NONE;
		return cdo->generic_packet(cdi, &cgc);
	cgc->cmd[0] = GPCMD_PLAY_AUDIO_MSF;
	cgc->cmd[3] = msf.cdmsf_min0;
	cgc->cmd[4] = msf.cdmsf_sec0;
	cgc->cmd[5] = msf.cdmsf_frame0;
	cgc->cmd[6] = msf.cdmsf_min1;
	cgc->cmd[7] = msf.cdmsf_sec1;
	cgc->cmd[8] = msf.cdmsf_frame1;
	cgc->data_direction = CGC_DATA_NONE;
	return cdo->generic_packet(cdi, cgc);
}
	case CDROMPLAYBLK: {

static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi,
					void __user *arg,
					struct packet_command *cgc)
{
	struct cdrom_device_ops *cdo = cdi->ops;
	struct cdrom_blk blk;
	cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n");
	IOCTL_IN(arg, struct cdrom_blk, blk);
		cgc.cmd[0] = GPCMD_PLAY_AUDIO_10;
		cgc.cmd[2] = (blk.from >> 24) & 0xff;
		cgc.cmd[3] = (blk.from >> 16) & 0xff;
		cgc.cmd[4] = (blk.from >>  8) & 0xff;
		cgc.cmd[5] = blk.from & 0xff;
		cgc.cmd[7] = (blk.len >> 8) & 0xff;
		cgc.cmd[8] = blk.len & 0xff;
		cgc.data_direction = CGC_DATA_NONE;
		return cdo->generic_packet(cdi, &cgc);
	cgc->cmd[0] = GPCMD_PLAY_AUDIO_10;
	cgc->cmd[2] = (blk.from >> 24) & 0xff;
	cgc->cmd[3] = (blk.from >> 16) & 0xff;
	cgc->cmd[4] = (blk.from >>  8) & 0xff;
	cgc->cmd[5] = blk.from & 0xff;
	cgc->cmd[7] = (blk.len >> 8) & 0xff;
	cgc->cmd[8] = blk.len & 0xff;
	cgc->data_direction = CGC_DATA_NONE;
	return cdo->generic_packet(cdi, cgc);
}
	case CDROMVOLCTRL:
	case CDROMVOLREAD: {

static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
					void __user *arg,
					struct packet_command *cgc,
					unsigned int cmd)
{
	struct cdrom_volctrl volctrl;
	unsigned char buffer[32];
	char mask[sizeof(buffer)];
	unsigned short offset;
	int ret;

	cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n");

	IOCTL_IN(arg, struct cdrom_volctrl, volctrl);

		cgc.buffer = buffer;
		cgc.buflen = 24;
		if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_AUDIO_CTL_PAGE, 0)))
	cgc->buffer = buffer;
	cgc->buflen = 24;
	ret = cdrom_mode_sense(cdi, cgc, GPMODE_AUDIO_CTL_PAGE, 0);
	if (ret)
		return ret;
		
	/* originally the code depended on buffer[1] to determine
@@ -2941,9 +2960,9 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
	if (offset + 16 > sizeof(buffer))
		return -E2BIG;

		if (offset + 16 > cgc.buflen) {
			cgc.buflen = offset+16;
			ret = cdrom_mode_sense(cdi, &cgc,
	if (offset + 16 > cgc->buflen) {
		cgc->buflen = offset + 16;
		ret = cdrom_mode_sense(cdi, cgc,
					GPMODE_AUDIO_CTL_PAGE, 0);
		if (ret)
			return ret;
@@ -2966,9 +2985,9 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
	}
		
	/* get the volume mask */
		cgc.buffer = mask;
		if ((ret = cdrom_mode_sense(cdi, &cgc, 
				GPMODE_AUDIO_CTL_PAGE, 1)))
	cgc->buffer = mask;
	ret = cdrom_mode_sense(cdi, cgc, GPMODE_AUDIO_CTL_PAGE, 1);
	if (ret)
		return ret;

	buffer[offset + 9]  = volctrl.channel0 & mask[offset + 9];
@@ -2977,81 +2996,150 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
	buffer[offset + 15] = volctrl.channel3 & mask[offset + 15];

	/* set volume */
		cgc.buffer = buffer + offset - 8;
		memset(cgc.buffer, 0, 8);
		return cdrom_mode_select(cdi, &cgc);
	cgc->buffer = buffer + offset - 8;
	memset(cgc->buffer, 0, 8);
	return cdrom_mode_select(cdi, cgc);
}

	case CDROMSTART:
	case CDROMSTOP: {
static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi,
					struct packet_command *cgc,
					int cmd)
{
	struct cdrom_device_ops *cdo = cdi->ops;
	cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n");
		cgc.cmd[0] = GPCMD_START_STOP_UNIT;
		cgc.cmd[1] = 1;
		cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
		cgc.data_direction = CGC_DATA_NONE;
		return cdo->generic_packet(cdi, &cgc);
	cgc->cmd[0] = GPCMD_START_STOP_UNIT;
	cgc->cmd[1] = 1;
	cgc->cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
	cgc->data_direction = CGC_DATA_NONE;
	return cdo->generic_packet(cdi, cgc);
}

	case CDROMPAUSE:
	case CDROMRESUME: {
static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi,
					struct packet_command *cgc,
					int cmd)
{
	struct cdrom_device_ops *cdo = cdi->ops;
	cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n");
		cgc.cmd[0] = GPCMD_PAUSE_RESUME;
		cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
		cgc.data_direction = CGC_DATA_NONE;
		return cdo->generic_packet(cdi, &cgc);
	cgc->cmd[0] = GPCMD_PAUSE_RESUME;
	cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
	cgc->data_direction = CGC_DATA_NONE;
	return cdo->generic_packet(cdi, cgc);
}

	case DVD_READ_STRUCT: {
static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi,
						void __user *arg)
{
	int ret;
	dvd_struct *s;
	int size = sizeof(dvd_struct);

	if (!CDROM_CAN(CDC_DVD))
		return -ENOSYS;
		if ((s = kmalloc(size, GFP_KERNEL)) == NULL)

	s = kmalloc(size, GFP_KERNEL);
	if (!s)
		return -ENOMEM;

	cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");
		if (copy_from_user(s, (dvd_struct __user *)arg, size)) {
	if (copy_from_user(s, arg, size)) {
		kfree(s);
		return -EFAULT;
	}
		if ((ret = dvd_read_struct(cdi, s))) {
			kfree(s);
			return ret;
		}
		if (copy_to_user((dvd_struct __user *)arg, s, size))

	ret = dvd_read_struct(cdi, s);
	if (ret)
		goto out;

	if (copy_to_user(arg, s, size))
		ret = -EFAULT;
out:
	kfree(s);
	return ret;
}

	case DVD_AUTH: {
static noinline int mmc_ioctl_dvd_auth(struct cdrom_device_info *cdi,
					void __user *arg)
{
	int ret;
	dvd_authinfo ai;
	if (!CDROM_CAN(CDC_DVD))
		return -ENOSYS;
	cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n");
	IOCTL_IN(arg, dvd_authinfo, ai);
		if ((ret = dvd_do_auth (cdi, &ai)))
	ret = dvd_do_auth(cdi, &ai);
	if (ret)
		return ret;
	IOCTL_OUT(arg, dvd_authinfo, ai);
	return 0;
}

	case CDROM_NEXT_WRITABLE: {
static noinline int mmc_ioctl_cdrom_next_writable(struct cdrom_device_info *cdi,
						void __user *arg)
{
	int ret;
	long next = 0;
	cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n");
		if ((ret = cdrom_get_next_writable(cdi, &next)))
	ret = cdrom_get_next_writable(cdi, &next);
	if (ret)
		return ret;
	IOCTL_OUT(arg, long, next);
	return 0;
}
	case CDROM_LAST_WRITTEN: {

static noinline int mmc_ioctl_cdrom_last_written(struct cdrom_device_info *cdi,
						void __user *arg)
{
	int ret;
	long last = 0;
	cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n");
		if ((ret = cdrom_get_last_written(cdi, &last)))
	ret = cdrom_get_last_written(cdi, &last);
	if (ret)
		return ret;
	IOCTL_OUT(arg, long, last);
	return 0;
}
	} /* switch */

static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
		     unsigned long arg)
{
	struct packet_command cgc;
	void __user *userptr = (void __user *)arg;

	memset(&cgc, 0, sizeof(cgc));

	/* build a unified command and queue it through
	   cdo->generic_packet() */
	switch (cmd) {
	case CDROMREADRAW:
	case CDROMREADMODE1:
	case CDROMREADMODE2:
		return mmc_ioctl_cdrom_read_data(cdi, userptr, &cgc, cmd);
	case CDROMREADAUDIO:
		return mmc_ioctl_cdrom_read_audio(cdi, userptr);
	case CDROMSUBCHNL:
		return mmc_ioctl_cdrom_subchannel(cdi, userptr);
	case CDROMPLAYMSF:
		return mmc_ioctl_cdrom_play_msf(cdi, userptr, &cgc);
	case CDROMPLAYBLK:
		return mmc_ioctl_cdrom_play_blk(cdi, userptr, &cgc);
	case CDROMVOLCTRL:
	case CDROMVOLREAD:
		return mmc_ioctl_cdrom_volume(cdi, userptr, &cgc, cmd);
	case CDROMSTART:
	case CDROMSTOP:
		return mmc_ioctl_cdrom_start_stop(cdi, &cgc, cmd);
	case CDROMPAUSE:
	case CDROMRESUME:
		return mmc_ioctl_cdrom_pause_resume(cdi, &cgc, cmd);
	case DVD_READ_STRUCT:
		return mmc_ioctl_dvd_read_struct(cdi, userptr);
	case DVD_AUTH:
		return mmc_ioctl_dvd_auth(cdi, userptr);
	case CDROM_NEXT_WRITABLE:
		return mmc_ioctl_cdrom_next_writable(cdi, userptr);
	case CDROM_LAST_WRITTEN:
		return mmc_ioctl_cdrom_last_written(cdi, userptr);
	}

	return -ENOTTY;
}