1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2000-2001 Christoph Hellwig. |
4 | * Copyright (c) 2016 Krzysztof Blaszkowski |
5 | */ |
6 | |
7 | /* |
8 | * Veritas filesystem driver - inode routines. |
9 | */ |
10 | #include <linux/fs.h> |
11 | #include <linux/buffer_head.h> |
12 | #include <linux/pagemap.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/namei.h> |
16 | |
17 | #include "vxfs.h" |
18 | #include "vxfs_inode.h" |
19 | #include "vxfs_extern.h" |
20 | |
21 | |
22 | #ifdef DIAGNOSTIC |
23 | /* |
24 | * Dump inode contents (partially). |
25 | */ |
26 | void |
27 | vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino) |
28 | { |
29 | printk(KERN_DEBUG "\n\n" ); |
30 | if (ino) |
31 | printk(KERN_DEBUG "dumping vxfs inode %ld\n" , ino); |
32 | else |
33 | printk(KERN_DEBUG "dumping unknown vxfs inode\n" ); |
34 | |
35 | printk(KERN_DEBUG "---------------------------\n" ); |
36 | printk(KERN_DEBUG "mode is %x\n" , vip->vii_mode); |
37 | printk(KERN_DEBUG "nlink:%u, uid:%u, gid:%u\n" , |
38 | vip->vii_nlink, vip->vii_uid, vip->vii_gid); |
39 | printk(KERN_DEBUG "size:%Lx, blocks:%u\n" , |
40 | vip->vii_size, vip->vii_blocks); |
41 | printk(KERN_DEBUG "orgtype:%u\n" , vip->vii_orgtype); |
42 | } |
43 | #endif |
44 | |
45 | /** |
46 | * vxfs_transmod - mode for a VxFS inode |
47 | * @vip: VxFS inode |
48 | * |
49 | * Description: |
50 | * vxfs_transmod returns a Linux mode_t for a given |
51 | * VxFS inode structure. |
52 | */ |
53 | static __inline__ umode_t |
54 | vxfs_transmod(struct vxfs_inode_info *vip) |
55 | { |
56 | umode_t ret = vip->vii_mode & ~VXFS_TYPE_MASK; |
57 | |
58 | if (VXFS_ISFIFO(vip)) |
59 | ret |= S_IFIFO; |
60 | if (VXFS_ISCHR(vip)) |
61 | ret |= S_IFCHR; |
62 | if (VXFS_ISDIR(vip)) |
63 | ret |= S_IFDIR; |
64 | if (VXFS_ISBLK(vip)) |
65 | ret |= S_IFBLK; |
66 | if (VXFS_ISLNK(vip)) |
67 | ret |= S_IFLNK; |
68 | if (VXFS_ISREG(vip)) |
69 | ret |= S_IFREG; |
70 | if (VXFS_ISSOC(vip)) |
71 | ret |= S_IFSOCK; |
72 | |
73 | return (ret); |
74 | } |
75 | |
76 | static inline void dip2vip_cpy(struct vxfs_sb_info *sbi, |
77 | struct vxfs_inode_info *vip, struct vxfs_dinode *dip) |
78 | { |
79 | struct inode *inode = &vip->vfs_inode; |
80 | |
81 | vip->vii_mode = fs32_to_cpu(sbi, a: dip->vdi_mode); |
82 | vip->vii_nlink = fs32_to_cpu(sbi, a: dip->vdi_nlink); |
83 | vip->vii_uid = fs32_to_cpu(sbi, a: dip->vdi_uid); |
84 | vip->vii_gid = fs32_to_cpu(sbi, a: dip->vdi_gid); |
85 | vip->vii_size = fs64_to_cpu(sbi, a: dip->vdi_size); |
86 | vip->vii_atime = fs32_to_cpu(sbi, a: dip->vdi_atime); |
87 | vip->vii_autime = fs32_to_cpu(sbi, a: dip->vdi_autime); |
88 | vip->vii_mtime = fs32_to_cpu(sbi, a: dip->vdi_mtime); |
89 | vip->vii_mutime = fs32_to_cpu(sbi, a: dip->vdi_mutime); |
90 | vip->vii_ctime = fs32_to_cpu(sbi, a: dip->vdi_ctime); |
91 | vip->vii_cutime = fs32_to_cpu(sbi, a: dip->vdi_cutime); |
92 | vip->vii_orgtype = dip->vdi_orgtype; |
93 | |
94 | vip->vii_blocks = fs32_to_cpu(sbi, a: dip->vdi_blocks); |
95 | vip->vii_gen = fs32_to_cpu(sbi, a: dip->vdi_gen); |
96 | |
97 | if (VXFS_ISDIR(vip)) |
98 | vip->vii_dotdot = fs32_to_cpu(sbi, a: dip->vdi_dotdot); |
99 | else if (!VXFS_ISREG(vip) && !VXFS_ISLNK(vip)) |
100 | vip->vii_rdev = fs32_to_cpu(sbi, a: dip->vdi_rdev); |
101 | |
102 | /* don't endian swap the fields that differ by orgtype */ |
103 | memcpy(&vip->vii_org, &dip->vdi_org, sizeof(vip->vii_org)); |
104 | |
105 | inode->i_mode = vxfs_transmod(vip); |
106 | i_uid_write(inode, uid: (uid_t)vip->vii_uid); |
107 | i_gid_write(inode, gid: (gid_t)vip->vii_gid); |
108 | |
109 | set_nlink(inode, nlink: vip->vii_nlink); |
110 | inode->i_size = vip->vii_size; |
111 | |
112 | inode_set_atime(inode, sec: vip->vii_atime, nsec: 0); |
113 | inode_set_ctime(inode, sec: vip->vii_ctime, nsec: 0); |
114 | inode_set_mtime(inode, sec: vip->vii_mtime, nsec: 0); |
115 | |
116 | inode->i_blocks = vip->vii_blocks; |
117 | inode->i_generation = vip->vii_gen; |
118 | } |
119 | |
120 | /** |
121 | * vxfs_blkiget - find inode based on extent # |
122 | * @sbp: superblock of the filesystem we search in |
123 | * @extent: number of the extent to search |
124 | * @ino: inode number to search |
125 | * |
126 | * Description: |
127 | * vxfs_blkiget searches inode @ino in the filesystem described by |
128 | * @sbp in the extent @extent. |
129 | * Returns the matching VxFS inode on success, else a NULL pointer. |
130 | * |
131 | * NOTE: |
132 | * While __vxfs_iget uses the pagecache vxfs_blkiget uses the |
133 | * buffercache. This function should not be used outside the |
134 | * read_super() method, otherwise the data may be incoherent. |
135 | */ |
136 | struct inode * |
137 | vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino) |
138 | { |
139 | struct buffer_head *bp; |
140 | struct inode *inode; |
141 | u_long block, offset; |
142 | |
143 | inode = new_inode(sb: sbp); |
144 | if (!inode) |
145 | return NULL; |
146 | inode->i_ino = get_next_ino(); |
147 | |
148 | block = extent + ((ino * VXFS_ISIZE) / sbp->s_blocksize); |
149 | offset = ((ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE); |
150 | bp = sb_bread(sb: sbp, block); |
151 | |
152 | if (bp && buffer_mapped(bh: bp)) { |
153 | struct vxfs_inode_info *vip = VXFS_INO(inode); |
154 | struct vxfs_dinode *dip; |
155 | |
156 | dip = (struct vxfs_dinode *)(bp->b_data + offset); |
157 | dip2vip_cpy(VXFS_SBI(sbp), vip, dip); |
158 | vip->vfs_inode.i_mapping->a_ops = &vxfs_aops; |
159 | #ifdef DIAGNOSTIC |
160 | vxfs_dumpi(vip, ino); |
161 | #endif |
162 | brelse(bh: bp); |
163 | return inode; |
164 | } |
165 | |
166 | printk(KERN_WARNING "vxfs: unable to read block %ld\n" , block); |
167 | brelse(bh: bp); |
168 | iput(inode); |
169 | return NULL; |
170 | } |
171 | |
172 | /** |
173 | * __vxfs_iget - generic find inode facility |
174 | * @ilistp: inode list |
175 | * @vip: VxFS inode to fill in |
176 | * @ino: inode number |
177 | * |
178 | * Description: |
179 | * Search the for inode number @ino in the filesystem |
180 | * described by @sbp. Use the specified inode table (@ilistp). |
181 | * Returns the matching inode on success, else an error code. |
182 | */ |
183 | static int |
184 | __vxfs_iget(struct inode *ilistp, struct vxfs_inode_info *vip, ino_t ino) |
185 | { |
186 | struct page *pp; |
187 | u_long offset; |
188 | |
189 | offset = (ino % (PAGE_SIZE / VXFS_ISIZE)) * VXFS_ISIZE; |
190 | pp = vxfs_get_page(ilistp->i_mapping, ino * VXFS_ISIZE / PAGE_SIZE); |
191 | |
192 | if (!IS_ERR(ptr: pp)) { |
193 | struct vxfs_dinode *dip; |
194 | caddr_t kaddr = (char *)page_address(pp); |
195 | |
196 | dip = (struct vxfs_dinode *)(kaddr + offset); |
197 | dip2vip_cpy(VXFS_SBI(ilistp->i_sb), vip, dip); |
198 | vip->vfs_inode.i_mapping->a_ops = &vxfs_aops; |
199 | #ifdef DIAGNOSTIC |
200 | vxfs_dumpi(vip, ino); |
201 | #endif |
202 | vxfs_put_page(pp); |
203 | return 0; |
204 | } |
205 | |
206 | printk(KERN_WARNING "vxfs: error on page 0x%p for inode %ld\n" , |
207 | pp, (unsigned long)ino); |
208 | return PTR_ERR(ptr: pp); |
209 | } |
210 | |
211 | /** |
212 | * vxfs_stiget - find inode using the structural inode list |
213 | * @sbp: VFS superblock |
214 | * @ino: inode # |
215 | * |
216 | * Description: |
217 | * Find inode @ino in the filesystem described by @sbp using |
218 | * the structural inode list. |
219 | * Returns the matching inode on success, else a NULL pointer. |
220 | */ |
221 | struct inode * |
222 | vxfs_stiget(struct super_block *sbp, ino_t ino) |
223 | { |
224 | struct inode *inode; |
225 | int error; |
226 | |
227 | inode = new_inode(sb: sbp); |
228 | if (!inode) |
229 | return NULL; |
230 | inode->i_ino = get_next_ino(); |
231 | |
232 | error = __vxfs_iget(VXFS_SBI(sbp)->vsi_stilist, vip: VXFS_INO(inode), ino); |
233 | if (error) { |
234 | iput(inode); |
235 | return NULL; |
236 | } |
237 | |
238 | return inode; |
239 | } |
240 | |
241 | /** |
242 | * vxfs_iget - get an inode |
243 | * @sbp: the superblock to get the inode for |
244 | * @ino: the number of the inode to get |
245 | * |
246 | * Description: |
247 | * vxfs_read_inode creates an inode, reads the disk inode for @ino and fills |
248 | * in all relevant fields in the new inode. |
249 | */ |
250 | struct inode * |
251 | vxfs_iget(struct super_block *sbp, ino_t ino) |
252 | { |
253 | struct vxfs_inode_info *vip; |
254 | const struct address_space_operations *aops; |
255 | struct inode *ip; |
256 | int error; |
257 | |
258 | ip = iget_locked(sbp, ino); |
259 | if (!ip) |
260 | return ERR_PTR(error: -ENOMEM); |
261 | if (!(ip->i_state & I_NEW)) |
262 | return ip; |
263 | |
264 | vip = VXFS_INO(inode: ip); |
265 | error = __vxfs_iget(VXFS_SBI(sbp)->vsi_ilist, vip, ino); |
266 | if (error) { |
267 | iget_failed(ip); |
268 | return ERR_PTR(error); |
269 | } |
270 | |
271 | if (VXFS_ISIMMED(vip)) |
272 | aops = &vxfs_immed_aops; |
273 | else |
274 | aops = &vxfs_aops; |
275 | |
276 | if (S_ISREG(ip->i_mode)) { |
277 | ip->i_fop = &generic_ro_fops; |
278 | ip->i_mapping->a_ops = aops; |
279 | } else if (S_ISDIR(ip->i_mode)) { |
280 | ip->i_op = &vxfs_dir_inode_ops; |
281 | ip->i_fop = &vxfs_dir_operations; |
282 | ip->i_mapping->a_ops = aops; |
283 | } else if (S_ISLNK(ip->i_mode)) { |
284 | if (!VXFS_ISIMMED(vip)) { |
285 | ip->i_op = &page_symlink_inode_operations; |
286 | inode_nohighmem(inode: ip); |
287 | ip->i_mapping->a_ops = &vxfs_aops; |
288 | } else { |
289 | ip->i_op = &simple_symlink_inode_operations; |
290 | ip->i_link = vip->vii_immed.vi_immed; |
291 | nd_terminate_link(name: ip->i_link, len: ip->i_size, |
292 | maxlen: sizeof(vip->vii_immed.vi_immed) - 1); |
293 | } |
294 | } else |
295 | init_special_inode(ip, ip->i_mode, old_decode_dev(val: vip->vii_rdev)); |
296 | |
297 | unlock_new_inode(ip); |
298 | return ip; |
299 | } |
300 | |
301 | /** |
302 | * vxfs_evict_inode - remove inode from main memory |
303 | * @ip: inode to discard. |
304 | * |
305 | * Description: |
306 | * vxfs_evict_inode() is called on the final iput and frees the private |
307 | * inode area. |
308 | */ |
309 | void |
310 | vxfs_evict_inode(struct inode *ip) |
311 | { |
312 | truncate_inode_pages_final(&ip->i_data); |
313 | clear_inode(ip); |
314 | } |
315 | |