2 * open_by_handle.c - attempt to create a file handle and open it
3 * with open_by_handle_at() syscall
5 * Copyright (C) 2017 CTERA Networks. All Rights Reserved.
6 * Author: Amir Goldstein <amir73il@gmail.com>
11 * Copyright (C) 2010 Red Hat, Inc. All Rights reserved.
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 usage: open_by_handle [-cludmrwa] <test_dir> [num_files]
34 1. Create test set of N files and try to get their NFS handles:
36 open_by_handle -c <test_dir> [N]
38 This is used by new helper _require_exportfs() to check
39 if filesystem supports exportfs
41 2. Get file handles for existing test set, drop caches and try to
42 open all files by handle:
44 open_by_handle <test_dir> [N]
46 3. Get file handles for existing test set, write data to files,
47 drop caches, open all files by handle, read and verify written
48 data, write new data to file:
50 open_by_handle -rwa <test_dir> [N]
52 4. Get file handles for existing test set, unlink all test files,
53 drop caches, try to open all files by handle and expect ESTALE:
55 open_by_handle -d <test_dir> [N]
57 5. Get file handles for existing test set, rename all test files,
58 drop caches, try to open all files by handle (should work):
60 open_by_handle -m <test_dir> [N]
62 6. Get file handles for existing test set, hardlink all test files,
63 then unlink the original files, drop caches and try to open all
64 files by handle (should work):
66 open_by_handle -l <test_dir> [N]
67 open_by_handle -u <test_dir> [N]
69 This test is done with 2 invocations of the program, first to
70 hardlink (-l) and then to unlink the originals (-u), because
71 we would like to be able to perform the hardlinks on overlay
72 lower layer and unlink on upper layer.
74 NOTE that open_by_handle -u doesn't check if the files are
75 hardlinked, it just assumes that they are. If they are not
76 then the test will fail, because file handles would be stale.
85 #include <sys/types.h>
87 #include <linux/limits.h>
92 struct file_handle fh;
93 unsigned char fid[MAX_HANDLE_SZ];
98 fprintf(stderr, "usage: open_by_handle [-cludmrwa] <test_dir> [num_files]\n");
99 fprintf(stderr, "\n");
100 fprintf(stderr, "open_by_handle -c <test_dir> [N] - create N test files under test_dir, try to get file handles and exit\n");
101 fprintf(stderr, "open_by_handle <test_dir> [N] - get file handles of test files, drop caches and try to open by handle\n");
102 fprintf(stderr, "open_by_handle -w <test_dir> [N] - write data to test files before open by handle\n");
103 fprintf(stderr, "open_by_handle -r <test_dir> [N] - read data from test files after open by handle and verify written data\n");
104 fprintf(stderr, "open_by_handle -a <test_dir> [N] - write data to test files after open by handle\n");
105 fprintf(stderr, "open_by_handle -l <test_dir> [N] - create hardlinks to test files, drop caches and try to open by handle\n");
106 fprintf(stderr, "open_by_handle -u <test_dir> [N] - unlink (hardlinked) test files, drop caches and try to open by handle\n");
107 fprintf(stderr, "open_by_handle -d <test_dir> [N] - unlink test files and hardlinks, drop caches and try to open by handle\n");
108 fprintf(stderr, "open_by_handle -m <test_dir> [N] - rename test files, drop caches and try to open by handle\n");
112 int main(int argc, char **argv)
118 char fname[PATH_MAX];
119 char fname2[PATH_MAX];
121 int mount_fd, mount_id;
123 int create = 0, delete = 0, nlink = 1, move = 0;
124 int rd = 0, wr = 0, wrafter = 0;
126 if (argc < 2 || argc > 4)
129 while ((c = getopt(argc, argv, "cludmrwa")) != -1) {
135 /* Write data before open_by_handle_at() */
139 /* Read data after open_by_handle_at() */
143 /* Write data after open_by_handle_at() */
161 fprintf(stderr, "illegal option '%s'\n", argv[optind]);
166 if (optind == argc || optind > 2)
168 test_dir = argv[optind++];
170 numfiles = atoi(argv[optind]);
171 if (!numfiles || numfiles > MAXFILES) {
172 fprintf(stderr, "illegal value '%s' for num_files\n", argv[optind]);
176 mount_fd = open(test_dir, O_RDONLY|O_DIRECTORY);
183 * Create the test files and remove leftover hardlinks from previous run
185 for (i=0; create && i < numfiles; i++) {
186 sprintf(fname, "%s/file%06d", test_dir, i);
187 sprintf(fname2, "%s/link%06d", test_dir, i);
188 fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
190 strcat(fname, ": open");
195 /* blow up leftovers hardlinks if they exist */
196 ret = unlink(fname2);
197 if (ret < 0 && errno != ENOENT) {
198 strcat(fname2, ": unlink");
204 /* sync to get the new inodes to hit the disk */
207 /* create the handles */
208 for (i=0; i < numfiles; i++) {
209 sprintf(fname, "%s/file%06d", test_dir, i);
210 handle[i].fh.handle_bytes = MAX_HANDLE_SZ;
211 ret = name_to_handle_at(AT_FDCWD, fname, &handle[i].fh, &mount_id, 0);
213 strcat(fname, ": name_to_handle");
219 /* write data to files */
220 for (i=0; wr && i < numfiles; i++) {
221 sprintf(fname, "%s/file%06d", test_dir, i);
222 fd = open(fname, O_WRONLY, 0644);
224 strcat(fname, ": open");
228 if (write(fd, "aaaa", 4) != 4) {
229 strcat(fname, ": write before");
236 /* after creating test set only check that fs supports exportfs */
240 /* hardlink the files */
241 for (i=0; nlink > 1 && i < numfiles; i++) {
242 sprintf(fname, "%s/file%06d", test_dir, i);
243 sprintf(fname2, "%s/link%06d", test_dir, i);
244 ret = link(fname, fname2);
246 strcat(fname2, ": link");
252 /* rename the files */
253 for (i=0; move && i < numfiles; i++) {
254 sprintf(fname, "%s/file%06d", test_dir, i);
255 sprintf(fname2, "%s/link%06d", test_dir, i);
256 ret = rename(fname, fname2);
258 strcat(fname2, ": rename");
264 /* unlink the files */
265 for (i=0; delete && i < numfiles; i++) {
266 sprintf(fname, "%s/file%06d", test_dir, i);
267 sprintf(fname2, "%s/link%06d", test_dir, i);
270 strcat(fname, ": unlink");
274 /* with -d flag, delete the hardlink if it exists */
276 ret = unlink(fname2);
277 if (ret < 0 && errno != ENOENT) {
278 strcat(fname2, ": unlink");
284 /* sync to get log forced for unlink transactions to hit the disk */
287 /* sync once more FTW */
291 * now drop the caches so that unlinked inodes are reclaimed and
292 * buftarg page cache is emptied so that the inode cluster has to be
293 * fetched from disk again for the open_by_handle() call.
295 ret = system("echo 3 > /proc/sys/vm/drop_caches");
297 perror("drop_caches");
302 * now try to open the files by the stored handles. Expecting ESTALE
303 * if all files and their hardlinks have been unlinked.
305 for (i=0; i < numfiles; i++) {
307 fd = open_by_handle_at(mount_fd, &handle[i].fh, wrafter ? O_RDWR : O_RDONLY);
308 if (nlink && fd >= 0) {
311 int size = read(fd, buf, 4);
313 strcat(fname, ": read");
317 if (size < 4 || memcmp(buf, "aaaa", 4)) {
318 printf("open_by_handle(%s) returned stale data '%.*s'!\n", fname, size, buf);
321 if (wrafter && write(fd, "aaaa", 4) != 4) {
322 strcat(fname, ": write after");
328 } else if (!nlink && fd < 0 && (errno == ENOENT || errno == ESTALE)) {
331 sprintf(fname, "%s/file%06d", test_dir, i);
333 printf("open_by_handle(%s) opened an unlinked file!\n", fname);
336 printf("open_by_handle(%s) returned %d incorrectly on %s file!\n",
338 nlink ? "a linked" : "an unlinked");