Around one year ago, the following was reported:
http://comments.gmane.org/gmane.comp.lib.libcg.devel/3116 (Error when
calling cgroup_modify_cgroup())
I ran into the very same error. Inspecting the code in libcg, it seemed
to me that the best thing to avoid that is to never attempt to write
something the user never wrote to.
That is because if the user actually tries to write to a read-only file,
we should yield an error, making skipping read-only a bad solution.
My solution is to add a field to the value structure indicating whether
or not it is dirty. That value will indicate whether or not an error in
the write-to-filesystem routine is considered fatal or not. Non-dirty
values will still be written, but their failures are not considered
fatal. cgroup_modify_cgroup then becomes a simple flusher, and the
problem goes away.
[ v2: Also mark dirty value writes using cgroup_set_value_* ]
[ v3: fail if write fails only for dirty values ]
Signed-off-by: Glauber Costa <glommer@parallels.com>
cgroup->controller[i]->values[j]->value);
free(path);
path = NULL;
+ /* don't consider error in files directly written by
+ * the user as fatal */
+ if (error && !cgroup->controller[i]->values[j]->dirty) {
+ error = 0;
+ continue;
+ }
if (error)
goto err;
+ cgroup->controller[i]->values[j]->dirty = false;
}
}
err:
*/
int cgroup_get_cgroup(struct cgroup *cgroup)
{
- int i;
+ int i, j;
char path[FILENAME_MAX];
DIR *dir = NULL;
struct dirent *ctrl_dir = NULL;
continue;
error = cgroup_fill_cgc(ctrl_dir, cgroup, cgc, i);
+ for (j = 0; j < cgc->index; j++)
+ cgc->values[j]->dirty = false;
+
if (error == ECGFAIL) {
closedir(dir);
goto unlock_error;
struct control_value {
char name[FILENAME_MAX];
char value[CG_VALUE_MAX];
+ bool dirty;
};
struct cgroup_controller {
strncpy(cntl_value->name, name, sizeof(cntl_value->name));
strncpy(cntl_value->value, value, sizeof(cntl_value->value));
+ cntl_value->dirty = true;
controller->values[controller->index] = cntl_value;
controller->index++;
struct control_value *val = controller->values[i];
if (!strcmp(val->name, name)) {
strncpy(val->value, value, CG_VALUE_MAX);
+ val->dirty = true;
return 0;
}
}
if (ret >= sizeof(val->value) || ret < 0)
return ECGINVAL;
+ val->dirty = true;
return 0;
}
}
if (ret >= sizeof(val->value) || ret < 0)
return ECGINVAL;
+ val->dirty = true;
return 0;
}
}
if (ret >= sizeof(val->value) || ret < 0)
return ECGINVAL;
+ val->dirty = true;
return 0;
}