]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - fs/aufs/fhsm.c
UBUNTU: SAUCE: Import aufs driver
[mirror_ubuntu-artful-kernel.git] / fs / aufs / fhsm.c
1 /*
2 * Copyright (C) 2011-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, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /*
20 * File-based Hierarchy Storage Management
21 */
22
23 #include <linux/anon_inodes.h>
24 #include <linux/poll.h>
25 #include <linux/seq_file.h>
26 #include <linux/statfs.h>
27 #include "aufs.h"
28
29 static aufs_bindex_t au_fhsm_bottom(struct super_block *sb)
30 {
31 struct au_sbinfo *sbinfo;
32 struct au_fhsm *fhsm;
33
34 SiMustAnyLock(sb);
35
36 sbinfo = au_sbi(sb);
37 fhsm = &sbinfo->si_fhsm;
38 AuDebugOn(!fhsm);
39 return fhsm->fhsm_bottom;
40 }
41
42 void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex)
43 {
44 struct au_sbinfo *sbinfo;
45 struct au_fhsm *fhsm;
46
47 SiMustWriteLock(sb);
48
49 sbinfo = au_sbi(sb);
50 fhsm = &sbinfo->si_fhsm;
51 AuDebugOn(!fhsm);
52 fhsm->fhsm_bottom = bindex;
53 }
54
55 /* ---------------------------------------------------------------------- */
56
57 static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br)
58 {
59 struct au_br_fhsm *bf;
60
61 bf = br->br_fhsm;
62 MtxMustLock(&bf->bf_lock);
63
64 return !bf->bf_readable
65 || time_after(jiffies,
66 bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire);
67 }
68
69 /* ---------------------------------------------------------------------- */
70
71 static void au_fhsm_notify(struct super_block *sb, int val)
72 {
73 struct au_sbinfo *sbinfo;
74 struct au_fhsm *fhsm;
75
76 SiMustAnyLock(sb);
77
78 sbinfo = au_sbi(sb);
79 fhsm = &sbinfo->si_fhsm;
80 if (au_fhsm_pid(fhsm)
81 && atomic_read(&fhsm->fhsm_readable) != -1) {
82 atomic_set(&fhsm->fhsm_readable, val);
83 if (val)
84 wake_up(&fhsm->fhsm_wqh);
85 }
86 }
87
88 static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex,
89 struct aufs_stfs *rstfs, int do_lock, int do_notify)
90 {
91 int err;
92 struct au_branch *br;
93 struct au_br_fhsm *bf;
94
95 br = au_sbr(sb, bindex);
96 AuDebugOn(au_br_rdonly(br));
97 bf = br->br_fhsm;
98 AuDebugOn(!bf);
99
100 if (do_lock)
101 mutex_lock(&bf->bf_lock);
102 else
103 MtxMustLock(&bf->bf_lock);
104
105 /* sb->s_root for NFS is unreliable */
106 err = au_br_stfs(br, &bf->bf_stfs);
107 if (unlikely(err)) {
108 AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err);
109 goto out;
110 }
111
112 bf->bf_jiffy = jiffies;
113 bf->bf_readable = 1;
114 if (do_notify)
115 au_fhsm_notify(sb, /*val*/1);
116 if (rstfs)
117 *rstfs = bf->bf_stfs;
118
119 out:
120 if (do_lock)
121 mutex_unlock(&bf->bf_lock);
122 au_fhsm_notify(sb, /*val*/1);
123
124 return err;
125 }
126
127 void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force)
128 {
129 int err;
130 struct au_sbinfo *sbinfo;
131 struct au_fhsm *fhsm;
132 struct au_branch *br;
133 struct au_br_fhsm *bf;
134
135 AuDbg("b%d, force %d\n", bindex, force);
136 SiMustAnyLock(sb);
137
138 sbinfo = au_sbi(sb);
139 fhsm = &sbinfo->si_fhsm;
140 if (!au_ftest_si(sbinfo, FHSM)
141 || fhsm->fhsm_bottom == bindex)
142 return;
143
144 br = au_sbr(sb, bindex);
145 bf = br->br_fhsm;
146 AuDebugOn(!bf);
147 mutex_lock(&bf->bf_lock);
148 if (force
149 || au_fhsm_pid(fhsm)
150 || au_fhsm_test_jiffy(sbinfo, br))
151 err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0,
152 /*do_notify*/1);
153 mutex_unlock(&bf->bf_lock);
154 }
155
156 void au_fhsm_wrote_all(struct super_block *sb, int force)
157 {
158 aufs_bindex_t bindex, bbot;
159 struct au_branch *br;
160
161 /* exclude the bottom */
162 bbot = au_fhsm_bottom(sb);
163 for (bindex = 0; bindex < bbot; bindex++) {
164 br = au_sbr(sb, bindex);
165 if (au_br_fhsm(br->br_perm))
166 au_fhsm_wrote(sb, bindex, force);
167 }
168 }
169
170 /* ---------------------------------------------------------------------- */
171
172 static unsigned int au_fhsm_poll(struct file *file,
173 struct poll_table_struct *wait)
174 {
175 unsigned int mask;
176 struct au_sbinfo *sbinfo;
177 struct au_fhsm *fhsm;
178
179 mask = 0;
180 sbinfo = file->private_data;
181 fhsm = &sbinfo->si_fhsm;
182 poll_wait(file, &fhsm->fhsm_wqh, wait);
183 if (atomic_read(&fhsm->fhsm_readable))
184 mask = POLLIN /* | POLLRDNORM */;
185
186 AuTraceErr((int)mask);
187 return mask;
188 }
189
190 static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr,
191 struct aufs_stfs *stfs, __s16 brid)
192 {
193 int err;
194
195 err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs));
196 if (!err)
197 err = __put_user(brid, &stbr->brid);
198 if (unlikely(err))
199 err = -EFAULT;
200
201 return err;
202 }
203
204 static ssize_t au_fhsm_do_read(struct super_block *sb,
205 struct aufs_stbr __user *stbr, size_t count)
206 {
207 ssize_t err;
208 int nstbr;
209 aufs_bindex_t bindex, bbot;
210 struct au_branch *br;
211 struct au_br_fhsm *bf;
212
213 /* except the bottom branch */
214 err = 0;
215 nstbr = 0;
216 bbot = au_fhsm_bottom(sb);
217 for (bindex = 0; !err && bindex < bbot; bindex++) {
218 br = au_sbr(sb, bindex);
219 if (!au_br_fhsm(br->br_perm))
220 continue;
221
222 bf = br->br_fhsm;
223 mutex_lock(&bf->bf_lock);
224 if (bf->bf_readable) {
225 err = -EFAULT;
226 if (count >= sizeof(*stbr))
227 err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs,
228 br->br_id);
229 if (!err) {
230 bf->bf_readable = 0;
231 count -= sizeof(*stbr);
232 nstbr++;
233 }
234 }
235 mutex_unlock(&bf->bf_lock);
236 }
237 if (!err)
238 err = sizeof(*stbr) * nstbr;
239
240 return err;
241 }
242
243 static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count,
244 loff_t *pos)
245 {
246 ssize_t err;
247 int readable;
248 aufs_bindex_t nfhsm, bindex, bbot;
249 struct au_sbinfo *sbinfo;
250 struct au_fhsm *fhsm;
251 struct au_branch *br;
252 struct super_block *sb;
253
254 err = 0;
255 sbinfo = file->private_data;
256 fhsm = &sbinfo->si_fhsm;
257 need_data:
258 spin_lock_irq(&fhsm->fhsm_wqh.lock);
259 if (!atomic_read(&fhsm->fhsm_readable)) {
260 if (vfsub_file_flags(file) & O_NONBLOCK)
261 err = -EAGAIN;
262 else
263 err = wait_event_interruptible_locked_irq
264 (fhsm->fhsm_wqh,
265 atomic_read(&fhsm->fhsm_readable));
266 }
267 spin_unlock_irq(&fhsm->fhsm_wqh.lock);
268 if (unlikely(err))
269 goto out;
270
271 /* sb may already be dead */
272 au_rw_read_lock(&sbinfo->si_rwsem);
273 readable = atomic_read(&fhsm->fhsm_readable);
274 if (readable > 0) {
275 sb = sbinfo->si_sb;
276 AuDebugOn(!sb);
277 /* exclude the bottom branch */
278 nfhsm = 0;
279 bbot = au_fhsm_bottom(sb);
280 for (bindex = 0; bindex < bbot; bindex++) {
281 br = au_sbr(sb, bindex);
282 if (au_br_fhsm(br->br_perm))
283 nfhsm++;
284 }
285 err = -EMSGSIZE;
286 if (nfhsm * sizeof(struct aufs_stbr) <= count) {
287 atomic_set(&fhsm->fhsm_readable, 0);
288 err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf,
289 count);
290 }
291 }
292 au_rw_read_unlock(&sbinfo->si_rwsem);
293 if (!readable)
294 goto need_data;
295
296 out:
297 return err;
298 }
299
300 static int au_fhsm_release(struct inode *inode, struct file *file)
301 {
302 struct au_sbinfo *sbinfo;
303 struct au_fhsm *fhsm;
304
305 /* sb may already be dead */
306 sbinfo = file->private_data;
307 fhsm = &sbinfo->si_fhsm;
308 spin_lock(&fhsm->fhsm_spin);
309 fhsm->fhsm_pid = 0;
310 spin_unlock(&fhsm->fhsm_spin);
311 kobject_put(&sbinfo->si_kobj);
312
313 return 0;
314 }
315
316 static const struct file_operations au_fhsm_fops = {
317 .owner = THIS_MODULE,
318 .llseek = noop_llseek,
319 .read = au_fhsm_read,
320 .poll = au_fhsm_poll,
321 .release = au_fhsm_release
322 };
323
324 int au_fhsm_fd(struct super_block *sb, int oflags)
325 {
326 int err, fd;
327 struct au_sbinfo *sbinfo;
328 struct au_fhsm *fhsm;
329
330 err = -EPERM;
331 if (unlikely(!capable(CAP_SYS_ADMIN)))
332 goto out;
333
334 err = -EINVAL;
335 if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK)))
336 goto out;
337
338 err = 0;
339 sbinfo = au_sbi(sb);
340 fhsm = &sbinfo->si_fhsm;
341 spin_lock(&fhsm->fhsm_spin);
342 if (!fhsm->fhsm_pid)
343 fhsm->fhsm_pid = current->pid;
344 else
345 err = -EBUSY;
346 spin_unlock(&fhsm->fhsm_spin);
347 if (unlikely(err))
348 goto out;
349
350 oflags |= O_RDONLY;
351 /* oflags |= FMODE_NONOTIFY; */
352 fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags);
353 err = fd;
354 if (unlikely(fd < 0))
355 goto out_pid;
356
357 /* succeed reglardless 'fhsm' status */
358 kobject_get(&sbinfo->si_kobj);
359 si_noflush_read_lock(sb);
360 if (au_ftest_si(sbinfo, FHSM))
361 au_fhsm_wrote_all(sb, /*force*/0);
362 si_read_unlock(sb);
363 goto out; /* success */
364
365 out_pid:
366 spin_lock(&fhsm->fhsm_spin);
367 fhsm->fhsm_pid = 0;
368 spin_unlock(&fhsm->fhsm_spin);
369 out:
370 AuTraceErr(err);
371 return err;
372 }
373
374 /* ---------------------------------------------------------------------- */
375
376 int au_fhsm_br_alloc(struct au_branch *br)
377 {
378 int err;
379
380 err = 0;
381 br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS);
382 if (br->br_fhsm)
383 au_br_fhsm_init(br->br_fhsm);
384 else
385 err = -ENOMEM;
386
387 return err;
388 }
389
390 /* ---------------------------------------------------------------------- */
391
392 void au_fhsm_fin(struct super_block *sb)
393 {
394 au_fhsm_notify(sb, /*val*/-1);
395 }
396
397 void au_fhsm_init(struct au_sbinfo *sbinfo)
398 {
399 struct au_fhsm *fhsm;
400
401 fhsm = &sbinfo->si_fhsm;
402 spin_lock_init(&fhsm->fhsm_spin);
403 init_waitqueue_head(&fhsm->fhsm_wqh);
404 atomic_set(&fhsm->fhsm_readable, 0);
405 fhsm->fhsm_expire
406 = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC);
407 fhsm->fhsm_bottom = -1;
408 }
409
410 void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec)
411 {
412 sbinfo->si_fhsm.fhsm_expire
413 = msecs_to_jiffies(sec * MSEC_PER_SEC);
414 }
415
416 void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo)
417 {
418 unsigned int u;
419
420 if (!au_ftest_si(sbinfo, FHSM))
421 return;
422
423 u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC;
424 if (u != AUFS_FHSM_CACHE_DEF_SEC)
425 seq_printf(seq, ",fhsm_sec=%u", u);
426 }