Whamcloud - gitweb
LU-14095 gss: use RCU protection for sunrpc cache
[fs/lustre-release.git] / lustre / tests / check_fhandle_syscalls.c
1 /* GPL HEADER START
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
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.
8  *
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).
14  *
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
18  *
19  * GPL HEADER END
20  */
21
22 /*
23  * Copyright (C) 2013, DataDirect Networks, Inc.
24  *
25  * Copyright (c) 2014, Intel Corporation.
26  *
27  * Author: Swapnil Pimpale <spimpale@ddn.com>
28  */
29
30 #ifndef _GNU_SOURCE
31 #define _GNU_SOURCE
32 #endif
33
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <string.h>
41 #include <mntent.h>
42 #include <linux/unistd.h>
43 #include <sys/stat.h>
44 #include <sys/syscall.h>
45
46 #include <linux/lustre/lustre_user.h>
47
48 #define MAX_HANDLE_SZ 128
49
50 void usage(char *prog)
51 {
52         fprintf(stderr, "usage: %s <filepath> <mount2>\n",
53                 prog);
54         fprintf(stderr, "the absolute path of a test file on a "
55                 "lustre file system is needed.\n");
56         exit(1);
57 }
58
59
60 #ifndef HAVE_FHANDLE_SYSCALLS
61
62 int main(int argc, char **argv)
63 {
64         if (argc != 3)
65                 usage(argv[0]);
66
67         fprintf(stderr, "HAVE_FHANDLE_SYSCALLS not defined\n");
68         return 0;
69 }
70
71 #else
72
73 #ifndef HAVE_FHANDLE_GLIBC_SUPPORT
74 /* Because the kernel supports this functions doesn't mean that glibc does.
75  * Just in case we define what we need */
76 struct file_handle {
77         __u32 handle_bytes;
78         int handle_type;
79         /* file identifier */
80         unsigned char f_handle[0];
81 };
82
83 #if defined(_ASM_X86_UNISTD_64_H)
84
85 #ifndef __NR_name_to_handle_at
86 #define __NR_name_to_handle_at 303
87 #endif
88
89 #ifndef __NR_open_by_handle_at
90 #define __NR_open_by_handle_at 304
91 #endif
92
93 #elif defined(_ASM_X86_UNISTD_32_H)
94
95 #ifndef __NR_name_to_handle_at
96 #define __NR_name_to_handle_at 341
97 #endif
98
99 #ifndef __NR_open_by_handle_at
100 #define __NR_open_by_handle_at 342
101 #endif
102
103 #else
104
105 #ifndef __NR_name_to_handle_at
106 #define __NR_name_to_handle_at 264
107 #endif
108
109 #ifndef __NR_open_by_handle_at
110 #define __NR_open_by_handle_at 265
111 #endif
112
113 #endif
114
115 static inline int
116 name_to_handle_at(int mnt_fd, const char *filename, struct file_handle *fh,
117                   int *mnt_id, int flags)
118 {
119         return syscall(__NR_name_to_handle_at, mnt_fd, filename, fh,
120                        &mnt_id, flags);
121 }
122
123 static inline int
124 open_by_handle_at(int mnt_fd, struct file_handle *fh, int mode)
125 {
126         return syscall(__NR_open_by_handle_at, mnt_fd, fh, mode);
127 }
128 #endif
129
130 /* verify a file contents */
131 int check_access(const char *filename,
132                  int mnt_fd, struct file_handle *fh, struct stat *st_orig)
133 {
134         int fd2, rc, len, offset;
135         struct stat st;
136         char *readbuf = NULL;
137
138         /* Open the file handle */
139         fd2 = open_by_handle_at(mnt_fd, fh, O_RDONLY);
140         if (fd2 < 0) {
141                 fprintf(stderr, "open_by_handle_at(%s) error: %s\n", filename,
142                         strerror(errno));
143                 rc = errno;
144                 goto out_f_handle;
145         }
146
147         /* Get file size */
148         bzero(&st, sizeof(struct stat));
149         rc = fstat(fd2, &st);
150         if (rc < 0) {
151                 fprintf(stderr, "fstat(%s) error: %s\n", filename,
152                         strerror(errno));
153                 rc = errno;
154                 goto out_fd2;
155         }
156
157         /* we can't check a ctime due unlink update */
158         if (st_orig->st_size != st.st_size ||
159             st_orig->st_ino != st.st_ino ||
160             st_orig->st_mtime != st.st_mtime) {
161                 fprintf(stderr, "stat data does not match between fopen "
162                         "and fhandle case\n");
163                 rc = EINVAL;
164                 goto out_fd2;
165         }
166
167         if (st.st_size) {
168                 len = st.st_blksize;
169                 readbuf = malloc(len);
170                 if (readbuf == NULL) {
171                         fprintf(stderr, "malloc(%d) error: %s\n", len,
172                                 strerror(errno));
173                         rc = errno;
174                         goto out_fd2;
175                 }
176
177                 for (offset = 0; offset < st.st_size; offset += len) {
178                         /* read from the file */
179                         rc = read(fd2, readbuf, len);
180                         if (rc < 0) {
181                                 fprintf(stderr, "read(%s) error: %s\n",
182                                         filename, strerror(errno));
183                                 rc = errno;
184                                 goto out_readbuf;
185                         }
186                 }
187         }
188         rc = 0;
189 out_readbuf:
190         free(readbuf);
191 out_fd2:
192         close(fd2);
193 out_f_handle:
194         return rc;
195 }
196
197 int main(int argc, char **argv)
198 {
199         char *filename, *file;
200         int ret, rc = -EINVAL, mnt_fd, mnt_id, fd1, i;
201         struct file_handle *fh = NULL;
202         struct lu_fid *parent, *fid;
203         struct stat st;
204
205         if (argc != 3)
206                 usage(argv[0]);
207
208         file = argv[1];
209         if (file[0] != '/') {
210                 fprintf(stderr, "Need the absolete path of the file\n");
211                 goto out;
212         }
213
214         if (*argv[2] != '/') {
215                 fprintf(stderr, "Need the absolete path of the mount point\n");
216                 goto out;
217         }
218         filename = rindex(file, '/') + 1;
219
220         fd1 = open(file, O_RDONLY);
221         if (fd1 < 0) {
222                 fprintf(stderr, "open file %s error: %s\n",
223                         file, strerror(errno));
224                 rc = errno;
225                 goto out;
226         }
227
228         /* Get file stats using fd1 from traditional open */
229         bzero(&st, sizeof(struct stat));
230         rc = fstat(fd1, &st);
231         if (rc < 0) {
232                 fprintf(stderr, "fstat(%s) error: %s\n", file,
233                         strerror(errno));
234                 rc = errno;
235                 goto out_fd1;
236         }
237
238         /* Open mount point directory */
239         mnt_fd = open(argv[2], O_DIRECTORY);
240         if (mnt_fd < 0) {
241                 fprintf(stderr, "open(%s) error: %s\n)", argv[2],
242                         strerror(errno));
243                 rc = errno;
244                 goto out_fd1;
245         }
246
247         /* Allocate memory for file handle */
248         fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
249         if (!fh) {
250                 fprintf(stderr, "malloc(%d) error: %s\n", MAX_HANDLE_SZ,
251                         strerror(errno));
252                 rc = errno;
253                 goto out_mnt_fd;
254         }
255         fh->handle_bytes = MAX_HANDLE_SZ;
256
257         /* Convert name to handle */
258         ret = name_to_handle_at(AT_FDCWD, file, fh, &mnt_id,
259                                 AT_SYMLINK_FOLLOW);
260         if (ret) {
261                 fprintf(stderr, "name_by_handle_at(%s) error: %s\n", filename,
262                         strerror(errno));
263                 rc = errno;
264                 goto out_f_handle;
265         }
266
267         /* Print out the contents of the file handle */
268         fprintf(stdout, "fh_bytes: %u\nfh_type: %d\nfh_data: ",
269                 fh->handle_bytes, fh->handle_type);
270         for (i = 0; i < fh->handle_bytes; i++)
271                 fprintf(stdout, "%02x ", fh->f_handle[i]);
272         fprintf(stdout, "\n");
273
274         /* Lustre stores both the parents FID and the file FID
275          * in the f_handle. */
276         parent = (struct lu_fid *)(fh->f_handle + 16);
277         fid = (struct lu_fid *)fh->f_handle;
278         fprintf(stdout, "file's parent FID is "DFID"\n", PFID(parent));
279         fprintf(stdout, "file FID is "DFID"\n", PFID(fid));
280
281         fprintf(stdout, "just access via different mount point - ");
282         rc = check_access(filename, mnt_fd, fh, &st);
283         if (rc != 0)
284                 goto out_f_handle;
285         fprintf(stdout, "OK \n");
286
287         fprintf(stdout, "access after unlink - ");
288         ret = unlink(file);
289         if (ret < 0) {
290                 fprintf(stderr, "can't unlink a file. check permissions?\n");
291                 goto out_f_handle;
292         }
293
294         rc = check_access(filename, mnt_fd, fh, &st);
295         if (rc != 0)
296                 goto out_f_handle;
297         fprintf(stdout, "OK\n");
298
299         rc = 0;
300         fprintf(stdout, "check_fhandle_syscalls test Passed!\n");
301
302 out_f_handle:
303         free(fh);
304 out_mnt_fd:
305         close(mnt_fd);
306 out_fd1:
307         close(fd1);
308 out:
309         return rc;
310 }
311
312 #endif