~ubuntu-branches/ubuntu/precise/slurm-llnl/precise

« back to all changes in this revision

Viewing changes to src/plugins/proctrack/cgroup/proctrack_cgroup.c

  • Committer: Bazaar Package Importer
  • Author(s): Gennaro Oliva
  • Date: 2011-04-08 11:21:17 UTC
  • mfrom: (3.3.16 sid)
  • Revision ID: james.westby@ubuntu.com-20110408112117-nfnyq9dtm55hqoaw
Tags: 2.2.4-1
* New upstream releases 
* Cleaning spare file and directories, not belonging to the sources
  generated by the building process and not removed by distclean.
  Added debian/clean with spare files and rm -rf inside debian/rules
  for directories.
* Added new packages libslurm-perl, libslurmdb-perl, slurm-llnl-torque
  (Closes: #575822) thanks to Julien Blache

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************\
 
2
 *  proctrack_cgroup.c - process tracking via linux cgroup containers
 
3
 *****************************************************************************
 
4
 *  Copyright (C) 2009 CEA/DAM/DIF
 
5
 *  Written by Matthieu Hautreux <matthieu.hautreux@cea.fr>
 
6
 *  
 
7
 *  This file is part of SLURM, a resource management program.
 
8
 *  For details, see <https://computing.llnl.gov/linux/slurm/>.
 
9
 *  Please also read the included file: DISCLAIMER.
 
10
 *  
 
11
 *  SLURM is free software; you can redistribute it and/or modify it under
 
12
 *  the terms of the GNU General Public License as published by the Free
 
13
 *  Software Foundation; either version 2 of the License, or (at your option)
 
14
 *  any later version.
 
15
 *
 
16
 *  In addition, as a special exception, the copyright holders give permission 
 
17
 *  to link the code of portions of this program with the OpenSSL library under 
 
18
 *  certain conditions as described in each individual source file, and 
 
19
 *  distribute linked combinations including the two. You must obey the GNU 
 
20
 *  General Public License in all respects for all of the code used other than 
 
21
 *  OpenSSL. If you modify file(s) with this exception, you may extend this 
 
22
 *  exception to your version of the file(s), but you are not obligated to do 
 
23
 *  so. If you do not wish to do so, delete this exception statement from your
 
24
 *  version.  If you delete this exception statement from all source files in 
 
25
 *  the program, then also delete it here.
 
26
 *  
 
27
 *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
 
28
 *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
29
 *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
30
 *  details.
 
31
 *  
 
32
 *  You should have received a copy of the GNU General Public License along
 
33
 *  with SLURM; if not, write to the Free Software Foundation, Inc.,
 
34
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
 
35
\*****************************************************************************/
 
36
 
 
37
#if HAVE_CONFIG_H
 
38
#   include "config.h"
 
39
#endif
 
40
 
 
41
#if HAVE_STDINT_H
 
42
#  include <stdint.h>
 
43
#endif
 
44
#if HAVE_INTTYPES_H
 
45
#  include <inttypes.h>
 
46
#endif
 
47
 
 
48
#include <slurm/slurm.h>
 
49
#include <slurm/slurm_errno.h>
 
50
#include "src/common/log.h"
 
51
#include "src/slurmd/slurmd/slurmd.h"
 
52
 
 
53
#include "src/slurmd/slurmstepd/slurmstepd_job.h"
 
54
 
 
55
#include <sys/types.h>
 
56
#include <sys/stat.h>
 
57
#include <fcntl.h>
 
58
#include <stdlib.h>
 
59
 
 
60
#include "read_config.h"
 
61
#include "xcgroup.h"
 
62
#include "xcpuinfo.h"
 
63
 
 
64
/*
 
65
 * These variables are required by the generic plugin interface.  If they
 
66
 * are not found in the plugin, the plugin loader will ignore it.
 
67
 *
 
68
 * plugin_name - a string giving a human-readable description of the
 
69
 * plugin.  There is no maximum length, but the symbol must refer to
 
70
 * a valid string.
 
71
 *
 
72
 * plugin_type - a string suggesting the type of the plugin or its
 
73
 * applicability to a particular form of data or method of data handling.
 
74
 * If the low-level plugin API is used, the contents of this string are
 
75
 * unimportant and may be anything.  SLURM uses the higher-level plugin
 
76
 * interface which requires this string to be of the form
 
77
 *
 
78
 *      <application>/<method>
 
79
 *
 
80
 * where <application> is a description of the intended application of
 
81
 * the plugin (e.g., "jobcomp" for SLURM job completion logging) and <method>
 
82
 * is a description of how this plugin satisfies that application.  SLURM will
 
83
 * only load job completion logging plugins if the plugin_type string has a 
 
84
 * prefix of "jobcomp/".
 
85
 *
 
86
 * plugin_version - an unsigned 32-bit integer giving the version number
 
87
 * of the plugin.  If major and minor revisions are desired, the major
 
88
 * version number may be multiplied by a suitable magnitude constant such
 
89
 * as 100 or 1000.  Various SLURM versions will likely require a certain
 
90
 * minimum version for their plugins as the job completion logging API
 
91
 * matures.
 
92
 */
 
93
const char plugin_name[]      = "Process tracking via linux cgroup";
 
94
const char plugin_type[]      = "proctrack/cgroup";
 
95
const uint32_t plugin_version = 10;
 
96
 
 
97
#ifndef PATH_MAX
 
98
#define PATH_MAX 256
 
99
#endif
 
100
 
 
101
#define CGROUP_SLURMDIR CGROUP_BASEDIR "/slurm"
 
102
 
 
103
char user_cgroup_path[PATH_MAX];
 
104
char job_cgroup_path[PATH_MAX];
 
105
char jobstep_cgroup_path[PATH_MAX];
 
106
 
 
107
int _slurm_cgroup_init()
 
108
{
 
109
        int fstatus;
 
110
        xcgroup_opts_t opts;
 
111
 
 
112
        /* initialize job/jobstep cgroup path */
 
113
        user_cgroup_path[0]='\0';
 
114
        job_cgroup_path[0]='\0';
 
115
        jobstep_cgroup_path[0]='\0';
 
116
 
 
117
        /* we first check that cgroup is mounted */
 
118
        if ( ! xcgroup_is_available() ) {
 
119
                if ( slurm_cgroup_conf->cgroup_automount ) {
 
120
                        if ( xcgroup_mount(slurm_cgroup_conf->
 
121
                                           cgroup_mount_opts) ) {
 
122
                                error("unable to mount cgroup");
 
123
                                return SLURM_ERROR;
 
124
                        }
 
125
                        info("cgroup system is now mounted");
 
126
                        /* we then set the release_agent if necessary */
 
127
                        if ( slurm_cgroup_conf->cgroup_release_agent ) {
 
128
                                xcgroup_set_release_agent(slurm_cgroup_conf->
 
129
                                                          cgroup_release_agent);
 
130
                        }
 
131
                }
 
132
                else {
 
133
                        error("cgroup is not mounted. aborting");
 
134
                        return SLURM_ERROR;
 
135
                }
 
136
        }
 
137
 
 
138
        /* create a non releasable root cgroup for slurm usage */
 
139
        opts.uid=getuid();
 
140
        opts.gid=getgid();
 
141
        opts.create_only=0;
 
142
        opts.notify=0;
 
143
        fstatus = xcgroup_create(CGROUP_SLURMDIR,&opts);
 
144
        if ( fstatus != SLURM_SUCCESS ) {
 
145
                error("unable to create SLURM cgroup directory '%s'. aborting",
 
146
                      CGROUP_SLURMDIR);
 
147
                return SLURM_ERROR;
 
148
        }
 
149
 
 
150
        return SLURM_SUCCESS;
 
151
}
 
152
 
 
153
int _slurm_cgroup_create(slurmd_job_t *job,uint32_t id,uid_t uid,gid_t gid)
 
154
{
 
155
        int fstatus;
 
156
 
 
157
        xcgroup_opts_t opts;
 
158
        uint32_t cur_memlimit,cur_memswlimit;
 
159
 
 
160
        /* build user cgroup path if no set (should not be) */
 
161
        if ( *user_cgroup_path == '\0' ) {
 
162
                if ( snprintf(user_cgroup_path,PATH_MAX,CGROUP_SLURMDIR 
 
163
                              "/uid_%u",uid) >= PATH_MAX ) {
 
164
                        error("unable to build uid %u cgroup filepath : %m",
 
165
                              uid);
 
166
                        return SLURM_ERROR;
 
167
                }
 
168
        }
 
169
 
 
170
        /* build job cgroup path if no set (should not be) */
 
171
        if ( *job_cgroup_path == '\0' ) {
 
172
                if ( snprintf(job_cgroup_path,PATH_MAX,"%s/job_%u",
 
173
                              user_cgroup_path,job->jobid) >= PATH_MAX ) {
 
174
                        error("unable to build job %u cgroup filepath : %m",
 
175
                              job->jobid);
 
176
                        return SLURM_ERROR;
 
177
                }
 
178
        }
 
179
 
 
180
        /* build job step cgroup path (should not be) */
 
181
        if ( *jobstep_cgroup_path == '\0' ) {
 
182
                if ( snprintf(jobstep_cgroup_path,PATH_MAX,"%s/step_%u",
 
183
                              job_cgroup_path,job->stepid) >= PATH_MAX ) {
 
184
                        error("unable to build job step %u cgroup filepath "
 
185
                              ": %m",job->stepid);
 
186
                        return SLURM_ERROR;
 
187
                }
 
188
        }
 
189
 
 
190
        /* create user cgroup (it could already exist) */
 
191
        opts.uid=getuid();
 
192
        opts.gid=getgid();
 
193
        opts.create_only=0;
 
194
        opts.notify=1;
 
195
        if ( xcgroup_create(user_cgroup_path,&opts)
 
196
             != SLURM_SUCCESS )
 
197
                return SLURM_ERROR;
 
198
        if ( slurm_cgroup_conf->user_cgroup_params )
 
199
                xcgroup_set_params(user_cgroup_path,
 
200
                                   slurm_cgroup_conf->user_cgroup_params);
 
201
        
 
202
        /*
 
203
         * if memory constraints have to be added to uid cgroup 
 
204
         * use_hierachy=1 must be set here, but this would result
 
205
         * in impossibility to configure some job memory parameters
 
206
         * differently, so skip this stage for now
 
207
         */
 
208
 
 
209
        /* create job cgroup (it could already exist) */
 
210
        opts.uid=getuid();
 
211
        opts.gid=getgid();
 
212
        opts.create_only=0;
 
213
        opts.notify=1;
 
214
        if ( xcgroup_create(job_cgroup_path,&opts)
 
215
             != SLURM_SUCCESS )
 
216
                return SLURM_ERROR;
 
217
        
 
218
        /* job cgroup parameters must be set before any sub cgroups 
 
219
           are created */
 
220
        xcgroup_set_mem_use_hierarchy(job_cgroup_path,1);
 
221
        if ( slurm_cgroup_conf->job_cgroup_params )
 
222
                xcgroup_set_params(job_cgroup_path,
 
223
                                   slurm_cgroup_conf->job_cgroup_params);
 
224
 
 
225
        /*
 
226
         *  Warning: OOM Killer must be disabled for slurmstepd
 
227
         *  or it would be destroyed if the application use
 
228
         *  more memory than permitted
 
229
         *
 
230
         *  If an env value is already set for slurmstepd
 
231
         *  OOM killer behavior, keep it, otherwise set the 
 
232
         *  -17 value, wich means do not let OOM killer kill it
 
233
         *  
 
234
         *  FYI, setting "export SLURMSTEPD_OOM_ADJ=-17" 
 
235
         *  in /etc/sysconfig/slurm would be the same
 
236
         */
 
237
        setenv("SLURMSTEPD_OOM_ADJ","-17",0);
 
238
 
 
239
        /* 
 
240
         * FIXME!
 
241
         * Warning, with slurm-2.1.0 job_mem more corresponds to the
 
242
         * missing field jobstep_mem and thus must not be
 
243
         * trusted to set the job mem limit constraint
 
244
         * Due to the lack of jobstep_mem field in slurm-2.1.0
 
245
         * we only allow to extend the amount of allowed memory
 
246
         * as a step requiring less than the max allowed amount
 
247
         * for the job could otherwise reduce the allowed amount of other
 
248
         * already running steps
 
249
         * Thus, as a long as a step comes with a value that is higher
 
250
         * than the current value, we use it as it means that the
 
251
         * job is at least authorized to use this amount
 
252
         * In the future, a jobstep_mem field should be added
 
253
         * to avoid this workaround and be more deterministic
 
254
         *
 
255
         * Unfortunately with this workaround comes a collateral problem ! 
 
256
         * As we propose to alter already fixed limits for both mem and 
 
257
         * mem+swap, we have to respect a certain order while doing the
 
258
         * modification to respect the kernel cgroup implementation
 
259
         * requirements : when sets, memory limit must be lower or equal
 
260
         * to memory+swap limit
 
261
         *
 
262
         * Notes : a limit value of -1 means that the limit was not
 
263
         * previously set
 
264
         * Notes : this whole part should be much more simpler when 
 
265
         * the jobstep_mem field will be added
 
266
         *
 
267
         */
 
268
 
 
269
        /*
 
270
         * Get current limits for both mem and mem+swap
 
271
         */
 
272
        xcgroup_get_memlimit(job_cgroup_path,&cur_memlimit);
 
273
        xcgroup_get_memswlimit(job_cgroup_path,&cur_memswlimit);
 
274
 
 
275
        /* 
 
276
         * set memory constraints according to cgroup conf
 
277
         */
 
278
        if ( slurm_cgroup_conf->constrain_ram_space &&
 
279
             cur_memlimit == -1 ) {
 
280
                uint32_t limit;
 
281
                limit = (uint32_t) job->job_mem ;
 
282
                limit = (uint32_t) limit *
 
283
                        ( slurm_cgroup_conf->allowed_ram_space / 100.0 ) ;
 
284
                xcgroup_set_memlimit(job_cgroup_path,limit);
 
285
        }
 
286
        if ( slurm_cgroup_conf->constrain_swap_space ) {
 
287
                uint32_t limit,memlimit,swaplimit;
 
288
                memlimit = (uint32_t) job->job_mem ;
 
289
                swaplimit = memlimit ;
 
290
                memlimit = (uint32_t) memlimit * 
 
291
                        ( slurm_cgroup_conf->allowed_ram_space / 100.0 ) ;
 
292
                swaplimit = (uint32_t) swaplimit * 
 
293
                        ( slurm_cgroup_conf->allowed_swap_space / 100.0 ) ;
 
294
                limit = memlimit + swaplimit ;
 
295
                /* 
 
296
                 * if memlimit was not set in the previous block, 
 
297
                 * we have to set it here or it will not be possible 
 
298
                 * to set mem+swap limit as the mem limit value could be
 
299
                 * higher.
 
300
                 * FIXME!
 
301
                 * However, due to the restriction mentioned in the previous
 
302
                 * block (job_mem...) if a step already set it, we will
 
303
                 * have to skip this as if the new amount is bigger
 
304
                 * we will not be allowed by the kernel to set it as 
 
305
                 * the mem+swap value will certainly be lower. In such 
 
306
                 * scenario, we will have to set memlimit after mem+swap limit
 
307
                 * to still be clean regarding to cgroup kernel implementation
 
308
                 * ( memlimit must be lower or equal to mem+swap limit when
 
309
                 * set ). See stage 2 below...
 
310
                 */
 
311
                if ( !slurm_cgroup_conf->constrain_ram_space && 
 
312
                     cur_memlimit == -1 )
 
313
                        xcgroup_set_memlimit(job_cgroup_path,limit);
 
314
                /*
 
315
                 * FIXME!
 
316
                 * for the reason why we do this, see the previous block too
 
317
                 */
 
318
 
 
319
                if ( cur_memswlimit == -1 || cur_memswlimit < limit )
 
320
                        xcgroup_set_memswlimit(job_cgroup_path,limit);
 
321
                else
 
322
                        debug3("keeping previously set mem+swap limit of %uMB"
 
323
                               " for '%s'",cur_memswlimit,job_cgroup_path);
 
324
                /* 
 
325
                 * FIXME!
 
326
                 * stage 2
 
327
                 */
 
328
                if ( !slurm_cgroup_conf->constrain_ram_space && 
 
329
                     cur_memlimit != -1 ) {
 
330
                        /*
 
331
                         * FIXME!
 
332
                         * for the reason why we do this, see the previous 
 
333
                         * block
 
334
                         */
 
335
                        if ( cur_memlimit == -1 || cur_memlimit < limit ) 
 
336
                                xcgroup_set_memlimit(job_cgroup_path,limit);
 
337
                        else
 
338
                                debug3("keeping previously set mem limit of "
 
339
                                       "%uMB for '%s'",cur_memlimit,
 
340
                                       job_cgroup_path);
 
341
                }
 
342
        }
 
343
        /*
 
344
         * FIXME!
 
345
         * yet an other stage 2 due to jobstep_mem lack... 
 
346
         * only used when ram_space constraint is enforced
 
347
         */
 
348
        if ( slurm_cgroup_conf->constrain_ram_space &&
 
349
             cur_memlimit != -1 ) {
 
350
                uint32_t limit;
 
351
                limit = (uint32_t) job->job_mem ;
 
352
                limit = (uint32_t) limit *
 
353
                        ( slurm_cgroup_conf->allowed_ram_space / 100.0 ) ;
 
354
                if ( cur_memlimit == -1 || cur_memlimit < limit )
 
355
                        xcgroup_set_memlimit(job_cgroup_path,limit);
 
356
                else
 
357
                        debug3("keeping previously set mem limit of "
 
358
                               "%uMB for '%s'",cur_memlimit,job_cgroup_path);
 
359
        }
 
360
 
 
361
        /* set cores constraints if required by conf */
 
362
        if ( slurm_cgroup_conf->constrain_cores && 
 
363
             job->job_alloc_cores ) {
 
364
                /*
 
365
                 * abstract mapping of cores in slurm must
 
366
                 * first be mapped into the machine one
 
367
                 */
 
368
                char* mach;
 
369
                if ( xcpuinfo_abs_to_mac(job->job_alloc_cores,&mach) !=
 
370
                     XCPUINFO_SUCCESS ) {
 
371
                        error("unable to convert abstract slurm allocated "
 
372
                              "cores '%s' into a valid machine map",
 
373
                              job->job_alloc_cores);
 
374
                }
 
375
                else {
 
376
                        debug3("allocated cores conversion done : "
 
377
                               "%s (abstract) -> %s (machine)",
 
378
                               job->job_alloc_cores,mach);
 
379
                        xcgroup_set_cpuset_cpus(job_cgroup_path,
 
380
                                                mach);
 
381
                        xfree(mach);
 
382
                }
 
383
        }
 
384
        else if ( ! job->job_alloc_cores ) {
 
385
                error("job_alloc_cores not defined for this job! ancestor's conf"
 
386
                      " will be used instead");
 
387
        }
 
388
 
 
389
        /* create the step sub cgroup  (it sould not already exists) */
 
390
        opts.uid=uid;
 
391
        opts.gid=gid;
 
392
        opts.create_only=1;
 
393
        opts.notify=1;
 
394
        fstatus = xcgroup_create(jobstep_cgroup_path,&opts);
 
395
        if ( fstatus != XCGROUP_SUCCESS ) {
 
396
                rmdir(job_cgroup_path);
 
397
                return fstatus;
 
398
        }
 
399
 
 
400
        /* set jobstep cgroup parameters */
 
401
        if ( slurm_cgroup_conf->jobstep_cgroup_params )
 
402
                xcgroup_set_params(jobstep_cgroup_path,
 
403
                                   slurm_cgroup_conf->jobstep_cgroup_params);
 
404
 
 
405
        return fstatus;
 
406
}
 
407
 
 
408
int _slurm_cgroup_destroy(void)
 
409
{
 
410
        if ( jobstep_cgroup_path[0] != '\0' )
 
411
                xcgroup_destroy(jobstep_cgroup_path);
 
412
        
 
413
        if ( job_cgroup_path[0] != '\0' )
 
414
                xcgroup_destroy(job_cgroup_path);
 
415
        
 
416
        if ( user_cgroup_path[0] != '\0' )
 
417
                xcgroup_destroy(user_cgroup_path);
 
418
        
 
419
        return SLURM_SUCCESS;
 
420
}
 
421
 
 
422
int _slurm_cgroup_add_pids(uint32_t id,pid_t* pids,int npids)
 
423
{
 
424
        if ( *jobstep_cgroup_path == '\0' )
 
425
                return SLURM_ERROR;
 
426
        
 
427
        return xcgroup_add_pids(jobstep_cgroup_path,pids,npids);
 
428
}
 
429
 
 
430
int
 
431
_slurm_cgroup_get_pids(uint32_t id, pid_t **pids, int *npids)
 
432
{
 
433
        if ( *jobstep_cgroup_path == '\0' )
 
434
                return SLURM_ERROR;
 
435
        
 
436
        return xcgroup_get_pids(jobstep_cgroup_path,pids,npids);
 
437
}
 
438
 
 
439
int _slurm_cgroup_set_memlimit(uint32_t id,uint32_t memlimit)
 
440
{
 
441
        if ( *jobstep_cgroup_path == '\0' )
 
442
                return SLURM_ERROR;
 
443
        
 
444
        return xcgroup_set_memlimit(jobstep_cgroup_path,memlimit);
 
445
}
 
446
 
 
447
int _slurm_cgroup_set_memswlimit(uint32_t id,uint32_t memlimit)
 
448
{
 
449
        if ( *jobstep_cgroup_path == '\0' )
 
450
                return SLURM_ERROR;
 
451
        
 
452
        return xcgroup_set_memswlimit(jobstep_cgroup_path,memlimit);
 
453
}
 
454
 
 
455
int
 
456
_slurm_cgroup_find_by_pid(uint32_t* pcont_id, pid_t pid)
 
457
{
 
458
        int fstatus;
 
459
        int rc;
 
460
        uint32_t cont_id;
 
461
        char cpath[PATH_MAX];
 
462
        char* token;
 
463
 
 
464
        fstatus = xcgroup_find_by_pid(cpath,pid);
 
465
        if (  fstatus != SLURM_SUCCESS )
 
466
                return fstatus;
 
467
 
 
468
        token = rindex(cpath,'/');
 
469
        if ( token == NULL ) {
 
470
                debug3("pid %u cgroup '%s' does not match %s cgroup pattern",
 
471
                      pid,cpath,plugin_type);
 
472
                return SLURM_ERROR;
 
473
        }
 
474
 
 
475
        rc = sscanf(token,"/%u",&cont_id);
 
476
        if ( rc == 1 ) {
 
477
                if ( pcont_id != NULL )
 
478
                        *pcont_id=cont_id;
 
479
                fstatus = SLURM_SUCCESS;
 
480
        }
 
481
        else {
 
482
                fstatus = SLURM_ERROR;
 
483
        }
 
484
 
 
485
        return fstatus;
 
486
}
 
487
 
 
488
/*
 
489
 * init() is called when the plugin is loaded, before any other functions
 
490
 * are called.  Put global initialization here.
 
491
 */
 
492
extern int init ( void )
 
493
{
 
494
        /* read cgroup configuration */
 
495
        if ( read_slurm_cgroup_conf() )
 
496
                return SLURM_ERROR;
 
497
 
 
498
        /* initialize cpuinfo internal data */
 
499
        if ( xcpuinfo_init() != XCPUINFO_SUCCESS ) {
 
500
                free_slurm_cgroup_conf();
 
501
                return SLURM_ERROR;
 
502
        }
 
503
 
 
504
        /* initialize cgroup internal data */
 
505
        if ( _slurm_cgroup_init() != SLURM_SUCCESS ) {
 
506
                xcpuinfo_fini();
 
507
                free_slurm_cgroup_conf();
 
508
                return SLURM_ERROR;
 
509
        }
 
510
 
 
511
        return SLURM_SUCCESS;
 
512
}
 
513
 
 
514
extern int fini ( void )
 
515
{
 
516
        _slurm_cgroup_destroy();
 
517
        xcpuinfo_fini();
 
518
        free_slurm_cgroup_conf();
 
519
        return SLURM_SUCCESS;
 
520
}
 
521
 
 
522
/*
 
523
 * Uses slurmd job-step manager's pid as the unique container id.
 
524
 */
 
525
extern int slurm_container_create ( slurmd_job_t *job )
 
526
{
 
527
        int fstatus;
 
528
 
 
529
        /* create a new cgroup for that container */ 
 
530
        fstatus = _slurm_cgroup_create(job,(uint32_t)job->jmgr_pid,
 
531
                                       job->uid,job->gid);
 
532
        if ( fstatus )
 
533
                return SLURM_ERROR;
 
534
 
 
535
        /* set the cgroup paths to adhoc env variables */
 
536
        env_array_overwrite(&job->env,"SLURM_JOB_CGROUP",
 
537
                            job_cgroup_path);
 
538
        env_array_overwrite(&job->env,"SLURM_STEP_CGROUP",
 
539
                            jobstep_cgroup_path);
 
540
 
 
541
        /* add slurmstepd pid to this newly created container */
 
542
        fstatus = _slurm_cgroup_add_pids((uint32_t)job->jmgr_pid,
 
543
                                         &(job->jmgr_pid),1);
 
544
        if ( fstatus ) {
 
545
                _slurm_cgroup_destroy();                
 
546
                return SLURM_ERROR;
 
547
        }
 
548
 
 
549
        /* we use slurmstepd pid as the identifier of the container 
 
550
         * the corresponding cgroup could be found using
 
551
         * _slurm_cgroup_find_by_pid */
 
552
        job->cont_id = (uint32_t)job->jmgr_pid;
 
553
 
 
554
        return SLURM_SUCCESS;
 
555
}
 
556
 
 
557
extern int slurm_container_add ( slurmd_job_t *job, pid_t pid )
 
558
{
 
559
        return _slurm_cgroup_add_pids(job->cont_id,&pid,1);
 
560
}
 
561
 
 
562
extern int slurm_container_signal ( uint32_t id, int signal )
 
563
{
 
564
        pid_t* pids = NULL;
 
565
        int npids;
 
566
        int i;
 
567
 
 
568
        if ( _slurm_cgroup_get_pids(id,&pids,&npids) !=
 
569
             SLURM_SUCCESS ) {
 
570
                error("unable to get pids list for cont_id=%u",id);
 
571
                return SLURM_ERROR;
 
572
        }
 
573
        
 
574
        for ( i = 0 ; i<npids ; i++ ) {
 
575
                /* do not kill slurmstepd */
 
576
                if ( pids[i] != id ) {
 
577
                        debug2("killing process %d with signal %d",
 
578
                               pids[i],signal);
 
579
                        kill(pids[i],signal);
 
580
                }
 
581
        }
 
582
        
 
583
        xfree(pids);
 
584
        
 
585
        return SLURM_SUCCESS;
 
586
}
 
587
 
 
588
extern int slurm_container_destroy ( uint32_t id )
 
589
{
 
590
        _slurm_cgroup_destroy();
 
591
        return SLURM_SUCCESS;
 
592
}
 
593
 
 
594
extern uint32_t slurm_container_find(pid_t pid)
 
595
{
 
596
        uint32_t cont_id=-1;
 
597
        _slurm_cgroup_find_by_pid(&cont_id,pid);
 
598
        return cont_id;
 
599
}
 
600
 
 
601
extern bool slurm_container_has_pid(uint32_t cont_id, pid_t pid)
 
602
{
 
603
        int fstatus;
 
604
        uint32_t lid;
 
605
 
 
606
        fstatus = _slurm_cgroup_find_by_pid(&lid,pid);
 
607
        if ( fstatus != SLURM_SUCCESS )
 
608
                return false;
 
609
 
 
610
        if ( lid == cont_id )
 
611
                return true;
 
612
        else
 
613
                return false;
 
614
 
 
615
}
 
616
 
 
617
extern int slurm_container_wait(uint32_t cont_id)
 
618
{
 
619
        int delay = 1;
 
620
 
 
621
        if (cont_id == 0 || cont_id == 1) {
 
622
                errno = EINVAL;
 
623
                return SLURM_ERROR;
 
624
        }
 
625
 
 
626
        /* Spin until the container is successfully destroyed */
 
627
        while (slurm_container_destroy(cont_id) != SLURM_SUCCESS) {
 
628
                slurm_container_signal(cont_id, SIGKILL);
 
629
                sleep(delay);
 
630
                if (delay < 120) {
 
631
                        delay *= 2;
 
632
                } else {
 
633
                        error("Unable to destroy container %u", cont_id);
 
634
                }
 
635
        }
 
636
 
 
637
        return SLURM_SUCCESS;
 
638
}
 
639
 
 
640
extern int slurm_container_get_pids(uint32_t cont_id, pid_t **pids, int *npids)
 
641
{
 
642
        return _slurm_cgroup_get_pids(cont_id,pids,npids);
 
643
}