From: James Simmons Date: Mon, 13 Jan 2014 14:08:36 +0000 (-0500) Subject: LU-3344 tests: Verify file handle system calls X-Git-Tag: 2.5.55~10 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=3f5fc6412d3ae2d3a57f8fdb8a457f35e9d9576e LU-3344 tests: Verify file handle system calls 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 Signed-off-by: James Simmons Change-Id: Icbfc9642cd550ac44d379263836782ffbf4a74f4 Reviewed-on: http://review.whamcloud.com/7247 Reviewed-by: Andreas Dilger Tested-by: Jenkins Reviewed-by: Jian Yu Tested-by: Maloo Reviewed-by: John L. Hammond --- diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index 1904bcd..e6207c9 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -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 diff --git a/lustre/tests/.gitignore b/lustre/tests/.gitignore index 90f12b7..ebd19e6 100644 --- a/lustre/tests/.gitignore +++ b/lustre/tests/.gitignore @@ -2,6 +2,7 @@ /*.xml /Makefile.in /XMLCONFIG +/check_fhandle_syscalls /checkfiemap /checkstat /chownmany @@ -13,10 +14,12 @@ /createtest /directio /fchdir_test +/flock_deadlock /flock_test /flocks_test /fsx /getdents +/listxattr_size_check /iopentest1 /iopentest2 /it_test diff --git a/lustre/tests/Makefile.am b/lustre/tests/Makefile.am index 820ef34..13e8169 100644 --- a/lustre/tests/Makefile.am +++ b/lustre/tests/Makefile.am @@ -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 index 0000000..8094774 --- /dev/null +++ b/lustre/tests/check_fhandle_syscalls.c @@ -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 + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 \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 */ +} diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 79e19a7..268cc14 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -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 #