Skip to content

Commit a61ea56

Browse files
sjp38torvalds
authored andcommitted
mm/damon/sysfs: link DAMON for virtual address spaces monitoring
This commit links the DAMON sysfs interface to DAMON so that users can control DAMON via the interface. In detail, this commit makes writing 'on' to 'state' file constructs DAMON contexts based on values that users have written to relevant sysfs files and start the context. It supports only virtual address spaces monitoring at the moment, though. The files hierarchy of DAMON sysfs interface after this commit is shown below. In the below figure, parents-children relations are represented with indentations, each directory is having ``/`` suffix, and files in each directory are separated by comma (","). /sys/kernel/mm/damon/admin │ kdamonds/nr_kdamonds │ │ 0/state,pid │ │ │ contexts/nr_contexts │ │ │ │ 0/operations │ │ │ │ │ monitoring_attrs/ │ │ │ │ │ │ intervals/sample_us,aggr_us,update_us │ │ │ │ │ │ nr_regions/min,max │ │ │ │ │ targets/nr_targets │ │ │ │ │ │ 0/pid_target │ │ │ │ │ │ ... │ │ │ │ ... │ │ ... The usage is straightforward. Writing a number ('N') to each 'nr_*' file makes directories named '0' to 'N-1'. Users can construct DAMON contexts by writing proper values to the files in the straightforward manner and start each kdamond by writing 'on' to 'kdamonds/<N>/state'. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: SeongJae Park <[email protected]> Cc: David Rientjes <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Jonathan Corbet <[email protected]> Cc: Shuah Khan <[email protected]> Cc: Xin Hao <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent c951cd3 commit a61ea56

File tree

1 file changed

+189
-3
lines changed

1 file changed

+189
-3
lines changed

mm/damon/sysfs.c

Lines changed: 189 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -808,22 +808,208 @@ static void damon_sysfs_kdamond_rm_dirs(struct damon_sysfs_kdamond *kdamond)
808808
kobject_put(&kdamond->contexts->kobj);
809809
}
810810

811+
static bool damon_sysfs_ctx_running(struct damon_ctx *ctx)
812+
{
813+
bool running;
814+
815+
mutex_lock(&ctx->kdamond_lock);
816+
running = ctx->kdamond != NULL;
817+
mutex_unlock(&ctx->kdamond_lock);
818+
return running;
819+
}
820+
811821
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
812822
char *buf)
813823
{
814-
return -EINVAL;
824+
struct damon_sysfs_kdamond *kdamond = container_of(kobj,
825+
struct damon_sysfs_kdamond, kobj);
826+
struct damon_ctx *ctx = kdamond->damon_ctx;
827+
bool running;
828+
829+
if (!ctx)
830+
running = false;
831+
else
832+
running = damon_sysfs_ctx_running(ctx);
833+
834+
return sysfs_emit(buf, "%s\n", running ? "on" : "off");
835+
}
836+
837+
static int damon_sysfs_set_attrs(struct damon_ctx *ctx,
838+
struct damon_sysfs_attrs *sys_attrs)
839+
{
840+
struct damon_sysfs_intervals *sys_intervals = sys_attrs->intervals;
841+
struct damon_sysfs_ul_range *sys_nr_regions =
842+
sys_attrs->nr_regions_range;
843+
844+
return damon_set_attrs(ctx, sys_intervals->sample_us,
845+
sys_intervals->aggr_us, sys_intervals->update_us,
846+
sys_nr_regions->min, sys_nr_regions->max);
847+
}
848+
849+
static void damon_sysfs_destroy_targets(struct damon_ctx *ctx)
850+
{
851+
struct damon_target *t, *next;
852+
853+
damon_for_each_target_safe(t, next, ctx) {
854+
if (ctx->ops.id == DAMON_OPS_VADDR)
855+
put_pid(t->pid);
856+
damon_destroy_target(t);
857+
}
858+
}
859+
860+
static int damon_sysfs_set_targets(struct damon_ctx *ctx,
861+
struct damon_sysfs_targets *sysfs_targets)
862+
{
863+
int i;
864+
865+
for (i = 0; i < sysfs_targets->nr; i++) {
866+
struct damon_sysfs_target *sys_target =
867+
sysfs_targets->targets_arr[i];
868+
struct damon_target *t = damon_new_target();
869+
870+
if (!t) {
871+
damon_sysfs_destroy_targets(ctx);
872+
return -ENOMEM;
873+
}
874+
if (ctx->ops.id == DAMON_OPS_VADDR) {
875+
t->pid = find_get_pid(sys_target->pid);
876+
if (!t->pid) {
877+
damon_sysfs_destroy_targets(ctx);
878+
return -EINVAL;
879+
}
880+
}
881+
damon_add_target(ctx, t);
882+
}
883+
return 0;
884+
}
885+
886+
static void damon_sysfs_before_terminate(struct damon_ctx *ctx)
887+
{
888+
struct damon_target *t, *next;
889+
890+
if (ctx->ops.id != DAMON_OPS_VADDR)
891+
return;
892+
893+
mutex_lock(&ctx->kdamond_lock);
894+
damon_for_each_target_safe(t, next, ctx) {
895+
put_pid(t->pid);
896+
damon_destroy_target(t);
897+
}
898+
mutex_unlock(&ctx->kdamond_lock);
899+
}
900+
901+
static struct damon_ctx *damon_sysfs_build_ctx(
902+
struct damon_sysfs_context *sys_ctx)
903+
{
904+
struct damon_ctx *ctx = damon_new_ctx();
905+
int err;
906+
907+
if (!ctx)
908+
return ERR_PTR(-ENOMEM);
909+
910+
err = damon_select_ops(ctx, sys_ctx->ops_id);
911+
if (err)
912+
goto out;
913+
err = damon_sysfs_set_attrs(ctx, sys_ctx->attrs);
914+
if (err)
915+
goto out;
916+
err = damon_sysfs_set_targets(ctx, sys_ctx->targets);
917+
if (err)
918+
goto out;
919+
920+
ctx->callback.before_terminate = damon_sysfs_before_terminate;
921+
return ctx;
922+
923+
out:
924+
damon_destroy_ctx(ctx);
925+
return ERR_PTR(err);
926+
}
927+
928+
static int damon_sysfs_turn_damon_on(struct damon_sysfs_kdamond *kdamond)
929+
{
930+
struct damon_ctx *ctx;
931+
int err;
932+
933+
if (kdamond->damon_ctx &&
934+
damon_sysfs_ctx_running(kdamond->damon_ctx))
935+
return -EBUSY;
936+
/* TODO: support multiple contexts per kdamond */
937+
if (kdamond->contexts->nr != 1)
938+
return -EINVAL;
939+
940+
if (kdamond->damon_ctx)
941+
damon_destroy_ctx(kdamond->damon_ctx);
942+
kdamond->damon_ctx = NULL;
943+
944+
ctx = damon_sysfs_build_ctx(kdamond->contexts->contexts_arr[0]);
945+
if (IS_ERR(ctx))
946+
return PTR_ERR(ctx);
947+
err = damon_start(&ctx, 1, false);
948+
if (err) {
949+
damon_destroy_ctx(ctx);
950+
return err;
951+
}
952+
kdamond->damon_ctx = ctx;
953+
return err;
954+
}
955+
956+
static int damon_sysfs_turn_damon_off(struct damon_sysfs_kdamond *kdamond)
957+
{
958+
if (!kdamond->damon_ctx)
959+
return -EINVAL;
960+
return damon_stop(&kdamond->damon_ctx, 1);
961+
/*
962+
* To allow users show final monitoring results of already turned-off
963+
* DAMON, we free kdamond->damon_ctx in next
964+
* damon_sysfs_turn_damon_on(), or kdamonds_nr_store()
965+
*/
815966
}
816967

817968
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
818969
const char *buf, size_t count)
819970
{
820-
return -EINVAL;
971+
struct damon_sysfs_kdamond *kdamond = container_of(kobj,
972+
struct damon_sysfs_kdamond, kobj);
973+
ssize_t ret;
974+
975+
if (!mutex_trylock(&damon_sysfs_lock))
976+
return -EBUSY;
977+
if (sysfs_streq(buf, "on"))
978+
ret = damon_sysfs_turn_damon_on(kdamond);
979+
else if (sysfs_streq(buf, "off"))
980+
ret = damon_sysfs_turn_damon_off(kdamond);
981+
else
982+
ret = -EINVAL;
983+
mutex_unlock(&damon_sysfs_lock);
984+
if (!ret)
985+
ret = count;
986+
return ret;
821987
}
822988

823989
static ssize_t pid_show(struct kobject *kobj,
824990
struct kobj_attribute *attr, char *buf)
825991
{
826-
return -EINVAL;
992+
struct damon_sysfs_kdamond *kdamond = container_of(kobj,
993+
struct damon_sysfs_kdamond, kobj);
994+
struct damon_ctx *ctx;
995+
int pid;
996+
997+
if (!mutex_trylock(&damon_sysfs_lock))
998+
return -EBUSY;
999+
ctx = kdamond->damon_ctx;
1000+
if (!ctx) {
1001+
pid = -1;
1002+
goto out;
1003+
}
1004+
mutex_lock(&ctx->kdamond_lock);
1005+
if (!ctx->kdamond)
1006+
pid = -1;
1007+
else
1008+
pid = ctx->kdamond->pid;
1009+
mutex_unlock(&ctx->kdamond_lock);
1010+
out:
1011+
mutex_unlock(&damon_sysfs_lock);
1012+
return sysfs_emit(buf, "%d\n", pid);
8271013
}
8281014

8291015
static void damon_sysfs_kdamond_release(struct kobject *kobj)

0 commit comments

Comments
 (0)