Whamcloud - gitweb
LU-10337 mdt: Allow open of open orphans 05/30405/23
authorPatrick Farrell <paf@cray.com>
Thu, 8 Mar 2018 11:47:56 +0000 (05:47 -0600)
committerOleg Drokin <green@whamcloud.com>
Mon, 29 Oct 2018 16:00:36 +0000 (16:00 +0000)
Standard open by handle behavior allows opening of open
unlinked files files.  This currently only works in Lustre
if the file is already open on the same node, which is
insufficient.

When an open file is unlinked, we make it an orphan.
These files can be recognized by checking their open count
(mod_count).  It's enough to just make opening these files
possible, because the client cannot look them up to do an
open except when using a file handle.

Cray-bug-id: LUS-2626
Change-Id: Idd7898cefcf60b28c682e578774411e476216c9e
Signed-off-by: Patrick Farrell <paf@cray.com>
Reviewed-on: https://review.whamcloud.com/30405
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Alexey Lyashkov <c17817@cray.com>
Reviewed-by: James Simmons <uja.ornl@yahoo.com>
Reviewed-by: Andrew Perepechko <c17827@cray.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/mdd/mdd_internal.h
lustre/mdd/mdd_object.c
lustre/tests/check_fhandle_syscalls.c
lustre/tests/sanity.sh
lustre/tests/sanityn.sh

index 7d50e68..78863de 100644 (file)
@@ -494,6 +494,11 @@ static inline bool mdd_is_volatile_obj(struct mdd_object *obj)
        return obj->mod_flags & VOLATILE_OBJ;
 }
 
+static inline bool mdd_is_orphan_obj(struct mdd_object *obj)
+{
+       return obj->mod_flags & ORPHAN_OBJ;
+}
+
 static inline int mdd_object_exists(struct mdd_object *obj)
 {
         return lu_object_exists(mdd2lu_obj(obj));
index 3fedd2d..1025a0d 100644 (file)
@@ -2988,8 +2988,11 @@ static int mdd_open_sanity_check(const struct lu_env *env,
        int mode, rc;
        ENTRY;
 
-       /* EEXIST check */
-       if (mdd_is_dead_obj(obj))
+       /* EEXIST check, also opening of *open* orphans is allowed so we can
+        * open-by-handle unlinked files
+        */
+       if (mdd_is_dead_obj(obj) &&
+           likely(!(mdd_is_orphan_obj(obj) && obj->mod_count > 0)))
                RETURN(-ENOENT);
 
        if (S_ISLNK(attr->la_mode))
index 7080ee8..4806974 100644 (file)
 
 #define MAX_HANDLE_SZ 128
 
-#if !defined(HAVE_FHANDLE_GLIBC_SUPPORT) && defined(HAVE_FHANDLE_SYSCALLS)
+void usage(char *prog)
+{
+       fprintf(stderr, "usage: %s <filepath> <mount2>\n",
+               prog);
+       fprintf(stderr, "the absolute path of a test file on a "
+               "lustre file system is needed.\n");
+       exit(1);
+}
+
+
+#ifndef HAVE_FHANDLE_SYSCALLS
+
+int main(int argc, char **argv)
+{
+       if (argc != 3)
+               usage(argv[0]);
+
+       fprintf(stderr, "HAVE_FHANDLE_SYSCALLS not defined\n");
+       return 0;
+}
+
+#else
+
+#ifndef HAVE_FHANDLE_GLIBC_SUPPORT
 /* Because the kernel supports this functions doesn't mean that glibc does.
  * Just in case we define what we need */
 struct file_handle {
@@ -87,7 +110,6 @@ struct file_handle {
 #define __NR_open_by_handle_at 265
 #endif
 
-
 #endif
 
 static inline int
@@ -105,29 +127,82 @@ open_by_handle_at(int mnt_fd, struct file_handle *fh, int mode)
 }
 #endif
 
-void usage(char *prog)
+/* verify a file contents */
+int check_access(const char *filename,
+                int mnt_fd, struct file_handle *fh, struct stat *st_orig)
 {
-       fprintf(stderr, "usage: %s <filepath>\n",
-               prog);
-       fprintf(stderr, "the absolute path of a test file on a "
-               "lustre file system is needed.\n");
-       exit(1);
+       int fd2, rc, len, offset;
+       struct stat st;
+       char *readbuf = NULL;
+
+       /* Open the file handle */
+       fd2 = open_by_handle_at(mnt_fd, fh, O_RDONLY);
+       if (fd2 < 0) {
+               fprintf(stderr, "open_by_handle_at(%s) error: %s\n", filename,
+                       strerror(errno));
+               rc = errno;
+               goto out_f_handle;
+       }
+
+       /* Get file size */
+       bzero(&st, sizeof(struct stat));
+       rc = fstat(fd2, &st);
+       if (rc < 0) {
+               fprintf(stderr, "fstat(%s) error: %s\n", filename,
+                       strerror(errno));
+               rc = errno;
+               goto out_fd2;
+       }
+
+       /* we can't check a ctime due unlink update */
+       if (st_orig->st_size != st.st_size ||
+           st_orig->st_ino != st.st_ino ||
+           st_orig->st_mtime != st.st_mtime) {
+               fprintf(stderr, "stat data does not match between fopen "
+                       "and fhandle case\n");
+               rc = EINVAL;
+               goto out_fd2;
+       }
+
+       if (st.st_size) {
+               len = st.st_blksize;
+               readbuf = malloc(len);
+               if (readbuf == NULL) {
+                       fprintf(stderr, "malloc(%d) error: %s\n", len,
+                               strerror(errno));
+                       rc = errno;
+                       goto out_fd2;
+               }
+
+               for (offset = 0; offset < st.st_size; offset += len) {
+                       /* read from the file */
+                       rc = read(fd2, readbuf, len);
+                       if (rc < 0) {
+                               fprintf(stderr, "read(%s) error: %s\n",
+                                       filename, strerror(errno));
+                               rc = errno;
+                               goto out_readbuf;
+                       }
+               }
+       }
+       rc = 0;
+out_readbuf:
+       free(readbuf);
+out_fd2:
+       close(fd2);
+out_f_handle:
+       return rc;
 }
 
 int main(int argc, char **argv)
 {
-#ifdef HAVE_FHANDLE_SYSCALLS
-       char *filename, *file, *mount_point = NULL, *readbuf = NULL;
-       int ret, rc = -EINVAL, mnt_id, mnt_fd, fd1, fd2, i, len, offset;
+       char *filename, *file;
+       int ret, rc = -EINVAL, mnt_fd, mnt_id, fd1, i;
        struct file_handle *fh = NULL;
-       int file_size, mtime, ctime;
        struct lu_fid *parent, *fid;
-       struct mntent *ent;
        struct stat st;
-       __ino_t inode;
-       FILE *mntpt;
 
-       if (argc != 2)
+       if (argc != 3)
                usage(argv[0]);
 
        file = argv[1];
@@ -136,6 +211,12 @@ int main(int argc, char **argv)
                goto out;
        }
 
+       if (*argv[2] != '/') {
+               fprintf(stderr, "Need the absolete path of the mount point\n");
+               goto out;
+       }
+       filename = rindex(file, '/') + 1;
+
        fd1 = open(file, O_RDONLY);
        if (fd1 < 0) {
                fprintf(stderr, "open file %s error: %s\n",
@@ -154,41 +235,10 @@ int main(int argc, char **argv)
                goto out_fd1;
        }
 
-       inode = st.st_ino;
-       mtime = st.st_mtime;
-       ctime = st.st_ctime;
-       file_size = st.st_size;
-
-       /* Now for the setup to use fhandles */
-       mntpt = setmntent("/etc/mtab", "r");
-       if (mntpt == NULL) {
-               fprintf(stderr, "setmntent error: %s\n",
-                       strerror(errno));
-               rc = errno;
-               goto out_fd1;
-       }
-
-       while (NULL != (ent = getmntent(mntpt))) {
-               if ((strncmp(file, ent->mnt_dir, strlen(ent->mnt_dir)) == 0) &&
-                   (strcmp(ent->mnt_type, "lustre") == 0)) {
-                       mount_point = ent->mnt_dir;
-                       break;
-               }
-       }
-       endmntent(mntpt);
-
-       if (mount_point == NULL) {
-               fprintf(stderr, "file is not located on a lustre file "
-                       "system?\n");
-               goto out_fd1;
-       }
-
-       filename = rindex(file, '/') + 1;
-
        /* Open mount point directory */
-       mnt_fd = open(mount_point, O_DIRECTORY);
+       mnt_fd = open(argv[2], O_DIRECTORY);
        if (mnt_fd < 0) {
-               fprintf(stderr, "open(%s) error: %s\n)", mount_point,
+               fprintf(stderr, "open(%s) error: %s\n)", argv[2],
                        strerror(errno));
                rc = errno;
                goto out_fd1;
@@ -205,7 +255,7 @@ int main(int argc, char **argv)
        fh->handle_bytes = MAX_HANDLE_SZ;
 
        /* Convert name to handle */
-       ret = name_to_handle_at(mnt_fd, filename, fh, &mnt_id,
+       ret = name_to_handle_at(AT_FDCWD, file, fh, &mnt_id,
                                AT_SYMLINK_FOLLOW);
        if (ret) {
                fprintf(stderr, "name_by_handle_at(%s) error: %s\n", filename,
@@ -228,62 +278,27 @@ int main(int argc, char **argv)
        fprintf(stdout, "file's parent FID is "DFID"\n", PFID(parent));
        fprintf(stdout, "file FID is "DFID"\n", PFID(fid));
 
-       /* Open the file handle */
-       fd2 = open_by_handle_at(mnt_fd, fh, O_RDONLY);
-       if (fd2 < 0) {
-               fprintf(stderr, "open_by_handle_at(%s) error: %s\n", filename,
-                       strerror(errno));
-               rc = errno;
+       fprintf(stdout, "just access via different mount point - ");
+       rc = check_access(filename, mnt_fd, fh, &st);
+       if (rc != 0)
                goto out_f_handle;
-       }
-
-       /* Get file size */
-       bzero(&st, sizeof(struct stat));
-       rc = fstat(fd2, &st);
-       if (rc < 0) {
-               fprintf(stderr, "fstat(%s) error: %s\n", filename,
-                       strerror(errno));
-               rc = errno;
-               goto out_fd2;
-       }
+       fprintf(stdout, "OK \n");
 
-       if (ctime != st.st_ctime || file_size != st.st_size ||
-           inode != st.st_ino || mtime != st.st_mtime) {
-               fprintf(stderr, "stat data does not match between fopen "
-                       "and fhandle case\n");
-               goto out_fd2;
+       fprintf(stdout, "access after unlink - ");
+       ret = unlink(file);
+       if (ret < 0) {
+               fprintf(stderr, "can't unlink a file. check permissions?\n");
+               goto out_f_handle;
        }
 
-       if (st.st_size) {
-               len = st.st_blksize;
-               readbuf = malloc(len);
-               if (readbuf == NULL) {
-                       fprintf(stderr, "malloc(%d) error: %s\n", len,
-                               strerror(errno));
-                       rc = errno;
-                       goto out_fd2;
-               }
-
-               for (offset = 0; offset < st.st_size; offset += len) {
-                       /* read from the file */
-                       rc = read(fd2, readbuf, len);
-                       if (rc < 0) {
-                               fprintf(stderr, "read(%s) error: %s\n",
-                                       filename, strerror(errno));
-                               rc = errno;
-                               goto out_readbuf;
-                       }
-               }
-       }
+       rc = check_access(filename, mnt_fd, fh, &st);
+       if (rc != 0)
+               goto out_f_handle;
+       fprintf(stdout, "OK\n");
 
        rc = 0;
        fprintf(stdout, "check_fhandle_syscalls test Passed!\n");
 
-out_readbuf:
-       if (readbuf != NULL)
-               free(readbuf);
-out_fd2:
-       close(fd2);
 out_f_handle:
        free(fh);
 out_mnt_fd:
@@ -292,11 +307,6 @@ out_fd1:
        close(fd1);
 out:
        return rc;
-#else /* !HAVE_FHANDLE_SYSCALLS */
-       if (argc != 2)
-               usage(argv[0]);
-
-       fprintf(stderr, "HAVE_FHANDLE_SYSCALLS not defined\n");
-       return 0;
-#endif /* HAVE_FHANDLE_SYSCALLS */
 }
+
+#endif
index 45920b4..4e192ec 100755 (executable)
@@ -15602,18 +15602,6 @@ test_236() {
 }
 run_test 236 "Layout swap on open unlinked file"
 
-# test to verify file handle related system calls
-# (name_to_handle_at/open_by_handle_at)
-# The new system calls are supported in glibc >= 2.14.
-
-test_237() {
-       echo "Test file_handle syscalls" > $DIR/$tfile ||
-               error "write failed"
-       check_fhandle_syscalls $DIR/$tfile ||
-               error "check_fhandle_syscalls failed"
-}
-run_test 237 "Verify name_to_handle_at/open_by_handle_at syscalls"
-
 # LU-4659 linkea consistency
 test_238() {
        local server_version=$(lustre_version_code $SINGLEMDS)
index 4cd17e5..d77c7ba 100755 (executable)
@@ -4469,6 +4469,22 @@ test_101c() {
 }
 run_test 101c "Discard DoM data on close-unlink"
 
+# test to verify file handle related system calls
+# (name_to_handle_at/open_by_handle_at)
+# The new system calls are supported in glibc >= 2.14.
+
+# test to verify we can open by handle an unlinked file from > 1 client
+# This test opens the file normally on $DIR1, which is on one mount, and then
+# opens it by handle on $DIR2, which is on a different mount.
+test_102() {
+       echo "Test file_handle syscalls" > $DIR/$tfile ||
+               error "write failed"
+       check_fhandle_syscalls $DIR/$tfile $DIR2 ||
+               error "check_fhandle_syscalls failed"
+       rm -f $DIR2/$tfile
+}
+run_test 102 "Test open by handle of unlinked file"
+
 log "cleanup: ======================================================"
 
 # kill and wait in each test only guarentee script finish, but command in script