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 [-c|-l|-u|-d] <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, unlink all test files,
47 drop caches, try to open all files by handle and expect ESTALE:
49 open_by_handle -d <test_dir> [N]
51 4. Get file handles for existing test set, hardlink all test files,
52 then unlink the original files, drop caches and try to open all
53 files by handle (should work):
55 open_by_handle -l <test_dir> [N]
56 open_by_handle -u <test_dir> [N]
58 This test is done with 2 invocations of the program, first to
59 hardlink (-l) and then to unlink the originals (-u), because
60 we would like to be able to perform the hardlinks on overlay
61 lower layer and unlink on upper layer.
63 NOTE that open_by_handle -u doesn't check if the files are
64 hardlinked, it just assumes that they are. If they are not
65 then the test will fail, because file handles would be stale.
74 #include <sys/types.h>
76 #include <linux/limits.h>
81 struct file_handle fh;
82 unsigned char fid[MAX_HANDLE_SZ];
87 fprintf(stderr, "usage: open_by_handle [-c|-l|-u|-d] <test_dir> [num_files]\n");
88 fprintf(stderr, "\n");
89 fprintf(stderr, "open_by_handle -c <test_dir> [N] - create N test files under test_dir, try to get file handles and exit\n");
90 fprintf(stderr, "open_by_handle <test_dir> [N] - get file handles of test files, drop caches and try to open by handle\n");
91 fprintf(stderr, "open_by_handle -l <test_dir> [N] - create hardlinks to test files, drop caches and try to open by handle\n");
92 fprintf(stderr, "open_by_handle -u <test_dir> [N] - unlink (hardlinked) test files, drop caches and try to open by handle\n");
93 fprintf(stderr, "open_by_handle -d <test_dir> [N] - unlink test files and hardlinks, drop caches and try to open by handle\n");
97 int main(int argc, char **argv)
103 char fname[PATH_MAX];
104 char fname2[PATH_MAX];
106 int mount_fd, mount_id;
108 int create = 0, delete = 0, nlink = 1;
110 if (argc < 2 || argc > 4)
113 while ((c = getopt(argc, argv, "clud")) != -1) {
130 fprintf(stderr, "illegal option '%s'\n", argv[optind]);
135 if (optind == argc || optind > 2)
137 test_dir = argv[optind++];
139 numfiles = atoi(argv[optind]);
140 if (!numfiles || numfiles > MAXFILES) {
141 fprintf(stderr, "illegal value '%s' for num_files\n", argv[optind]);
145 mount_fd = open(test_dir, O_RDONLY|O_DIRECTORY);
152 * Create the test files and remove leftover hardlinks from previous run
154 for (i=0; create && i < numfiles; i++) {
155 sprintf(fname, "%s/file%06d", test_dir, i);
156 sprintf(fname2, "%s/link%06d", test_dir, i);
157 fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
159 printf("Warning (%s,%d), open(%s) failed.\n", __FILE__, __LINE__, fname);
164 /* blow up leftovers hardlinks if they exist */
165 ret = unlink(fname2);
166 if (ret < 0 && errno != ENOENT) {
172 /* sync to get the new inodes to hit the disk */
175 /* create the handles */
176 for (i=0; i < numfiles; i++) {
177 sprintf(fname, "%s/file%06d", test_dir, i);
178 handle[i].fh.handle_bytes = MAX_HANDLE_SZ;
179 ret = name_to_handle_at(AT_FDCWD, fname, &handle[i].fh, &mount_id, 0);
181 perror("name_to_handle");
186 /* after creating test set only check that fs supports exportfs */
190 /* hardlink the files */
191 for (i=0; nlink > 1 && i < numfiles; i++) {
192 sprintf(fname, "%s/file%06d", test_dir, i);
193 sprintf(fname2, "%s/link%06d", test_dir, i);
194 ret = link(fname, fname2);
201 /* unlink the files */
202 for (i=0; delete && i < numfiles; i++) {
203 sprintf(fname, "%s/file%06d", test_dir, i);
204 sprintf(fname2, "%s/link%06d", test_dir, i);
210 /* with -d flag, delete the hardlink if it exists */
212 ret = unlink(fname2);
213 if (ret < 0 && errno != ENOENT) {
219 /* sync to get log forced for unlink transactions to hit the disk */
222 /* sync once more FTW */
226 * now drop the caches so that unlinked inodes are reclaimed and
227 * buftarg page cache is emptied so that the inode cluster has to be
228 * fetched from disk again for the open_by_handle() call.
230 ret = system("echo 3 > /proc/sys/vm/drop_caches");
232 perror("drop_caches");
237 * now try to open the files by the stored handles. Expecting ESTALE
238 * if all files and their hardlinks have been unlinked.
240 for (i=0; i < numfiles; i++) {
242 fd = open_by_handle_at(mount_fd, &handle[i].fh, O_RDWR);
243 if (nlink && fd >= 0) {
246 } else if (!nlink && fd < 0 && (errno == ENOENT || errno == ESTALE)) {
250 printf("open_by_handle(%d) opened an unlinked file!\n", i);
253 printf("open_by_handle(%d) returned %d incorrectly on %s file!\n", i, errno,
254 nlink ? "a linked" : "an unlinked");