1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _BCACHEFS_FS_H |
3 | #define _BCACHEFS_FS_H |
4 | |
5 | #include "inode.h" |
6 | #include "opts.h" |
7 | #include "str_hash.h" |
8 | #include "quota_types.h" |
9 | #include "two_state_shared_lock.h" |
10 | |
11 | #include <linux/seqlock.h> |
12 | #include <linux/stat.h> |
13 | |
14 | struct bch_inode_info { |
15 | struct inode v; |
16 | struct list_head ei_vfs_inode_list; |
17 | unsigned long ei_flags; |
18 | |
19 | struct mutex ei_update_lock; |
20 | u64 ei_quota_reserved; |
21 | unsigned long ei_last_dirtied; |
22 | two_state_lock_t ei_pagecache_lock; |
23 | |
24 | struct mutex ei_quota_lock; |
25 | struct bch_qid ei_qid; |
26 | |
27 | u32 ei_subvol; |
28 | |
29 | /* |
30 | * When we've been doing nocow writes we'll need to issue flushes to the |
31 | * underlying block devices |
32 | * |
33 | * XXX: a device may have had a flush issued by some other codepath. It |
34 | * would be better to keep for each device a sequence number that's |
35 | * incremented when we isusue a cache flush, and track here the sequence |
36 | * number that needs flushing. |
37 | */ |
38 | struct bch_devs_mask ei_devs_need_flush; |
39 | |
40 | /* copy of inode in btree: */ |
41 | struct bch_inode_unpacked ei_inode; |
42 | }; |
43 | |
44 | #define bch2_pagecache_add_put(i) bch2_two_state_unlock(&i->ei_pagecache_lock, 0) |
45 | #define bch2_pagecache_add_tryget(i) bch2_two_state_trylock(&i->ei_pagecache_lock, 0) |
46 | #define bch2_pagecache_add_get(i) bch2_two_state_lock(&i->ei_pagecache_lock, 0) |
47 | |
48 | #define bch2_pagecache_block_put(i) bch2_two_state_unlock(&i->ei_pagecache_lock, 1) |
49 | #define bch2_pagecache_block_get(i) bch2_two_state_lock(&i->ei_pagecache_lock, 1) |
50 | |
51 | static inline subvol_inum inode_inum(struct bch_inode_info *inode) |
52 | { |
53 | return (subvol_inum) { |
54 | .subvol = inode->ei_subvol, |
55 | .inum = inode->ei_inode.bi_inum, |
56 | }; |
57 | } |
58 | |
59 | /* |
60 | * Set if we've gotten a btree error for this inode, and thus the vfs inode and |
61 | * btree inode may be inconsistent: |
62 | */ |
63 | #define EI_INODE_ERROR 0 |
64 | |
65 | /* |
66 | * Set in the inode is in a snapshot subvolume - we don't do quota accounting in |
67 | * those: |
68 | */ |
69 | #define EI_INODE_SNAPSHOT 1 |
70 | |
71 | #define to_bch_ei(_inode) \ |
72 | container_of_or_null(_inode, struct bch_inode_info, v) |
73 | |
74 | static inline int ptrcmp(void *l, void *r) |
75 | { |
76 | return cmp_int(l, r); |
77 | } |
78 | |
79 | enum bch_inode_lock_op { |
80 | INODE_PAGECACHE_BLOCK = (1U << 0), |
81 | INODE_UPDATE_LOCK = (1U << 1), |
82 | }; |
83 | |
84 | #define bch2_lock_inodes(_locks, ...) \ |
85 | do { \ |
86 | struct bch_inode_info *a[] = { NULL, __VA_ARGS__ }; \ |
87 | unsigned i; \ |
88 | \ |
89 | bubble_sort(&a[1], ARRAY_SIZE(a) - 1, ptrcmp); \ |
90 | \ |
91 | for (i = 1; i < ARRAY_SIZE(a); i++) \ |
92 | if (a[i] != a[i - 1]) { \ |
93 | if ((_locks) & INODE_PAGECACHE_BLOCK) \ |
94 | bch2_pagecache_block_get(a[i]);\ |
95 | if ((_locks) & INODE_UPDATE_LOCK) \ |
96 | mutex_lock_nested(&a[i]->ei_update_lock, i);\ |
97 | } \ |
98 | } while (0) |
99 | |
100 | #define bch2_unlock_inodes(_locks, ...) \ |
101 | do { \ |
102 | struct bch_inode_info *a[] = { NULL, __VA_ARGS__ }; \ |
103 | unsigned i; \ |
104 | \ |
105 | bubble_sort(&a[1], ARRAY_SIZE(a) - 1, ptrcmp); \ |
106 | \ |
107 | for (i = 1; i < ARRAY_SIZE(a); i++) \ |
108 | if (a[i] != a[i - 1]) { \ |
109 | if ((_locks) & INODE_PAGECACHE_BLOCK) \ |
110 | bch2_pagecache_block_put(a[i]);\ |
111 | if ((_locks) & INODE_UPDATE_LOCK) \ |
112 | mutex_unlock(&a[i]->ei_update_lock); \ |
113 | } \ |
114 | } while (0) |
115 | |
116 | static inline struct bch_inode_info *file_bch_inode(struct file *file) |
117 | { |
118 | return to_bch_ei(file_inode(file)); |
119 | } |
120 | |
121 | static inline bool inode_attr_changing(struct bch_inode_info *dir, |
122 | struct bch_inode_info *inode, |
123 | enum inode_opt_id id) |
124 | { |
125 | return !(inode->ei_inode.bi_fields_set & (1 << id)) && |
126 | bch2_inode_opt_get(inode: &dir->ei_inode, id) != |
127 | bch2_inode_opt_get(inode: &inode->ei_inode, id); |
128 | } |
129 | |
130 | static inline bool inode_attrs_changing(struct bch_inode_info *dir, |
131 | struct bch_inode_info *inode) |
132 | { |
133 | unsigned id; |
134 | |
135 | for (id = 0; id < Inode_opt_nr; id++) |
136 | if (inode_attr_changing(dir, inode, id)) |
137 | return true; |
138 | |
139 | return false; |
140 | } |
141 | |
142 | struct bch_inode_unpacked; |
143 | |
144 | #ifndef NO_BCACHEFS_FS |
145 | |
146 | struct bch_inode_info * |
147 | __bch2_create(struct mnt_idmap *, struct bch_inode_info *, |
148 | struct dentry *, umode_t, dev_t, subvol_inum, unsigned); |
149 | |
150 | int bch2_fs_quota_transfer(struct bch_fs *, |
151 | struct bch_inode_info *, |
152 | struct bch_qid, |
153 | unsigned, |
154 | enum quota_acct_mode); |
155 | |
156 | static inline int bch2_set_projid(struct bch_fs *c, |
157 | struct bch_inode_info *inode, |
158 | u32 projid) |
159 | { |
160 | struct bch_qid qid = inode->ei_qid; |
161 | |
162 | qid.q[QTYP_PRJ] = projid; |
163 | |
164 | return bch2_fs_quota_transfer(c, inode, qid, |
165 | 1 << QTYP_PRJ, |
166 | KEY_TYPE_QUOTA_PREALLOC); |
167 | } |
168 | |
169 | struct inode *bch2_vfs_inode_get(struct bch_fs *, subvol_inum); |
170 | |
171 | /* returns 0 if we want to do the update, or error is passed up */ |
172 | typedef int (*inode_set_fn)(struct btree_trans *, |
173 | struct bch_inode_info *, |
174 | struct bch_inode_unpacked *, void *); |
175 | |
176 | void bch2_inode_update_after_write(struct btree_trans *, |
177 | struct bch_inode_info *, |
178 | struct bch_inode_unpacked *, |
179 | unsigned); |
180 | int __must_check bch2_write_inode(struct bch_fs *, struct bch_inode_info *, |
181 | inode_set_fn, void *, unsigned); |
182 | |
183 | int bch2_setattr_nonsize(struct mnt_idmap *, |
184 | struct bch_inode_info *, |
185 | struct iattr *); |
186 | int __bch2_unlink(struct inode *, struct dentry *, bool); |
187 | |
188 | void bch2_evict_subvolume_inodes(struct bch_fs *, snapshot_id_list *); |
189 | |
190 | void bch2_vfs_exit(void); |
191 | int bch2_vfs_init(void); |
192 | |
193 | #else |
194 | |
195 | #define bch2_inode_update_after_write(_trans, _inode, _inode_u, _fields) ({ do {} while (0); }) |
196 | |
197 | static inline void bch2_evict_subvolume_inodes(struct bch_fs *c, |
198 | snapshot_id_list *s) {} |
199 | static inline void bch2_vfs_exit(void) {} |
200 | static inline int bch2_vfs_init(void) { return 0; } |
201 | |
202 | #endif /* NO_BCACHEFS_FS */ |
203 | |
204 | #endif /* _BCACHEFS_FS_H */ |
205 | |