]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (c) 2000-2001 Christoph Hellwig. | |
1cce1701 | 3 | * Copyright (c) 2016 Krzysztof Blaszkowski |
1da177e4 LT |
4 | * All rights reserved. |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions, and the following disclaimer, | |
11 | * without modification. | |
12 | * 2. The name of the author may not be used to endorse or promote products | |
13 | * derived from this software without specific prior written permission. | |
14 | * | |
15 | * Alternatively, this software may be distributed under the terms of the | |
16 | * GNU General Public License ("GPL"). | |
17 | * | |
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | |
22 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
28 | * SUCH DAMAGE. | |
29 | */ | |
30 | ||
31 | /* | |
32 | * Veritas filesystem driver - inode routines. | |
33 | */ | |
34 | #include <linux/fs.h> | |
35 | #include <linux/buffer_head.h> | |
36 | #include <linux/pagemap.h> | |
37 | #include <linux/kernel.h> | |
38 | #include <linux/slab.h> | |
df64c082 | 39 | #include <linux/namei.h> |
1da177e4 LT |
40 | |
41 | #include "vxfs.h" | |
42 | #include "vxfs_inode.h" | |
43 | #include "vxfs_extern.h" | |
44 | ||
45 | ||
1da177e4 LT |
46 | #ifdef DIAGNOSTIC |
47 | /* | |
48 | * Dump inode contents (partially). | |
49 | */ | |
50 | void | |
51 | vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino) | |
52 | { | |
53 | printk(KERN_DEBUG "\n\n"); | |
54 | if (ino) | |
55 | printk(KERN_DEBUG "dumping vxfs inode %ld\n", ino); | |
56 | else | |
57 | printk(KERN_DEBUG "dumping unknown vxfs inode\n"); | |
58 | ||
59 | printk(KERN_DEBUG "---------------------------\n"); | |
60 | printk(KERN_DEBUG "mode is %x\n", vip->vii_mode); | |
61 | printk(KERN_DEBUG "nlink:%u, uid:%u, gid:%u\n", | |
62 | vip->vii_nlink, vip->vii_uid, vip->vii_gid); | |
63 | printk(KERN_DEBUG "size:%Lx, blocks:%u\n", | |
64 | vip->vii_size, vip->vii_blocks); | |
65 | printk(KERN_DEBUG "orgtype:%u\n", vip->vii_orgtype); | |
66 | } | |
67 | #endif | |
68 | ||
2f137e31 CH |
69 | /** |
70 | * vxfs_transmod - mode for a VxFS inode | |
71 | * @vip: VxFS inode | |
72 | * | |
73 | * Description: | |
74 | * vxfs_transmod returns a Linux mode_t for a given | |
75 | * VxFS inode structure. | |
76 | */ | |
77 | static __inline__ umode_t | |
78 | vxfs_transmod(struct vxfs_inode_info *vip) | |
79 | { | |
80 | umode_t ret = vip->vii_mode & ~VXFS_TYPE_MASK; | |
81 | ||
82 | if (VXFS_ISFIFO(vip)) | |
83 | ret |= S_IFIFO; | |
84 | if (VXFS_ISCHR(vip)) | |
85 | ret |= S_IFCHR; | |
86 | if (VXFS_ISDIR(vip)) | |
87 | ret |= S_IFDIR; | |
88 | if (VXFS_ISBLK(vip)) | |
89 | ret |= S_IFBLK; | |
90 | if (VXFS_ISLNK(vip)) | |
91 | ret |= S_IFLNK; | |
92 | if (VXFS_ISREG(vip)) | |
93 | ret |= S_IFREG; | |
94 | if (VXFS_ISSOC(vip)) | |
95 | ret |= S_IFSOCK; | |
96 | ||
97 | return (ret); | |
98 | } | |
99 | ||
0d83f7fc KB |
100 | static inline void dip2vip_cpy(struct vxfs_sb_info *sbi, |
101 | struct vxfs_inode_info *vip, struct vxfs_dinode *dip) | |
102 | { | |
2f137e31 CH |
103 | struct inode *inode = &vip->vfs_inode; |
104 | ||
0d83f7fc KB |
105 | vip->vii_mode = fs32_to_cpu(sbi, dip->vdi_mode); |
106 | vip->vii_nlink = fs32_to_cpu(sbi, dip->vdi_nlink); | |
107 | vip->vii_uid = fs32_to_cpu(sbi, dip->vdi_uid); | |
108 | vip->vii_gid = fs32_to_cpu(sbi, dip->vdi_gid); | |
109 | vip->vii_size = fs64_to_cpu(sbi, dip->vdi_size); | |
110 | vip->vii_atime = fs32_to_cpu(sbi, dip->vdi_atime); | |
111 | vip->vii_autime = fs32_to_cpu(sbi, dip->vdi_autime); | |
112 | vip->vii_mtime = fs32_to_cpu(sbi, dip->vdi_mtime); | |
113 | vip->vii_mutime = fs32_to_cpu(sbi, dip->vdi_mutime); | |
114 | vip->vii_ctime = fs32_to_cpu(sbi, dip->vdi_ctime); | |
115 | vip->vii_cutime = fs32_to_cpu(sbi, dip->vdi_cutime); | |
116 | vip->vii_orgtype = dip->vdi_orgtype; | |
117 | ||
118 | vip->vii_blocks = fs32_to_cpu(sbi, dip->vdi_blocks); | |
119 | vip->vii_gen = fs32_to_cpu(sbi, dip->vdi_gen); | |
120 | ||
121 | if (VXFS_ISDIR(vip)) | |
122 | vip->vii_dotdot = fs32_to_cpu(sbi, dip->vdi_dotdot); | |
123 | else if (!VXFS_ISREG(vip) && !VXFS_ISLNK(vip)) | |
124 | vip->vii_rdev = fs32_to_cpu(sbi, dip->vdi_rdev); | |
125 | ||
126 | /* don't endian swap the fields that differ by orgtype */ | |
127 | memcpy(&vip->vii_org, &dip->vdi_org, sizeof(vip->vii_org)); | |
2f137e31 CH |
128 | |
129 | inode->i_mode = vxfs_transmod(vip); | |
130 | i_uid_write(inode, (uid_t)vip->vii_uid); | |
131 | i_gid_write(inode, (gid_t)vip->vii_gid); | |
132 | ||
133 | set_nlink(inode, vip->vii_nlink); | |
134 | inode->i_size = vip->vii_size; | |
135 | ||
136 | inode->i_atime.tv_sec = vip->vii_atime; | |
137 | inode->i_ctime.tv_sec = vip->vii_ctime; | |
138 | inode->i_mtime.tv_sec = vip->vii_mtime; | |
139 | inode->i_atime.tv_nsec = 0; | |
140 | inode->i_ctime.tv_nsec = 0; | |
141 | inode->i_mtime.tv_nsec = 0; | |
142 | ||
143 | inode->i_blocks = vip->vii_blocks; | |
144 | inode->i_generation = vip->vii_gen; | |
0d83f7fc | 145 | } |
1da177e4 LT |
146 | |
147 | /** | |
148 | * vxfs_blkiget - find inode based on extent # | |
149 | * @sbp: superblock of the filesystem we search in | |
150 | * @extent: number of the extent to search | |
151 | * @ino: inode number to search | |
152 | * | |
153 | * Description: | |
154 | * vxfs_blkiget searches inode @ino in the filesystem described by | |
155 | * @sbp in the extent @extent. | |
156 | * Returns the matching VxFS inode on success, else a NULL pointer. | |
157 | * | |
158 | * NOTE: | |
159 | * While __vxfs_iget uses the pagecache vxfs_blkiget uses the | |
160 | * buffercache. This function should not be used outside the | |
161 | * read_super() method, otherwise the data may be incoherent. | |
162 | */ | |
8985f53e | 163 | struct inode * |
1da177e4 LT |
164 | vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino) |
165 | { | |
166 | struct buffer_head *bp; | |
8985f53e | 167 | struct inode *inode; |
1da177e4 LT |
168 | u_long block, offset; |
169 | ||
2f137e31 CH |
170 | inode = new_inode(sbp); |
171 | if (!inode) | |
172 | return NULL; | |
173 | inode->i_ino = get_next_ino(); | |
174 | ||
1da177e4 LT |
175 | block = extent + ((ino * VXFS_ISIZE) / sbp->s_blocksize); |
176 | offset = ((ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE); | |
177 | bp = sb_bread(sbp, block); | |
178 | ||
82f703bb | 179 | if (bp && buffer_mapped(bp)) { |
2f137e31 | 180 | struct vxfs_inode_info *vip = VXFS_INO(inode); |
1da177e4 LT |
181 | struct vxfs_dinode *dip; |
182 | ||
1da177e4 | 183 | dip = (struct vxfs_dinode *)(bp->b_data + offset); |
0d83f7fc | 184 | dip2vip_cpy(VXFS_SBI(sbp), vip, dip); |
2f137e31 | 185 | vip->vfs_inode.i_mapping->a_ops = &vxfs_aops; |
1da177e4 LT |
186 | #ifdef DIAGNOSTIC |
187 | vxfs_dumpi(vip, ino); | |
188 | #endif | |
189 | brelse(bp); | |
8985f53e | 190 | return inode; |
1da177e4 LT |
191 | } |
192 | ||
1da177e4 LT |
193 | printk(KERN_WARNING "vxfs: unable to read block %ld\n", block); |
194 | brelse(bp); | |
2f137e31 | 195 | iput(inode); |
1da177e4 LT |
196 | return NULL; |
197 | } | |
198 | ||
199 | /** | |
200 | * __vxfs_iget - generic find inode facility | |
1da177e4 | 201 | * @ilistp: inode list |
2f137e31 CH |
202 | * @vip: VxFS inode to fill in |
203 | * @ino: inode number | |
1da177e4 LT |
204 | * |
205 | * Description: | |
206 | * Search the for inode number @ino in the filesystem | |
207 | * described by @sbp. Use the specified inode table (@ilistp). | |
8985f53e | 208 | * Returns the matching inode on success, else an error code. |
1da177e4 | 209 | */ |
2f137e31 CH |
210 | static int |
211 | __vxfs_iget(struct inode *ilistp, struct vxfs_inode_info *vip, ino_t ino) | |
1da177e4 LT |
212 | { |
213 | struct page *pp; | |
214 | u_long offset; | |
215 | ||
216 | offset = (ino % (PAGE_SIZE / VXFS_ISIZE)) * VXFS_ISIZE; | |
217 | pp = vxfs_get_page(ilistp->i_mapping, ino * VXFS_ISIZE / PAGE_SIZE); | |
218 | ||
219 | if (!IS_ERR(pp)) { | |
1da177e4 LT |
220 | struct vxfs_dinode *dip; |
221 | caddr_t kaddr = (char *)page_address(pp); | |
222 | ||
1da177e4 | 223 | dip = (struct vxfs_dinode *)(kaddr + offset); |
0d83f7fc | 224 | dip2vip_cpy(VXFS_SBI(ilistp->i_sb), vip, dip); |
2f137e31 | 225 | vip->vfs_inode.i_mapping->a_ops = &vxfs_aops; |
1da177e4 LT |
226 | #ifdef DIAGNOSTIC |
227 | vxfs_dumpi(vip, ino); | |
228 | #endif | |
229 | vxfs_put_page(pp); | |
2f137e31 | 230 | return 0; |
1da177e4 LT |
231 | } |
232 | ||
2f137e31 CH |
233 | printk(KERN_WARNING "vxfs: error on page 0x%p for inode %ld\n", |
234 | pp, (unsigned long)ino); | |
235 | return PTR_ERR(pp); | |
1da177e4 LT |
236 | } |
237 | ||
238 | /** | |
239 | * vxfs_stiget - find inode using the structural inode list | |
240 | * @sbp: VFS superblock | |
241 | * @ino: inode # | |
242 | * | |
243 | * Description: | |
244 | * Find inode @ino in the filesystem described by @sbp using | |
245 | * the structural inode list. | |
8985f53e | 246 | * Returns the matching inode on success, else a NULL pointer. |
1da177e4 | 247 | */ |
8985f53e | 248 | struct inode * |
1da177e4 LT |
249 | vxfs_stiget(struct super_block *sbp, ino_t ino) |
250 | { | |
8985f53e | 251 | struct inode *inode; |
2f137e31 | 252 | int error; |
d0b07948 | 253 | |
2f137e31 | 254 | inode = new_inode(sbp); |
8985f53e | 255 | if (!inode) |
2f137e31 CH |
256 | return NULL; |
257 | inode->i_ino = get_next_ino(); | |
1da177e4 | 258 | |
2f137e31 CH |
259 | error = __vxfs_iget(VXFS_SBI(sbp)->vsi_stilist, VXFS_INO(inode), ino); |
260 | if (error) { | |
261 | iput(inode); | |
262 | return NULL; | |
1da177e4 | 263 | } |
2f137e31 CH |
264 | |
265 | return inode; | |
1da177e4 LT |
266 | } |
267 | ||
1da177e4 | 268 | /** |
d0b07948 DH |
269 | * vxfs_iget - get an inode |
270 | * @sbp: the superblock to get the inode for | |
271 | * @ino: the number of the inode to get | |
1da177e4 LT |
272 | * |
273 | * Description: | |
d0b07948 DH |
274 | * vxfs_read_inode creates an inode, reads the disk inode for @ino and fills |
275 | * in all relevant fields in the new inode. | |
1da177e4 | 276 | */ |
d0b07948 DH |
277 | struct inode * |
278 | vxfs_iget(struct super_block *sbp, ino_t ino) | |
1da177e4 | 279 | { |
1da177e4 | 280 | struct vxfs_inode_info *vip; |
f5e54d6e | 281 | const struct address_space_operations *aops; |
d0b07948 | 282 | struct inode *ip; |
2f137e31 | 283 | int error; |
d0b07948 DH |
284 | |
285 | ip = iget_locked(sbp, ino); | |
286 | if (!ip) | |
287 | return ERR_PTR(-ENOMEM); | |
288 | if (!(ip->i_state & I_NEW)) | |
289 | return ip; | |
290 | ||
2f137e31 CH |
291 | vip = VXFS_INO(ip); |
292 | error = __vxfs_iget(VXFS_SBI(sbp)->vsi_ilist, vip, ino); | |
293 | if (error) { | |
d0b07948 | 294 | iget_failed(ip); |
2f137e31 | 295 | return ERR_PTR(error); |
d0b07948 | 296 | } |
1da177e4 | 297 | |
1da177e4 LT |
298 | if (VXFS_ISIMMED(vip)) |
299 | aops = &vxfs_immed_aops; | |
300 | else | |
301 | aops = &vxfs_aops; | |
302 | ||
303 | if (S_ISREG(ip->i_mode)) { | |
dc487002 | 304 | ip->i_fop = &generic_ro_fops; |
1da177e4 LT |
305 | ip->i_mapping->a_ops = aops; |
306 | } else if (S_ISDIR(ip->i_mode)) { | |
307 | ip->i_op = &vxfs_dir_inode_ops; | |
308 | ip->i_fop = &vxfs_dir_operations; | |
309 | ip->i_mapping->a_ops = aops; | |
310 | } else if (S_ISLNK(ip->i_mode)) { | |
311 | if (!VXFS_ISIMMED(vip)) { | |
312 | ip->i_op = &page_symlink_inode_operations; | |
21fc61c7 | 313 | inode_nohighmem(ip); |
1da177e4 | 314 | ip->i_mapping->a_ops = &vxfs_aops; |
a63d0ff3 | 315 | } else { |
df64c082 AV |
316 | ip->i_op = &simple_symlink_inode_operations; |
317 | ip->i_link = vip->vii_immed.vi_immed; | |
318 | nd_terminate_link(ip->i_link, ip->i_size, | |
319 | sizeof(vip->vii_immed.vi_immed) - 1); | |
a63d0ff3 | 320 | } |
1da177e4 LT |
321 | } else |
322 | init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev)); | |
323 | ||
d0b07948 DH |
324 | unlock_new_inode(ip); |
325 | return ip; | |
1da177e4 LT |
326 | } |
327 | ||
328 | /** | |
b57922d9 | 329 | * vxfs_evict_inode - remove inode from main memory |
1da177e4 LT |
330 | * @ip: inode to discard. |
331 | * | |
332 | * Description: | |
b57922d9 | 333 | * vxfs_evict_inode() is called on the final iput and frees the private |
1da177e4 LT |
334 | * inode area. |
335 | */ | |
336 | void | |
b57922d9 | 337 | vxfs_evict_inode(struct inode *ip) |
1da177e4 | 338 | { |
91b0abe3 | 339 | truncate_inode_pages_final(&ip->i_data); |
dbd5768f | 340 | clear_inode(ip); |
1da177e4 | 341 | } |