1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * NILFS inode file |
4 | * |
5 | * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation. |
6 | * |
7 | * Written by Amagai Yoshiji. |
8 | * Revised by Ryusuke Konishi. |
9 | * |
10 | */ |
11 | |
12 | #include <linux/types.h> |
13 | #include <linux/buffer_head.h> |
14 | #include "nilfs.h" |
15 | #include "mdt.h" |
16 | #include "alloc.h" |
17 | #include "ifile.h" |
18 | |
19 | /** |
20 | * struct nilfs_ifile_info - on-memory private data of ifile |
21 | * @mi: on-memory private data of metadata file |
22 | * @palloc_cache: persistent object allocator cache of ifile |
23 | */ |
24 | struct nilfs_ifile_info { |
25 | struct nilfs_mdt_info mi; |
26 | struct nilfs_palloc_cache palloc_cache; |
27 | }; |
28 | |
29 | static inline struct nilfs_ifile_info *NILFS_IFILE_I(struct inode *ifile) |
30 | { |
31 | return (struct nilfs_ifile_info *)NILFS_MDT(inode: ifile); |
32 | } |
33 | |
34 | /** |
35 | * nilfs_ifile_create_inode - create a new disk inode |
36 | * @ifile: ifile inode |
37 | * @out_ino: pointer to a variable to store inode number |
38 | * @out_bh: buffer_head contains newly allocated disk inode |
39 | * |
40 | * Return Value: On success, 0 is returned and the newly allocated inode |
41 | * number is stored in the place pointed by @ino, and buffer_head pointer |
42 | * that contains newly allocated disk inode structure is stored in the |
43 | * place pointed by @out_bh |
44 | * On error, one of the following negative error codes is returned. |
45 | * |
46 | * %-EIO - I/O error. |
47 | * |
48 | * %-ENOMEM - Insufficient amount of memory available. |
49 | * |
50 | * %-ENOSPC - No inode left. |
51 | */ |
52 | int nilfs_ifile_create_inode(struct inode *ifile, ino_t *out_ino, |
53 | struct buffer_head **out_bh) |
54 | { |
55 | struct nilfs_palloc_req req; |
56 | int ret; |
57 | |
58 | req.pr_entry_nr = 0; /* |
59 | * 0 says find free inode from beginning |
60 | * of a group. dull code!! |
61 | */ |
62 | req.pr_entry_bh = NULL; |
63 | |
64 | ret = nilfs_palloc_prepare_alloc_entry(ifile, &req); |
65 | if (!ret) { |
66 | ret = nilfs_palloc_get_entry_block(ifile, req.pr_entry_nr, 1, |
67 | &req.pr_entry_bh); |
68 | if (ret < 0) |
69 | nilfs_palloc_abort_alloc_entry(ifile, &req); |
70 | } |
71 | if (ret < 0) { |
72 | brelse(bh: req.pr_entry_bh); |
73 | return ret; |
74 | } |
75 | nilfs_palloc_commit_alloc_entry(ifile, &req); |
76 | mark_buffer_dirty(bh: req.pr_entry_bh); |
77 | nilfs_mdt_mark_dirty(inode: ifile); |
78 | *out_ino = (ino_t)req.pr_entry_nr; |
79 | *out_bh = req.pr_entry_bh; |
80 | return 0; |
81 | } |
82 | |
83 | /** |
84 | * nilfs_ifile_delete_inode - delete a disk inode |
85 | * @ifile: ifile inode |
86 | * @ino: inode number |
87 | * |
88 | * Return Value: On success, 0 is returned. On error, one of the following |
89 | * negative error codes is returned. |
90 | * |
91 | * %-EIO - I/O error. |
92 | * |
93 | * %-ENOMEM - Insufficient amount of memory available. |
94 | * |
95 | * %-ENOENT - The inode number @ino have not been allocated. |
96 | */ |
97 | int nilfs_ifile_delete_inode(struct inode *ifile, ino_t ino) |
98 | { |
99 | struct nilfs_palloc_req req = { |
100 | .pr_entry_nr = ino, .pr_entry_bh = NULL |
101 | }; |
102 | struct nilfs_inode *raw_inode; |
103 | void *kaddr; |
104 | int ret; |
105 | |
106 | ret = nilfs_palloc_prepare_free_entry(ifile, &req); |
107 | if (!ret) { |
108 | ret = nilfs_palloc_get_entry_block(ifile, req.pr_entry_nr, 0, |
109 | &req.pr_entry_bh); |
110 | if (ret < 0) |
111 | nilfs_palloc_abort_free_entry(ifile, &req); |
112 | } |
113 | if (ret < 0) { |
114 | brelse(bh: req.pr_entry_bh); |
115 | return ret; |
116 | } |
117 | |
118 | kaddr = kmap_atomic(page: req.pr_entry_bh->b_page); |
119 | raw_inode = nilfs_palloc_block_get_entry(ifile, req.pr_entry_nr, |
120 | req.pr_entry_bh, kaddr); |
121 | raw_inode->i_flags = 0; |
122 | kunmap_atomic(kaddr); |
123 | |
124 | mark_buffer_dirty(bh: req.pr_entry_bh); |
125 | brelse(bh: req.pr_entry_bh); |
126 | |
127 | nilfs_palloc_commit_free_entry(ifile, &req); |
128 | |
129 | return 0; |
130 | } |
131 | |
132 | int nilfs_ifile_get_inode_block(struct inode *ifile, ino_t ino, |
133 | struct buffer_head **out_bh) |
134 | { |
135 | struct super_block *sb = ifile->i_sb; |
136 | int err; |
137 | |
138 | if (unlikely(!NILFS_VALID_INODE(sb, ino))) { |
139 | nilfs_error(sb, "bad inode number: %lu" , (unsigned long)ino); |
140 | return -EINVAL; |
141 | } |
142 | |
143 | err = nilfs_palloc_get_entry_block(ifile, ino, 0, out_bh); |
144 | if (unlikely(err)) |
145 | nilfs_warn(sb, "error %d reading inode: ino=%lu" , |
146 | err, (unsigned long)ino); |
147 | return err; |
148 | } |
149 | |
150 | /** |
151 | * nilfs_ifile_count_free_inodes - calculate free inodes count |
152 | * @ifile: ifile inode |
153 | * @nmaxinodes: current maximum of available inodes count [out] |
154 | * @nfreeinodes: free inodes count [out] |
155 | */ |
156 | int nilfs_ifile_count_free_inodes(struct inode *ifile, |
157 | u64 *nmaxinodes, u64 *nfreeinodes) |
158 | { |
159 | u64 nused; |
160 | int err; |
161 | |
162 | *nmaxinodes = 0; |
163 | *nfreeinodes = 0; |
164 | |
165 | nused = atomic64_read(v: &NILFS_I(inode: ifile)->i_root->inodes_count); |
166 | err = nilfs_palloc_count_max_entries(ifile, nused, nmaxinodes); |
167 | if (likely(!err)) |
168 | *nfreeinodes = *nmaxinodes - nused; |
169 | return err; |
170 | } |
171 | |
172 | /** |
173 | * nilfs_ifile_read - read or get ifile inode |
174 | * @sb: super block instance |
175 | * @root: root object |
176 | * @inode_size: size of an inode |
177 | * @raw_inode: on-disk ifile inode |
178 | * @inodep: buffer to store the inode |
179 | */ |
180 | int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root, |
181 | size_t inode_size, struct nilfs_inode *raw_inode, |
182 | struct inode **inodep) |
183 | { |
184 | struct inode *ifile; |
185 | int err; |
186 | |
187 | ifile = nilfs_iget_locked(sb, root, NILFS_IFILE_INO); |
188 | if (unlikely(!ifile)) |
189 | return -ENOMEM; |
190 | if (!(ifile->i_state & I_NEW)) |
191 | goto out; |
192 | |
193 | err = nilfs_mdt_init(inode: ifile, NILFS_MDT_GFP, |
194 | objsz: sizeof(struct nilfs_ifile_info)); |
195 | if (err) |
196 | goto failed; |
197 | |
198 | err = nilfs_palloc_init_blockgroup(ifile, inode_size); |
199 | if (err) |
200 | goto failed; |
201 | |
202 | nilfs_palloc_setup_cache(inode: ifile, cache: &NILFS_IFILE_I(ifile)->palloc_cache); |
203 | |
204 | err = nilfs_read_inode_common(ifile, raw_inode); |
205 | if (err) |
206 | goto failed; |
207 | |
208 | unlock_new_inode(ifile); |
209 | out: |
210 | *inodep = ifile; |
211 | return 0; |
212 | failed: |
213 | iget_failed(ifile); |
214 | return err; |
215 | } |
216 | |