LCOV - code coverage report
Current view: top level - kernel/power - user.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 2 236 0.8 %
Date: 2022-04-01 14:35:51 Functions: 1 7 14.3 %
Branches: 0 123 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * linux/kernel/power/user.c
       4                 :            :  *
       5                 :            :  * This file provides the user space interface for software suspend/resume.
       6                 :            :  *
       7                 :            :  * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/suspend.h>
      11                 :            : #include <linux/reboot.h>
      12                 :            : #include <linux/string.h>
      13                 :            : #include <linux/device.h>
      14                 :            : #include <linux/miscdevice.h>
      15                 :            : #include <linux/mm.h>
      16                 :            : #include <linux/swap.h>
      17                 :            : #include <linux/swapops.h>
      18                 :            : #include <linux/pm.h>
      19                 :            : #include <linux/fs.h>
      20                 :            : #include <linux/compat.h>
      21                 :            : #include <linux/console.h>
      22                 :            : #include <linux/cpu.h>
      23                 :            : #include <linux/freezer.h>
      24                 :            : 
      25                 :            : #include <linux/uaccess.h>
      26                 :            : 
      27                 :            : #include "power.h"
      28                 :            : 
      29                 :            : 
      30                 :            : #define SNAPSHOT_MINOR  231
      31                 :            : 
      32                 :            : static struct snapshot_data {
      33                 :            :         struct snapshot_handle handle;
      34                 :            :         int swap;
      35                 :            :         int mode;
      36                 :            :         bool frozen;
      37                 :            :         bool ready;
      38                 :            :         bool platform_support;
      39                 :            :         bool free_bitmaps;
      40                 :            : } snapshot_state;
      41                 :            : 
      42                 :            : atomic_t snapshot_device_available = ATOMIC_INIT(1);
      43                 :            : 
      44                 :          0 : static int snapshot_open(struct inode *inode, struct file *filp)
      45                 :            : {
      46                 :          0 :         struct snapshot_data *data;
      47                 :          0 :         int error, nr_calls = 0;
      48                 :            : 
      49         [ #  # ]:          0 :         if (!hibernation_available())
      50                 :            :                 return -EPERM;
      51                 :            : 
      52                 :          0 :         lock_system_sleep();
      53                 :            : 
      54         [ #  # ]:          0 :         if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
      55                 :          0 :                 error = -EBUSY;
      56                 :          0 :                 goto Unlock;
      57                 :            :         }
      58                 :            : 
      59         [ #  # ]:          0 :         if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
      60                 :          0 :                 atomic_inc(&snapshot_device_available);
      61                 :          0 :                 error = -ENOSYS;
      62                 :          0 :                 goto Unlock;
      63                 :            :         }
      64                 :          0 :         nonseekable_open(inode, filp);
      65                 :          0 :         data = &snapshot_state;
      66                 :          0 :         filp->private_data = data;
      67                 :          0 :         memset(&data->handle, 0, sizeof(struct snapshot_handle));
      68         [ #  # ]:          0 :         if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
      69                 :            :                 /* Hibernating.  The image device should be accessible. */
      70                 :          0 :                 data->swap = swsusp_resume_device ?
      71         [ #  # ]:          0 :                         swap_type_of(swsusp_resume_device, 0, NULL) : -1;
      72                 :          0 :                 data->mode = O_RDONLY;
      73                 :          0 :                 data->free_bitmaps = false;
      74                 :          0 :                 error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
      75         [ #  # ]:          0 :                 if (error)
      76                 :          0 :                         __pm_notifier_call_chain(PM_POST_HIBERNATION, --nr_calls, NULL);
      77                 :            :         } else {
      78                 :            :                 /*
      79                 :            :                  * Resuming.  We may need to wait for the image device to
      80                 :            :                  * appear.
      81                 :            :                  */
      82                 :          0 :                 wait_for_device_probe();
      83                 :            : 
      84                 :          0 :                 data->swap = -1;
      85                 :          0 :                 data->mode = O_WRONLY;
      86                 :          0 :                 error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls);
      87         [ #  # ]:          0 :                 if (!error) {
      88                 :          0 :                         error = create_basic_memory_bitmaps();
      89                 :          0 :                         data->free_bitmaps = !error;
      90                 :            :                 } else
      91                 :          0 :                         nr_calls--;
      92                 :            : 
      93         [ #  # ]:          0 :                 if (error)
      94                 :          0 :                         __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
      95                 :            :         }
      96         [ #  # ]:          0 :         if (error)
      97                 :          0 :                 atomic_inc(&snapshot_device_available);
      98                 :            : 
      99                 :          0 :         data->frozen = false;
     100                 :          0 :         data->ready = false;
     101                 :          0 :         data->platform_support = false;
     102                 :            : 
     103                 :          0 :  Unlock:
     104                 :          0 :         unlock_system_sleep();
     105                 :            : 
     106                 :          0 :         return error;
     107                 :            : }
     108                 :            : 
     109                 :          0 : static int snapshot_release(struct inode *inode, struct file *filp)
     110                 :            : {
     111                 :          0 :         struct snapshot_data *data;
     112                 :            : 
     113                 :          0 :         lock_system_sleep();
     114                 :            : 
     115                 :          0 :         swsusp_free();
     116                 :          0 :         data = filp->private_data;
     117                 :          0 :         free_all_swap_pages(data->swap);
     118         [ #  # ]:          0 :         if (data->frozen) {
     119                 :          0 :                 pm_restore_gfp_mask();
     120                 :          0 :                 free_basic_memory_bitmaps();
     121                 :          0 :                 thaw_processes();
     122         [ #  # ]:          0 :         } else if (data->free_bitmaps) {
     123                 :          0 :                 free_basic_memory_bitmaps();
     124                 :            :         }
     125         [ #  # ]:          0 :         pm_notifier_call_chain(data->mode == O_RDONLY ?
     126                 :            :                         PM_POST_HIBERNATION : PM_POST_RESTORE);
     127                 :          0 :         atomic_inc(&snapshot_device_available);
     128                 :            : 
     129                 :          0 :         unlock_system_sleep();
     130                 :            : 
     131                 :          0 :         return 0;
     132                 :            : }
     133                 :            : 
     134                 :          0 : static ssize_t snapshot_read(struct file *filp, char __user *buf,
     135                 :            :                              size_t count, loff_t *offp)
     136                 :            : {
     137                 :          0 :         struct snapshot_data *data;
     138                 :          0 :         ssize_t res;
     139                 :          0 :         loff_t pg_offp = *offp & ~PAGE_MASK;
     140                 :            : 
     141                 :          0 :         lock_system_sleep();
     142                 :            : 
     143                 :          0 :         data = filp->private_data;
     144         [ #  # ]:          0 :         if (!data->ready) {
     145                 :          0 :                 res = -ENODATA;
     146                 :          0 :                 goto Unlock;
     147                 :            :         }
     148         [ #  # ]:          0 :         if (!pg_offp) { /* on page boundary? */
     149                 :          0 :                 res = snapshot_read_next(&data->handle);
     150         [ #  # ]:          0 :                 if (res <= 0)
     151                 :          0 :                         goto Unlock;
     152                 :            :         } else {
     153                 :          0 :                 res = PAGE_SIZE - pg_offp;
     154                 :            :         }
     155                 :            : 
     156                 :          0 :         res = simple_read_from_buffer(buf, count, &pg_offp,
     157                 :          0 :                         data_of(data->handle), res);
     158         [ #  # ]:          0 :         if (res > 0)
     159                 :          0 :                 *offp += res;
     160                 :            : 
     161                 :          0 :  Unlock:
     162                 :          0 :         unlock_system_sleep();
     163                 :            : 
     164                 :          0 :         return res;
     165                 :            : }
     166                 :            : 
     167                 :          0 : static ssize_t snapshot_write(struct file *filp, const char __user *buf,
     168                 :            :                               size_t count, loff_t *offp)
     169                 :            : {
     170                 :          0 :         struct snapshot_data *data;
     171                 :          0 :         ssize_t res;
     172                 :          0 :         loff_t pg_offp = *offp & ~PAGE_MASK;
     173                 :            : 
     174                 :          0 :         lock_system_sleep();
     175                 :            : 
     176                 :          0 :         data = filp->private_data;
     177                 :            : 
     178         [ #  # ]:          0 :         if (!pg_offp) {
     179                 :          0 :                 res = snapshot_write_next(&data->handle);
     180         [ #  # ]:          0 :                 if (res <= 0)
     181                 :          0 :                         goto unlock;
     182                 :            :         } else {
     183                 :          0 :                 res = PAGE_SIZE - pg_offp;
     184                 :            :         }
     185                 :            : 
     186         [ #  # ]:          0 :         if (!data_of(data->handle)) {
     187                 :          0 :                 res = -EINVAL;
     188                 :          0 :                 goto unlock;
     189                 :            :         }
     190                 :            : 
     191                 :          0 :         res = simple_write_to_buffer(data_of(data->handle), res, &pg_offp,
     192                 :            :                         buf, count);
     193         [ #  # ]:          0 :         if (res > 0)
     194                 :          0 :                 *offp += res;
     195                 :          0 : unlock:
     196                 :          0 :         unlock_system_sleep();
     197                 :            : 
     198                 :          0 :         return res;
     199                 :            : }
     200                 :            : 
     201                 :          0 : static long snapshot_ioctl(struct file *filp, unsigned int cmd,
     202                 :            :                                                         unsigned long arg)
     203                 :            : {
     204                 :          0 :         int error = 0;
     205                 :          0 :         struct snapshot_data *data;
     206                 :          0 :         loff_t size;
     207                 :          0 :         sector_t offset;
     208                 :            : 
     209         [ #  # ]:          0 :         if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
     210                 :            :                 return -ENOTTY;
     211         [ #  # ]:          0 :         if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
     212                 :            :                 return -ENOTTY;
     213         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     214                 :            :                 return -EPERM;
     215                 :            : 
     216         [ #  # ]:          0 :         if (!mutex_trylock(&system_transition_mutex))
     217                 :            :                 return -EBUSY;
     218                 :            : 
     219                 :          0 :         lock_device_hotplug();
     220                 :          0 :         data = filp->private_data;
     221                 :            : 
     222   [ #  #  #  #  :          0 :         switch (cmd) {
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     223                 :            : 
     224                 :          0 :         case SNAPSHOT_FREEZE:
     225         [ #  # ]:          0 :                 if (data->frozen)
     226                 :            :                         break;
     227                 :            : 
     228                 :          0 :                 ksys_sync_helper();
     229                 :            : 
     230                 :          0 :                 error = freeze_processes();
     231         [ #  # ]:          0 :                 if (error)
     232                 :            :                         break;
     233                 :            : 
     234                 :          0 :                 error = create_basic_memory_bitmaps();
     235         [ #  # ]:          0 :                 if (error)
     236                 :          0 :                         thaw_processes();
     237                 :            :                 else
     238                 :          0 :                         data->frozen = true;
     239                 :            : 
     240                 :            :                 break;
     241                 :            : 
     242                 :          0 :         case SNAPSHOT_UNFREEZE:
     243   [ #  #  #  # ]:          0 :                 if (!data->frozen || data->ready)
     244                 :            :                         break;
     245                 :          0 :                 pm_restore_gfp_mask();
     246                 :          0 :                 free_basic_memory_bitmaps();
     247                 :          0 :                 data->free_bitmaps = false;
     248                 :          0 :                 thaw_processes();
     249                 :          0 :                 data->frozen = false;
     250                 :          0 :                 break;
     251                 :            : 
     252                 :          0 :         case SNAPSHOT_CREATE_IMAGE:
     253   [ #  #  #  #  :          0 :                 if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
                   #  # ]
     254                 :            :                         error = -EPERM;
     255                 :            :                         break;
     256                 :            :                 }
     257                 :          0 :                 pm_restore_gfp_mask();
     258                 :          0 :                 error = hibernation_snapshot(data->platform_support);
     259         [ #  # ]:          0 :                 if (!error) {
     260                 :          0 :                         error = put_user(in_suspend, (int __user *)arg);
     261   [ #  #  #  # ]:          0 :                         data->ready = !freezer_test_done && !error;
     262                 :          0 :                         freezer_test_done = false;
     263                 :            :                 }
     264                 :            :                 break;
     265                 :            : 
     266                 :          0 :         case SNAPSHOT_ATOMIC_RESTORE:
     267                 :          0 :                 snapshot_write_finalize(&data->handle);
     268   [ #  #  #  #  :          0 :                 if (data->mode != O_WRONLY || !data->frozen ||
                   #  # ]
     269                 :          0 :                     !snapshot_image_loaded(&data->handle)) {
     270                 :            :                         error = -EPERM;
     271                 :            :                         break;
     272                 :            :                 }
     273                 :          0 :                 error = hibernation_restore(data->platform_support);
     274                 :          0 :                 break;
     275                 :            : 
     276                 :          0 :         case SNAPSHOT_FREE:
     277                 :          0 :                 swsusp_free();
     278                 :          0 :                 memset(&data->handle, 0, sizeof(struct snapshot_handle));
     279                 :          0 :                 data->ready = false;
     280                 :            :                 /*
     281                 :            :                  * It is necessary to thaw kernel threads here, because
     282                 :            :                  * SNAPSHOT_CREATE_IMAGE may be invoked directly after
     283                 :            :                  * SNAPSHOT_FREE.  In that case, if kernel threads were not
     284                 :            :                  * thawed, the preallocation of memory carried out by
     285                 :            :                  * hibernation_snapshot() might run into problems (i.e. it
     286                 :            :                  * might fail or even deadlock).
     287                 :            :                  */
     288                 :          0 :                 thaw_kernel_threads();
     289                 :          0 :                 break;
     290                 :            : 
     291                 :          0 :         case SNAPSHOT_PREF_IMAGE_SIZE:
     292                 :          0 :                 image_size = arg;
     293                 :          0 :                 break;
     294                 :            : 
     295                 :          0 :         case SNAPSHOT_GET_IMAGE_SIZE:
     296         [ #  # ]:          0 :                 if (!data->ready) {
     297                 :            :                         error = -ENODATA;
     298                 :            :                         break;
     299                 :            :                 }
     300                 :          0 :                 size = snapshot_get_image_size();
     301                 :          0 :                 size <<= PAGE_SHIFT;
     302                 :          0 :                 error = put_user(size, (loff_t __user *)arg);
     303                 :          0 :                 break;
     304                 :            : 
     305                 :          0 :         case SNAPSHOT_AVAIL_SWAP_SIZE:
     306                 :          0 :                 size = count_swap_pages(data->swap, 1);
     307                 :          0 :                 size <<= PAGE_SHIFT;
     308                 :          0 :                 error = put_user(size, (loff_t __user *)arg);
     309                 :          0 :                 break;
     310                 :            : 
     311                 :          0 :         case SNAPSHOT_ALLOC_SWAP_PAGE:
     312         [ #  # ]:          0 :                 if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
     313                 :            :                         error = -ENODEV;
     314                 :            :                         break;
     315                 :            :                 }
     316                 :          0 :                 offset = alloc_swapdev_block(data->swap);
     317         [ #  # ]:          0 :                 if (offset) {
     318                 :          0 :                         offset <<= PAGE_SHIFT;
     319                 :          0 :                         error = put_user(offset, (loff_t __user *)arg);
     320                 :            :                 } else {
     321                 :            :                         error = -ENOSPC;
     322                 :            :                 }
     323                 :            :                 break;
     324                 :            : 
     325                 :          0 :         case SNAPSHOT_FREE_SWAP_PAGES:
     326         [ #  # ]:          0 :                 if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
     327                 :            :                         error = -ENODEV;
     328                 :            :                         break;
     329                 :            :                 }
     330                 :          0 :                 free_all_swap_pages(data->swap);
     331                 :          0 :                 break;
     332                 :            : 
     333                 :          0 :         case SNAPSHOT_S2RAM:
     334         [ #  # ]:          0 :                 if (!data->frozen) {
     335                 :            :                         error = -EPERM;
     336                 :            :                         break;
     337                 :            :                 }
     338                 :            :                 /*
     339                 :            :                  * Tasks are frozen and the notifiers have been called with
     340                 :            :                  * PM_HIBERNATION_PREPARE
     341                 :            :                  */
     342                 :          0 :                 error = suspend_devices_and_enter(PM_SUSPEND_MEM);
     343                 :          0 :                 data->ready = false;
     344                 :          0 :                 break;
     345                 :            : 
     346                 :          0 :         case SNAPSHOT_PLATFORM_SUPPORT:
     347                 :          0 :                 data->platform_support = !!arg;
     348                 :          0 :                 break;
     349                 :            : 
     350                 :          0 :         case SNAPSHOT_POWER_OFF:
     351         [ #  # ]:          0 :                 if (data->platform_support)
     352                 :          0 :                         error = hibernation_platform_enter();
     353                 :            :                 break;
     354                 :            : 
     355                 :          0 :         case SNAPSHOT_SET_SWAP_AREA:
     356         [ #  # ]:          0 :                 if (swsusp_swap_in_use()) {
     357                 :            :                         error = -EPERM;
     358                 :            :                 } else {
     359                 :          0 :                         struct resume_swap_area swap_area;
     360                 :          0 :                         dev_t swdev;
     361                 :            : 
     362                 :          0 :                         error = copy_from_user(&swap_area, (void __user *)arg,
     363                 :            :                                         sizeof(struct resume_swap_area));
     364         [ #  # ]:          0 :                         if (error) {
     365                 :          0 :                                 error = -EFAULT;
     366                 :          0 :                                 break;
     367                 :            :                         }
     368                 :            : 
     369                 :            :                         /*
     370                 :            :                          * User space encodes device types as two-byte values,
     371                 :            :                          * so we need to recode them
     372                 :            :                          */
     373         [ #  # ]:          0 :                         swdev = new_decode_dev(swap_area.dev);
     374         [ #  # ]:          0 :                         if (swdev) {
     375                 :          0 :                                 offset = swap_area.offset;
     376                 :          0 :                                 data->swap = swap_type_of(swdev, offset, NULL);
     377         [ #  # ]:          0 :                                 if (data->swap < 0)
     378                 :          0 :                                         error = -ENODEV;
     379                 :            :                         } else {
     380                 :          0 :                                 data->swap = -1;
     381                 :          0 :                                 error = -EINVAL;
     382                 :            :                         }
     383                 :            :                 }
     384                 :            :                 break;
     385                 :            : 
     386                 :            :         default:
     387                 :            :                 error = -ENOTTY;
     388                 :            : 
     389                 :            :         }
     390                 :            : 
     391                 :          0 :         unlock_device_hotplug();
     392                 :          0 :         mutex_unlock(&system_transition_mutex);
     393                 :            : 
     394                 :          0 :         return error;
     395                 :            : }
     396                 :            : 
     397                 :            : #ifdef CONFIG_COMPAT
     398                 :            : 
     399                 :            : struct compat_resume_swap_area {
     400                 :            :         compat_loff_t offset;
     401                 :            :         u32 dev;
     402                 :            : } __packed;
     403                 :            : 
     404                 :            : static long
     405                 :          0 : snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
     406                 :            : {
     407                 :          0 :         BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t));
     408                 :            : 
     409   [ #  #  #  # ]:          0 :         switch (cmd) {
     410                 :          0 :         case SNAPSHOT_GET_IMAGE_SIZE:
     411                 :            :         case SNAPSHOT_AVAIL_SWAP_SIZE:
     412                 :            :         case SNAPSHOT_ALLOC_SWAP_PAGE: {
     413                 :          0 :                 compat_loff_t __user *uoffset = compat_ptr(arg);
     414                 :          0 :                 loff_t offset;
     415                 :          0 :                 mm_segment_t old_fs;
     416                 :          0 :                 int err;
     417                 :            : 
     418                 :          0 :                 old_fs = get_fs();
     419                 :          0 :                 set_fs(KERNEL_DS);
     420                 :          0 :                 err = snapshot_ioctl(file, cmd, (unsigned long) &offset);
     421                 :          0 :                 set_fs(old_fs);
     422   [ #  #  #  # ]:          0 :                 if (!err && put_user(offset, uoffset))
     423                 :          0 :                         err = -EFAULT;
     424                 :          0 :                 return err;
     425                 :            :         }
     426                 :            : 
     427                 :          0 :         case SNAPSHOT_CREATE_IMAGE:
     428                 :          0 :                 return snapshot_ioctl(file, cmd,
     429                 :            :                                       (unsigned long) compat_ptr(arg));
     430                 :            : 
     431                 :          0 :         case SNAPSHOT_SET_SWAP_AREA: {
     432                 :          0 :                 struct compat_resume_swap_area __user *u_swap_area =
     433                 :            :                         compat_ptr(arg);
     434                 :          0 :                 struct resume_swap_area swap_area;
     435                 :          0 :                 mm_segment_t old_fs;
     436                 :          0 :                 int err;
     437                 :            : 
     438                 :          0 :                 err = get_user(swap_area.offset, &u_swap_area->offset);
     439                 :          0 :                 err |= get_user(swap_area.dev, &u_swap_area->dev);
     440         [ #  # ]:          0 :                 if (err)
     441                 :            :                         return -EFAULT;
     442                 :          0 :                 old_fs = get_fs();
     443                 :          0 :                 set_fs(KERNEL_DS);
     444                 :          0 :                 err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA,
     445                 :            :                                      (unsigned long) &swap_area);
     446                 :          0 :                 set_fs(old_fs);
     447                 :          0 :                 return err;
     448                 :            :         }
     449                 :            : 
     450                 :          0 :         default:
     451                 :          0 :                 return snapshot_ioctl(file, cmd, arg);
     452                 :            :         }
     453                 :            : }
     454                 :            : 
     455                 :            : #endif /* CONFIG_COMPAT */
     456                 :            : 
     457                 :            : static const struct file_operations snapshot_fops = {
     458                 :            :         .open = snapshot_open,
     459                 :            :         .release = snapshot_release,
     460                 :            :         .read = snapshot_read,
     461                 :            :         .write = snapshot_write,
     462                 :            :         .llseek = no_llseek,
     463                 :            :         .unlocked_ioctl = snapshot_ioctl,
     464                 :            : #ifdef CONFIG_COMPAT
     465                 :            :         .compat_ioctl = snapshot_compat_ioctl,
     466                 :            : #endif
     467                 :            : };
     468                 :            : 
     469                 :            : static struct miscdevice snapshot_device = {
     470                 :            :         .minor = SNAPSHOT_MINOR,
     471                 :            :         .name = "snapshot",
     472                 :            :         .fops = &snapshot_fops,
     473                 :            : };
     474                 :            : 
     475                 :         21 : static int __init snapshot_device_init(void)
     476                 :            : {
     477                 :         21 :         return misc_register(&snapshot_device);
     478                 :            : };
     479                 :            : 
     480                 :            : device_initcall(snapshot_device_init);

Generated by: LCOV version 1.14