0

I'd like to guarantee that what I write to a sysfs file (specifically the /sys/class/gpio files) is sync'd to the actual register. The code I had initially opened the file with the O_SYNC flag, which I assumed did this. However, in another piece of code, I tried using fsync(), but it failed with EINVAL, and man fsync tells me:

   EROFS, EINVAL
          fd is bound to a special file which does not support synchronization

I've checked the code for possible operations on a sysfs file, and did not find any sort of do_sync_write or do_fsync functions.

So, does the O_SYNC flag have any effect when opening a sysfs file? Shouldn't open return an error code when trying to open a file that does not support sync read/write with O_SYNC?

Regards,

Guilherme

  • Note, writing to /sys/class/gpio/export will probably not affect any register, as it is used to create other /sys files, which then can be opened to do i/o to the gpio line itself. – meuh Apr 1 '16 at 14:34
2

/sys is a completely RAM-based filesystem for access to kernel data structures. This includes the GPIO interfaces.

All you need to do is open the pseudofile normally, and use a single write to write the data. If it succeeds, and all of the data (except possibly any trailing whitespace like newlines) was written, the kernel assures you it has accepted all of it. In other words:

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#define GPIO_EXPORT_PATH "/sys/class/gpio/export"

static int gpio_export(int pin)
{
    char        buffer[32];
    ssize_t     written;
    int         fd;
    char *const q = buffer + sizeof buffer;
    char       *p = buffer + sizeof buffer;

    if (pin < 0)
        return errno = EINVAL;

    *(--p) = '\n';

    do {
        *(--p) = '0' + (pin % 10);
        pin /= 10;
    } while (pin > 0);

    do {
        fd = open(GPIO_EXPORT_PATH, O_WRONLY);
    } while (fd == -1 && errno == EINTR);
    if (fd == -1)
        return errno;

    do {
        written = write(fd, p, (size_t)(q - p));
    } while (written == -1 && errno == EINTR);
    if (written == -1) {
        const int saved_errno = errno;
        close(fd);
        return errno = saved_errno;
    }

    if (close(fd))
        return errno;

    /* Not all written?
     * It is okay if the last char, '\n' was not written. */
    if (written != (ssize_t)(q - p) &&
        written != (ssize_t)(q - 1 - p))
        return errno = EIO; /* Partial write, data not accepted! */

    return errno = 0;
}

Note that when we do the write(), we verify that all characters (except for the trailing newline) were written. This is the atomicity requirement you need. I also like to be careful, and verify that close() does not fail either. (Although it does not currently occur, it is the only way to report certain errors, so I like to be prepared for the time when those errors are reported. If they were to occur.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.