Whamcloud - gitweb
LU-9558 llite: user enhanced getattr functionality in newer kernels
[fs/lustre-release.git] / lustre / tests / kernel / kinode.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22
23 /*
24  * Copyright 2017 Cray Inc. All rights reserved.
25  * Author: Frank Zago.
26  */
27
28 /* Check that the inode number is the same whether the call to
29  * vfs_getattr is coming from a system call or from a kthread. When
30  * CONFIG_X86_X32 was set, the result used to be different for
31  * Lustre. In addition, a user can also check that the same inode
32  * number is also seen from the kernel and userspace.  */
33
34 #include <linux/module.h>
35 #include <linux/kernel.h>
36 #include <linux/kthread.h>
37 #include <linux/fs.h>
38 #include <linux/version.h>
39
40 /* Random ID passed by userspace, and printed in messages, used to
41  * separate different runs of that module. */
42 static int run_id;
43 module_param(run_id, int, 0644);
44 MODULE_PARM_DESC(run_id, "run ID");
45
46 /* Name of the file to stat. */
47 static char fname[4096];
48 module_param_string(fname, fname, sizeof(fname), 0644);
49 MODULE_PARM_DESC(fname, "name of file to stat");
50
51 struct completion thr_start;
52
53 #define PREFIX "lustre_kinode_%u:"
54
55 static int stat_file(struct kstat *stbuf)
56 {
57         struct file *fd;
58         int rc;
59
60         fd = filp_open(fname, O_RDONLY, 0);
61         if (IS_ERR(fd)) {
62                 pr_err(PREFIX " can't open file %s\n", run_id, fname);
63                 return -EIO;
64         }
65
66 #ifdef HAVE_INODEOPS_ENHANCED_GETATTR
67         rc = vfs_getattr(&fd->f_path, stbuf, STATX_INO, AT_STATX_SYNC_AS_STAT);
68 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
69         rc = vfs_getattr(&fd->f_path, stbuf);
70 #else
71         rc = vfs_getattr(fd->f_path.mnt, fd->f_path.dentry, stbuf);
72 #endif
73         if (rc != 0) {
74                 pr_err(PREFIX " vfs_getattr failed: %d\n", run_id, rc);
75                 goto out;
76         }
77
78         pr_err(PREFIX " inode is %llu\n", run_id, stbuf->ino);
79         rc = 0;
80
81 out:
82         filp_close(fd, NULL);
83
84         return rc;
85 }
86
87 static int stat_thread(void *data)
88 {
89         struct kstat *stbuf = data;
90         int rc;
91
92         /* Signal caller that thread has started. */
93         complete(&thr_start);
94
95         rc = stat_file(stbuf);
96
97         /* Wait for call to kthread_stop. */
98         set_current_state(TASK_INTERRUPTIBLE);
99         while (!kthread_should_stop()) {
100                 schedule();
101                 set_current_state(TASK_INTERRUPTIBLE);
102         }
103         set_current_state(TASK_RUNNING);
104
105         return rc;
106 }
107
108 static int __init kinode_init(void)
109 {
110         struct task_struct *thr;
111         struct kstat stbuf1;
112         struct kstat stbuf2;
113         int rc;
114
115 #ifdef CONFIG_X86_X32
116         pr_err(PREFIX " CONFIG_X86_X32 is set\n", run_id);
117 #else
118         pr_err(PREFIX " CONFIG_X86_X32 is not set\n", run_id);
119 #endif
120
121         if (strlen(fname) < 1) {
122                 pr_err(PREFIX " invalid file name '%s'\n", run_id, fname);
123                 goto out;
124         }
125
126         rc = stat_file(&stbuf1);
127         if (rc) {
128                 pr_err(PREFIX " direct stat failed: %d\n", run_id, rc);
129                 goto out;
130         }
131
132         /* Run the same from a kthread. */
133         init_completion(&thr_start);
134         thr = kthread_run(stat_thread, &stbuf2, "kinode_%u", run_id);
135         if (IS_ERR(thr)) {
136                 pr_err(PREFIX " Cannot create kthread\n", run_id);
137                 goto out;
138         }
139
140         /* Wait for the thread to start, then wait for it to
141          * terminate. */
142         wait_for_completion(&thr_start);
143         rc = kthread_stop(thr);
144         if (rc) {
145                 pr_err(PREFIX " indirect stat failed: %d\n", run_id, rc);
146                 goto out;
147         }
148
149         if (stbuf1.ino != stbuf2.ino)
150                 pr_err(PREFIX " inode numbers are different: %llu %llu\n",
151                        run_id, stbuf1.ino, stbuf2.ino);
152         else
153                 pr_err(PREFIX " inode numbers are identical: %llu\n",
154                        run_id, stbuf1.ino);
155
156 out:
157         /* Don't load. */
158         return -EINVAL;
159 }
160
161 static void __exit kinode_exit(void)
162 {
163 }
164
165 MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
166 MODULE_DESCRIPTION("Lustre inode stat test module");
167 MODULE_VERSION(LUSTRE_VERSION_STRING);
168 MODULE_LICENSE("GPL");
169
170 module_init(kinode_init);
171 module_exit(kinode_exit);