char/nvram: Allow the set_checksum and initialize ioctls to be omitted
authorFinn Thain <fthain@telegraphics.com.au>
Tue, 15 Jan 2019 04:18:56 +0000 (15:18 +1100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 22 Jan 2019 09:21:43 +0000 (10:21 +0100)
The drivers/char/nvram.c module has previously supported only RTC "CMOS"
NVRAM, for which it provides appropriate checksum ioctls. Make these
ioctls optional so the module can be re-used with other kinds of NVRAM.

The ops struct methods that implement the ioctls now return error
codes so that a multi-platform kernel binary can do the right thing when
running on hardware without a suitable NVRAM.

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/char/nvram.c
include/linux/nvram.h

index 2df391f7898649e0a3e8ae759d0a4c222b1a9dfd..f88ef41d0598bd870959a3cbcbf626a48444d9ad 100644 (file)
@@ -136,16 +136,25 @@ static void __nvram_set_checksum(void)
        __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
 }
 
-#if 0
-void nvram_set_checksum(void)
+static long pc_nvram_set_checksum(void)
 {
-       unsigned long flags;
+       spin_lock_irq(&rtc_lock);
+       __nvram_set_checksum();
+       spin_unlock_irq(&rtc_lock);
+       return 0;
+}
 
-       spin_lock_irqsave(&rtc_lock, flags);
+static long pc_nvram_initialize(void)
+{
+       ssize_t i;
+
+       spin_lock_irq(&rtc_lock);
+       for (i = 0; i < NVRAM_BYTES; ++i)
+               __nvram_write_byte(0, i);
        __nvram_set_checksum();
-       spin_unlock_irqrestore(&rtc_lock, flags);
+       spin_unlock_irq(&rtc_lock);
+       return 0;
 }
-#endif  /*  0  */
 
 static ssize_t pc_nvram_get_size(void)
 {
@@ -156,6 +165,8 @@ const struct nvram_ops arch_nvram_ops = {
        .read_byte      = pc_nvram_read_byte,
        .write_byte     = pc_nvram_write_byte,
        .get_size       = pc_nvram_get_size,
+       .set_checksum   = pc_nvram_set_checksum,
+       .initialize     = pc_nvram_initialize,
 };
 EXPORT_SYMBOL(arch_nvram_ops);
 #endif /* CONFIG_X86 */
@@ -241,51 +252,50 @@ checksum_err:
 static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
                             unsigned long arg)
 {
-       int i;
+       long ret = -ENOTTY;
 
        switch (cmd) {
-
        case NVRAM_INIT:
                /* initialize NVRAM contents and checksum */
                if (!capable(CAP_SYS_ADMIN))
                        return -EACCES;
 
-               mutex_lock(&nvram_mutex);
-               spin_lock_irq(&rtc_lock);
-
-               for (i = 0; i < NVRAM_BYTES; ++i)
-                       __nvram_write_byte(0, i);
-               __nvram_set_checksum();
-
-               spin_unlock_irq(&rtc_lock);
-               mutex_unlock(&nvram_mutex);
-               return 0;
-
+               if (arch_nvram_ops.initialize != NULL) {
+                       mutex_lock(&nvram_mutex);
+                       ret = arch_nvram_ops.initialize();
+                       mutex_unlock(&nvram_mutex);
+               }
+               break;
        case NVRAM_SETCKS:
                /* just set checksum, contents unchanged (maybe useful after
                 * checksum garbaged somehow...) */
                if (!capable(CAP_SYS_ADMIN))
                        return -EACCES;
 
-               mutex_lock(&nvram_mutex);
-               spin_lock_irq(&rtc_lock);
-               __nvram_set_checksum();
-               spin_unlock_irq(&rtc_lock);
-               mutex_unlock(&nvram_mutex);
-               return 0;
-
-       default:
-               return -ENOTTY;
+               if (arch_nvram_ops.set_checksum != NULL) {
+                       mutex_lock(&nvram_mutex);
+                       ret = arch_nvram_ops.set_checksum();
+                       mutex_unlock(&nvram_mutex);
+               }
+               break;
        }
+       return ret;
 }
 
 static int nvram_misc_open(struct inode *inode, struct file *file)
 {
        spin_lock(&nvram_state_lock);
 
+       /* Prevent multiple readers/writers if desired. */
        if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
-           (nvram_open_mode & NVRAM_EXCL) ||
-           ((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) {
+           (nvram_open_mode & NVRAM_EXCL)) {
+               spin_unlock(&nvram_state_lock);
+               return -EBUSY;
+       }
+
+       /* Prevent multiple writers if the set_checksum ioctl is implemented. */
+       if ((arch_nvram_ops.set_checksum != NULL) &&
+           (file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE)) {
                spin_unlock(&nvram_state_lock);
                return -EBUSY;
        }
index bb4ea8cc6ea624e56c83f555857156eb37083430..31c763087746fd1f3abdbe950eb17e3dccd26e7c 100644 (file)
@@ -31,6 +31,8 @@ struct nvram_ops {
        void            (*write_byte)(unsigned char, int);
        ssize_t         (*read)(char *, size_t, loff_t *);
        ssize_t         (*write)(char *, size_t, loff_t *);
+       long            (*initialize)(void);
+       long            (*set_checksum)(void);
 };
 
 extern const struct nvram_ops arch_nvram_ops;