1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2011-2021 Junjiro R. Okajima
5 * This program, aufs is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 * File-based Hierarchy Storage Management
24 #include <linux/anon_inodes.h>
25 #include <linux/poll.h>
26 #include <linux/seq_file.h>
27 #include <linux/statfs.h>
30 static aufs_bindex_t
au_fhsm_bottom(struct super_block
*sb
)
32 struct au_sbinfo
*sbinfo
;
38 fhsm
= &sbinfo
->si_fhsm
;
40 return fhsm
->fhsm_bottom
;
43 void au_fhsm_set_bottom(struct super_block
*sb
, aufs_bindex_t bindex
)
45 struct au_sbinfo
*sbinfo
;
51 fhsm
= &sbinfo
->si_fhsm
;
53 fhsm
->fhsm_bottom
= bindex
;
56 /* ---------------------------------------------------------------------- */
58 static int au_fhsm_test_jiffy(struct au_sbinfo
*sbinfo
, struct au_branch
*br
)
60 struct au_br_fhsm
*bf
;
63 MtxMustLock(&bf
->bf_lock
);
65 return !bf
->bf_readable
66 || time_after(jiffies
,
67 bf
->bf_jiffy
+ sbinfo
->si_fhsm
.fhsm_expire
);
70 /* ---------------------------------------------------------------------- */
72 static void au_fhsm_notify(struct super_block
*sb
, int val
)
74 struct au_sbinfo
*sbinfo
;
80 fhsm
= &sbinfo
->si_fhsm
;
82 && atomic_read(&fhsm
->fhsm_readable
) != -1) {
83 atomic_set(&fhsm
->fhsm_readable
, val
);
85 wake_up(&fhsm
->fhsm_wqh
);
89 static int au_fhsm_stfs(struct super_block
*sb
, aufs_bindex_t bindex
,
90 struct aufs_stfs
*rstfs
, int do_lock
, int do_notify
)
94 struct au_br_fhsm
*bf
;
96 br
= au_sbr(sb
, bindex
);
97 AuDebugOn(au_br_rdonly(br
));
102 mutex_lock(&bf
->bf_lock
);
104 MtxMustLock(&bf
->bf_lock
);
106 /* sb->s_root for NFS is unreliable */
107 err
= au_br_stfs(br
, &bf
->bf_stfs
);
109 AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex
, err
);
113 bf
->bf_jiffy
= jiffies
;
116 au_fhsm_notify(sb
, /*val*/1);
118 *rstfs
= bf
->bf_stfs
;
122 mutex_unlock(&bf
->bf_lock
);
123 au_fhsm_notify(sb
, /*val*/1);
128 void au_fhsm_wrote(struct super_block
*sb
, aufs_bindex_t bindex
, int force
)
131 struct au_sbinfo
*sbinfo
;
132 struct au_fhsm
*fhsm
;
133 struct au_branch
*br
;
134 struct au_br_fhsm
*bf
;
136 AuDbg("b%d, force %d\n", bindex
, force
);
140 fhsm
= &sbinfo
->si_fhsm
;
141 if (!au_ftest_si(sbinfo
, FHSM
)
142 || fhsm
->fhsm_bottom
== bindex
)
145 br
= au_sbr(sb
, bindex
);
148 mutex_lock(&bf
->bf_lock
);
151 || au_fhsm_test_jiffy(sbinfo
, br
))
152 err
= au_fhsm_stfs(sb
, bindex
, /*rstfs*/NULL
, /*do_lock*/0,
154 mutex_unlock(&bf
->bf_lock
);
157 void au_fhsm_wrote_all(struct super_block
*sb
, int force
)
159 aufs_bindex_t bindex
, bbot
;
160 struct au_branch
*br
;
162 /* exclude the bottom */
163 bbot
= au_fhsm_bottom(sb
);
164 for (bindex
= 0; bindex
< bbot
; bindex
++) {
165 br
= au_sbr(sb
, bindex
);
166 if (au_br_fhsm(br
->br_perm
))
167 au_fhsm_wrote(sb
, bindex
, force
);
171 /* ---------------------------------------------------------------------- */
173 static __poll_t
au_fhsm_poll(struct file
*file
, 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
= EPOLLIN
/* | EPOLLRDNORM */;
187 AuDbg("mask 0x%x\n", mask
);
191 static int au_fhsm_do_read_one(struct aufs_stbr __user
*stbr
,
192 struct aufs_stfs
*stfs
, __s16 brid
)
196 err
= copy_to_user(&stbr
->stfs
, stfs
, sizeof(*stfs
));
198 err
= __put_user(brid
, &stbr
->brid
);
205 static ssize_t
au_fhsm_do_read(struct super_block
*sb
,
206 struct aufs_stbr __user
*stbr
, size_t count
)
210 aufs_bindex_t bindex
, bbot
;
211 struct au_branch
*br
;
212 struct au_br_fhsm
*bf
;
214 /* except the bottom branch */
217 bbot
= au_fhsm_bottom(sb
);
218 for (bindex
= 0; !err
&& bindex
< bbot
; bindex
++) {
219 br
= au_sbr(sb
, bindex
);
220 if (!au_br_fhsm(br
->br_perm
))
224 mutex_lock(&bf
->bf_lock
);
225 if (bf
->bf_readable
) {
227 if (count
>= sizeof(*stbr
))
228 err
= au_fhsm_do_read_one(stbr
++, &bf
->bf_stfs
,
232 count
-= sizeof(*stbr
);
236 mutex_unlock(&bf
->bf_lock
);
239 err
= sizeof(*stbr
) * nstbr
;
244 static ssize_t
au_fhsm_read(struct file
*file
, char __user
*buf
, size_t count
,
249 aufs_bindex_t nfhsm
, bindex
, bbot
;
250 struct au_sbinfo
*sbinfo
;
251 struct au_fhsm
*fhsm
;
252 struct au_branch
*br
;
253 struct super_block
*sb
;
256 sbinfo
= file
->private_data
;
257 fhsm
= &sbinfo
->si_fhsm
;
259 spin_lock_irq(&fhsm
->fhsm_wqh
.lock
);
260 if (!atomic_read(&fhsm
->fhsm_readable
)) {
261 if (vfsub_file_flags(file
) & O_NONBLOCK
)
264 err
= wait_event_interruptible_locked_irq
266 atomic_read(&fhsm
->fhsm_readable
));
268 spin_unlock_irq(&fhsm
->fhsm_wqh
.lock
);
272 /* sb may already be dead */
273 au_rw_read_lock(&sbinfo
->si_rwsem
);
274 readable
= atomic_read(&fhsm
->fhsm_readable
);
278 /* exclude the bottom branch */
280 bbot
= au_fhsm_bottom(sb
);
281 for (bindex
= 0; bindex
< bbot
; bindex
++) {
282 br
= au_sbr(sb
, bindex
);
283 if (au_br_fhsm(br
->br_perm
))
287 if (nfhsm
* sizeof(struct aufs_stbr
) <= count
) {
288 atomic_set(&fhsm
->fhsm_readable
, 0);
289 err
= au_fhsm_do_read(sbinfo
->si_sb
, (void __user
*)buf
,
293 au_rw_read_unlock(&sbinfo
->si_rwsem
);
301 static int au_fhsm_release(struct inode
*inode
, struct file
*file
)
303 struct au_sbinfo
*sbinfo
;
304 struct au_fhsm
*fhsm
;
306 /* sb may already be dead */
307 sbinfo
= file
->private_data
;
308 fhsm
= &sbinfo
->si_fhsm
;
309 spin_lock(&fhsm
->fhsm_spin
);
311 spin_unlock(&fhsm
->fhsm_spin
);
312 kobject_put(&sbinfo
->si_kobj
);
317 static const struct file_operations au_fhsm_fops
= {
318 .owner
= THIS_MODULE
,
319 .llseek
= noop_llseek
,
320 .read
= au_fhsm_read
,
321 .poll
= au_fhsm_poll
,
322 .release
= au_fhsm_release
325 int au_fhsm_fd(struct super_block
*sb
, int oflags
)
328 struct au_sbinfo
*sbinfo
;
329 struct au_fhsm
*fhsm
;
332 if (unlikely(!capable(CAP_SYS_ADMIN
)))
336 if (unlikely(oflags
& ~(O_CLOEXEC
| O_NONBLOCK
)))
341 fhsm
= &sbinfo
->si_fhsm
;
342 spin_lock(&fhsm
->fhsm_spin
);
344 fhsm
->fhsm_pid
= current
->pid
;
347 spin_unlock(&fhsm
->fhsm_spin
);
352 /* oflags |= FMODE_NONOTIFY; */
353 fd
= anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops
, sbinfo
, oflags
);
355 if (unlikely(fd
< 0))
358 /* succeed regardless 'fhsm' status */
359 kobject_get(&sbinfo
->si_kobj
);
360 si_noflush_read_lock(sb
);
361 if (au_ftest_si(sbinfo
, FHSM
))
362 au_fhsm_wrote_all(sb
, /*force*/0);
364 goto out
; /* success */
367 spin_lock(&fhsm
->fhsm_spin
);
369 spin_unlock(&fhsm
->fhsm_spin
);
375 /* ---------------------------------------------------------------------- */
377 int au_fhsm_br_alloc(struct au_branch
*br
)
382 br
->br_fhsm
= kmalloc(sizeof(*br
->br_fhsm
), GFP_NOFS
);
384 au_br_fhsm_init(br
->br_fhsm
);
391 /* ---------------------------------------------------------------------- */
393 void au_fhsm_fin(struct super_block
*sb
)
395 au_fhsm_notify(sb
, /*val*/-1);
398 void au_fhsm_init(struct au_sbinfo
*sbinfo
)
400 struct au_fhsm
*fhsm
;
402 fhsm
= &sbinfo
->si_fhsm
;
403 spin_lock_init(&fhsm
->fhsm_spin
);
404 init_waitqueue_head(&fhsm
->fhsm_wqh
);
405 atomic_set(&fhsm
->fhsm_readable
, 0);
407 = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC
* MSEC_PER_SEC
);
408 fhsm
->fhsm_bottom
= -1;
411 void au_fhsm_set(struct au_sbinfo
*sbinfo
, unsigned int sec
)
413 sbinfo
->si_fhsm
.fhsm_expire
414 = msecs_to_jiffies(sec
* MSEC_PER_SEC
);
417 void au_fhsm_show(struct seq_file
*seq
, struct au_sbinfo
*sbinfo
)
421 if (!au_ftest_si(sbinfo
, FHSM
))
424 u
= jiffies_to_msecs(sbinfo
->si_fhsm
.fhsm_expire
) / MSEC_PER_SEC
;
425 if (u
!= AUFS_FHSM_CACHE_DEF_SEC
)
426 seq_printf(seq
, ",fhsm_sec=%u", u
);