Whamcloud - gitweb
LU-9679 modules: convert MIN/MAX to kernel style
[fs/lustre-release.git] / lustre / obdclass / jobid.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2014, Intel Corporation.
27  *
28  * Copyright 2017 Cray Inc, all rights reserved.
29  * Author: Ben Evans.
30  *
31  * Store PID->JobID mappings
32  */
33
34 #define DEBUG_SUBSYSTEM S_RPC
35 #include <linux/user_namespace.h>
36 #include <linux/uidgid.h>
37 #include <linux/utsname.h>
38
39 #include <libcfs/libcfs.h>
40 #include <obd_support.h>
41 #include <obd_class.h>
42 #include <lustre_net.h>
43
44 static struct cfs_hash *jobid_hash;
45 static struct cfs_hash_ops jobid_hash_ops;
46 spinlock_t jobid_hash_lock;
47
48 #define RESCAN_INTERVAL 30
49 #define DELETE_INTERVAL 300
50
51 char obd_jobid_var[JOBSTATS_JOBID_VAR_MAX_LEN + 1] = JOBSTATS_DISABLE;
52 char obd_jobid_name[LUSTRE_JOBID_SIZE] = "%e.%u";
53
54 /**
55  * Structure to store a single PID->JobID mapping
56  */
57 struct jobid_pid_map {
58         struct hlist_node       jp_hash;
59         time64_t                jp_time;
60         spinlock_t              jp_lock; /* protects jp_jobid */
61         char                    jp_jobid[LUSTRE_JOBID_SIZE];
62         unsigned int            jp_joblen;
63         atomic_t                jp_refcount;
64         pid_t                   jp_pid;
65 };
66
67 /*
68  * Jobid can be set for a session (see setsid(2)) by writing to
69  * a sysfs file from any process in that session.
70  * The jobids are stored in a hash table indexed by the relevant
71  * struct pid.  We periodically look for entries where the pid has
72  * no PIDTYPE_SID tasks any more, and prune them.  This happens within
73  * 5 seconds of a jobid being added, and every 5 minutes when jobids exist,
74  * but none are added.
75  */
76 #define JOBID_EXPEDITED_CLEAN (5)
77 #define JOBID_BACKGROUND_CLEAN (5 * 60)
78
79 struct session_jobid {
80         struct pid              *sj_session;
81         struct rhash_head       sj_linkage;
82         struct rcu_head         sj_rcu;
83         char                    sj_jobid[1];
84 };
85
86 static const struct rhashtable_params jobid_params = {
87         .key_len        = sizeof(struct pid *),
88         .key_offset     = offsetof(struct session_jobid, sj_session),
89         .head_offset    = offsetof(struct session_jobid, sj_linkage),
90 };
91
92 static struct rhashtable session_jobids;
93
94 /*
95  * jobid_current must be called with rcu_read_lock held.
96  * if it returns non-NULL, the string can only be used
97  * until rcu_read_unlock is called.
98  */
99 char *jobid_current(void)
100 {
101         struct pid *sid = task_session(current);
102         struct session_jobid *sj;
103
104         sj = rhashtable_lookup_fast(&session_jobids, &sid, jobid_params);
105         if (sj)
106                 return sj->sj_jobid;
107         return NULL;
108 }
109
110 static void jobid_prune_expedite(void);
111 /*
112  * jobid_set_current will try to add a new entry
113  * to the table.  If one exists with the same key, the
114  * jobid will be replaced
115  */
116 int jobid_set_current(char *jobid)
117 {
118         struct pid *sid;
119         struct session_jobid *sj, *origsj;
120         int ret;
121         int len = strlen(jobid);
122
123         sj = kmalloc(sizeof(*sj) + len, GFP_KERNEL);
124         if (!sj)
125                 return -ENOMEM;
126         rcu_read_lock();
127         sid = task_session(current);
128         sj->sj_session = get_pid(sid);
129         strncpy(sj->sj_jobid, jobid, len+1);
130         origsj = rhashtable_lookup_get_insert_fast(&session_jobids,
131                                                    &sj->sj_linkage,
132                                                    jobid_params);
133         if (origsj == NULL) {
134                 /* successful insert */
135                 rcu_read_unlock();
136                 jobid_prune_expedite();
137                 return 0;
138         }
139
140         if (IS_ERR(origsj)) {
141                 put_pid(sj->sj_session);
142                 kfree(sj);
143                 rcu_read_unlock();
144                 return PTR_ERR(origsj);
145         }
146         ret = rhashtable_replace_fast(&session_jobids,
147                                       &origsj->sj_linkage,
148                                       &sj->sj_linkage,
149                                       jobid_params);
150         if (ret) {
151                 put_pid(sj->sj_session);
152                 kfree(sj);
153                 rcu_read_unlock();
154                 return ret;
155         }
156         put_pid(origsj->sj_session);
157         rcu_read_unlock();
158         kfree_rcu(origsj, sj_rcu);
159         jobid_prune_expedite();
160
161         return 0;
162 }
163
164 static void jobid_free(void *vsj, void *arg)
165 {
166         struct session_jobid *sj = vsj;
167
168         put_pid(sj->sj_session);
169         kfree(sj);
170 }
171
172 static void jobid_prune(struct work_struct *work);
173 static DECLARE_DELAYED_WORK(jobid_prune_work, jobid_prune);
174 static int jobid_prune_expedited;
175 static void jobid_prune(struct work_struct *work)
176 {
177         int remaining = 0;
178         struct rhashtable_iter iter;
179         struct session_jobid *sj;
180
181         jobid_prune_expedited = 0;
182         rhashtable_walk_enter(&session_jobids, &iter);
183         rhashtable_walk_start(&iter);
184         while ((sj = rhashtable_walk_next(&iter)) != NULL) {
185                 if (!hlist_empty(&sj->sj_session->tasks[PIDTYPE_SID])) {
186                         remaining++;
187                         continue;
188                 }
189                 if (rhashtable_remove_fast(&session_jobids,
190                                            &sj->sj_linkage,
191                                            jobid_params) == 0) {
192                         put_pid(sj->sj_session);
193                         kfree_rcu(sj, sj_rcu);
194                 }
195         }
196         rhashtable_walk_stop(&iter);
197         rhashtable_walk_exit(&iter);
198         if (remaining)
199                 schedule_delayed_work(&jobid_prune_work,
200                                       cfs_time_seconds(JOBID_BACKGROUND_CLEAN));
201 }
202
203 static void jobid_prune_expedite(void)
204 {
205         if (!jobid_prune_expedited) {
206                 jobid_prune_expedited = 1;
207                 mod_delayed_work(system_wq, &jobid_prune_work,
208                                  cfs_time_seconds(JOBID_EXPEDITED_CLEAN));
209         }
210 }
211
212 /*
213  * Get jobid of current process by reading the environment variable
214  * stored in between the "env_start" & "env_end" of task struct.
215  *
216  * If some job scheduler doesn't store jobid in the "env_start/end",
217  * then an upcall could be issued here to get the jobid by utilizing
218  * the userspace tools/API. Then, the jobid must be cached.
219  */
220 int jobid_get_from_environ(char *jobid_var, char *jobid, int *jobid_len)
221 {
222         int rc;
223
224         rc = cfs_get_environ(jobid_var, jobid, jobid_len);
225         if (!rc)
226                 goto out;
227
228         if (rc == -EOVERFLOW) {
229                 /* For the PBS_JOBID and LOADL_STEP_ID keys (which are
230                  * variable length strings instead of just numbers), it
231                  * might make sense to keep the unique parts for JobID,
232                  * instead of just returning an error.  That means a
233                  * larger temp buffer for cfs_get_environ(), then
234                  * truncating the string at some separator to fit into
235                  * the specified jobid_len.  Fix later if needed. */
236                 static ktime_t printed;
237
238                 if (unlikely(ktime_to_ns(printed) == 0 ||
239                              ktime_after(ktime_get(),
240                                          ktime_add_ns(printed,
241                                                       3600*24*NSEC_PER_SEC)))) {
242                         LCONSOLE_WARN("jobid: '%s' value too large (%d)\n",
243                                       obd_jobid_var, *jobid_len);
244                         printed = ktime_get();
245                 }
246
247                 rc = 0;
248         } else {
249                 CDEBUG_LIMIT((rc == -ENOENT || rc == -EINVAL ||
250                               rc == -EDEADLK) ? D_INFO : D_ERROR,
251                              "jobid: get '%s' failed: rc = %d\n",
252                              obd_jobid_var, rc);
253         }
254
255 out:
256         return rc;
257 }
258
259 /*
260  * jobid_should_free_item
261  *
262  * Each item is checked to see if it should be released
263  * Removed from hash table by caller
264  * Actually freed in jobid_put_locked
265  *
266  * Returns 1 if item is to be freed, 0 if it is to be kept
267  */
268
269 static int jobid_should_free_item(void *obj, void *data)
270 {
271         char *jobid = data;
272         struct jobid_pid_map *pidmap = obj;
273         int rc = 0;
274
275         if (obj == NULL)
276                 return 0;
277
278         if (jobid == NULL) {
279                 WARN_ON_ONCE(atomic_read(&pidmap->jp_refcount) != 1);
280                 return 1;
281         }
282
283         spin_lock(&pidmap->jp_lock);
284         /* prevent newly inserted items from deleting */
285         if (jobid[0] == '\0' && atomic_read(&pidmap->jp_refcount) == 1)
286                 rc = 1;
287         else if (ktime_get_real_seconds() - pidmap->jp_time > DELETE_INTERVAL)
288                 rc = 1;
289         else if (strcmp(pidmap->jp_jobid, jobid) == 0)
290                 rc = 1;
291         spin_unlock(&pidmap->jp_lock);
292
293         return rc;
294 }
295
296 /*
297  * jobid_name_is_valid
298  *
299  * Checks if the jobid is a Lustre process
300  *
301  * Returns true if jobid is valid
302  * Returns false if jobid looks like it's a Lustre process
303  */
304 static bool jobid_name_is_valid(char *jobid)
305 {
306         const char *const lustre_reserved[] = { "ll_ping", "ptlrpc",
307                                                 "ldlm", "ll_sa", NULL };
308         int i;
309
310         if (jobid[0] == '\0')
311                 return false;
312
313         for (i = 0; lustre_reserved[i] != NULL; i++) {
314                 if (strncmp(jobid, lustre_reserved[i],
315                             strlen(lustre_reserved[i])) == 0)
316                         return false;
317         }
318         return true;
319 }
320
321 /*
322  * jobid_get_from_cache()
323  *
324  * Returns contents of jobid_var from process environment for current PID,
325  * or from the per-session jobid table.
326  * Values fetch from process environment will be cached for some time to avoid
327  * the overhead of scanning the environment.
328  *
329  * Return: -ENOMEM if allocating a new pidmap fails
330  *         -ENOENT if no entry could be found
331  *         +ve string length for success (something was returned in jobid)
332  */
333 static int jobid_get_from_cache(char *jobid, size_t joblen)
334 {
335         static time64_t last_expire;
336         bool expire_cache = false;
337         pid_t pid = current_pid();
338         struct jobid_pid_map *pidmap = NULL;
339         time64_t now = ktime_get_real_seconds();
340         int rc = 0;
341         ENTRY;
342
343         if (strcmp(obd_jobid_var, JOBSTATS_SESSION) == 0) {
344                 char *jid;
345
346                 rcu_read_lock();
347                 jid = jobid_current();
348                 if (jid) {
349                         strlcpy(jobid, jid, joblen);
350                         joblen = strlen(jobid);
351                 } else {
352                         rc = -ENOENT;
353                 }
354                 rcu_read_unlock();
355                 GOTO(out, rc);
356         }
357
358         LASSERT(jobid_hash != NULL);
359
360         /* scan hash periodically to remove old PID entries from cache */
361         spin_lock(&jobid_hash_lock);
362         if (unlikely(last_expire + DELETE_INTERVAL <= now)) {
363                 expire_cache = true;
364                 last_expire = now;
365         }
366         spin_unlock(&jobid_hash_lock);
367
368         if (expire_cache)
369                 cfs_hash_cond_del(jobid_hash, jobid_should_free_item,
370                                   "intentionally_bad_jobid");
371
372         /* first try to find PID in the hash and use that value */
373         pidmap = cfs_hash_lookup(jobid_hash, &pid);
374         if (pidmap == NULL) {
375                 struct jobid_pid_map *pidmap2;
376
377                 OBD_ALLOC_PTR(pidmap);
378                 if (pidmap == NULL)
379                         GOTO(out, rc = -ENOMEM);
380
381                 pidmap->jp_pid = pid;
382                 pidmap->jp_time = 0;
383                 pidmap->jp_jobid[0] = '\0';
384                 spin_lock_init(&pidmap->jp_lock);
385                 INIT_HLIST_NODE(&pidmap->jp_hash);
386                 /*
387                  * @pidmap might be reclaimed just after it is added into
388                  * hash list, init @jp_refcount as 1 to make sure memory
389                  * could be not freed during access.
390                  */
391                 atomic_set(&pidmap->jp_refcount, 1);
392
393                 /*
394                  * Add the newly created map to the hash, on key collision we
395                  * lost a racing addition and must destroy our newly allocated
396                  * map.  The object which exists in the hash will be returned.
397                  */
398                 pidmap2 = cfs_hash_findadd_unique(jobid_hash, &pid,
399                                                   &pidmap->jp_hash);
400                 if (unlikely(pidmap != pidmap2)) {
401                         CDEBUG(D_INFO, "jobid: duplicate found for PID=%u\n",
402                                pid);
403                         OBD_FREE_PTR(pidmap);
404                         pidmap = pidmap2;
405                 }
406         }
407
408         /*
409          * If pidmap is old (this is always true for new entries) refresh it.
410          * If obd_jobid_var is not found, cache empty entry and try again
411          * later, to avoid repeat lookups for PID if obd_jobid_var missing.
412          */
413         spin_lock(&pidmap->jp_lock);
414         if (pidmap->jp_time + RESCAN_INTERVAL <= now) {
415                 char env_jobid[LUSTRE_JOBID_SIZE] = "";
416                 int env_len = sizeof(env_jobid);
417
418                 pidmap->jp_time = now;
419
420                 spin_unlock(&pidmap->jp_lock);
421                 rc = jobid_get_from_environ(obd_jobid_var, env_jobid, &env_len);
422
423                 CDEBUG(D_INFO, "jobid: PID mapping established: %d->%s\n",
424                        pidmap->jp_pid, env_jobid);
425                 spin_lock(&pidmap->jp_lock);
426                 if (!rc) {
427                         pidmap->jp_joblen = env_len;
428                         strlcpy(pidmap->jp_jobid, env_jobid,
429                                 sizeof(pidmap->jp_jobid));
430                         rc = 0;
431                 } else if (rc == -ENOENT) {
432                         /* It might have been deleted, clear out old entry */
433                         pidmap->jp_joblen = 0;
434                         pidmap->jp_jobid[0] = '\0';
435                 }
436         }
437
438         /*
439          * Regardless of how pidmap was found, if it contains a valid entry
440          * use that for now.  If there was a technical error (e.g. -ENOMEM)
441          * use the old cached value until it can be looked up again properly.
442          * If a cached missing entry was found, return -ENOENT.
443          */
444         if (pidmap->jp_joblen) {
445                 strlcpy(jobid, pidmap->jp_jobid, joblen);
446                 joblen = pidmap->jp_joblen;
447                 rc = 0;
448         } else if (!rc) {
449                 rc = -ENOENT;
450         }
451         spin_unlock(&pidmap->jp_lock);
452
453         cfs_hash_put(jobid_hash, &pidmap->jp_hash);
454
455         EXIT;
456 out:
457         return rc < 0 ? rc : joblen;
458 }
459
460 /*
461  * jobid_interpret_string()
462  *
463  * Interpret the jobfmt string to expand specified fields, like coredumps do:
464  *   %e = executable
465  *   %g = gid
466  *   %h = hostname
467  *   %j = jobid from environment
468  *   %p = pid
469  *   %u = uid
470  *
471  * Unknown escape strings are dropped.  Other characters are copied through,
472  * excluding whitespace (to avoid making jobid parsing difficult).
473  *
474  * Return: -EOVERFLOW if the expanded string does not fit within @joblen
475  *         0 for success
476  */
477 static int jobid_interpret_string(const char *jobfmt, char *jobid,
478                                   ssize_t joblen)
479 {
480         char c;
481
482         while ((c = *jobfmt++) && joblen > 1) {
483                 char f;
484                 int l;
485
486                 if (isspace(c)) /* Don't allow embedded spaces */
487                         continue;
488
489                 if (c != '%') {
490                         *jobid = c;
491                         joblen--;
492                         jobid++;
493                         continue;
494                 }
495
496                 switch ((f = *jobfmt++)) {
497                 case 'e': /* executable name */
498                         l = snprintf(jobid, joblen, "%s", current_comm());
499                         break;
500                 case 'g': /* group ID */
501                         l = snprintf(jobid, joblen, "%u",
502                                      from_kgid(&init_user_ns, current_fsgid()));
503                         break;
504                 case 'h': /* hostname */
505                         l = snprintf(jobid, joblen, "%s",
506                                      init_utsname()->nodename);
507                         break;
508                 case 'j': /* jobid stored in process environment */
509                         l = jobid_get_from_cache(jobid, joblen);
510                         if (l < 0)
511                                 l = 0;
512                         break;
513                 case 'p': /* process ID */
514                         l = snprintf(jobid, joblen, "%u", current_pid());
515                         break;
516                 case 'u': /* user ID */
517                         l = snprintf(jobid, joblen, "%u",
518                                      from_kuid(&init_user_ns, current_fsuid()));
519                         break;
520                 case '\0': /* '%' at end of format string */
521                         l = 0;
522                         goto out;
523                 default: /* drop unknown %x format strings */
524                         l = 0;
525                         break;
526                 }
527                 jobid += l;
528                 joblen -= l;
529         }
530         /*
531          * This points at the end of the buffer, so long as jobid is always
532          * incremented the same amount as joblen is decremented.
533          */
534 out:
535         jobid[joblen - 1] = '\0';
536
537         return joblen < 0 ? -EOVERFLOW : 0;
538 }
539
540 /*
541  * Hash initialization, copied from server-side job stats bucket sizes
542  */
543 #define HASH_JOBID_BKT_BITS 5
544 #define HASH_JOBID_CUR_BITS 7
545 #define HASH_JOBID_MAX_BITS 12
546
547 int jobid_cache_init(void)
548 {
549         int rc = 0;
550         ENTRY;
551
552         if (jobid_hash)
553                 return 0;
554
555         spin_lock_init(&jobid_hash_lock);
556         jobid_hash = cfs_hash_create("JOBID_HASH", HASH_JOBID_CUR_BITS,
557                                      HASH_JOBID_MAX_BITS, HASH_JOBID_BKT_BITS,
558                                      0, CFS_HASH_MIN_THETA, CFS_HASH_MAX_THETA,
559                                      &jobid_hash_ops, CFS_HASH_DEFAULT);
560         if (!jobid_hash) {
561                 rc = -ENOMEM;
562         } else {
563                 rc = rhashtable_init(&session_jobids, &jobid_params);
564                 if (rc) {
565                         cfs_hash_putref(jobid_hash);
566                         jobid_hash = NULL;
567                 }
568         }
569
570         RETURN(rc);
571 }
572 EXPORT_SYMBOL(jobid_cache_init);
573
574 void jobid_cache_fini(void)
575 {
576         struct cfs_hash *tmp_hash;
577         ENTRY;
578
579         spin_lock(&jobid_hash_lock);
580         tmp_hash = jobid_hash;
581         jobid_hash = NULL;
582         spin_unlock(&jobid_hash_lock);
583
584         cancel_delayed_work_sync(&jobid_prune_work);
585
586         if (tmp_hash != NULL) {
587                 cfs_hash_cond_del(tmp_hash, jobid_should_free_item, NULL);
588                 cfs_hash_putref(tmp_hash);
589
590                 rhashtable_free_and_destroy(&session_jobids, jobid_free, NULL);
591         }
592
593
594         EXIT;
595 }
596 EXPORT_SYMBOL(jobid_cache_fini);
597
598 /*
599  * Hash operations for pid<->jobid
600  */
601 static unsigned jobid_hashfn(struct cfs_hash *hs, const void *key,
602                              unsigned mask)
603 {
604         return cfs_hash_djb2_hash(key, sizeof(pid_t), mask);
605 }
606
607 static void *jobid_key(struct hlist_node *hnode)
608 {
609         struct jobid_pid_map *pidmap;
610
611         pidmap = hlist_entry(hnode, struct jobid_pid_map, jp_hash);
612         return &pidmap->jp_pid;
613 }
614
615 static int jobid_keycmp(const void *key, struct hlist_node *hnode)
616 {
617         const pid_t *pid_key1;
618         const pid_t *pid_key2;
619
620         LASSERT(key != NULL);
621         pid_key1 = (pid_t *)key;
622         pid_key2 = (pid_t *)jobid_key(hnode);
623
624         return *pid_key1 == *pid_key2;
625 }
626
627 static void *jobid_object(struct hlist_node *hnode)
628 {
629         return hlist_entry(hnode, struct jobid_pid_map, jp_hash);
630 }
631
632 static void jobid_get(struct cfs_hash *hs, struct hlist_node *hnode)
633 {
634         struct jobid_pid_map *pidmap;
635
636         pidmap = hlist_entry(hnode, struct jobid_pid_map, jp_hash);
637
638         atomic_inc(&pidmap->jp_refcount);
639 }
640
641 static void jobid_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
642 {
643         struct jobid_pid_map *pidmap;
644
645         if (hnode == NULL)
646                 return;
647
648         pidmap = hlist_entry(hnode, struct jobid_pid_map, jp_hash);
649         LASSERT(atomic_read(&pidmap->jp_refcount) > 0);
650         if (atomic_dec_and_test(&pidmap->jp_refcount)) {
651                 CDEBUG(D_INFO, "Freeing: %d->%s\n",
652                        pidmap->jp_pid, pidmap->jp_jobid);
653
654                 OBD_FREE_PTR(pidmap);
655         }
656 }
657
658 static struct cfs_hash_ops jobid_hash_ops = {
659         .hs_hash        = jobid_hashfn,
660         .hs_keycmp      = jobid_keycmp,
661         .hs_key         = jobid_key,
662         .hs_object      = jobid_object,
663         .hs_get         = jobid_get,
664         .hs_put         = jobid_put_locked,
665         .hs_put_locked  = jobid_put_locked,
666 };
667
668 /**
669  * Generate the job identifier string for this process for tracking purposes.
670  *
671  * Fill in @jobid string based on the value of obd_jobid_var:
672  * JOBSTATS_DISABLE:      none
673  * JOBSTATS_NODELOCAL:    content of obd_jobid_name (jobid_interpret_string())
674  * JOBSTATS_PROCNAME_UID: process name/UID
675  * JOBSTATS_SESSION       per-session value set by
676  *                            /sys/fs/lustre/jobid_this_session
677  * anything else:         look up obd_jobid_var in the processes environment
678  *
679  * Return -ve error number, 0 on success.
680  */
681 int lustre_get_jobid(char *jobid, size_t joblen)
682 {
683         int rc = 0;
684         ENTRY;
685
686         if (unlikely(joblen < 2)) {
687                 if (joblen == 1)
688                         jobid[0] = '\0';
689                 RETURN(-EINVAL);
690         }
691
692         if (strcmp(obd_jobid_var, JOBSTATS_DISABLE) == 0) {
693                 /* Jobstats isn't enabled */
694                 memset(jobid, 0, joblen);
695         } else if (strcmp(obd_jobid_var, JOBSTATS_NODELOCAL) == 0) {
696                 /* Whole node dedicated to single job */
697                 rc = jobid_interpret_string(obd_jobid_name, jobid, joblen);
698         } else if (strcmp(obd_jobid_var, JOBSTATS_PROCNAME_UID) == 0) {
699                 rc = jobid_interpret_string("%e.%u", jobid, joblen);
700         } else if (strcmp(obd_jobid_var, JOBSTATS_SESSION) == 0) {
701                 char *jid;
702
703                 rcu_read_lock();
704                 jid = jobid_current();
705                 if (jid)
706                         strlcpy(jobid, jid, sizeof(jobid));
707                 rcu_read_unlock();
708         } else if (jobid_name_is_valid(current_comm())) {
709                 /*
710                  * obd_jobid_var holds the jobid environment variable name.
711                  * Skip initial check if obd_jobid_name already uses "%j",
712                  * otherwise try just "%j" first, then fall back to whatever
713                  * is in obd_jobid_name if obd_jobid_var is not found.
714                  */
715                 rc = -EAGAIN;
716                 if (!strnstr(obd_jobid_name, "%j", joblen))
717                         rc = jobid_get_from_cache(jobid, joblen);
718
719                 /* fall back to jobid_node if jobid_var not in environment */
720                 if (rc < 0) {
721                         int rc2 = jobid_interpret_string(obd_jobid_name,
722                                                          jobid, joblen);
723                         if (!rc2)
724                                 rc = 0;
725                 }
726         }
727
728         RETURN(rc);
729 }
730 EXPORT_SYMBOL(lustre_get_jobid);
731
732 /*
733  * lustre_jobid_clear
734  *
735  * Search cache for JobID given by @find_jobid.
736  * If any entries in the hash table match the value, they are removed
737  */
738 void lustre_jobid_clear(const char *find_jobid)
739 {
740         char jobid[LUSTRE_JOBID_SIZE];
741         char *end;
742
743         if (jobid_hash == NULL)
744                 return;
745
746         strlcpy(jobid, find_jobid, sizeof(jobid));
747         /* trim \n off the end of the incoming jobid */
748         end = strchr(jobid, '\n');
749         if (end && *end == '\n')
750                 *end = '\0';
751
752         CDEBUG(D_INFO, "Clearing Jobid: %s\n", jobid);
753         cfs_hash_cond_del(jobid_hash, jobid_should_free_item, jobid);
754
755         CDEBUG(D_INFO, "%d items remain in jobID table\n",
756                atomic_read(&jobid_hash->hs_count));
757 }