1

I'm writing a module for the Linux kernel.

This module is exposing some I/O as a file /sys/kernel/mymodule/foo:

static struct kobj_attribute foo_attribute =__ATTR(foo, 0660, foo_show, foo_store);
...        
ret = sysfs_create_file(&mymodule->kobj, &foo_attribute.attr);

I want to be able to change the 0660 permissions to 0440 as soon as some data has been written into /sys/kernel/mymodule/foo. I will be doing this in the foo_store() function.

I have investigated the __ATTR macro - it produces an explosion of code, mostly manipulating the permissions. The code above is expanded into:

static struct foo_attribute = { .attr = {.name = "foo", .mode = ((sizeof(struct { int:-!!((0660) < 0); })) + (sizeof(struct { int:-!!((0660) > 0777); })) + (sizeof(struct { int:-!!(((0660) >> 6) < (((0660) >> 3) & 7)); })) + (sizeof(struct { int:-!!((((0660) >> 3) & 7) < ((0660) & 7)); })) + (sizeof(struct { int:-!!((0660) & 2); })) + (0660)) }, .show = foo_show, .store = foo_store, };
...
ret = sysfs_create_file(&vr2200pmu->kobj, &revision_attribute.attr);

by using gcc -E mymodule.c -I../../include -I../../arch/arm/include -I../../arch/arm/include/generated in the module's directory.

How can I achieve this in a clean, portable way?

fadedbee
  • 42,671
  • 44
  • 178
  • 308
  • It looks like the macro is simply compile-time checking the permissions, by using `sizeof(struct { int:-!!(whatever); })` which will result in a compile time error (negative length bitfield) if `whatever` is non-zero. – fadedbee Jan 26 '17 at 10:39
  • These are `BUILD_BUG_ON_ZERO` macro invocations, which check permissions validity. Just look into `__ATTR()` macro definition in [kernel source files](http://lxr.free-electrons.com/source/include/linux/sysfs.h#L100). – Tsyvarev Jan 26 '17 at 17:46

1 Answers1

2

Unsure, whether it is intended way for modify sysfs file permissions programmatically, but this should work:

// Obtain kernfs object for directory
struct kernfs_node* dir_knode = kobj->sd;
// Obtain kernfs object for file in the directory
struct kernfs_node* file_knode = sysfs_get_dirent(dir_knode, foo_attr.attr.name);
// Change permissions. Set only permissions-related bits.
file_knode->mode = (file_knode->mode & S_IFMT) | 0440;
Tsyvarev
  • 60,011
  • 17
  • 110
  • 153