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

Commit 5ad31a57 authored by David Brownell's avatar David Brownell Committed by Linus Torvalds
Browse files

rtc: remove BKL for ioctl()



Remove implicit use of BKL in ioctl() from the RTC framework.

Instead, the rtc->ops_lock is used.  That's the same lock that already
protects the RTC operations when they're issued through the exported
rtc_*() calls in drivers/rtc/interface.c ...  making this a bugfix, not
just a cleanup, since both ioctl calls and set_alarm() need to update IRQ
enable flags and that implies a common lock (which RTC drivers as a rule
do not provide on their own).

A new comment at the declaration of "struct rtc_class_ops" summarizes
current locking rules.  It's not clear to me that the exceptions listed
there should exist ...  if not, those are pre-existing problems which can
be fixed in a patch that doesn't relate to BKL removal.

Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Jonathan Corbet <corbet@lwn.net>
Acked-by: default avatarAlessandro Zummo <a.zummo@towertech.it>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 53f1b143
Loading
Loading
Loading
Loading
+38 −20
Original line number Diff line number Diff line
@@ -209,7 +209,7 @@ static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
	return (data != 0) ? (POLLIN | POLLRDNORM) : 0;
}

static int rtc_dev_ioctl(struct inode *inode, struct file *file,
static long rtc_dev_ioctl(struct file *file,
		unsigned int cmd, unsigned long arg)
{
	int err = 0;
@@ -219,6 +219,10 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
	struct rtc_wkalrm alarm;
	void __user *uarg = (void __user *) arg;

	err = mutex_lock_interruptible(&rtc->ops_lock);
	if (err)
		return -EBUSY;

	/* check that the calling task has appropriate permissions
	 * for certain ioctls. doing this check here is useful
	 * to avoid duplicate code in each driver.
@@ -227,27 +231,32 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
	case RTC_EPOCH_SET:
	case RTC_SET_TIME:
		if (!capable(CAP_SYS_TIME))
			return -EACCES;
			err = -EACCES;
		break;

	case RTC_IRQP_SET:
		if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
			return -EACCES;
			err = -EACCES;
		break;

	case RTC_PIE_ON:
		if (rtc->irq_freq > rtc->max_user_freq &&
				!capable(CAP_SYS_RESOURCE))
			return -EACCES;
			err = -EACCES;
		break;
	}

	if (err)
		goto done;

	/* try the driver's ioctl interface */
	if (ops->ioctl) {
		err = ops->ioctl(rtc->dev.parent, cmd, arg);
		if (err != -ENOIOCTLCMD)
		if (err != -ENOIOCTLCMD) {
			mutex_unlock(&rtc->ops_lock);
			return err;
		}
	}

	/* if the driver does not provide the ioctl interface
	 * or if that particular ioctl was not implemented
@@ -265,15 +274,19 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,

	switch (cmd) {
	case RTC_ALM_READ:
		mutex_unlock(&rtc->ops_lock);

		err = rtc_read_alarm(rtc, &alarm);
		if (err < 0)
			return err;

		if (copy_to_user(uarg, &alarm.time, sizeof(tm)))
			return -EFAULT;
		break;
			err = -EFAULT;
		return err;

	case RTC_ALM_SET:
		mutex_unlock(&rtc->ops_lock);

		if (copy_from_user(&alarm.time, uarg, sizeof(tm)))
			return -EFAULT;

@@ -321,24 +334,26 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
			}
		}

		err = rtc_set_alarm(rtc, &alarm);
		break;
		return rtc_set_alarm(rtc, &alarm);

	case RTC_RD_TIME:
		mutex_unlock(&rtc->ops_lock);

		err = rtc_read_time(rtc, &tm);
		if (err < 0)
			return err;

		if (copy_to_user(uarg, &tm, sizeof(tm)))
			return -EFAULT;
		break;
			err = -EFAULT;
		return err;

	case RTC_SET_TIME:
		mutex_unlock(&rtc->ops_lock);

		if (copy_from_user(&tm, uarg, sizeof(tm)))
			return -EFAULT;

		err = rtc_set_time(rtc, &tm);
		break;
		return rtc_set_time(rtc, &tm);

	case RTC_PIE_ON:
		err = rtc_irq_set_state(rtc, NULL, 1);
@@ -376,34 +391,37 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
		break;
#endif
	case RTC_WKALM_SET:
		mutex_unlock(&rtc->ops_lock);
		if (copy_from_user(&alarm, uarg, sizeof(alarm)))
			return -EFAULT;

		err = rtc_set_alarm(rtc, &alarm);
		break;
		return rtc_set_alarm(rtc, &alarm);

	case RTC_WKALM_RD:
		mutex_unlock(&rtc->ops_lock);
		err = rtc_read_alarm(rtc, &alarm);
		if (err < 0)
			return err;

		if (copy_to_user(uarg, &alarm, sizeof(alarm)))
			return -EFAULT;
		break;
			err = -EFAULT;
		return err;

#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
	case RTC_UIE_OFF:
		clear_uie(rtc);
		return 0;
		break;

	case RTC_UIE_ON:
		return set_uie(rtc);
		err = set_uie(rtc);
#endif
	default:
		err = -ENOTTY;
		break;
	}

done:
	mutex_unlock(&rtc->ops_lock);
	return err;
}

@@ -432,7 +450,7 @@ static const struct file_operations rtc_dev_fops = {
	.llseek		= no_llseek,
	.read		= rtc_dev_read,
	.poll		= rtc_dev_poll,
	.ioctl		= rtc_dev_ioctl,
	.unlocked_ioctl	= rtc_dev_ioctl,
	.open		= rtc_dev_open,
	.release	= rtc_dev_release,
	.fasync		= rtc_dev_fasync,
+17 −0
Original line number Diff line number Diff line
@@ -115,6 +115,23 @@ extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);

extern struct class *rtc_class;

/*
 * For these RTC methods the device parameter is the physical device
 * on whatever bus holds the hardware (I2C, Platform, SPI, etc), which
 * was passed to rtc_device_register().  Its driver_data normally holds
 * device state, including the rtc_device pointer for the RTC.
 *
 * Most of these methods are called with rtc_device.ops_lock held,
 * through the rtc_*(struct rtc_device *, ...) calls.
 *
 * The (current) exceptions are mostly filesystem hooks:
 *   - the proc() hook for procfs
 *   - non-ioctl() chardev hooks:  open(), release(), read_callback()
 *   - periodic irq calls:  irq_set_state(), irq_set_freq()
 *
 * REVISIT those periodic irq calls *do* have ops_lock when they're
 * issued through ioctl() ...
 */
struct rtc_class_ops {
	int (*open)(struct device *);
	void (*release)(struct device *);