From 8403967669eaa9405a43d430b4ac7e5f0ea1b75e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 2 Feb 2022 15:31:33 +0100 Subject: [PATCH] alsactl: add locking for per-card initialization Introduce the -K,--lock-dir parameter to specify the locking directory. If the locking is active, files card.lock are used to serialize the multiple initialization requests (udev, service). Allow the relative -O,--lock-file argument (it's default now). Signed-off-by: Jaroslav Kysela --- alsactl/Makefile.am | 3 ++- alsactl/alsactl.c | 5 ++++ alsactl/alsactl.h | 7 +++++- alsactl/lock.c | 56 +++++++++++++++++++++++++++++++++++++++------ alsactl/state.c | 18 +++++++++++++-- alsactl/utils.c | 2 +- 6 files changed, 79 insertions(+), 12 deletions(-) diff --git a/alsactl/Makefile.am b/alsactl/Makefile.am index deff2cd1e..3d2f6e82b 100644 --- a/alsactl/Makefile.am +++ b/alsactl/Makefile.am @@ -14,7 +14,8 @@ alsactl_SOURCES=alsactl.c state.c lock.c utils.c init_parse.c init_ucm.c \ alsactl_CFLAGS=$(AM_CFLAGS) -D__USE_GNU \ -DSYS_ASOUNDRC=\"$(ASOUND_STATE_DIR)/asound.state\" \ - -DSYS_LOCKFILE=\"$(ASOUND_LOCK_DIR)/asound.state.lock\" \ + -DSYS_LOCKPATH=\"$(ASOUND_LOCK_DIR)\" \ + -DSYS_LOCKFILE=\"asound.state.lock\" \ -DSYS_PIDFILE=\"$(ALSACTL_PIDFILE_DIR)/alsactl.pid\" noinst_HEADERS=alsactl.h list.h init_sysdeps.c init_utils_string.c \ diff --git a/alsactl/alsactl.c b/alsactl/alsactl.c index ecc5d2862..9719b8384 100644 --- a/alsactl/alsactl.c +++ b/alsactl/alsactl.c @@ -51,6 +51,7 @@ int do_lock = 0; int use_syslog = 0; char *command; char *statefile = NULL; +char *lockpath = SYS_LOCKPATH; char *lockfile = SYS_LOCKFILE; #define TITLE 0x0100 @@ -79,6 +80,7 @@ static struct arg args[] = { { FILEARG | 'a', "config-dir", "boot / hotplug configuration directory (default " SYS_ASOUND_DIR ")" }, { 'l', "lock", "use file locking to serialize concurrent access" }, { 'L', "no-lock", "do not use file locking to serialize concurrent access" }, +{ FILEARG | 'K', "lock-dir", "lock path (default " SYS_LOCKPATH ")" }, { FILEARG | 'O', "lock-state-file", "state lock file path (default " SYS_LOCKFILE ")" }, { 'F', "force", "try to restore the matching controls as much as possible" }, { 0, NULL, " (default mode)" }, @@ -306,6 +308,9 @@ int main(int argc, char *argv[]) case 'L': do_lock = -1; break; + case 'K': + lockpath = optarg; + break; case 'O': lockfile = optarg; break; diff --git a/alsactl/alsactl.h b/alsactl/alsactl.h index d0dd7ebc8..2f925700b 100644 --- a/alsactl/alsactl.h +++ b/alsactl/alsactl.h @@ -1,6 +1,8 @@ #include #include +#define LOCK_TIMEOUT 10 + extern int debugflag; extern int force_restore; extern int ignore_nocards; @@ -8,6 +10,7 @@ extern int do_lock; extern int use_syslog; extern char *command; extern char *statefile; +extern char *lockpath; extern char *lockfile; struct snd_card_iterator { @@ -50,7 +53,9 @@ int load_configuration(const char *file, snd_config_t **top, int *open_failed); int init(const char *cfgdir, const char *file, int flags, const char *cardname); int init_ucm(int flags, int cardno); int state_lock(const char *file, int timeout); -int state_unlock(int fd, const char *file); +int state_unlock(int lock_fd, const char *file); +int card_lock(int card_number, int timeout); +int card_unlock(int lock_fd, int card_number); int save_state(const char *file, const char *cardname); int load_state(const char *cfgdir, const char *file, const char *initfile, int initflags, diff --git a/alsactl/lock.c b/alsactl/lock.c index 0238e95b7..64bdaff85 100644 --- a/alsactl/lock.c +++ b/alsactl/lock.c @@ -32,6 +32,8 @@ #include #include "alsactl.h" +#define PATH_SIZE 512 + static int alarm_flag; static void signal_handler_alarm(int sig) @@ -39,7 +41,7 @@ static void signal_handler_alarm(int sig) alarm_flag = 1; } -static int state_lock_(int lock, int timeout, int _fd) +static int state_lock_(const char *lock_file, int lock, int timeout, int _fd) { int fd = -1, err = 0; struct flock lck; @@ -47,7 +49,6 @@ static int state_lock_(int lock, int timeout, int _fd) char lcktxt[14]; struct sigaction sig_alarm, sig_alarm_orig; struct itimerval itv; - char *nfile = lockfile; if (do_lock <= 0) return 0; @@ -64,20 +65,20 @@ static int state_lock_(int lock, int timeout, int _fd) fd = _fd; } while (fd < 0 && timeout-- > 0) { - fd = open(nfile, O_RDWR); + fd = open(lock_file, O_RDWR); if (!lock && fd < 0) { err = -EIO; goto out; } if (fd < 0) { - fd = open(nfile, O_RDWR|O_CREAT|O_EXCL, 0644); + fd = open(lock_file, O_RDWR|O_CREAT|O_EXCL, 0644); if (fd < 0) { if (errno == EBUSY || errno == EAGAIN) { sleep(1); continue; } if (errno == EEXIST) { - fd = open(nfile, O_RDWR); + fd = open(lock_file, O_RDWR); if (fd >= 0) break; } @@ -147,11 +148,21 @@ static int state_lock_(int lock, int timeout, int _fd) return err; } +static void state_lock_file(char *buf, size_t buflen) +{ + if (lockfile[0] == '/') + snprintf(buf, buflen, "%s", lockfile); + else + snprintf(buf, buflen, "%s/%s", lockpath, lockfile); +} + int state_lock(const char *file, int timeout) { + char fn[PATH_SIZE]; int err; - err = state_lock_(1, timeout, -1); + state_lock_file(fn, sizeof(fn)); + err = state_lock_(fn, 1, timeout, -1); if (err < 0) error("file %s lock error: %s", file, strerror(-err)); return err; @@ -159,10 +170,41 @@ int state_lock(const char *file, int timeout) int state_unlock(int _fd, const char *file) { + char fn[PATH_SIZE]; int err; - err = state_lock_(0, 10, _fd); + state_lock_file(fn, sizeof(fn)); + err = state_lock_(fn, 0, 10, _fd); if (err < 0) error("file %s unlock error: %s", file, strerror(-err)); return err; } + +static void card_lock_file(char *buf, size_t buflen, int card_number) +{ + snprintf(buf, buflen, "%s/card%i.lock", lockpath, card_number); +} + +int card_lock(int card_number, int timeout) +{ + char fn[PATH_SIZE]; + int err; + + card_lock_file(fn, sizeof(fn), card_number); + err = state_lock_(fn, 1, timeout, -1); + if (err < 0) + error("card %d lock error: %s", card_number, strerror(-err)); + return err; +} + +int card_unlock(int _fd, int card_number) +{ + char fn[PATH_SIZE]; + int err; + + card_lock_file(fn, sizeof(fn), card_number); + err = state_lock_(fn, 0, 10, _fd); + if (err < 0) + error("card %d unlock error: %s", card_number, strerror(-err)); + return err; +} diff --git a/alsactl/state.c b/alsactl/state.c index d943df43c..93f38883f 100644 --- a/alsactl/state.c +++ b/alsactl/state.c @@ -1614,7 +1614,7 @@ int save_state(const char *file, const char *cardname) } strcpy(nfile, file); strcat(nfile, ".new"); - lock_fd = state_lock(file, 10); + lock_fd = state_lock(file, LOCK_TIMEOUT); if (lock_fd < 0) { err = lock_fd; goto out; @@ -1675,7 +1675,7 @@ int load_state(const char *cfgdir, const char *file, const char *initfile, int initflags, const char *cardname, int do_init) { - int err, finalerr = 0, open_failed; + int err, finalerr = 0, open_failed, lock_fd; struct snd_card_iterator iter; snd_config_t *config; const char *cardname1; @@ -1695,7 +1695,14 @@ int load_state(const char *cfgdir, const char *file, while ((cardname1 = snd_card_iterator_next(&iter)) != NULL) { if (!do_init) break; + lock_fd = card_lock(iter.card, LOCK_TIMEOUT); + if (lock_fd < 0) { + finalerr = lock_fd; + initfailed(iter.card, "lock", err); + continue; + } err = init(cfgdir, initfile, initflags | FLAG_UCM_FBOOT | FLAG_UCM_BOOT, cardname1); + card_unlock(lock_fd, iter.card); if (err < 0) { finalerr = err; initfailed(iter.card, "init", err); @@ -1712,6 +1719,12 @@ int load_state(const char *cfgdir, const char *file, if (err < 0) goto out; while ((cardname1 = snd_card_iterator_next(&iter)) != NULL) { + lock_fd = card_lock(iter.card, LOCK_TIMEOUT); + if (lock_fd < 0) { + initfailed(iter.card, "lock", lock_fd); + finalerr = lock_fd; + continue; + } /* error is ignored */ init_ucm(initflags | FLAG_UCM_FBOOT, iter.card); /* do a check if controls matches state file */ @@ -1727,6 +1740,7 @@ int load_state(const char *cfgdir, const char *file, finalerr = err; initfailed(iter.card, "restore", err); } + card_unlock(lock_fd, iter.card); } err = finalerr ? finalerr : snd_card_iterator_error(&iter); out: diff --git a/alsactl/utils.c b/alsactl/utils.c index a50797259..d8cbf5355 100644 --- a/alsactl/utils.c +++ b/alsactl/utils.c @@ -211,7 +211,7 @@ int load_configuration(const char *file, snd_config_t **top, int *open_failed) if (stdio_flag) { err = snd_input_stdio_attach(&in, stdin, 0); } else { - lock_fd = state_lock(file, 10); + lock_fd = state_lock(file, LOCK_TIMEOUT); err = lock_fd >= 0 ? snd_input_stdio_open(&in, file, "r") : lock_fd; } if (err < 0) {