]>
git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - fs/aufs/dcsub.c
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2005-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, see <http://www.gnu.org/licenses/>.
20 * sub-routines for dentry cache
25 static void au_dpage_free(struct au_dpage
*dpage
)
31 for (i
= 0; i
< dpage
->ndentry
; i
++)
33 free_page((unsigned long)dpage
->dentries
);
36 int au_dpages_init(struct au_dcsub_pages
*dpages
, gfp_t gfp
)
42 dpages
->dpages
= kmalloc(sizeof(*dpages
->dpages
), gfp
);
43 if (unlikely(!dpages
->dpages
))
46 p
= (void *)__get_free_page(gfp
);
50 dpages
->dpages
[0].ndentry
= 0;
51 dpages
->dpages
[0].dentries
= p
;
53 return 0; /* success */
56 au_kfree_try_rcu(dpages
->dpages
);
61 void au_dpages_free(struct au_dcsub_pages
*dpages
)
67 for (i
= 0; i
< dpages
->ndpage
; i
++)
69 au_kfree_try_rcu(dpages
->dpages
);
72 static int au_dpages_append(struct au_dcsub_pages
*dpages
,
73 struct dentry
*dentry
, gfp_t gfp
)
76 struct au_dpage
*dpage
;
79 dpage
= dpages
->dpages
+ dpages
->ndpage
- 1;
80 sz
= PAGE_SIZE
/ sizeof(dentry
);
81 if (unlikely(dpage
->ndentry
>= sz
)) {
84 sz
= dpages
->ndpage
* sizeof(*dpages
->dpages
);
85 p
= au_kzrealloc(dpages
->dpages
, sz
,
86 sz
+ sizeof(*dpages
->dpages
), gfp
,
92 dpage
= dpages
->dpages
+ dpages
->ndpage
;
93 p
= (void *)__get_free_page(gfp
);
102 AuDebugOn(au_dcount(dentry
) <= 0);
103 dpage
->dentries
[dpage
->ndentry
++] = dget_dlock(dentry
);
104 return 0; /* success */
110 /* todo: BAD approach */
111 /* copied from linux/fs/dcache.c */
119 extern void d_walk(struct dentry
*parent
, void *data
,
120 enum d_walk_ret (*enter
)(void *, struct dentry
*));
122 struct ac_dpages_arg
{
124 struct au_dcsub_pages
*dpages
;
125 struct super_block
*sb
;
130 static enum d_walk_ret
au_call_dpages_append(void *_arg
, struct dentry
*dentry
)
133 struct ac_dpages_arg
*arg
= _arg
;
135 ret
= D_WALK_CONTINUE
;
136 if (dentry
->d_sb
== arg
->sb
138 && au_dcount(dentry
) > 0
140 && (!arg
->test
|| arg
->test(dentry
, arg
->arg
))) {
141 arg
->err
= au_dpages_append(arg
->dpages
, dentry
, GFP_ATOMIC
);
142 if (unlikely(arg
->err
))
149 int au_dcsub_pages(struct au_dcsub_pages
*dpages
, struct dentry
*root
,
150 au_dpages_test test
, void *arg
)
152 struct ac_dpages_arg args
= {
160 d_walk(root
, &args
, au_call_dpages_append
);
165 int au_dcsub_pages_rev(struct au_dcsub_pages
*dpages
, struct dentry
*dentry
,
166 int do_include
, au_dpages_test test
, void *arg
)
171 write_seqlock(&rename_lock
);
172 spin_lock(&dentry
->d_lock
);
174 && au_dcount(dentry
) > 0
175 && (!test
|| test(dentry
, arg
)))
176 err
= au_dpages_append(dpages
, dentry
, GFP_ATOMIC
);
177 spin_unlock(&dentry
->d_lock
);
182 * RCU for vfsmount is unnecessary since this is a traverse in a single
185 while (!IS_ROOT(dentry
)) {
186 dentry
= dentry
->d_parent
; /* rename_lock is locked */
187 spin_lock(&dentry
->d_lock
);
188 if (au_dcount(dentry
) > 0
189 && (!test
|| test(dentry
, arg
)))
190 err
= au_dpages_append(dpages
, dentry
, GFP_ATOMIC
);
191 spin_unlock(&dentry
->d_lock
);
197 write_sequnlock(&rename_lock
);
201 static inline int au_dcsub_dpages_aufs(struct dentry
*dentry
, void *arg
)
203 return au_di(dentry
) && dentry
->d_sb
== arg
;
206 int au_dcsub_pages_rev_aufs(struct au_dcsub_pages
*dpages
,
207 struct dentry
*dentry
, int do_include
)
209 return au_dcsub_pages_rev(dpages
, dentry
, do_include
,
210 au_dcsub_dpages_aufs
, dentry
->d_sb
);
213 int au_test_subdir(struct dentry
*d1
, struct dentry
*d2
)
215 struct path path
[2] = {
224 return path_is_under(path
+ 0, path
+ 1);