int lock_mtab (void) { int i; struct timespec waittime; struct timeval maxtime; char linktargetfile[MOUNTLOCK_LINKTARGET_LTH]; if (!signals_have_been_setup) { int sig = 0; struct sigaction sa; sa.sa_handler = handler; sa.sa_flags = 0; sigfillset (&sa.sa_mask); while (sigismember (&sa.sa_mask, ++sig) != -1 && sig != SIGCHLD) { if (sig == SIGALRM) sa.sa_handler = setlkw_timeout; else sa.sa_handler = handler; sigaction (sig, &sa, (struct sigaction *) 0); } signals_have_been_setup = 1; } sprintf(linktargetfile, MOUNTLOCK_LINKTARGET, getpid ()); i = open (linktargetfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); if (i < 0) { /* linktargetfile does not exist (as a file) and we cannot create it. Read-only filesystem? Too many files open in the system? Filesystem full? */ return EX_FILEIO; } close(i); maxtime = mono_time(); maxtime.tv_sec += MOUNTLOCK_MAXTIME; waittime.tv_sec = 0; waittime.tv_nsec = (1000 * MOUNTLOCK_WAITTIME); /* Repeat until it was us who made the link */ while (!we_created_lockfile) { struct timeval now; struct flock flock; int errsv, j; j = link(linktargetfile, _PATH_MOUNTED_LOCK); errsv = errno; if (j == 0) we_created_lockfile = 1; if (j < 0 && errsv != EEXIST) { (void) unlink(linktargetfile); return EX_FILEIO; } lockfile_fd = open (_PATH_MOUNTED_LOCK, O_WRONLY); if (lockfile_fd < 0) { /* Strange... Maybe the file was just deleted? */ now = mono_time(); if (errno == ENOENT && now.tv_sec < maxtime.tv_sec) { we_created_lockfile = 0; continue; } (void) unlink(linktargetfile); return EX_FILEIO; } flock.l_type = F_WRLCK; flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 0; if (j == 0) { /* We made the link. Now claim the lock. If we can't * get it, continue anyway */ fcntl (lockfile_fd, F_SETLK, &flock); (void) unlink(linktargetfile); } else { /* Someone else made the link. Wait. */ now = mono_time(); if (now.tv_sec < maxtime.tv_sec) { alarm(maxtime.tv_sec - now.tv_sec); if (fcntl (lockfile_fd, F_SETLKW, &flock) == -1) { (void) unlink(linktargetfile); return EX_FILEIO; } alarm(0); nanosleep(&waittime, NULL); } else { (void) unlink(linktargetfile); return EX_FILEIO; } close(lockfile_fd); } } return 0; }
int main(int argc, char **argv) { double t0, t1; if (argc != 5) { puts("Usage: syncbench file write_size write_qty (d|s)"); return 1; } if (strlen(argv[4]) != 1) { puts("You're a bad person."); return 1; } int d; if (argv[4][0] == 'd') { d = 1; } else if (argv[4][0] == 's') { d = 0; } else { puts("That last parameter should have been either 'd' or 's'."); return 1; } int write_size = atoi(argv[2]); int no_of_writes = atoi(argv[3]); if ((write_size <= 0) || (no_of_writes <= 0)) { puts("You want me to write no bytes?"); return 1; } int fd = open(argv[1], O_CREAT | O_WRONLY | O_EXCL); if (fd == -1) { if (errno == EEXIST) { printf("Refusing to nuke existing file %s.\n", argv[1]); } else { printf("Can't open %s for write.\n", argv[1]); } return 1; } char *bytes = malloc(write_size); if (bytes == NULL) { puts("malloc() failed, FML."); return 1; } int i; for (i = 0; i < write_size; i++) { bytes[i] = '0' + (i % 10); } if (mono_time(&t0)) { puts("can't consult a clock."); return 1; } for (i = 0; i < no_of_writes; i++) { ssize_t r = write(fd, bytes, write_size); if (r != write_size) { puts("write() failed."); return 1; } if (d) { if (fdatasync(fd)) { puts("fdatasync() failed."); return 1; } } else { if (fsync(fd)) { puts("fsync() failed."); return 1; } } } if (mono_time(&t1)) { puts("really, can't consult the clock?"); return 1; } char *c = d ? "fdatasync" : "fsync"; printf("Performed %d %s()s in %f seconds.\n", no_of_writes, c, t1 - t0); double rate = no_of_writes / (t1 - t0); printf("That's %f calls/second, or %f seconds/call.\n", rate, 1 / rate); return 0; }