Whamcloud - gitweb
LU-10560 libcfs: Use kernel_write when appropriate 54/31154/17
authorMike Marciniszyn <mike.marciniszyn@intel.com>
Tue, 27 Feb 2018 15:25:59 +0000 (10:25 -0500)
committerOleg Drokin <oleg.drokin@intel.com>
Mon, 9 Apr 2018 19:48:38 +0000 (19:48 +0000)
Changes in the upstream kernel might have removed
vfs_write() in favor of kernel_write().

Unfortunately, the kernel_write() was initially exported
with an API that is not plug compatible with vfs_write()

The ring down is:
- kernel_write new API
- vfs_write

Change-Id: I67f73786308561dc42b06d51c26bfb94021b7589
Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
Reviewed-on: https://review.whamcloud.com/31154
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: James Simmons <uja.ornl@yahoo.com>
Reviewed-by: Dmitry Eremin <dmitry.eremin@intel.com>
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
libcfs/autoconf/lustre-libcfs.m4
libcfs/include/libcfs/linux/linux-misc.h
libcfs/libcfs/linux/linux-prim.c
libcfs/libcfs/tracefile.c
lustre/obdclass/kernelcomm.c
lustre/osc/osc_request.c
lustre/target/tgt_handler.c

index 39fc152..21c8208 100644 (file)
@@ -852,6 +852,30 @@ wait_queue_entry, [
 ]) # LIBCFS_WAIT_QUEUE_ENTRY
 
 #
+# LIBCFS_NEW_KERNEL_WRITE
+#
+# Kernel version 4.14 e13ec939e96b13e664bb6cee361cc976a0ee621a
+# changed kernel_write prototype to make is plug compatible
+# with the unexported vfs_write()
+#
+AC_DEFUN([LIBCFS_NEW_KERNEL_WRITE], [
+tmp_flags="$EXTRA_KCFLAGS"
+EXTRA_KCFLAGS="-Werror"
+LB_CHECK_COMPILE([if 'kernel_write' matches other read/write helpers],
+kernel_write_match, [
+       #include <linux/fs.h>
+],[
+       const void *buf = NULL;
+       loff_t pos = 0;
+       return kernel_write(NULL, buf, 0, &pos);
+],[
+       AC_DEFINE(HAVE_NEW_KERNEL_WRITE, 1,
+               ['kernel_write' aligns with read/write helpers])
+])
+EXTRA_KCFLAGS="$tmp_flags"
+]) # LIBCFS_NEW_KERNEL_WRITE
+
+#
 # LIBCFS_PROG_LINUX
 #
 # LibCFS linux kernel checks
@@ -934,6 +958,8 @@ LIBCFS_HOTPLUG_STATE_MACHINE
 LIBCFS_SCHED_HEADERS
 # 4.13
 LIBCFS_WAIT_QUEUE_ENTRY
+# 4.14
+LIBCFS_NEW_KERNEL_WRITE
 ]) # LIBCFS_PROG_LINUX
 
 #
index 68f37ec..06f58e2 100644 (file)
@@ -33,6 +33,7 @@
 #ifndef __LIBCFS_LINUX_MISC_H__
 #define __LIBCFS_LINUX_MISC_H__
 
+#include <linux/fs.h>
 #include <linux/mutex.h>
 #include <linux/user_namespace.h>
 
@@ -116,6 +117,8 @@ int cfs_get_environ(const char *key, char *value, int *val_len);
 #define wait_queue_entry_t wait_queue_t
 #endif
 
+int cfs_kernel_write(struct file *filp, char *buf, size_t count, loff_t *pos);
+
 /*
  * For RHEL6 struct kernel_parm_ops doesn't exist. Also
  * the arguments for .set and .get take different
index c78d886..d9fd96b 100644 (file)
 #define DEBUG_SUBSYSTEM S_LNET
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/fs.h>
 #include <linux/fs_struct.h>
 #include <linux/sched.h>
 #ifdef HAVE_SCHED_HEADERS
 #include <linux/sched/signal.h>
 #include <linux/sched/mm.h>
 #endif
+#include <linux/uaccess.h>
 #include <libcfs/libcfs.h>
 
 #if defined(CONFIG_KGDB)
@@ -99,6 +101,24 @@ time64_t ktime_get_seconds(void)
 EXPORT_SYMBOL(ktime_get_seconds);
 #endif /* HAVE_KTIME_GET_SECONDS */
 
+int cfs_kernel_write(struct file *filp, const void *buf, size_t count,
+                    loff_t *pos)
+{
+#ifdef HAVE_NEW_KERNEL_WRITE
+       return kernel_write(filp, buf, count, pos);
+#else
+       mm_segment_t __old_fs = get_fs();
+       int rc;
+
+       set_fs(get_ds());
+       rc = vfs_write(filp, (__force const char __user *)buf, count, pos);
+       set_fs(__old_fs);
+
+       return rc;
+#endif
+}
+EXPORT_SYMBOL(cfs_kernel_write);
+
 #ifndef HAVE_KSET_FIND_OBJ
 struct kobject *kset_find_obj(struct kset *kset, const char *name)
 {
index 9079941..5074ab1 100644 (file)
@@ -666,7 +666,6 @@ int cfs_tracefile_dump_all_pages(char *filename)
        struct file             *filp;
        struct cfs_trace_page   *tage;
        struct cfs_trace_page   *tmp;
-       mm_segment_t            __oldfs;
        char                    *buf;
        int rc;
 
@@ -687,8 +686,6 @@ int cfs_tracefile_dump_all_pages(char *filename)
                 rc = 0;
                 goto close;
         }
-       __oldfs = get_fs();
-       set_fs(get_ds());
 
        /* ok, for now, just write the pages.  in the future we'll be building
         * iobufs with the pages and calling generic_direct_IO */
@@ -697,8 +694,7 @@ int cfs_tracefile_dump_all_pages(char *filename)
                __LASSERT_TAGE_INVARIANT(tage);
 
                buf = kmap(tage->page);
-               rc = vfs_write(filp, (__force const char __user *)buf,
-                              tage->used, &filp->f_pos);
+               rc = cfs_kernel_write(filp, buf, tage->used, &filp->f_pos);
                kunmap(tage->page);
                if (rc != (int)tage->used) {
                        printk(KERN_WARNING "wanted to write %u but wrote "
@@ -710,7 +706,7 @@ int cfs_tracefile_dump_all_pages(char *filename)
                list_del(&tage->linkage);
                 cfs_tage_free(tage);
         }
-       set_fs(__oldfs);
+
        rc = ll_vfs_fsync_range(filp, 0, LLONG_MAX, 1);
        if (rc)
                printk(KERN_ERR "sync returns %d\n", rc);
@@ -940,7 +936,6 @@ static int tracefiled(void *arg)
        struct tracefiled_ctl *tctl = arg;
        struct cfs_trace_page *tage;
        struct cfs_trace_page *tmp;
-       mm_segment_t __oldfs;
        struct file *filp;
        char *buf;
        int last_loop = 0;
@@ -978,8 +973,6 @@ static int tracefiled(void *arg)
                        __LASSERT(list_empty(&pc.pc_pages));
                         goto end_loop;
                 }
-               __oldfs = get_fs();
-               set_fs(get_ds());
 
                list_for_each_entry_safe(tage, tmp, &pc.pc_pages, linkage) {
                        struct dentry *de = file_dentry(filp);
@@ -993,8 +986,7 @@ static int tracefiled(void *arg)
                                f_pos = i_size_read(de->d_inode);
 
                        buf = kmap(tage->page);
-                       rc = vfs_write(filp, (__force const char __user *)buf,
-                                      tage->used, &f_pos);
+                       rc = cfs_kernel_write(filp, buf, tage->used, &f_pos);
                        kunmap(tage->page);
                        if (rc != (int)tage->used) {
                                printk(KERN_WARNING "wanted to write %u "
@@ -1004,7 +996,6 @@ static int tracefiled(void *arg)
                                break;
                        }
                 }
-               set_fs(__oldfs);
 
                filp_close(filp, NULL);
                 put_pages_on_daemon_list(&pc);
index 85e925e..7afb948 100644 (file)
 #include <obd_support.h>
 #include <lustre_kernelcomm.h>
 
-/* write a userspace buffer to disk.
- * NOTE: this returns 0 on success, not the number of bytes written. */
-static ssize_t
-filp_user_write(struct file *filp, const void *buf, size_t count,
-               loff_t *offset)
-{
-       mm_segment_t fs;
-       ssize_t size = 0;
-
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       while ((ssize_t)count > 0) {
-               size = vfs_write(filp, (const void __user *)buf, count, offset);
-               if (size < 0)
-                       break;
-               count -= size;
-               buf += size;
-               size = 0;
-       }
-       set_fs(fs);
-
-       return size;
-}
-
 /**
  * libcfs_kkuc_msg_put - send an message from kernel to userspace
  * @param fp to send the message to
@@ -74,10 +50,11 @@ filp_user_write(struct file *filp, const void *buf, size_t count,
 int libcfs_kkuc_msg_put(struct file *filp, void *payload)
 {
        struct kuc_hdr *kuch = (struct kuc_hdr *)payload;
-       int rc = -ENOSYS;
+       ssize_t count = kuch->kuc_msglen;
        loff_t offset = 0;
+       int rc = 0;
 
-       if (filp == NULL || IS_ERR(filp))
+       if (IS_ERR_OR_NULL(filp))
                return -EBADF;
 
        if (kuch->kuc_magic != KUC_MAGIC) {
@@ -85,7 +62,15 @@ int libcfs_kkuc_msg_put(struct file *filp, void *payload)
                return -ENOSYS;
        }
 
-       rc = filp_user_write(filp, payload, kuch->kuc_msglen, &offset);
+       while (count > 0) {
+               rc = cfs_kernel_write(filp, payload, count, &offset);
+               if (rc < 0)
+                       break;
+               count -= rc;
+               payload += rc;
+               rc = 0;
+       }
+
        if (rc < 0)
                CWARN("message send failed (%d)\n", rc);
        else
index 0d75cd5..8ff9021 100644 (file)
@@ -1365,7 +1365,6 @@ static void dump_all_bulk_pages(struct obdo *oa, __u32 page_count,
        int rc, i;
        unsigned int len;
        char *buf;
-       mm_segment_t oldfs;
 
        /* will only keep dump of pages on first error for the same range in
         * file/fid, not during the resends/retries. */
@@ -1394,14 +1393,11 @@ static void dump_all_bulk_pages(struct obdo *oa, __u32 page_count,
                return;
        }
 
-       oldfs = get_fs();
-       set_fs(KERNEL_DS);
        for (i = 0; i < page_count; i++) {
                len = pga[i]->count;
                buf = kmap(pga[i]->pg);
                while (len != 0) {
-                       rc = vfs_write(filp, (__force const char __user *)buf,
-                                      len, &filp->f_pos);
+                       rc = cfs_kernel_write(filp, buf, len, &filp->f_pos);
                        if (rc < 0) {
                                CERROR("%s: wanted to write %u but got %d "
                                       "error\n", dbgcksum_file_name, len, rc);
@@ -1414,7 +1410,6 @@ static void dump_all_bulk_pages(struct obdo *oa, __u32 page_count,
                }
                kunmap(pga[i]->pg);
        }
-       set_fs(oldfs);
 
        rc = ll_vfs_fsync_range(filp, 0, LLONG_MAX, 1);
        if (rc)
index 745f92d..4a52875 100644 (file)
@@ -1811,7 +1811,6 @@ static void dump_all_bulk_pages(struct obdo *oa, int count,
        int rc, i;
        unsigned int len;
        char *buf;
-       mm_segment_t oldfs;
 
        /* will only keep dump of pages on first error for the same range in
         * file/fid, not during the resends/retries. */
@@ -1840,14 +1839,11 @@ static void dump_all_bulk_pages(struct obdo *oa, int count,
                return;
        }
 
-       oldfs = get_fs();
-       set_fs(KERNEL_DS);
        for (i = 0; i < count; i++) {
                len = local_nb[i].lnb_len;
                buf = kmap(local_nb[i].lnb_page);
                while (len != 0) {
-                       rc = vfs_write(filp, (__force const char __user *)buf,
-                                      len, &filp->f_pos);
+                       rc = cfs_kernel_write(filp, buf, len, &filp->f_pos);
                        if (rc < 0) {
                                CERROR("%s: wanted to write %u but got %d "
                                       "error\n", dbgcksum_file_name, len, rc);
@@ -1860,7 +1856,6 @@ static void dump_all_bulk_pages(struct obdo *oa, int count,
                }
                kunmap(local_nb[i].lnb_page);
        }
-       set_fs(oldfs);
 
        rc = ll_vfs_fsync_range(filp, 0, LLONG_MAX, 1);
        if (rc)