Whamcloud - gitweb
LU-3344 tests: Verify file handle system calls 47/7247/23
authorJames Simmons <uja.ornl@gmail.com>
Mon, 13 Jan 2014 14:08:36 +0000 (09:08 -0500)
committerOleg Drokin <oleg.drokin@intel.com>
Fri, 31 Jan 2014 22:07:57 +0000 (22:07 +0000)
New system calls name_to_handle_at() and open_by_handle_at() are added
to Linux kernel 2.6.39. Added test to verify these work correctly with
Lustre.

Signed-off-by: Swapnil Pimpale <spimpale@ddn.com>
Signed-off-by: James Simmons <uja.ornl@gmail.com>
Change-Id: Icbfc9642cd550ac44d379263836782ffbf4a74f4
Reviewed-on: http://review.whamcloud.com/7247
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Tested-by: Jenkins
Reviewed-by: Jian Yu <jian.yu@intel.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: John L. Hammond <john.hammond@intel.com>
lustre/autoconf/lustre-core.m4
lustre/tests/.gitignore
lustre/tests/Makefile.am
lustre/tests/check_fhandle_syscalls.c [new file with mode: 0644]
lustre/tests/sanity.sh

index 1904bcd..e6207c9 100644 (file)
@@ -82,6 +82,18 @@ AC_TRY_COMPILE([
 ])
 ])
 
+AC_DEFUN([LC_GLIBC_SUPPORT_FHANDLES],
+[AC_MSG_CHECKING([if file handle and related syscalls are supported by glibc])
+AC_CHECK_FUNCS([name_to_handle_at
+],[
+       AC_MSG_RESULT([yes])
+       AC_DEFINE(HAVE_FHANDLE_GLIBC_SUPPORT, 1,
+               [file handle and related syscalls are supported])
+],[
+       AC_MSG_RESULT([no])
+])
+])
+
 #
 # LC_FUNC_DEV_SET_RDONLY
 #
@@ -721,6 +733,18 @@ LB_LINUX_TRY_COMPILE([
 ])
 
 #
+# 2.6.39 The open_by_handle_at() and name_to_handle_at() system calls were
+# added to Linux kernel 2.6.39.
+# Check if client supports these functions
+#
+AC_DEFUN([LC_HAVE_FHANDLE_SYSCALLS],
+[LB_LINUX_CONFIG_IM([FHANDLE],[
+       AC_DEFINE(HAVE_FHANDLE_SYSCALLS, 1,
+               [kernel supports fhandles and related syscalls])
+],[])
+])
+
+#
 # 3.0 dirty_inode() has a flag parameter
 # see kernel commit aa38572954ade525817fe88c54faebf85e5a61c0
 #
@@ -1409,9 +1433,10 @@ AC_DEFUN([LC_PROG_LINUX],
          LC_CONFIG_LRU_RESIZE
          LC_LLITE_LLOOP_MODULE
 
-         LC_CAPA_CRYPTO
-         LC_CONFIG_RMTCLIENT
-         LC_CONFIG_GSS
+        LC_GLIBC_SUPPORT_FHANDLES
+        LC_CAPA_CRYPTO
+        LC_CONFIG_RMTCLIENT
+        LC_CONFIG_GSS
 
         # 2.6.32
         LC_BLK_QUEUE_MAX_SEGMENTS
@@ -1440,8 +1465,9 @@ AC_DEFUN([LC_PROG_LINUX],
          LC_D_COMPARE_7ARGS
          LC_D_DELETE_CONST
 
-         # 2.6.39
-         LC_REQUEST_QUEUE_UNPLUG_FN
+        # 2.6.39
+        LC_REQUEST_QUEUE_UNPLUG_FN
+        LC_HAVE_FHANDLE_SYSCALLS
         LC_HAVE_FSTYPE_MOUNT
         LC_IOP_TRUNCATE
 
index 90f12b7..ebd19e6 100644 (file)
@@ -2,6 +2,7 @@
 /*.xml
 /Makefile.in
 /XMLCONFIG
+/check_fhandle_syscalls
 /checkfiemap
 /checkstat
 /chownmany
 /createtest
 /directio
 /fchdir_test
+/flock_deadlock
 /flock_test
 /flocks_test
 /fsx
 /getdents
+/listxattr_size_check
 /iopentest1
 /iopentest2
 /it_test
index 820ef34..13e8169 100644 (file)
@@ -69,8 +69,7 @@ noinst_PROGRAMS += ll_sparseness_write mrename ll_dirstripe_verify mkdirmany
 noinst_PROGRAMS += openfilleddirunlink rename_many memhog
 noinst_PROGRAMS += mmap_sanity writemany reads flocks_test flock_deadlock
 noinst_PROGRAMS += write_time_limit rwv lgetxattr_size_check checkfiemap
-noinst_PROGRAMS += listxattr_size_check
-
+noinst_PROGRAMS += listxattr_size_check check_fhandle_syscalls
 
 bin_PROGRAMS = mcreate munlink
 testdir = $(libdir)/lustre/tests
diff --git a/lustre/tests/check_fhandle_syscalls.c b/lustre/tests/check_fhandle_syscalls.c
new file mode 100644 (file)
index 0000000..8094774
--- /dev/null
@@ -0,0 +1,276 @@
+/* GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * GPL HEADER END
+ */
+
+/*
+ * Copyright (C) 2013, DataDirect Networks, Inc.
+ * Author: Swapnil Pimpale <spimpale@ddn.com>
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <mntent.h>
+#include <linux/unistd.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#include <liblustre.h>
+#include <lustre/lustre_user.h>
+
+#define MAX_HANDLE_SZ 128
+
+#if !defined(HAVE_FHANDLE_GLIBC_SUPPORT) && defined(HAVE_FHANDLE_SYSCALLS)
+/* Because the kernel supports this functions doesn't mean that glibc does.
+ * Just in case we define what we need */
+struct file_handle
+{
+       unsigned int handle_bytes;
+       int handle_type;
+       /* File identifier.  */
+       unsigned char f_handle[0];
+};
+
+#ifndef __NR_name_to_handle_at
+#define __NR_name_to_handle_at 264
+#endif
+
+#ifndef __NR_open_by_handle_at
+#define __NR_open_by_handle_at 265
+#endif
+
+static inline int
+name_to_handle_at(int mnt_fd, const char *filename, struct file_handle *fh,
+                 int *mnt_id, int flags)
+{
+       return syscall(__NR_name_to_handle_at, mnt_fd, filename, fh,
+                      &mnt_id, flags);
+}
+
+static inline int
+open_by_handle_at(int mnt_fd, struct file_handle *fh, int mode)
+{
+       return syscall(__NR_open_by_handle_at, mnt_fd, fh, mode);
+}
+#endif
+
+void usage(char *prog)
+{
+       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 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;
+       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)
+               usage(argv[0]);
+
+       file = argv[1];
+       if (file[0] != '/') {
+               fprintf(stderr, "Need the absolete path of the file\n");
+               goto out;
+       }
+
+       fd1 = open(file, O_RDONLY);
+       if (fd1 < 0) {
+               fprintf(stderr, "open file %s error: %s\n",
+                       file, strerror(errno));
+               rc = errno;
+               goto out;
+       }
+
+       /* Get file stats using fd1 from traditional open */
+       bzero(&st, sizeof(struct stat));
+       rc = fstat(fd1, &st);
+       if (rc < 0) {
+               fprintf(stderr, "fstat(%s) error: %s\n", file,
+                       strerror(errno));
+               rc = errno;
+               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);
+       if (mnt_fd < 0) {
+               fprintf(stderr, "open(%s) error: %s\n)", mount_point,
+                       strerror(errno));
+               rc = errno;
+               goto out_fd1;
+       }
+
+       /* Allocate memory for file handle */
+       fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
+       if (!fh) {
+               fprintf(stderr, "malloc(%d) error: %s\n", MAX_HANDLE_SZ,
+                       strerror(errno));
+               rc = errno;
+               goto out_mnt_fd;
+       }
+       fh->handle_bytes = MAX_HANDLE_SZ;
+
+       /* Convert name to handle */
+       ret = name_to_handle_at(mnt_fd, filename, fh, &mnt_id,
+                               AT_SYMLINK_FOLLOW);
+       if (ret) {
+               fprintf(stderr, "name_by_handle_at(%s) error: %s\n", filename,
+                       strerror(errno));
+               rc = errno;
+               goto out_f_handle;
+       }
+
+       /* Print out the contents of the file handle */
+       fprintf(stdout, "fh_bytes: %u\nfh_type: %d\nfh_data: ",
+               fh->handle_bytes, fh->handle_type);
+       for (i = 0; i < fh->handle_bytes; i++)
+               fprintf(stdout, "%02x ", fh->f_handle[i]);
+       fprintf(stdout, "\n");
+
+       /* Lustre stores both the parents FID and the file FID
+        * in the f_handle. */
+       parent = (struct lu_fid *)(fh->f_handle + 16);
+       fid = (struct lu_fid *)fh->f_handle;
+       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;
+               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;
+       }
+
+       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;
+       }
+
+       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;
+       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:
+       close(mnt_fd);
+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 */
+}
index 79e19a7..268cc14 100644 (file)
@@ -11945,6 +11945,17 @@ 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
+       check_fhandle_syscalls $DIR/$tfile ||
+               error "check_fhandle_syscalls failed"
+}
+run_test 237 "Verify name_to_handle_at/open_by_handle_at syscalls"
+
 #
 # tests that do cleanup/setup should be run at the end
 #