[PATCH 1/2] nilfs-utils: use posix semaphore for making fs-operation exclusive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Ryusuke Konishi <ryusuke@xxxxxxxx>

This uses posix named semaphores instead of advisory lock of fcntl to
implement mutex between nilfs tools and the cleaner daemon.  With this
change, the .nilfs file will be no longer required for the locking
purpose.

Signed-off-by: Ryusuke Konishi <ryusuke@xxxxxxxx>
Cc: dexen deVries <dexen.devries@xxxxxxxxx>
Cc: Reinoud Zandijk <reinoud@xxxxxxxxxx>
---
 bin/Makefile.am             |    9 +------
 bin/chcp.c                  |    6 ++--
 bin/mkcp.c                  |    6 ++--
 configure.ac                |    7 +++++-
 include/nilfs.h             |   38 +++++++++++++++------------------
 lib/Makefile.am             |    6 ++--
 lib/nilfs.c                 |   49 +++++++++++++++++++++++++++++++++++++++++-
 sbin/cleanerd/Makefile.am   |    4 +-
 sbin/cleanerd/cleanerd.c    |    7 +++--
 sbin/nilfs-tune/Makefile.am |    4 +-
 10 files changed, 89 insertions(+), 47 deletions(-)

diff --git a/bin/Makefile.am b/bin/Makefile.am
index 6516ede..98fa83a 100644
--- a/bin/Makefile.am
+++ b/bin/Makefile.am
@@ -1,24 +1,19 @@
 ## Makefile.am
 
-AM_CFLAGS = -Wall
+AM_CFLAGS = -Wall -pthread
 AM_CPPFLAGS = -I$(top_srcdir)/include
+LDADD = $(top_builddir)/lib/libnilfs.la -lpthread
 
 bin_PROGRAMS = chcp dumpseg lscp lssu mkcp rmcp
 
 chcp_SOURCES = chcp.c
-chcp_LDADD = $(top_builddir)/lib/libnilfs.la
 
 dumpseg_SOURCES = dumpseg.c
-dumpseg_LDADD = $(top_builddir)/lib/libnilfs.la
 
 lscp_SOURCES = lscp.c
-lscp_LDADD = $(top_builddir)/lib/libnilfs.la
 
 lssu_SOURCES = lssu.c
-lssu_LDADD = $(top_builddir)/lib/libnilfs.la
 
 mkcp_SOURCES = mkcp.c
-mkcp_LDADD = $(top_builddir)/lib/libnilfs.la
 
 rmcp_SOURCES = rmcp.c
-rmcp_LDADD = $(top_builddir)/lib/libnilfs.la
diff --git a/bin/chcp.c b/bin/chcp.c
index a66e437..ef50159 100644
--- a/bin/chcp.c
+++ b/bin/chcp.c
@@ -137,7 +137,7 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	nilfs = nilfs_open(dev, NULL, NILFS_OPEN_RDWR);
+	nilfs = nilfs_open(dev, NULL, NILFS_OPEN_RDWR | NILFS_OPEN_GCLK);
 	if (nilfs == NULL) {
 		fprintf(stderr, "%s: %s: cannot open NILFS\n", progname, dev);
 		exit(1);
@@ -145,7 +145,7 @@ int main(int argc, char *argv[])
 
 	status = 0;
 
-	if (nilfs_lock_write(nilfs) < 0) {
+	if (nilfs_lock_cleaner(nilfs) < 0) {
 		fprintf(stderr, "%s: cannot lock NILFS\n", progname);
 		status = 1;
 		goto out;
@@ -177,7 +177,7 @@ int main(int argc, char *argv[])
 		}
 	}
 
-	nilfs_unlock_write(nilfs);
+	nilfs_unlock_cleaner(nilfs);
 
  out:
 	nilfs_close(nilfs);
diff --git a/bin/mkcp.c b/bin/mkcp.c
index 716b809..2965e40 100644
--- a/bin/mkcp.c
+++ b/bin/mkcp.c
@@ -115,7 +115,7 @@ int main(int argc, char *argv[])
 	else
 		dev = argv[optind];
 
-	nilfs = nilfs_open(dev, NULL, NILFS_OPEN_RDWR);
+	nilfs = nilfs_open(dev, NULL, NILFS_OPEN_RDWR | NILFS_OPEN_GCLK);
 	if (nilfs == NULL) {
 		fprintf(stderr, "%s: %s: cannot open NILFS\n", progname, dev);
 		exit(1);
@@ -128,7 +128,7 @@ int main(int argc, char *argv[])
 		goto out;
 	}
 	if (ss) {
-		if (nilfs_lock_write(nilfs) < 0) {
+		if (nilfs_lock_cleaner(nilfs) < 0) {
 			fprintf(stderr, "%s: %s\n", progname, strerror(errno));
 			status = 1;
 			goto out;
@@ -137,7 +137,7 @@ int main(int argc, char *argv[])
 			fprintf(stderr, "%s: %s\n", progname, strerror(errno));
 			status = 1;
 		}
-		if (nilfs_unlock_write(nilfs) < 0) {
+		if (nilfs_unlock_cleaner(nilfs) < 0) {
 			fprintf(stderr, "%s: %s\n", progname, strerror(errno));
 			status = 1;
 		}
diff --git a/configure.ac b/configure.ac
index 4c5e603..9bfc8f0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,13 +33,18 @@ AC_CHECK_LIB([uuid], [uuid_generate],
 	  [Define to 1 if you have the `uuid' library (-luuid).])],
 	[AC_MSG_ERROR([UUID library not found])])
 
+AC_CHECK_LIB([pthread],[sem_open],
+	[AC_DEFINE([HAVE_LIBPTHREAD], 1,
+	  [Define to 1 if you have the `pthread' library (-lpthread).])],
+	[AC_MSG_ERROR([pthread library not found])])
+
 # Checks for header files.
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
 AC_CHECK_HEADERS([fcntl.h libintl.h limits.h locale.h mntent.h paths.h \
 		  stdlib.h string.h strings.h sys/ioctl.h sys/mount.h \
 		  sys/time.h syslog.h unistd.h linux/types.h grp.h pwd.h \
-		  mntent.h])
+		  mntent.h semaphore.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
diff --git a/include/nilfs.h b/include/nilfs.h
index af2584e..cf3bbc3 100644
--- a/include/nilfs.h
+++ b/include/nilfs.h
@@ -31,6 +31,7 @@
 #include <fcntl.h>
 #include <time.h>
 #include <sys/ioctl.h>
+#include <semaphore.h>
 #include <linux/types.h>
 #include <endian.h>
 #include <byteswap.h>
@@ -106,6 +107,8 @@ typedef __u64 nilfs_cno_t;
  * @n_iocfd: file descriptor of ioctl file
  * @n_opts: options
  * @n_mincno: the minimum of valid checkpoint numbers
+ * @n_sems: array of semaphores
+ *     sems[0] protects garbage collection process
  */
 struct nilfs {
 	struct nilfs_super_block *n_sb;
@@ -116,12 +119,14 @@ struct nilfs {
 	int n_iocfd;
 	int n_opts;
 	nilfs_cno_t n_mincno;
+	sem_t *n_sems[1];
 };
 
-#define NILFS_OPEN_RAW		0x01
-#define NILFS_OPEN_RDONLY	0x02
-#define NILFS_OPEN_WRONLY	0x04
-#define NILFS_OPEN_RDWR		0x08
+#define NILFS_OPEN_RAW		0x0001	/* Open RAW device */
+#define NILFS_OPEN_RDONLY	0x0002	/* Open NILFS API in read only mode */
+#define NILFS_OPEN_WRONLY	0x0004	/* Open NILFS API in write only mode */
+#define NILFS_OPEN_RDWR		0x0008	/* Open NILFS API in read/write mode */
+#define NILFS_OPEN_GCLK		0x1000	/* Open GC lock primitive */
 
 #define NILFS_OPT_MMAP	0x01
 
@@ -140,31 +145,22 @@ int nilfs_parse_cno_range(const char *, nilfs_cno_t *, nilfs_cno_t *, int);
 
 struct nilfs_super_block *nilfs_get_sb(struct nilfs *);
 
-static inline int nilfs_lock(struct nilfs *nilfs, int cmd, int type,
-			     off_t start, int whence, off_t len)
-{
-	struct flock flock;
-
-	flock.l_type = type;
-	flock.l_start = start;
-	flock.l_whence = whence;
-	flock.l_len = len;
-	return fcntl(nilfs->n_iocfd, cmd, &flock);
-}
 
-#define NILFS_LOCK_FNS(name, type)					\
+#define NILFS_LOCK_FNS(name, index)					\
 static inline int nilfs_lock_##name(struct nilfs *nilfs)		\
 {									\
-	return nilfs_lock(nilfs, F_SETLKW, type, 0, SEEK_SET, 1);	\
+	return sem_wait(nilfs->n_sems[index]);				\
+}									\
+static inline int nilfs_trylock_##name(struct nilfs *nilfs)		\
+{									\
+	return sem_trywait(nilfs->n_sems[index]);			\
 }									\
 static inline int nilfs_unlock_##name(struct nilfs *nilfs)		\
 {									\
-	return nilfs_lock(nilfs, F_SETLK, F_UNLCK, 0, SEEK_SET, 1);	\
+	return sem_post(nilfs->n_sems[index]);				\
 }
 
-NILFS_LOCK_FNS(read, F_RDLCK)
-NILFS_LOCK_FNS(write, F_WRLCK)
-
+NILFS_LOCK_FNS(cleaner, 0)
 
 /**
  * struct nilfs_psegment - partial segment iterator
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 2dd5491..7bfcc39 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -9,12 +9,12 @@ lib_LTLIBRARIES = libnilfs.la
 noinst_LTLIBRARIES = libnilfsmisc.la
 
 libnilfsmisc_la_SOURCES = crc32.c realpath.c
-libnilfsmisc_la_CFLAGS = -Wall -fPIC
+libnilfsmisc_la_CFLAGS = -Wall -fPIC -pthread
 libnilfsmisc_la_CPPFLAGS = -I$(top_srcdir)/include
-libnilfsmisc_la_LDFLAGS = -static
+libnilfsmisc_la_LDFLAGS = -static -lpthread
 
 libnilfs_la_SOURCES = nilfs.c sb.c cno.c $(COMMONSOURCES)
 libnilfs_la_CFLAGS = -Wall
 libnilfs_la_CPPFLAGS = -I$(top_srcdir)/include
 libnilfs_la_LDFLAGS = -version-info $(VERSIONINFO)
-libnilfs_la_LIBADD = libnilfsmisc.la
+libnilfs_la_LIBADD = libnilfsmisc.la -lpthread
diff --git a/lib/nilfs.c b/lib/nilfs.c
index 3ba5571..bc48933 100644
--- a/lib/nilfs.c
+++ b/lib/nilfs.c
@@ -270,6 +270,42 @@ int nilfs_opt_test_mmap(struct nilfs *nilfs)
 	return !!(nilfs->n_opts & NILFS_OPT_MMAP);
 }
 
+static int nilfs_open_sem(struct nilfs *nilfs)
+{
+	char semnambuf[NAME_MAX - 4];
+	struct stat stbuf;
+	int devnum;
+	int ret;
+
+	ret = stat(nilfs->n_dev, &stbuf);
+	if (ret < 0)
+		return -1;
+
+	if (S_ISBLK(stbuf.st_mode)) {
+		ret = snprintf(semnambuf, sizeof(semnambuf),
+			       "/nilfs-cleaner-%lu", stbuf.st_rdev);
+	} else if (S_ISREG(stbuf.st_mode) || S_ISDIR(stbuf.st_mode)) {
+		ret = snprintf(semnambuf, sizeof(semnambuf),
+			       "/nilfs-cleaner-%lu-%lu",
+			       stbuf.st_dev, stbuf.st_ino);
+	} else {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (ret < 0)
+		return -1;
+
+	assert(ret < sizeof(semnambuf));
+
+	nilfs->n_sems[0] = sem_open(semnambuf, O_CREAT, S_IRWXU, 1);
+	if (nilfs->n_sems[0] == SEM_FAILED) {
+		nilfs->n_sems[0] = NULL;
+		return -1;
+	}
+	return 0;
+}
+
 /**
  * nilfs_open - create a NILFS object
  * @dev: device
@@ -298,6 +334,7 @@ struct nilfs *nilfs_open(const char *dev, const char *dir, int flags)
 	nilfs->n_dev = NULL;
 	nilfs->n_ioc = NULL;
 	nilfs->n_mincno = NILFS_CNO_MIN;
+	memset(nilfs->n_sems, 0, sizeof(nilfs->n_sems));
 
 	if (flags & NILFS_OPEN_RAW) {
 		if (dev == NULL) {
@@ -344,11 +381,17 @@ struct nilfs *nilfs_open(const char *dev, const char *dir, int flags)
 			goto out_fd;
 	}
 
+	if (flags & NILFS_OPEN_GCLK) {
+		/* Initialize cleaner semaphore */
+		if (nilfs_open_sem(nilfs) < 0)
+			goto out_fd;
+	}
+
 	/* success */
 	return nilfs;
 
 	/* error */
- out_fd:
+out_fd:
 	if (nilfs->n_devfd >= 0)
 		close(nilfs->n_devfd);
 	if (nilfs->n_iocfd >= 0)
@@ -360,7 +403,7 @@ struct nilfs *nilfs_open(const char *dev, const char *dir, int flags)
 	if (nilfs->n_sb != NULL)
 		free(nilfs->n_sb);
 
- out_nilfs:
+out_nilfs:
 	free(nilfs);
 	return NULL;
 }
@@ -371,6 +414,8 @@ struct nilfs *nilfs_open(const char *dev, const char *dir, int flags)
  */
 void nilfs_close(struct nilfs *nilfs)
 {
+	if (nilfs->n_sems[0] != NULL)
+		sem_close(nilfs->n_sems[0]);
 	if (nilfs->n_devfd >= 0)
 		close(nilfs->n_devfd);
 	if (nilfs->n_iocfd >= 0)
diff --git a/sbin/cleanerd/Makefile.am b/sbin/cleanerd/Makefile.am
index 34e48c5..d72483a 100644
--- a/sbin/cleanerd/Makefile.am
+++ b/sbin/cleanerd/Makefile.am
@@ -1,12 +1,12 @@
 ## Makefile.am
 
 sbin_PROGRAMS = nilfs_cleanerd
+LDADD = $(top_builddir)/lib/libnilfs.la -lpthread
 
 nilfs_cleanerd_SOURCES = cleanerd.c cldconfig.c vector.c \
 	cleanerd.h cldconfig.h vector.h
-nilfs_cleanerd_CFLAGS = -Wall
+nilfs_cleanerd_CFLAGS = -Wall -pthread
 nilfs_cleanerd_CPPFLAGS = -I$(top_srcdir)/include \
 	-DSYSCONFDIR=\"$(sysconfdir)\"
-nilfs_cleanerd_LDADD = $(top_builddir)/lib/libnilfs.la
 
 dist_sysconf_DATA = nilfs_cleanerd.conf
diff --git a/sbin/cleanerd/cleanerd.c b/sbin/cleanerd/cleanerd.c
index d717079..b0a77fe 100644
--- a/sbin/cleanerd/cleanerd.c
+++ b/sbin/cleanerd/cleanerd.c
@@ -194,7 +194,8 @@ nilfs_cleanerd_create(const char *dev, const char *dir, const char *conffile)
 	memset(cleanerd, 0, sizeof(*cleanerd));
 
 	cleanerd->c_nilfs = nilfs_open(dev, dir,
-				       NILFS_OPEN_RAW | NILFS_OPEN_RDWR);
+				       NILFS_OPEN_RAW | NILFS_OPEN_RDWR |
+				       NILFS_OPEN_GCLK);
 	if (cleanerd->c_nilfs == NULL) {
 		syslog(LOG_ERR, "cannot open nilfs on %s: %s", dev,
 		       strerror(errno));
@@ -955,7 +956,7 @@ static ssize_t nilfs_cleanerd_clean_segments(struct nilfs_cleanerd *cleanerd,
 	if (ret < 0)
 		goto out_vec;
 
-	ret = nilfs_lock_write(cleanerd->c_nilfs);
+	ret = nilfs_lock_cleaner(cleanerd->c_nilfs);
 	if (ret < 0)
 		goto out_vec;
 
@@ -1002,7 +1003,7 @@ static ssize_t nilfs_cleanerd_clean_segments(struct nilfs_cleanerd *cleanerd,
 	}
 
  out_lock:
-	if (nilfs_unlock_write(cleanerd->c_nilfs) < 0)
+	if (nilfs_unlock_cleaner(cleanerd->c_nilfs) < 0)
 		ret = -1;
 
  out_vec:
diff --git a/sbin/nilfs-tune/Makefile.am b/sbin/nilfs-tune/Makefile.am
index e29ba2e..270dd7b 100644
--- a/sbin/nilfs-tune/Makefile.am
+++ b/sbin/nilfs-tune/Makefile.am
@@ -1,9 +1,9 @@
 ## Makefile.am
 
-AM_CFLAGS = -Wall
+AM_CFLAGS = -Wall -pthread
 AM_CPPFLAGS = -I$(top_srcdir)/include
+LDADD = $(top_builddir)/lib/libnilfs.la -lpthread
 
 sbin_PROGRAMS = nilfs-tune
 
 nilfs_tune_SOURCES = nilfs-tune.c
-nilfs_tune_LDADD = $(top_builddir)/lib/libnilfs.la
-- 
1.7.3.5

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux BTRFS]     [Linux CIFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux