]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - fs/aufs/sysfs.c
UBUNTU: ubuntu: vbox -- update to 5.2.6-dfsg-5
[mirror_ubuntu-bionic-kernel.git] / fs / aufs / sysfs.c
CommitLineData
0006ebb4
SF
1/*
2 * Copyright (C) 2005-2017 Junjiro R. Okajima
3 *
4 * This program, aufs is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * sysfs interface
20 */
21
22#include <linux/compat.h>
23#include <linux/seq_file.h>
24#include "aufs.h"
25
26#ifdef CONFIG_AUFS_FS_MODULE
27/* this entry violates the "one line per file" policy of sysfs */
28static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr,
29 char *buf)
30{
31 ssize_t err;
32 static char *conf =
33/* this file is generated at compiling */
34#include "conf.str"
35 ;
36
37 err = snprintf(buf, PAGE_SIZE, conf);
38 if (unlikely(err >= PAGE_SIZE))
39 err = -EFBIG;
40 return err;
41}
42
43static struct kobj_attribute au_config_attr = __ATTR_RO(config);
44#endif
45
46static struct attribute *au_attr[] = {
47#ifdef CONFIG_AUFS_FS_MODULE
48 &au_config_attr.attr,
49#endif
50 NULL, /* need to NULL terminate the list of attributes */
51};
52
53static struct attribute_group sysaufs_attr_group_body = {
54 .attrs = au_attr
55};
56
57struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body;
58
59/* ---------------------------------------------------------------------- */
60
61int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb)
62{
63 int err;
64
65 SiMustAnyLock(sb);
66
67 err = 0;
68 if (au_opt_test(au_mntflags(sb), XINO)) {
69 err = au_xino_path(seq, au_sbi(sb)->si_xib);
70 seq_putc(seq, '\n');
71 }
72 return err;
73}
74
75/*
76 * the lifetime of branch is independent from the entry under sysfs.
77 * sysfs handles the lifetime of the entry, and never call ->show() after it is
78 * unlinked.
79 */
80static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb,
81 aufs_bindex_t bindex, int idx)
82{
83 int err;
84 struct path path;
85 struct dentry *root;
86 struct au_branch *br;
87 au_br_perm_str_t perm;
88
89 AuDbg("b%d\n", bindex);
90
91 err = 0;
92 root = sb->s_root;
93 di_read_lock_parent(root, !AuLock_IR);
94 br = au_sbr(sb, bindex);
95
96 switch (idx) {
97 case AuBrSysfs_BR:
98 path.mnt = au_br_mnt(br);
99 path.dentry = au_h_dptr(root, bindex);
100 err = au_seq_path(seq, &path);
101 if (!err) {
102 au_optstr_br_perm(&perm, br->br_perm);
103 seq_printf(seq, "=%s\n", perm.a);
104 }
105 break;
106 case AuBrSysfs_BRID:
107 seq_printf(seq, "%d\n", br->br_id);
108 break;
109 }
110 di_read_unlock(root, !AuLock_IR);
111 if (unlikely(err || seq_has_overflowed(seq)))
112 err = -E2BIG;
113
114 return err;
115}
116
117/* ---------------------------------------------------------------------- */
118
119static struct seq_file *au_seq(char *p, ssize_t len)
120{
121 struct seq_file *seq;
122
123 seq = kzalloc(sizeof(*seq), GFP_NOFS);
124 if (seq) {
125 /* mutex_init(&seq.lock); */
126 seq->buf = p;
127 seq->size = len;
128 return seq; /* success */
129 }
130
131 seq = ERR_PTR(-ENOMEM);
132 return seq;
133}
134
135#define SysaufsBr_PREFIX "br"
136#define SysaufsBrid_PREFIX "brid"
137
138/* todo: file size may exceed PAGE_SIZE */
139ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr,
140 char *buf)
141{
142 ssize_t err;
143 int idx;
144 long l;
145 aufs_bindex_t bbot;
146 struct au_sbinfo *sbinfo;
147 struct super_block *sb;
148 struct seq_file *seq;
149 char *name;
150 struct attribute **cattr;
151
152 sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
153 sb = sbinfo->si_sb;
154
155 /*
156 * prevent a race condition between sysfs and aufs.
157 * for instance, sysfs_file_read() calls sysfs_get_active_two() which
158 * prohibits maintaining the sysfs entries.
159 * hew we acquire read lock after sysfs_get_active_two().
160 * on the other hand, the remount process may maintain the sysfs/aufs
161 * entries after acquiring write lock.
162 * it can cause a deadlock.
163 * simply we gave up processing read here.
164 */
165 err = -EBUSY;
166 if (unlikely(!si_noflush_read_trylock(sb)))
167 goto out;
168
169 seq = au_seq(buf, PAGE_SIZE);
170 err = PTR_ERR(seq);
171 if (IS_ERR(seq))
172 goto out_unlock;
173
174 name = (void *)attr->name;
175 cattr = sysaufs_si_attrs;
176 while (*cattr) {
177 if (!strcmp(name, (*cattr)->name)) {
178 err = container_of(*cattr, struct sysaufs_si_attr, attr)
179 ->show(seq, sb);
180 goto out_seq;
181 }
182 cattr++;
183 }
184
185 if (!strncmp(name, SysaufsBrid_PREFIX,
186 sizeof(SysaufsBrid_PREFIX) - 1)) {
187 idx = AuBrSysfs_BRID;
188 name += sizeof(SysaufsBrid_PREFIX) - 1;
189 } else if (!strncmp(name, SysaufsBr_PREFIX,
190 sizeof(SysaufsBr_PREFIX) - 1)) {
191 idx = AuBrSysfs_BR;
192 name += sizeof(SysaufsBr_PREFIX) - 1;
193 } else
194 BUG();
195
196 err = kstrtol(name, 10, &l);
197 if (!err) {
198 bbot = au_sbbot(sb);
199 if (l <= bbot)
200 err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx);
201 else
202 err = -ENOENT;
203 }
204
205out_seq:
206 if (!err) {
207 err = seq->count;
208 /* sysfs limit */
209 if (unlikely(err == PAGE_SIZE))
210 err = -EFBIG;
211 }
212 kfree(seq);
213out_unlock:
214 si_read_unlock(sb);
215out:
216 return err;
217}
218
219/* ---------------------------------------------------------------------- */
220
221static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg)
222{
223 int err;
224 int16_t brid;
225 aufs_bindex_t bindex, bbot;
226 size_t sz;
227 char *buf;
228 struct seq_file *seq;
229 struct au_branch *br;
230
231 si_read_lock(sb, AuLock_FLUSH);
232 bbot = au_sbbot(sb);
233 err = bbot + 1;
234 if (!arg)
235 goto out;
236
237 err = -ENOMEM;
238 buf = (void *)__get_free_page(GFP_NOFS);
239 if (unlikely(!buf))
240 goto out;
241
242 seq = au_seq(buf, PAGE_SIZE);
243 err = PTR_ERR(seq);
244 if (IS_ERR(seq))
245 goto out_buf;
246
247 sz = sizeof(*arg) - offsetof(union aufs_brinfo, path);
248 for (bindex = 0; bindex <= bbot; bindex++, arg++) {
249 err = !access_ok(VERIFY_WRITE, arg, sizeof(*arg));
250 if (unlikely(err))
251 break;
252
253 br = au_sbr(sb, bindex);
254 brid = br->br_id;
255 BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id));
256 err = __put_user(brid, &arg->id);
257 if (unlikely(err))
258 break;
259
260 BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm));
261 err = __put_user(br->br_perm, &arg->perm);
262 if (unlikely(err))
263 break;
264
265 err = au_seq_path(seq, &br->br_path);
266 if (unlikely(err))
267 break;
268 seq_putc(seq, '\0');
269 if (!seq_has_overflowed(seq)) {
270 err = copy_to_user(arg->path, seq->buf, seq->count);
271 seq->count = 0;
272 if (unlikely(err))
273 break;
274 } else {
275 err = -E2BIG;
276 goto out_seq;
277 }
278 }
279 if (unlikely(err))
280 err = -EFAULT;
281
282out_seq:
283 kfree(seq);
284out_buf:
285 free_page((unsigned long)buf);
286out:
287 si_read_unlock(sb);
288 return err;
289}
290
291long au_brinfo_ioctl(struct file *file, unsigned long arg)
292{
293 return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg);
294}
295
296#ifdef CONFIG_COMPAT
297long au_brinfo_compat_ioctl(struct file *file, unsigned long arg)
298{
299 return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg));
300}
301#endif
302
303/* ---------------------------------------------------------------------- */
304
305void sysaufs_br_init(struct au_branch *br)
306{
307 int i;
308 struct au_brsysfs *br_sysfs;
309 struct attribute *attr;
310
311 br_sysfs = br->br_sysfs;
312 for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) {
313 attr = &br_sysfs->attr;
314 sysfs_attr_init(attr);
315 attr->name = br_sysfs->name;
316 attr->mode = S_IRUGO;
317 br_sysfs++;
318 }
319}
320
321void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex)
322{
323 struct au_branch *br;
324 struct kobject *kobj;
325 struct au_brsysfs *br_sysfs;
326 int i;
327 aufs_bindex_t bbot;
328
329 dbgaufs_brs_del(sb, bindex);
330
331 if (!sysaufs_brs)
332 return;
333
334 kobj = &au_sbi(sb)->si_kobj;
335 bbot = au_sbbot(sb);
336 for (; bindex <= bbot; bindex++) {
337 br = au_sbr(sb, bindex);
338 br_sysfs = br->br_sysfs;
339 for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) {
340 sysfs_remove_file(kobj, &br_sysfs->attr);
341 br_sysfs++;
342 }
343 }
344}
345
346void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex)
347{
348 int err, i;
349 aufs_bindex_t bbot;
350 struct kobject *kobj;
351 struct au_branch *br;
352 struct au_brsysfs *br_sysfs;
353
354 dbgaufs_brs_add(sb, bindex);
355
356 if (!sysaufs_brs)
357 return;
358
359 kobj = &au_sbi(sb)->si_kobj;
360 bbot = au_sbbot(sb);
361 for (; bindex <= bbot; bindex++) {
362 br = au_sbr(sb, bindex);
363 br_sysfs = br->br_sysfs;
364 snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name),
365 SysaufsBr_PREFIX "%d", bindex);
366 snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name),
367 SysaufsBrid_PREFIX "%d", bindex);
368 for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) {
369 err = sysfs_create_file(kobj, &br_sysfs->attr);
370 if (unlikely(err))
371 pr_warn("failed %s under sysfs(%d)\n",
372 br_sysfs->name, err);
373 br_sysfs++;
374 }
375 }
376}