[PATCH 2/4] staging/lustre/obdclass: read jobid from proc

From: Peng Tao
Date: Wed Oct 30 2013 - 07:31:01 EST


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.

Reviewed-by: Niu Yawei <yawei.niu@xxxxxxxxx>
Signed-off-by: Peng Tao <bergwolf@xxxxxxxxx>
Signed-off-by: Andreas Dilger <andreas.dilger@xxxxxxxxx>
---
drivers/staging/lustre/lustre/obdclass/class_obd.c | 119 +++++++++++++++++++-
1 file changed, 115 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c
index b1024a6..99ce863 100644
--- a/drivers/staging/lustre/lustre/obdclass/class_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c
@@ -96,8 +96,117 @@ EXPORT_SYMBOL(obd_dirty_transit_pages);
char obd_jobid_var[JOBSTATS_JOBID_VAR_MAX_LEN + 1] = JOBSTATS_DISABLE;
EXPORT_SYMBOL(obd_jobid_var);

-/* Get jobid of current process by reading the environment variable
- * stored in between the "env_start" & "env_end" of task struct.
+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) {
+ mmput(mm);
+ 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)) {
+ rc = -EINVAL;
+ CWARN("Environment variable '%s' too long: rc = %d\n",
+ key, rc);
+ 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
+ * from /proc/self/environ.
*
* TODO:
* It's better to cache the jobid for later use if there is any
@@ -126,14 +235,14 @@ 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
* variable length strings instead of just numbers), it
* might make sense to keep the unique parts for JobID,
* instead of just returning an error. That means a
- * larger temp buffer for cfs_get_environ(), then
+ * larger temp buffer for obd_get_environ(), then
* truncating the string at some separator to fit into
* the specified jobid_len. Fix later if needed. */
static bool printed;
@@ -149,6 +258,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;
}
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/