2 * Copyright (C) 2011-2017 Junjiro R. Okajima
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.
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.
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
20 * File-based Hierarchy Storage Management
23 #include <linux/anon_inodes.h>
24 #include <linux/poll.h>
25 #include <linux/seq_file.h>
26 #include <linux/statfs.h>
29 static aufs_bindex_t
au_fhsm_bottom(struct super_block
*sb
)
31 struct au_sbinfo
*sbinfo
;
37 fhsm
= &sbinfo
->si_fhsm
;
39 return fhsm
->fhsm_bottom
;
42 void au_fhsm_set_bottom(struct super_block
*sb
, aufs_bindex_t bindex
)
44 struct au_sbinfo
*sbinfo
;
50 fhsm
= &sbinfo
->si_fhsm
;
52 fhsm
->fhsm_bottom
= bindex
;
55 /* ---------------------------------------------------------------------- */
57 static int au_fhsm_test_jiffy(struct au_sbinfo
*sbinfo
, struct au_branch
*br
)
59 struct au_br_fhsm
*bf
;
62 MtxMustLock(&bf
->bf_lock
);
64 return !bf
->bf_readable
65 || time_after(jiffies
,
66 bf
->bf_jiffy
+ sbinfo
->si_fhsm
.fhsm_expire
);
69 /* ---------------------------------------------------------------------- */
71 static void au_fhsm_notify(struct super_block
*sb
, int val
)
73 struct au_sbinfo
*sbinfo
;
79 fhsm
= &sbinfo
->si_fhsm
;
81 && atomic_read(&fhsm
->fhsm_readable
) != -1) {
82 atomic_set(&fhsm
->fhsm_readable
, val
);
84 wake_up(&fhsm
->fhsm_wqh
);
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
)
93 struct au_br_fhsm
*bf
;
95 br
= au_sbr(sb
, bindex
);
96 AuDebugOn(au_br_rdonly(br
));
101 mutex_lock(&bf
->bf_lock
);
103 MtxMustLock(&bf
->bf_lock
);
105 /* sb->s_root for NFS is unreliable */
106 err
= au_br_stfs(br
, &bf
->bf_stfs
);
108 AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex
, err
);
112 bf
->bf_jiffy
= jiffies
;
115 au_fhsm_notify(sb
, /*val*/1);
117 *rstfs
= bf
->bf_stfs
;
121 mutex_unlock(&bf
->bf_lock
);
122 au_fhsm_notify(sb
, /*val*/1);
127 void au_fhsm_wrote(struct super_block
*sb
, aufs_bindex_t bindex
, int force
)
130 struct au_sbinfo
*sbinfo
;
131 struct au_fhsm
*fhsm
;
132 struct au_branch
*br
;
133 struct au_br_fhsm
*bf
;
135 AuDbg("b%d, force %d\n", bindex
, force
);
139 fhsm
= &sbinfo
->si_fhsm
;
140 if (!au_ftest_si(sbinfo
, FHSM
)
141 || fhsm
->fhsm_bottom
== bindex
)
144 br
= au_sbr(sb
, bindex
);
147 mutex_lock(&bf
->bf_lock
);
150 || au_fhsm_test_jiffy(sbinfo
, br
))
151 err
= au_fhsm_stfs(sb
, bindex
, /*rstfs*/NULL
, /*do_lock*/0,
153 mutex_unlock(&bf
->bf_lock
);
156 void au_fhsm_wrote_all(struct super_block
*sb
, int force
)
158 aufs_bindex_t bindex
, bbot
;
159 struct au_branch
*br
;
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
);
170 /* ---------------------------------------------------------------------- */
172 static unsigned int au_fhsm_poll(struct file
*file
,
173 struct poll_table_struct
*wait
)
176 struct au_sbinfo
*sbinfo
;
177 struct au_fhsm
*fhsm
;
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 */;
186 AuTraceErr((int)mask
);
190 static int au_fhsm_do_read_one(struct aufs_stbr __user
*stbr
,
191 struct aufs_stfs
*stfs
, __s16 brid
)
195 err
= copy_to_user(&stbr
->stfs
, stfs
, sizeof(*stfs
));
197 err
= __put_user(brid
, &stbr
->brid
);
204 static ssize_t
au_fhsm_do_read(struct super_block
*sb
,
205 struct aufs_stbr __user
*stbr
, size_t count
)
209 aufs_bindex_t bindex
, bbot
;
210 struct au_branch
*br
;
211 struct au_br_fhsm
*bf
;
213 /* except the bottom branch */
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
))
223 mutex_lock(&bf
->bf_lock
);
224 if (bf
->bf_readable
) {
226 if (count
>= sizeof(*stbr
))
227 err
= au_fhsm_do_read_one(stbr
++, &bf
->bf_stfs
,
231 count
-= sizeof(*stbr
);
235 mutex_unlock(&bf
->bf_lock
);
238 err
= sizeof(*stbr
) * nstbr
;
243 static ssize_t
au_fhsm_read(struct file
*file
, char __user
*buf
, size_t count
,
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
;
255 sbinfo
= file
->private_data
;
256 fhsm
= &sbinfo
->si_fhsm
;
258 spin_lock_irq(&fhsm
->fhsm_wqh
.lock
);
259 if (!atomic_read(&fhsm
->fhsm_readable
)) {
260 if (vfsub_file_flags(file
) & O_NONBLOCK
)
263 err
= wait_event_interruptible_locked_irq
265 atomic_read(&fhsm
->fhsm_readable
));
267 spin_unlock_irq(&fhsm
->fhsm_wqh
.lock
);
271 /* sb may already be dead */
272 au_rw_read_lock(&sbinfo
->si_rwsem
);
273 readable
= atomic_read(&fhsm
->fhsm_readable
);
277 /* exclude the bottom branch */
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
))
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
,
292 au_rw_read_unlock(&sbinfo
->si_rwsem
);
300 static int au_fhsm_release(struct inode
*inode
, struct file
*file
)
302 struct au_sbinfo
*sbinfo
;
303 struct au_fhsm
*fhsm
;
305 /* sb may already be dead */
306 sbinfo
= file
->private_data
;
307 fhsm
= &sbinfo
->si_fhsm
;
308 spin_lock(&fhsm
->fhsm_spin
);
310 spin_unlock(&fhsm
->fhsm_spin
);
311 kobject_put(&sbinfo
->si_kobj
);
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
324 int au_fhsm_fd(struct super_block
*sb
, int oflags
)
327 struct au_sbinfo
*sbinfo
;
328 struct au_fhsm
*fhsm
;
331 if (unlikely(!capable(CAP_SYS_ADMIN
)))
335 if (unlikely(oflags
& ~(O_CLOEXEC
| O_NONBLOCK
)))
340 fhsm
= &sbinfo
->si_fhsm
;
341 spin_lock(&fhsm
->fhsm_spin
);
343 fhsm
->fhsm_pid
= current
->pid
;
346 spin_unlock(&fhsm
->fhsm_spin
);
351 /* oflags |= FMODE_NONOTIFY; */
352 fd
= anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops
, sbinfo
, oflags
);
354 if (unlikely(fd
< 0))
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);
363 goto out
; /* success */
366 spin_lock(&fhsm
->fhsm_spin
);
368 spin_unlock(&fhsm
->fhsm_spin
);
374 /* ---------------------------------------------------------------------- */
376 int au_fhsm_br_alloc(struct au_branch
*br
)
381 br
->br_fhsm
= kmalloc(sizeof(*br
->br_fhsm
), GFP_NOFS
);
383 au_br_fhsm_init(br
->br_fhsm
);
390 /* ---------------------------------------------------------------------- */
392 void au_fhsm_fin(struct super_block
*sb
)
394 au_fhsm_notify(sb
, /*val*/-1);
397 void au_fhsm_init(struct au_sbinfo
*sbinfo
)
399 struct au_fhsm
*fhsm
;
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);
406 = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC
* MSEC_PER_SEC
);
407 fhsm
->fhsm_bottom
= -1;
410 void au_fhsm_set(struct au_sbinfo
*sbinfo
, unsigned int sec
)
412 sbinfo
->si_fhsm
.fhsm_expire
413 = msecs_to_jiffies(sec
* MSEC_PER_SEC
);
416 void au_fhsm_show(struct seq_file
*seq
, struct au_sbinfo
*sbinfo
)
420 if (!au_ftest_si(sbinfo
, FHSM
))
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
);