3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 only,
7 * as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License version 2 for more details (a copy is included
13 * in the LICENSE file that accompanied this code).
15 * You should have received a copy of the GNU General Public License
16 * version 2 along with this program; If not, see
17 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (C) 2013, DataDirect Networks, Inc.
25 * Copyright (c) 2014, Intel Corporation.
27 * Author: Swapnil Pimpale <spimpale@ddn.com>
42 #include <linux/unistd.h>
44 #include <sys/syscall.h>
46 #include <linux/lustre/lustre_user.h>
48 #define MAX_HANDLE_SZ 128
50 static void usage(char *prog)
52 fprintf(stderr, "usage: %s <filepath> <mount2>\n",
54 fprintf(stderr, "the absolute path of a test file on a "
55 "lustre file system is needed.\n");
60 #ifndef HAVE_FHANDLE_GLIBC_SUPPORT
61 /* Because the kernel supports this functions doesn't mean that glibc does.
62 * Just in case we define what we need */
67 unsigned char f_handle[0];
70 #if defined(_ASM_X86_UNISTD_64_H)
72 #ifndef __NR_name_to_handle_at
73 #define __NR_name_to_handle_at 303
76 #ifndef __NR_open_by_handle_at
77 #define __NR_open_by_handle_at 304
80 #elif defined(_ASM_X86_UNISTD_32_H)
82 #ifndef __NR_name_to_handle_at
83 #define __NR_name_to_handle_at 341
86 #ifndef __NR_open_by_handle_at
87 #define __NR_open_by_handle_at 342
92 #ifndef __NR_name_to_handle_at
93 #define __NR_name_to_handle_at 264
96 #ifndef __NR_open_by_handle_at
97 #define __NR_open_by_handle_at 265
103 name_to_handle_at(int mnt_fd, const char *filename, struct file_handle *fh,
104 int *mnt_id, int flags)
106 return syscall(__NR_name_to_handle_at, mnt_fd, filename, fh,
111 open_by_handle_at(int mnt_fd, struct file_handle *fh, int mode)
113 return syscall(__NR_open_by_handle_at, mnt_fd, fh, mode);
117 static int debug_mark(const char *msg)
121 snprintf(cmd, sizeof(cmd), "../utils/lctl mark %s 2>/dev/null", msg);
125 /* verify a file contents */
126 static int check_access(const char *filename,
127 int mnt_fd, struct file_handle *fh, struct stat *st_orig)
129 int fd2, rc, len, offset;
131 char *readbuf = NULL;
133 debug_mark("before open by handle");
134 /* Open the file handle */
135 fd2 = open_by_handle_at(mnt_fd, fh, O_RDONLY |
136 (S_ISDIR(st_orig->st_mode) ? O_DIRECTORY : 0));
137 debug_mark("after open by handle");
139 fprintf(stderr, "open_by_handle_at(%s) error: %s\n", filename,
142 fprintf(stderr, "second mountpoint not mounted?\n");
148 bzero(&st, sizeof(struct stat));
149 debug_mark("before stat");
150 rc = fstat(fd2, &st);
151 debug_mark("after stat");
153 fprintf(stderr, "fstat(%s) error: %s\n", filename,
159 /* we can't check a ctime due unlink update */
160 if (st_orig->st_size != st.st_size ||
161 st_orig->st_ino != st.st_ino ||
162 st_orig->st_mode != st.st_mode ||
163 st_orig->st_mtime != st.st_mtime) {
165 "stat data mismatch between fopen and fhandle case\n");
170 if (st.st_size && S_ISREG(st.st_mode)) {
172 readbuf = malloc(len);
173 if (readbuf == NULL) {
174 fprintf(stderr, "malloc(%d) error: %s\n", len,
180 for (offset = 0; offset < st.st_size; offset += len) {
181 /* read from the file */
182 rc = read(fd2, readbuf, len);
184 fprintf(stderr, "read(%s) error: %s\n",
185 filename, strerror(errno));
200 int main(int argc, char **argv)
202 char *filename, *file;
203 int ret, rc = -EINVAL, mnt_fd, mnt_id, fd1, i;
204 struct file_handle *fh = NULL;
205 struct lu_fid *parent, *fid;
212 if (file[0] != '/') {
213 fprintf(stderr, "Need the absolete path of the file\n");
217 if (*argv[2] != '/') {
218 fprintf(stderr, "Need the absolete path of the mount point\n");
221 filename = rindex(file, '/') + 1;
223 debug_mark("before first open");
224 fd1 = open(file, O_RDONLY);
225 debug_mark("after first open");
227 fprintf(stderr, "open file %s error: %s\n",
228 file, strerror(errno));
233 /* Get file stats using fd1 from traditional open */
234 bzero(&st, sizeof(struct stat));
235 debug_mark("before first stat");
236 rc = fstat(fd1, &st);
237 debug_mark("after first stat");
239 fprintf(stderr, "fstat(%s) error: %s\n", file,
245 /* Open mount point directory */
246 debug_mark("before directory open");
247 mnt_fd = open(argv[2], O_DIRECTORY);
248 debug_mark("after directory open");
250 fprintf(stderr, "open(%s) error: %s\n)", argv[2],
256 /* Allocate memory for file handle */
257 fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
259 fprintf(stderr, "malloc(%d) error: %s\n", MAX_HANDLE_SZ,
264 fh->handle_bytes = MAX_HANDLE_SZ;
266 /* Convert name to handle */
267 debug_mark("before get handle");
268 ret = name_to_handle_at(AT_FDCWD, file, fh, &mnt_id,
270 debug_mark("after get handle");
272 fprintf(stderr, "name_by_handle_at(%s) error: %s\n", filename,
278 /* Print out the contents of the file handle */
279 fprintf(stdout, "file: %s\nfh_bytes: %u\nfh_type: %d\nfh_data: ",
280 file, fh->handle_bytes, fh->handle_type);
281 for (i = 0; i < fh->handle_bytes; i++)
282 fprintf(stdout, "%02x ", fh->f_handle[i]);
283 fprintf(stdout, "\n");
285 /* Lustre stores both the parents FID and the file FID
286 * in the f_handle. */
287 parent = (struct lu_fid *)(fh->f_handle + 16);
288 fid = (struct lu_fid *)fh->f_handle;
289 fprintf(stdout, "file's parent FID is "DFID"\n", PFID(parent));
290 fprintf(stdout, "file FID is "DFID"\n", PFID(fid));
292 fprintf(stdout, "access via mount point '%s' - ", argv[2]);
294 rc = check_access(filename, mnt_fd, fh, &st);
297 fprintf(stdout, "OK \n");
300 if (S_ISREG(st.st_mode)) {
301 fprintf(stdout, "access after unlink - ");
306 "can't unlink '%s'. check permissions?\n",
311 rc = check_access(filename, mnt_fd, fh, &st);
314 fprintf(stdout, "OK\n");
319 fprintf(stdout, "check_fhandle_syscalls test Passed!\n");