]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - drivers/char/mem.c
/dev/mem: make size_inside_page() logic straight
[mirror_ubuntu-jammy-kernel.git] / drivers / char / mem.c
index fba76fb55abfd302bbd87e6433ed858b8b5d2c4d..192af59afc139ed1db5df369e3edde865e491709 100644 (file)
 # include <linux/efi.h>
 #endif
 
+static inline unsigned long size_inside_page(unsigned long start,
+                                            unsigned long size)
+{
+       unsigned long sz;
+
+       sz = PAGE_SIZE - (start & (PAGE_SIZE - 1));
+
+       return min(sz, size);
+}
+
 /*
  * Architectures vary in how they handle caching for addresses
  * outside of main memory.
@@ -126,9 +136,7 @@ static ssize_t read_mem(struct file * file, char __user * buf,
 #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
        /* we don't have page 0 mapped on sparc and m68k.. */
        if (p < PAGE_SIZE) {
-               sz = PAGE_SIZE - p;
-               if (sz > count) 
-                       sz = count; 
+               sz = size_inside_page(p, count);
                if (sz > 0) {
                        if (clear_user(buf, sz))
                                return -EFAULT;
@@ -141,15 +149,9 @@ static ssize_t read_mem(struct file * file, char __user * buf,
 #endif
 
        while (count > 0) {
-               /*
-                * Handle first page in case it's not aligned
-                */
-               if (-p & (PAGE_SIZE - 1))
-                       sz = -p & (PAGE_SIZE - 1);
-               else
-                       sz = PAGE_SIZE;
+               unsigned long remaining;
 
-               sz = min_t(unsigned long, sz, count);
+               sz = size_inside_page(p, count);
 
                if (!range_is_allowed(p >> PAGE_SHIFT, count))
                        return -EPERM;
@@ -163,12 +165,10 @@ static ssize_t read_mem(struct file * file, char __user * buf,
                if (!ptr)
                        return -EFAULT;
 
-               if (copy_to_user(buf, ptr, sz)) {
-                       unxlate_dev_mem_ptr(p, ptr);
-                       return -EFAULT;
-               }
-
+               remaining = copy_to_user(buf, ptr, sz);
                unxlate_dev_mem_ptr(p, ptr);
+               if (remaining)
+                       return -EFAULT;
 
                buf += sz;
                p += sz;
@@ -196,9 +196,7 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
 #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
        /* we don't have page 0 mapped on sparc and m68k.. */
        if (p < PAGE_SIZE) {
-               unsigned long sz = PAGE_SIZE - p;
-               if (sz > count)
-                       sz = count;
+               sz = size_inside_page(p, count);
                /* Hmm. Do something? */
                buf += sz;
                p += sz;
@@ -208,15 +206,7 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
 #endif
 
        while (count > 0) {
-               /*
-                * Handle first page in case it's not aligned
-                */
-               if (-p & (PAGE_SIZE - 1))
-                       sz = -p & (PAGE_SIZE - 1);
-               else
-                       sz = PAGE_SIZE;
-
-               sz = min_t(unsigned long, sz, count);
+               sz = size_inside_page(p, count);
 
                if (!range_is_allowed(p >> PAGE_SHIFT, sz))
                        return -EPERM;
@@ -234,16 +224,14 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
                }
 
                copied = copy_from_user(ptr, buf, sz);
+               unxlate_dev_mem_ptr(p, ptr);
                if (copied) {
                        written += sz - copied;
-                       unxlate_dev_mem_ptr(p, ptr);
                        if (written)
                                break;
                        return -EFAULT;
                }
 
-               unxlate_dev_mem_ptr(p, ptr);
-
                buf += sz;
                p += sz;
                count -= sz;
@@ -417,27 +405,18 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
 #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
                /* we don't have page 0 mapped on sparc and m68k.. */
                if (p < PAGE_SIZE && low_count > 0) {
-                       size_t tmp = PAGE_SIZE - p;
-                       if (tmp > low_count) tmp = low_count;
-                       if (clear_user(buf, tmp))
+                       sz = size_inside_page(p, low_count);
+                       if (clear_user(buf, sz))
                                return -EFAULT;
-                       buf += tmp;
-                       p += tmp;
-                       read += tmp;
-                       low_count -= tmp;
-                       count -= tmp;
+                       buf += sz;
+                       p += sz;
+                       read += sz;
+                       low_count -= sz;
+                       count -= sz;
                }
 #endif
                while (low_count > 0) {
-                       /*
-                        * Handle first page in case it's not aligned
-                        */
-                       if (-p & (PAGE_SIZE - 1))
-                               sz = -p & (PAGE_SIZE - 1);
-                       else
-                               sz = PAGE_SIZE;
-
-                       sz = min_t(unsigned long, sz, low_count);
+                       sz = size_inside_page(p, low_count);
 
                        /*
                         * On ia64 if a page has been mapped somewhere as
@@ -461,10 +440,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
                if (!kbuf)
                        return -ENOMEM;
                while (count > 0) {
-                       int len = count;
+                       int len = size_inside_page(p, count);
 
-                       if (len > PAGE_SIZE)
-                               len = PAGE_SIZE;
                        len = vread(kbuf, (char *)p, len);
                        if (!len)
                                break;
@@ -495,9 +472,7 @@ do_write_kmem(void *p, unsigned long realp, const char __user * buf,
 #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
        /* we don't have page 0 mapped on sparc and m68k.. */
        if (realp < PAGE_SIZE) {
-               unsigned long sz = PAGE_SIZE - realp;
-               if (sz > count)
-                       sz = count;
+               sz = size_inside_page(realp, count);
                /* Hmm. Do something? */
                buf += sz;
                p += sz;
@@ -509,15 +484,8 @@ do_write_kmem(void *p, unsigned long realp, const char __user * buf,
 
        while (count > 0) {
                char *ptr;
-               /*
-                * Handle first page in case it's not aligned
-                */
-               if (-realp & (PAGE_SIZE - 1))
-                       sz = -realp & (PAGE_SIZE - 1);
-               else
-                       sz = PAGE_SIZE;
 
-               sz = min_t(unsigned long, sz, count);
+               sz = size_inside_page(realp, count);
 
                /*
                 * On ia64 if a page has been mapped somewhere as
@@ -577,18 +545,14 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
                if (!kbuf)
                        return wrote ? wrote : -ENOMEM;
                while (count > 0) {
-                       int len = count;
-
-                       if (len > PAGE_SIZE)
-                               len = PAGE_SIZE;
-                       if (len) {
-                               written = copy_from_user(kbuf, buf, len);
-                               if (written) {
-                                       if (wrote + virtr)
-                                               break;
-                                       free_page((unsigned long)kbuf);
-                                       return -EFAULT;
-                               }
+                       int len = size_inside_page(p, count);
+
+                       written = copy_from_user(kbuf, buf, len);
+                       if (written) {
+                               if (wrote + virtr)
+                                       break;
+                               free_page((unsigned long)kbuf);
+                               return -EFAULT;
                        }
                        len = vwrite(kbuf, (char *)p, len);
                        count -= len;