From e506e96880da318ac0189b27163e6cb9bcaad332 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Tue, 15 Oct 2013 15:43:55 +0800 Subject: [PATCH 1/4] staging/lustre/obdclass: read jobid from proc so that we can get rid of cfs_get_environ() that needs access_process_vm() that is a core mm function and is not available on some architectures. Signed-off-by: Peng Tao --- .../lustre/lustre/obdclass/class_obd.c | 114 +++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index b1024a6d37dd95..a9910af63aaf9c 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -96,6 +96,116 @@ EXPORT_SYMBOL(obd_dirty_transit_pages); char obd_jobid_var[JOBSTATS_JOBID_VAR_MAX_LEN + 1] = JOBSTATS_DISABLE; EXPORT_SYMBOL(obd_jobid_var); +static char *self_environ_file = "/proc/self/environ"; +static int obd_get_environ(const char *key, char *value, int *val_len) +{ + struct mm_struct *mm; + struct path path; + struct file *filp = NULL; + int buf_len = PAGE_CACHE_SIZE; + int key_len = strlen(key); + char *buffer = NULL; + loff_t pos = 0; + int rc; + + /* + * test mm->mmap_sem to avoid deadlock if this ever gets called from + * mmap code. + */ + mm = get_task_mm(current); + if (!mm) + return -EINVAL; + if (down_read_trylock(&mm->mmap_sem) == 0) + return -EDEADLK; + up_read(&mm->mmap_sem); + mmput(mm); + + buffer = kmalloc(buf_len, GFP_NOIO); + if (!buffer) + return -ENOMEM; + + rc = kern_path(self_environ_file, LOOKUP_FOLLOW, &path); + if (rc) + goto out; + + filp = dentry_open(&path, O_RDONLY, current_cred()); + if (IS_ERR(filp)) { + rc = PTR_ERR(filp); + filp = NULL; + goto out; + } + + /* loop reading... */ + while (1) { + int scan_len, this_len; + char *env_start, *env_end; + rc = kernel_read(filp, pos, buffer, buf_len); + if (rc <= 0) + break; + + pos += rc; + /* Parse the buffer to find out the specified key/value pair. + * The "key=value" entries are separated by '\0'. */ + env_start = buffer; + scan_len = this_len = rc; + while (scan_len) { + char *entry; + int entry_len; + + env_end = memscan(env_start, '\0', scan_len); + LASSERT(env_end >= env_start && + env_end <= env_start + scan_len); + + /* The last entry of this buffer cross the buffer + * boundary, reread it in next cycle. */ + if (unlikely(env_end - env_start == scan_len)) { + /* This entry is too large to fit in buffer */ + if (unlikely(scan_len == this_len)) { + static bool printed; + rc = -EINVAL; + if (!printed) { + CWARN("Environment variable '%s' too long: rc = %d\n", + key, rc); + printed = true; + } + goto out; + } + pos -= scan_len; + break; + } + + entry = env_start; + entry_len = env_end - env_start; + + /* Key length + length of '=' */ + if (entry_len > key_len + 1 && + !memcmp(entry, key, key_len)) { + entry += key_len + 1; + entry_len -= key_len + 1; + /* The 'value' buffer passed in is too small.*/ + if (entry_len >= *val_len) + GOTO(out, rc = -EOVERFLOW); + + memcpy(value, entry, entry_len); + *val_len = entry_len; + rc = 0; + goto out; + } + + scan_len -= (env_end - env_start + 1); + env_start = env_end + 1; + } + } + if (rc >= 0) + rc = -ENOENT; +out: + if (filp) + fput(filp); + if (buffer) + kfree(buffer); + return rc; +} + /* Get jobid of current process by reading the environment variable * stored in between the "env_start" & "env_end" of task struct. * @@ -126,7 +236,7 @@ int lustre_get_jobid(char *jobid) return 0; } - rc = cfs_get_environ(obd_jobid_var, jobid, &jobid_len); + rc = obd_get_environ(obd_jobid_var, jobid, &jobid_len); if (rc) { if (rc == -EOVERFLOW) { /* For the PBS_JOBID and LOADL_STEP_ID keys (which are @@ -149,6 +259,8 @@ int lustre_get_jobid(char *jobid) "Get jobid for (%s) failed: rc = %d\n", obd_jobid_var, rc); } + } else { + CDEBUG(D_INFO, "Got jobid for (%s) value (%s)\n", obd_jobid_var, jobid); } return rc; } From e2f9c4e0372b632d0ed59c755a45e36b9003d6f6 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Thu, 24 Oct 2013 22:26:12 +0800 Subject: [PATCH 2/4] staging/lustre/llite: cache jobid in lu_env Now we need an extra memory copy to get jobid, let's cache it in lu_env. It then is copied from lu_env to ll_inode_info upon every read/write. Signed-off-by: Peng Tao --- drivers/staging/lustre/lustre/llite/file.c | 2 ++ .../staging/lustre/lustre/llite/llite_internal.h | 16 ++++++++++++++++ drivers/staging/lustre/lustre/llite/llite_mmap.c | 1 + drivers/staging/lustre/lustre/llite/vvp_io.c | 8 -------- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index bc534db1243169..2fa010746269f5 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -846,6 +846,8 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args, struct cl_io *io; ssize_t result; + ll_io_set_jobid(env, lli); + restart: io = ccc_env_thread_io(env); ll_io_init(io, file, iot == CIT_WRITE); diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 47e443d90fe1a5..afa9aaf5f88070 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -968,6 +968,7 @@ struct vvp_thread_info { struct ra_io_arg vti_ria; struct kiocb vti_kiocb; struct ll_cl_context vti_io_ctx; + char vti_jobid[JOBSTATS_JOBID_SIZE]; }; static inline struct vvp_thread_info *vvp_env_info(const struct lu_env *env) @@ -980,6 +981,21 @@ static inline struct vvp_thread_info *vvp_env_info(const struct lu_env *env) return info; } +static inline char *vvp_env_jobid(const struct lu_env *env) +{ + return vvp_env_info(env)->vti_jobid; +} + +static inline void ll_io_set_jobid(const struct lu_env *env, struct ll_inode_info *lli) +{ + char *jobid = vvp_env_jobid(env); + + if (jobid[0] == '\0') + lustre_get_jobid(jobid); + + memcpy(lli->lli_jobid, jobid, JOBSTATS_JOBID_SIZE); +} + static inline struct vvp_io_args *vvp_env_args(const struct lu_env *env, enum vvp_io_subtype type) { diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c index caed6423e4ef20..f64f9153c6647f 100644 --- a/drivers/staging/lustre/lustre/llite/llite_mmap.c +++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c @@ -205,6 +205,7 @@ static int ll_page_mkwrite0(struct vm_area_struct *vma, struct page *vmpage, * while truncate is on-going. */ inode = ccc_object_inode(io->ci_obj); lli = ll_i2info(inode); + ll_io_set_jobid(env, lli); down_read(&lli->lli_trunc_sem); result = cl_io_loop(env, io); diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c index 3ff664ce7503b6..efcce2948260a8 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_io.c +++ b/drivers/staging/lustre/lustre/llite/vvp_io.c @@ -1117,7 +1117,6 @@ int vvp_io_init(const struct lu_env *env, struct cl_object *obj, result = 0; if (io->ci_type == CIT_READ || io->ci_type == CIT_WRITE) { size_t count; - struct ll_inode_info *lli = ll_i2info(inode); count = io->u.ci_rw.crw_count; /* "If nbyte is 0, read() will return 0 and have no other @@ -1128,13 +1127,6 @@ int vvp_io_init(const struct lu_env *env, struct cl_object *obj, cio->cui_tot_count = count; cio->cui_tot_nrsegs = 0; } - /* for read/write, we store the jobid in the inode, and - * it'll be fetched by osc when building RPC. - * - * it's not accurate if the file is shared by different - * jobs. - */ - lustre_get_jobid(lli->lli_jobid); } else if (io->ci_type == CIT_SETATTR) { if (!cl_io_is_trunc(io)) io->ci_lockreq = CILR_MANDATORY; From ea16d28afe6a60abcc422a5c1e2876fff3b57a12 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Tue, 15 Oct 2013 15:50:14 +0800 Subject: [PATCH 3/4] staging/lustre: remove cfs_get_environ and cfs_access_process_vm Signed-off-by: Peng Tao --- .../lustre/include/linux/libcfs/curproc.h | 1 - .../lustre/libcfs/linux/linux-curproc.c | 150 ------------------ 2 files changed, 151 deletions(-) diff --git a/drivers/staging/lustre/include/linux/libcfs/curproc.h b/drivers/staging/lustre/include/linux/libcfs/curproc.h index de8e35b796ab47..1c49ef487c58d2 100644 --- a/drivers/staging/lustre/include/linux/libcfs/curproc.h +++ b/drivers/staging/lustre/include/linux/libcfs/curproc.h @@ -64,7 +64,6 @@ int cfs_curproc_groups_nr(void); int current_is_32bit(void); #define current_pid() (current->pid) #define current_comm() (current->comm) -int cfs_get_environ(const char *key, char *value, int *val_len); typedef __u32 cfs_cap_t; diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c index ea9e9490031fc8..007f19736fa21e 100644 --- a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c +++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c @@ -152,156 +152,6 @@ int current_is_32bit(void) return is_compat_task(); } -static int cfs_access_process_vm(struct task_struct *tsk, unsigned long addr, - void *buf, int len, int write) -{ - /* Just copied from kernel for the kernels which doesn't - * have access_process_vm() exported */ - struct mm_struct *mm; - struct vm_area_struct *vma; - struct page *page; - void *old_buf = buf; - - mm = get_task_mm(tsk); - if (!mm) - return 0; - - down_read(&mm->mmap_sem); - /* ignore errors, just check how much was sucessfully transfered */ - while (len) { - int bytes, rc, offset; - void *maddr; - - rc = get_user_pages(tsk, mm, addr, 1, - write, 1, &page, &vma); - if (rc <= 0) - break; - - bytes = len; - offset = addr & (PAGE_SIZE-1); - if (bytes > PAGE_SIZE-offset) - bytes = PAGE_SIZE-offset; - - maddr = kmap(page); - if (write) { - copy_to_user_page(vma, page, addr, - maddr + offset, buf, bytes); - set_page_dirty_lock(page); - } else { - copy_from_user_page(vma, page, addr, - buf, maddr + offset, bytes); - } - kunmap(page); - page_cache_release(page); - len -= bytes; - buf += bytes; - addr += bytes; - } - up_read(&mm->mmap_sem); - mmput(mm); - - return buf - old_buf; -} - -/* Read the environment variable of current process specified by @key. */ -int cfs_get_environ(const char *key, char *value, int *val_len) -{ - struct mm_struct *mm; - char *buffer, *tmp_buf = NULL; - int buf_len = PAGE_CACHE_SIZE; - int key_len = strlen(key); - unsigned long addr; - int rc; - - buffer = kmalloc(buf_len, GFP_USER); - if (!buffer) - return -ENOMEM; - - mm = get_task_mm(current); - if (!mm) { - kfree(buffer); - return -EINVAL; - } - - /* Avoid deadlocks on mmap_sem if called from sys_mmap_pgoff(), - * which is already holding mmap_sem for writes. If some other - * thread gets the write lock in the meantime, this thread will - * block, but at least it won't deadlock on itself. LU-1735 */ - if (down_read_trylock(&mm->mmap_sem) == 0) - return -EDEADLK; - up_read(&mm->mmap_sem); - - addr = mm->env_start; - while (addr < mm->env_end) { - int this_len, retval, scan_len; - char *env_start, *env_end; - - memset(buffer, 0, buf_len); - - this_len = min_t(int, mm->env_end - addr, buf_len); - retval = cfs_access_process_vm(current, addr, buffer, - this_len, 0); - if (retval != this_len) - break; - - addr += retval; - - /* Parse the buffer to find out the specified key/value pair. - * The "key=value" entries are separated by '\0'. */ - env_start = buffer; - scan_len = this_len; - while (scan_len) { - char *entry; - int entry_len; - - env_end = memscan(env_start, '\0', scan_len); - LASSERT(env_end >= env_start && - env_end <= env_start + scan_len); - - /* The last entry of this buffer cross the buffer - * boundary, reread it in next cycle. */ - if (unlikely(env_end - env_start == scan_len)) { - /* This entry is too large to fit in buffer */ - if (unlikely(scan_len == this_len)) { - CERROR("Too long env variable.\n"); - GOTO(out, rc = -EINVAL); - } - addr -= scan_len; - break; - } - - entry = env_start; - entry_len = env_end - env_start; - - /* Key length + length of '=' */ - if (entry_len > key_len + 1 && - !memcmp(entry, key, key_len)) { - entry += key_len + 1; - entry_len -= key_len + 1; - /* The 'value' buffer passed in is too small.*/ - if (entry_len >= *val_len) - GOTO(out, rc = -EOVERFLOW); - - memcpy(value, entry, entry_len); - *val_len = entry_len; - GOTO(out, rc = 0); - } - - scan_len -= (env_end - env_start + 1); - env_start = env_end + 1; - } - } - GOTO(out, rc = -ENOENT); - -out: - mmput(mm); - kfree((void *)buffer); - if (tmp_buf) - kfree((void *)tmp_buf); - return rc; -} -EXPORT_SYMBOL(cfs_get_environ); - EXPORT_SYMBOL(cfs_curproc_groups_nr); EXPORT_SYMBOL(cfs_cap_raise); EXPORT_SYMBOL(cfs_cap_lower); From fd166fb97b83e3ddab49e65166deff21bc2e7746 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Tue, 15 Oct 2013 15:50:47 +0800 Subject: [PATCH 4/4] staging/lustre: enable build on MIPS/XTENSA/SUPERH The missing symbol copy_from_user_page() is not needed now. Cc: Guenter Roeck Signed-off-by: Peng Tao --- drivers/staging/lustre/lustre/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lustre/Kconfig b/drivers/staging/lustre/lustre/Kconfig index 2156a44d07409c..e44965bdaac3fa 100644 --- a/drivers/staging/lustre/lustre/Kconfig +++ b/drivers/staging/lustre/lustre/Kconfig @@ -1,6 +1,6 @@ config LUSTRE_FS tristate "Lustre file system client support" - depends on INET && m && !MIPS && !XTENSA && !SUPERH + depends on INET && m select LNET select CRYPTO select CRYPTO_CRC32