Commit | Line | Data |
---|---|---|
1c6fdbd8 KO |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _BCACHEFS_FS_H | |
3 | #define _BCACHEFS_FS_H | |
4 | ||
2ea90048 | 5 | #include "inode.h" |
1c6fdbd8 KO |
6 | #include "opts.h" |
7 | #include "str_hash.h" | |
8 | #include "quota_types.h" | |
9 | ||
10 | #include <linux/seqlock.h> | |
11 | #include <linux/stat.h> | |
12 | ||
13 | /* | |
14 | * Two-state lock - can be taken for add or block - both states are shared, | |
15 | * like read side of rwsem, but conflict with other state: | |
16 | */ | |
17 | struct pagecache_lock { | |
18 | atomic_long_t v; | |
19 | wait_queue_head_t wait; | |
20 | }; | |
21 | ||
22 | static inline void pagecache_lock_init(struct pagecache_lock *lock) | |
23 | { | |
24 | atomic_long_set(&lock->v, 0); | |
25 | init_waitqueue_head(&lock->wait); | |
26 | } | |
27 | ||
28 | void bch2_pagecache_add_put(struct pagecache_lock *); | |
eb8e6e9c | 29 | bool bch2_pagecache_add_tryget(struct pagecache_lock *); |
1c6fdbd8 KO |
30 | void bch2_pagecache_add_get(struct pagecache_lock *); |
31 | void bch2_pagecache_block_put(struct pagecache_lock *); | |
32 | void bch2_pagecache_block_get(struct pagecache_lock *); | |
33 | ||
34 | struct bch_inode_info { | |
35 | struct inode v; | |
33c74e41 | 36 | unsigned long ei_flags; |
1c6fdbd8 KO |
37 | |
38 | struct mutex ei_update_lock; | |
39 | u64 ei_journal_seq; | |
40 | u64 ei_quota_reserved; | |
41 | unsigned long ei_last_dirtied; | |
42 | struct pagecache_lock ei_pagecache_lock; | |
43 | ||
44 | struct mutex ei_quota_lock; | |
45 | struct bch_qid ei_qid; | |
46 | ||
1c6fdbd8 KO |
47 | /* copy of inode in btree: */ |
48 | struct bch_inode_unpacked ei_inode; | |
49 | }; | |
50 | ||
33c74e41 KO |
51 | /* |
52 | * Set if we've gotten a btree error for this inode, and thus the vfs inode and | |
53 | * btree inode may be inconsistent: | |
54 | */ | |
55 | #define EI_INODE_ERROR 0 | |
56 | ||
1c6fdbd8 KO |
57 | #define to_bch_ei(_inode) \ |
58 | container_of_or_null(_inode, struct bch_inode_info, v) | |
59 | ||
8095708f KO |
60 | static inline int ptrcmp(void *l, void *r) |
61 | { | |
3ea2b1e1 | 62 | return cmp_int(l, r); |
8095708f KO |
63 | } |
64 | ||
168f4c5f KO |
65 | enum bch_inode_lock_op { |
66 | INODE_LOCK = (1U << 0), | |
76426098 KO |
67 | INODE_PAGECACHE_BLOCK = (1U << 1), |
68 | INODE_UPDATE_LOCK = (1U << 2), | |
168f4c5f KO |
69 | }; |
70 | ||
71 | #define bch2_lock_inodes(_locks, ...) \ | |
8095708f KO |
72 | do { \ |
73 | struct bch_inode_info *a[] = { NULL, __VA_ARGS__ }; \ | |
74 | unsigned i; \ | |
75 | \ | |
168f4c5f | 76 | bubble_sort(&a[1], ARRAY_SIZE(a) - 1, ptrcmp); \ |
8095708f | 77 | \ |
168f4c5f | 78 | for (i = 1; i < ARRAY_SIZE(a); i++) \ |
8095708f | 79 | if (a[i] != a[i - 1]) { \ |
76426098 | 80 | if ((_locks) & INODE_LOCK) \ |
168f4c5f | 81 | down_write_nested(&a[i]->v.i_rwsem, i); \ |
76426098 KO |
82 | if ((_locks) & INODE_PAGECACHE_BLOCK) \ |
83 | bch2_pagecache_block_get(&a[i]->ei_pagecache_lock);\ | |
84 | if ((_locks) & INODE_UPDATE_LOCK) \ | |
8095708f | 85 | mutex_lock_nested(&a[i]->ei_update_lock, i);\ |
8095708f KO |
86 | } \ |
87 | } while (0) | |
88 | ||
168f4c5f KO |
89 | #define bch2_unlock_inodes(_locks, ...) \ |
90 | do { \ | |
91 | struct bch_inode_info *a[] = { NULL, __VA_ARGS__ }; \ | |
92 | unsigned i; \ | |
93 | \ | |
94 | bubble_sort(&a[1], ARRAY_SIZE(a) - 1, ptrcmp); \ | |
95 | \ | |
96 | for (i = 1; i < ARRAY_SIZE(a); i++) \ | |
97 | if (a[i] != a[i - 1]) { \ | |
76426098 | 98 | if ((_locks) & INODE_LOCK) \ |
168f4c5f | 99 | up_write(&a[i]->v.i_rwsem); \ |
76426098 KO |
100 | if ((_locks) & INODE_PAGECACHE_BLOCK) \ |
101 | bch2_pagecache_block_put(&a[i]->ei_pagecache_lock);\ | |
102 | if ((_locks) & INODE_UPDATE_LOCK) \ | |
168f4c5f KO |
103 | mutex_unlock(&a[i]->ei_update_lock); \ |
104 | } \ | |
105 | } while (0) | |
8095708f | 106 | |
1c6fdbd8 KO |
107 | static inline struct bch_inode_info *file_bch_inode(struct file *file) |
108 | { | |
109 | return to_bch_ei(file_inode(file)); | |
110 | } | |
111 | ||
96012e14 KO |
112 | static inline bool inode_attr_changing(struct bch_inode_info *dir, |
113 | struct bch_inode_info *inode, | |
114 | enum inode_opt_id id) | |
115 | { | |
116 | return !(inode->ei_inode.bi_fields_set & (1 << id)) && | |
117 | bch2_inode_opt_get(&dir->ei_inode, id) != | |
118 | bch2_inode_opt_get(&inode->ei_inode, id); | |
119 | } | |
120 | ||
121 | static inline bool inode_attrs_changing(struct bch_inode_info *dir, | |
122 | struct bch_inode_info *inode) | |
123 | { | |
124 | unsigned id; | |
125 | ||
126 | for (id = 0; id < Inode_opt_nr; id++) | |
127 | if (inode_attr_changing(dir, inode, id)) | |
128 | return true; | |
129 | ||
130 | return false; | |
131 | } | |
132 | ||
1c6fdbd8 KO |
133 | struct bch_inode_unpacked; |
134 | ||
135 | #ifndef NO_BCACHEFS_FS | |
136 | ||
0f5254aa KO |
137 | int bch2_fs_quota_transfer(struct bch_fs *, |
138 | struct bch_inode_info *, | |
139 | struct bch_qid, | |
140 | unsigned, | |
141 | enum quota_acct_mode); | |
142 | ||
2fab25cd KO |
143 | static inline int bch2_set_projid(struct bch_fs *c, |
144 | struct bch_inode_info *inode, | |
145 | u32 projid) | |
146 | { | |
147 | struct bch_qid qid = inode->ei_qid; | |
148 | ||
149 | qid.q[QTYP_PRJ] = projid; | |
150 | ||
151 | return bch2_fs_quota_transfer(c, inode, qid, | |
152 | 1 << QTYP_PRJ, | |
153 | KEY_TYPE_QUOTA_PREALLOC); | |
154 | } | |
155 | ||
8095708f KO |
156 | struct inode *bch2_vfs_inode_get(struct bch_fs *, u64); |
157 | ||
1c6fdbd8 KO |
158 | /* returns 0 if we want to do the update, or error is passed up */ |
159 | typedef int (*inode_set_fn)(struct bch_inode_info *, | |
160 | struct bch_inode_unpacked *, void *); | |
161 | ||
162 | void bch2_inode_update_after_write(struct bch_fs *, | |
163 | struct bch_inode_info *, | |
164 | struct bch_inode_unpacked *, | |
165 | unsigned); | |
2ea90048 KO |
166 | int __must_check bch2_write_inode(struct bch_fs *, struct bch_inode_info *, |
167 | inode_set_fn, void *, unsigned); | |
1c6fdbd8 KO |
168 | |
169 | void bch2_vfs_exit(void); | |
170 | int bch2_vfs_init(void); | |
171 | ||
172 | #else | |
173 | ||
174 | static inline void bch2_vfs_exit(void) {} | |
175 | static inline int bch2_vfs_init(void) { return 0; } | |
176 | ||
177 | #endif /* NO_BCACHEFS_FS */ | |
178 | ||
179 | #endif /* _BCACHEFS_FS_H */ |