gfs2-utils/bz1079286-1-libgfs2_Add_lgfs2_open_mnt_functions.patch
Andrew Price ee416b3fe3 * Fri Mar 21 2014 Andrew Price <anprice@redhat.com> - 3.1.6-6
- gfs2_grow: Don't try to open an empty string
- libgfs2: Add lgfs2 open mnt functions
- Switch is pathname mounted callers to lgfs2 open mnt
- libgfs2 Remove is pathname mounted
  Resolves: bz#1079286
2014-03-21 12:49:29 +00:00

142 lines
4.3 KiB
Diff

commit 25c6e51bb4d083eb341bbc8541bb2ad278988f10
Author: Andrew Price <anprice@redhat.com>
Date: Sat Nov 16 02:10:52 2013 -0600
libgfs2: Add lgfs2_open_mnt* functions
lgfs2_open_mnt is a replacement for is_pathname_mounted which tries to reduce
races by opening paths speculatively and passing back the open fds once they're
known to be correct. lgfs2_open_mnt_{dev,dir} build on this to provide a
convenient way to open just the device or mount directory relating to a path
which could be either.
Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index f864a08..3e5d09c 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -12,6 +12,7 @@
#include <linux/limits.h>
#include <endian.h>
#include <byteswap.h>
+#include <mntent.h>
#include <linux/gfs2_ondisk.h>
#include "osi_list.h"
@@ -715,6 +716,9 @@ extern int compute_heightsize(struct gfs2_sbd *sdp, uint64_t *heightsize,
uint32_t *maxheight, uint32_t bsize1, int diptrs, int inptrs);
extern int compute_constants(struct gfs2_sbd *sdp);
extern int is_pathname_mounted(char *path_name, char *device_name, int *ro_mount);
+extern int lgfs2_open_mnt(const char *path, int dirflags, int *dirfd, int devflags, int *devfd, struct mntent **mnt);
+extern int lgfs2_open_mnt_dev(const char *path, int flags, struct mntent **mnt);
+extern int lgfs2_open_mnt_dir(const char *path, int flags, struct mntent **mnt);
extern int find_gfs2_meta(struct gfs2_sbd *sdp);
extern int dir_exists(const char *dir);
extern int mount_gfs2_meta(struct gfs2_sbd *sdp);
diff --git a/gfs2/libgfs2/misc.c b/gfs2/libgfs2/misc.c
index 7f500e6..195b983 100644
--- a/gfs2/libgfs2/misc.c
+++ b/gfs2/libgfs2/misc.c
@@ -163,6 +163,100 @@ int is_pathname_mounted(char *path_name, char *device_name, int *ro_mount)
return 1; /* mounted */
}
+/* Returns 0 if fd1 and fd2 refer to the same device/file, 1 otherwise, or -1 on error */
+static int fdcmp(int fd1, int fd2)
+{
+ struct stat st1, st2;
+ if ((fstat(fd1, &st1) != 0) || (fstat(fd2, &st2) != 0))
+ return -1;
+ if (S_ISBLK(st1.st_mode) && S_ISBLK(st2.st_mode)) {
+ if (st1.st_rdev == st2.st_rdev) {
+ return 0;
+ }
+ } else if ((st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino)) {
+ return 0;
+ }
+ return 1;
+}
+
+int lgfs2_open_mnt(const char *path, int dirflags, int *dirfd, int devflags, int *devfd, struct mntent **mnt)
+{
+ FILE *fp = setmntent("/proc/mounts", "r");
+ if (fp == NULL) {
+ perror("open: /proc/mounts");
+ return 1;
+ }
+ /* Assume path is mount point until we know better. */
+ *dirfd = open(path, dirflags);
+ if (*dirfd < 0)
+ return 1;
+
+ while ((*mnt = getmntent(fp)) != NULL) {
+ int fd;
+ if (strcmp((*mnt)->mnt_type, "gfs2") != 0)
+ continue;
+ *devfd = open((*mnt)->mnt_fsname, devflags);
+ /* Defer checking *devfd until later: whether it's ok to ignore
+ * the error depends on whether we find the mount point. */
+
+ if (strcmp(path, (*mnt)->mnt_dir) == 0)
+ break;
+ if (strcmp(path, (*mnt)->mnt_fsname) == 0 || fdcmp(*dirfd, *devfd) == 0) {
+ /* We have a match but our above assumption was
+ incorrect and *dirfd is actually the device. */
+ close(*dirfd);
+ *dirfd = open((*mnt)->mnt_dir, dirflags);
+ break;
+ }
+
+ fd = open((*mnt)->mnt_dir, dirflags);
+ if (fd >= 0) {
+ int diff = fdcmp(*dirfd, fd);
+ close(fd);
+ if (diff == 0)
+ break;
+ }
+ if (*devfd >= 0)
+ close(*devfd);
+ }
+ endmntent(fp);
+ if (*mnt == NULL) {
+ close(*dirfd);
+ return 0; /* Success. Answer is no. Both fds closed. */
+ }
+ if (*dirfd < 0) {
+ close(*devfd);
+ return 1;
+ }
+ if (*devfd < 0) {
+ close(*dirfd);
+ return 1;
+ }
+ return 0; /* Success. Answer is yes. Both fds open. */
+}
+
+int lgfs2_open_mnt_dev(const char *path, int flags, struct mntent **mnt)
+{
+ int dirfd = -1;
+ int devfd = -1;
+ if (lgfs2_open_mnt(path, O_RDONLY, &dirfd, flags, &devfd, mnt) != 0)
+ return -1;
+ if (*mnt != NULL)
+ close(dirfd);
+ return devfd;
+}
+
+int lgfs2_open_mnt_dir(const char *path, int flags, struct mntent **mnt)
+{
+ int dirfd = -1;
+ int devfd = -1;
+ if (lgfs2_open_mnt(path, flags, &dirfd, O_RDONLY, &devfd, mnt) != 0)
+ return -1;
+ if (*mnt != NULL)
+ close(devfd);
+ return dirfd;
+}
+
static int lock_for_admin(struct gfs2_sbd *sdp)
{
int error;