{"id":438,"date":"2015-03-21T14:42:47","date_gmt":"2015-03-21T13:42:47","guid":{"rendered":"http:\/\/queen.run.montefiore.ulg.ac.be\/~barbette\/?p=438"},"modified":"2015-03-21T14:50:59","modified_gmt":"2015-03-21T13:50:59","slug":"sysfs-entries","status":"publish","type":"post","link":"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/","title":{"rendered":"sysfs entries"},"content":{"rendered":"<p>Entries in the <em>\/sys<\/em> folder are represented by &#8220;<em>struct kobject<\/em>&#8220;.<\/p>\n<p>A <em>kobject<\/em> is &#8230; a kernel object. So it can be anything. Regarding the \/sys system, <em>kobject<\/em> can be more or less thinked as a &#8220;folder&#8221; of \/sys. To obtain the &#8220;kobject&#8221; entry for \/sys of an md device, one can do<em>\u00a0&amp;disk_to_dev(mddev-&gt;gendisk)-&gt;kobj<\/em>. This object will handle the &#8220;folder&#8221;\u00a0<em>\/sys\/block\/md\/mdX\/<\/em> where X is the number of the md device.<\/p>\n<p>To initialize your own <em>kobject<\/em> and add it as a child of the <em>kobject<\/em> of the <em>mddev<\/em>, one can use\u00a0<em>kobject_init_and_add(yourobject, &amp;yourobect_type,<\/em><br \/>\n<em> &amp;disk_to_dev(mddev-&gt;gendisk)-&gt;kobj, &#8220;%s&#8221;, &#8220;foldername&#8221;)<\/em>; In practice this will create a folder named &#8220;foldername&#8221; in \/sys\/block\/md\/mdX\/.<\/p>\n<p>&#8220;<em>yourobject<\/em>&#8221; should be a pointer to your <em>kobject<\/em>. It must be persistent, allocated with <em>kmalloc<\/em> or something like that and not in your function stack, even if you don&#8217;t plan to modify it. As <em>kobject<\/em> are more or less anything, you have to describe your <em>kobject<\/em> by passing to <em>kobject_init_and_add<\/em> a <em>struct kobj_type<\/em><\/p>\n<p><em>static struct kobj_type myobject_ktype = {<\/em><br \/>\n<em> .release = release_function,<\/em><br \/>\n<em> .sysfs_ops = &amp;myobject_sysfs_ops,<\/em><br \/>\n<em>};\u00a0<\/em><\/p>\n<p><em>release<\/em>\u00a0is the function which will be called when it&#8217;s time to destroy your kobject, while <em>sysfs_ops is a struct sys_ops<\/em>. We&#8217;ll come back to them later.<\/p>\n<p>The &#8220;files&#8221; in your sys folder are represented by<em>\u00a0struct attribute<\/em>. You have two choices here. Either the files in your folder do not change, and you add all the attribute as the &#8220;default list&#8221;of attributesof your kobject\u00a0<strong>before the kobject initialisation\u00a0<\/strong>\u00a0, or you start with an empty kobject (or with some default files in the list but not all) and you add some files\u00a0<strong>after kobject initialization<\/strong> using\u00a0<em>sysfs_create_file(yourobject, attr);<\/em> where attr is a pointer to the attribute that you want to add. We&#8217;ll consider that all files are known in advance and we&#8217;ll put everything in the &#8220;default&#8221; list.<\/p>\n<p>The &#8220;default&#8221; list is more a default array and is referenced\u00a0via\u00a0\u00a0<em>yourobject_ktype.default_attr .<\/em>\u00a0It is a pointer to the array of pointer to attributes. Yes, re-read that sentence twice \ud83d\ude09 It means you&#8217;ll give an array of pointer to attributes and not an array of attributes.<\/p>\n<p><em>struct attribute **all_attrs;<br \/>\nall_attrs = \u00a0kzalloc(sizeof(struct attribute *) * number_of_files);<br \/>\n<em>attrs = \u00a0kzalloc(sizeof(struct attribute) * number_of_files);<\/em><br \/>\n<\/em><em>[fill attrs]<br \/>\nfor (i = 0; i &lt; number_of_files;i++)<br \/>\nall_attrs[i] = &amp;attrs[i];<br \/>\n<\/em><em>yourobject_ktype.default_attrs =<em>all_attrs<\/em>;<\/em><\/p>\n<p>If we look at struct attributes it contains :<\/p>\n<p><em>struct attribute {<\/em><br \/>\n<em> const char *name;<\/em><br \/>\n<em> mode_t mode;<\/em><br \/>\n<em>};<\/em><\/p>\n<p>You should find by yourself how to initialize the attrs. Note that name is a char pointer, and in noway can store character themselves. So you need to allocate somewhere all the names of your attributes, and obviously not on your function stack&#8230;<\/p>\n<p>Now, let&#8217;s go back to the\u00a0<em><em>myobject_sysfs_ops<\/em><\/em> which describes how to read and write to these attributes<\/p>\n<p>The main two\u00a0functions in the sys_ops are <em>show<\/em> an <em>store<\/em><\/p>\n<p><em>static const struct sysfs_ops\u00a0<em>myobject_sysfs_ops<\/em>\u00a0= {<\/em><br \/>\n<em> .show = myobject_attr_show,<\/em><br \/>\n<em> .store = myobject_attr_store,<\/em><br \/>\n<em>};<\/em><\/p>\n<p>These two functions will be called when any kobject attr is read or written in your kobject entry. Let&#8217;s see the show function\u00a0:<\/p>\n<p><em>static ssize_t<\/em><br \/>\n<em>myobject_attr_show(struct kobject *kobj, struct attribute *attr, char *page)<\/em><br \/>\n<em>{}<\/em><\/p>\n<p>kobj is the pointer to your kobject, the attr is the attribute the user is trying to read and the page is a pointer to a space where you should print the content which was trying to be read.<\/p>\n<p>The function\u00a0<em>container_of()<\/em> is very usefull and often used in this case. Let&#8217;s say your kobject is stored in another structure, that we will call &#8220;struct conf&#8221; in our example. To recover the conf storing the kobject, one can do :<\/p>\n<p><em>struct conf* conf = container_of(kobj, struct conf, kobj);<\/em><\/p>\n<p>And you can use the attribute name to find what to write in the page.<\/p>\n<p><strong>This should be sufficient for most usage, using some tricks to respond according the attribute name.<\/strong><\/p>\n<p>If the treatment need to be specific\u00a0according to the attribute\/file, or if you absolutely need to store some data with each attribute,\u00a0you have to allocate another bigger structure which contains the struct attr, this explains by the way why you give pointer to attributes and not an array of attributes to the ktype, because attributes could be scattered inside an array of a bigger structure. As an exemple, here the per-file structure of the md driver :<\/p>\n<p><em>struct md_sysfs_entry {<\/em><br \/>\n<em> struct attribute attr;<\/em><br \/>\n<em> ssize_t (*show)(struct mddev *, char *);<\/em><br \/>\n<em> ssize_t (*store)(struct mddev *, const char *, size_t);<\/em><br \/>\n<em>};<\/em><\/p>\n<p>The default_attributes cointains pointers to all the md_sysfs_entry-&gt;attr. And the show function of the kobject use cointainer_of() to find the md_sysfs_entry containing the attr. Then it calls the specific show and store functions of the md_sysfs_entry instead of doing something similar for all attributes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Entries in the \/sys folder are represented by &#8220;struct kobject&#8220;. A kobject is &#8230; a kernel object. So it can be anything. Regarding the \/sys system, kobject can be more or less thinked as a &#8220;folder&#8221; of \/sys. To obtain the &#8220;kobject&#8221; entry for \/sys of an md device, one can do\u00a0&amp;disk_to_dev(mddev-&gt;gendisk)-&gt;kobj. This object will &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;sysfs entries&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[18],"tags":[],"class_list":["post-438","post","type-post","status-publish","format-standard","hentry","category-os"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>sysfs entries - Tom Barbette<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"sysfs entries - Tom Barbette\" \/>\n<meta property=\"og:description\" content=\"Entries in the \/sys folder are represented by &#8220;struct kobject&#8220;. A kobject is &#8230; a kernel object. So it can be anything. Regarding the \/sys system, kobject can be more or less thinked as a &#8220;folder&#8221; of \/sys. To obtain the &#8220;kobject&#8221; entry for \/sys of an md device, one can do\u00a0&amp;disk_to_dev(mddev-&gt;gendisk)-&gt;kobj. This object will &hellip; Continue reading &quot;sysfs entries&quot;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/\" \/>\n<meta property=\"og:site_name\" content=\"Tom Barbette\" \/>\n<meta property=\"article:published_time\" content=\"2015-03-21T13:42:47+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2015-03-21T13:50:59+00:00\" \/>\n<meta name=\"author\" content=\"Tom Barbette\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@TomBarbette\" \/>\n<meta name=\"twitter:site\" content=\"@TomBarbette\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tom Barbette\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/sysfs-entries\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/sysfs-entries\\\/\"},\"author\":{\"name\":\"Tom Barbette\",\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/#\\\/schema\\\/person\\\/7f791766092e1207bc7a94a65e74f4fd\"},\"headline\":\"sysfs entries\",\"datePublished\":\"2015-03-21T13:42:47+00:00\",\"dateModified\":\"2015-03-21T13:50:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/sysfs-entries\\\/\"},\"wordCount\":860,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/#organization\"},\"articleSection\":[\"INFO-0940 Operating Systems\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/sysfs-entries\\\/\",\"url\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/sysfs-entries\\\/\",\"name\":\"sysfs entries - Tom Barbette\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/#website\"},\"datePublished\":\"2015-03-21T13:42:47+00:00\",\"dateModified\":\"2015-03-21T13:50:59+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/sysfs-entries\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/sysfs-entries\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/sysfs-entries\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"sysfs entries\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/#website\",\"url\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/\",\"name\":\"Tom Barbette\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/#organization\",\"name\":\"Efficiency of Networked Systems Group\",\"url\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/wp-content\\\/uploads\\\/2022\\\/04\\\/cropped-logo-uclouvain-2021-barbette.png\",\"contentUrl\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/wp-content\\\/uploads\\\/2022\\\/04\\\/cropped-logo-uclouvain-2021-barbette.png\",\"width\":512,\"height\":512,\"caption\":\"Efficiency of Networked Systems Group\"},\"image\":{\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/TomBarbette\",\"https:\\\/\\\/www.linkedin.com\\\/in\\\/tom-barbette\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/#\\\/schema\\\/person\\\/7f791766092e1207bc7a94a65e74f4fd\",\"name\":\"Tom Barbette\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/aecd99cba3b4d91d3775fde3219bfa362cd99acfbe95848ec303b9685f366fcd?s=96&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/aecd99cba3b4d91d3775fde3219bfa362cd99acfbe95848ec303b9685f366fcd?s=96&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/aecd99cba3b4d91d3775fde3219bfa362cd99acfbe95848ec303b9685f366fcd?s=96&r=g\",\"caption\":\"Tom Barbette\"},\"sameAs\":[\"https:\\\/\\\/www.tombarbette.be\"],\"url\":\"https:\\\/\\\/perso.uclouvain.be\\\/tom.barbette\\\/author\\\/tom\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"sysfs entries - Tom Barbette","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/","og_locale":"en_US","og_type":"article","og_title":"sysfs entries - Tom Barbette","og_description":"Entries in the \/sys folder are represented by &#8220;struct kobject&#8220;. A kobject is &#8230; a kernel object. So it can be anything. Regarding the \/sys system, kobject can be more or less thinked as a &#8220;folder&#8221; of \/sys. To obtain the &#8220;kobject&#8221; entry for \/sys of an md device, one can do\u00a0&amp;disk_to_dev(mddev-&gt;gendisk)-&gt;kobj. This object will &hellip; Continue reading \"sysfs entries\"","og_url":"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/","og_site_name":"Tom Barbette","article_published_time":"2015-03-21T13:42:47+00:00","article_modified_time":"2015-03-21T13:50:59+00:00","author":"Tom Barbette","twitter_card":"summary_large_image","twitter_creator":"@TomBarbette","twitter_site":"@TomBarbette","twitter_misc":{"Written by":"Tom Barbette","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/#article","isPartOf":{"@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/"},"author":{"name":"Tom Barbette","@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/#\/schema\/person\/7f791766092e1207bc7a94a65e74f4fd"},"headline":"sysfs entries","datePublished":"2015-03-21T13:42:47+00:00","dateModified":"2015-03-21T13:50:59+00:00","mainEntityOfPage":{"@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/"},"wordCount":860,"commentCount":0,"publisher":{"@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/#organization"},"articleSection":["INFO-0940 Operating Systems"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/","url":"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/","name":"sysfs entries - Tom Barbette","isPartOf":{"@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/#website"},"datePublished":"2015-03-21T13:42:47+00:00","dateModified":"2015-03-21T13:50:59+00:00","breadcrumb":{"@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/sysfs-entries\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/perso.uclouvain.be\/tom.barbette\/"},{"@type":"ListItem","position":2,"name":"sysfs entries"}]},{"@type":"WebSite","@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/#website","url":"https:\/\/perso.uclouvain.be\/tom.barbette\/","name":"Tom Barbette","description":"","publisher":{"@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/perso.uclouvain.be\/tom.barbette\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/#organization","name":"Efficiency of Networked Systems Group","url":"https:\/\/perso.uclouvain.be\/tom.barbette\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/#\/schema\/logo\/image\/","url":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-content\/uploads\/2022\/04\/cropped-logo-uclouvain-2021-barbette.png","contentUrl":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-content\/uploads\/2022\/04\/cropped-logo-uclouvain-2021-barbette.png","width":512,"height":512,"caption":"Efficiency of Networked Systems Group"},"image":{"@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/TomBarbette","https:\/\/www.linkedin.com\/in\/tom-barbette"]},{"@type":"Person","@id":"https:\/\/perso.uclouvain.be\/tom.barbette\/#\/schema\/person\/7f791766092e1207bc7a94a65e74f4fd","name":"Tom Barbette","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/aecd99cba3b4d91d3775fde3219bfa362cd99acfbe95848ec303b9685f366fcd?s=96&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/aecd99cba3b4d91d3775fde3219bfa362cd99acfbe95848ec303b9685f366fcd?s=96&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/aecd99cba3b4d91d3775fde3219bfa362cd99acfbe95848ec303b9685f366fcd?s=96&r=g","caption":"Tom Barbette"},"sameAs":["https:\/\/www.tombarbette.be"],"url":"https:\/\/perso.uclouvain.be\/tom.barbette\/author\/tom\/"}]}},"_links":{"self":[{"href":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-json\/wp\/v2\/posts\/438","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-json\/wp\/v2\/comments?post=438"}],"version-history":[{"count":1,"href":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-json\/wp\/v2\/posts\/438\/revisions"}],"predecessor-version":[{"id":439,"href":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-json\/wp\/v2\/posts\/438\/revisions\/439"}],"wp:attachment":[{"href":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-json\/wp\/v2\/media?parent=438"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-json\/wp\/v2\/categories?post=438"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/perso.uclouvain.be\/tom.barbette\/wp-json\/wp\/v2\/tags?post=438"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}