]> rtime.felk.cvut.cz Git - lisovros/linux_canprio.git/blobdiff - kernel/power/user.c
PM / Hibernate: Fix memory corruption related to swap
[lisovros/linux_canprio.git] / kernel / power / user.c
index a8c96212bc1b4fdfb9f0c212066ff9bd9812690a..1b2ea31e6bd8c0eca7eaaf985bc84337a1e750d0 100644 (file)
@@ -151,6 +151,7 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf,
 {
        struct snapshot_data *data;
        ssize_t res;
+       loff_t pg_offp = *offp & ~PAGE_MASK;
 
        mutex_lock(&pm_mutex);
 
@@ -159,14 +160,19 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf,
                res = -ENODATA;
                goto Unlock;
        }
-       res = snapshot_read_next(&data->handle, count);
-       if (res > 0) {
-               if (copy_to_user(buf, data_of(data->handle), res))
-                       res = -EFAULT;
-               else
-                       *offp = data->handle.offset;
+       if (!pg_offp) { /* on page boundary? */
+               res = snapshot_read_next(&data->handle);
+               if (res <= 0)
+                       goto Unlock;
+       } else {
+               res = PAGE_SIZE - pg_offp;
        }
 
+       res = simple_read_from_buffer(buf, count, &pg_offp,
+                       data_of(data->handle), res);
+       if (res > 0)
+               *offp += res;
+
  Unlock:
        mutex_unlock(&pm_mutex);
 
@@ -178,18 +184,25 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
 {
        struct snapshot_data *data;
        ssize_t res;
+       loff_t pg_offp = *offp & ~PAGE_MASK;
 
        mutex_lock(&pm_mutex);
 
        data = filp->private_data;
-       res = snapshot_write_next(&data->handle, count);
-       if (res > 0) {
-               if (copy_from_user(data_of(data->handle), buf, res))
-                       res = -EFAULT;
-               else
-                       *offp = data->handle.offset;
+
+       if (!pg_offp) {
+               res = snapshot_write_next(&data->handle);
+               if (res <= 0)
+                       goto unlock;
+       } else {
+               res = PAGE_SIZE - pg_offp;
        }
 
+       res = simple_write_to_buffer(data_of(data->handle), res, &pg_offp,
+                       buf, count);
+       if (res > 0)
+               *offp += res;
+unlock:
        mutex_unlock(&pm_mutex);
 
        return res;
@@ -250,6 +263,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
        case SNAPSHOT_UNFREEZE:
                if (!data->frozen || data->ready)
                        break;
+               pm_restore_gfp_mask();
                thaw_processes();
                usermodehelper_enable();
                data->frozen = 0;
@@ -262,6 +276,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
                        error = -EPERM;
                        break;
                }
+               pm_restore_gfp_mask();
                error = hibernation_snapshot(data->platform_support);
                if (!error)
                        error = put_user(in_suspend, (int __user *)arg);