From b9a32054600a8d63948cced361191aa6ae7ea8f2 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Tue, 27 Feb 2018 10:25:59 -0500 Subject: [PATCH] LU-10560 libcfs: Use kernel_write when appropriate 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 Reviewed-on: https://review.whamcloud.com/31154 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: James Simmons Reviewed-by: Dmitry Eremin Reviewed-by: John L. Hammond Reviewed-by: Oleg Drokin --- libcfs/autoconf/lustre-libcfs.m4 | 26 +++++++++++++++++++++ libcfs/include/libcfs/linux/linux-misc.h | 3 +++ libcfs/libcfs/linux/linux-prim.c | 20 ++++++++++++++++ libcfs/libcfs/tracefile.c | 15 +++--------- lustre/obdclass/kernelcomm.c | 39 ++++++++++---------------------- lustre/osc/osc_request.c | 7 +----- lustre/target/tgt_handler.c | 7 +----- 7 files changed, 66 insertions(+), 51 deletions(-) diff --git a/libcfs/autoconf/lustre-libcfs.m4 b/libcfs/autoconf/lustre-libcfs.m4 index 39fc152..21c8208 100644 --- a/libcfs/autoconf/lustre-libcfs.m4 +++ b/libcfs/autoconf/lustre-libcfs.m4 @@ -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 +],[ + 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 # diff --git a/libcfs/include/libcfs/linux/linux-misc.h b/libcfs/include/libcfs/linux/linux-misc.h index 68f37ec..06f58e2 100644 --- a/libcfs/include/libcfs/linux/linux-misc.h +++ b/libcfs/include/libcfs/linux/linux-misc.h @@ -33,6 +33,7 @@ #ifndef __LIBCFS_LINUX_MISC_H__ #define __LIBCFS_LINUX_MISC_H__ +#include #include #include @@ -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 diff --git a/libcfs/libcfs/linux/linux-prim.c b/libcfs/libcfs/linux/linux-prim.c index c78d886..d9fd96b 100644 --- a/libcfs/libcfs/linux/linux-prim.c +++ b/libcfs/libcfs/linux/linux-prim.c @@ -33,12 +33,14 @@ #define DEBUG_SUBSYSTEM S_LNET #include #include +#include #include #include #ifdef HAVE_SCHED_HEADERS #include #include #endif +#include #include #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) { diff --git a/libcfs/libcfs/tracefile.c b/libcfs/libcfs/tracefile.c index 9079941..5074ab1 100644 --- a/libcfs/libcfs/tracefile.c +++ b/libcfs/libcfs/tracefile.c @@ -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); diff --git a/lustre/obdclass/kernelcomm.c b/lustre/obdclass/kernelcomm.c index 85e925e..7afb948 100644 --- a/lustre/obdclass/kernelcomm.c +++ b/lustre/obdclass/kernelcomm.c @@ -41,30 +41,6 @@ #include #include -/* 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 diff --git a/lustre/osc/osc_request.c b/lustre/osc/osc_request.c index 0d75cd5..8ff9021 100644 --- a/lustre/osc/osc_request.c +++ b/lustre/osc/osc_request.c @@ -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) diff --git a/lustre/target/tgt_handler.c b/lustre/target/tgt_handler.c index 745f92d..4a52875 100644 --- a/lustre/target/tgt_handler.c +++ b/lustre/target/tgt_handler.c @@ -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) -- 1.8.3.1