This source file includes following definitions.
- ext2fs_size
- ext2fs_setsize
- ext2fs_inactive
- ext2fs_update
- ext2fs_truncate
- ext2fs_indirtrunc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/mount.h>
40 #include <sys/proc.h>
41 #include <sys/file.h>
42 #include <sys/buf.h>
43 #include <sys/vnode.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/resourcevar.h>
47
48 #include <uvm/uvm_extern.h>
49
50 #include <ufs/ufs/quota.h>
51 #include <ufs/ufs/inode.h>
52 #include <ufs/ufs/ufsmount.h>
53 #include <ufs/ufs/ufs_extern.h>
54
55 #include <ufs/ext2fs/ext2fs.h>
56 #include <ufs/ext2fs/ext2fs_extern.h>
57
58 static int ext2fs_indirtrunc(struct inode *, int32_t, int32_t,
59 int32_t, int, long *);
60
61
62
63
64 u_int64_t
65 ext2fs_size(struct inode *ip)
66 {
67 u_int64_t size = ip->i_e2fs_size;
68
69 if ((ip->i_e2fs_mode & IFMT) == IFREG)
70 size |= (u_int64_t)ip->i_e2fs_dacl << 32;
71
72 return (size);
73 }
74
75 int
76 ext2fs_setsize(struct inode *ip, u_int64_t size)
77 {
78 if ((ip->i_e2fs_mode & IFMT) == IFREG ||
79 ip->i_e2fs_mode == 0) {
80 ip->i_e2fs_dacl = size >> 32;
81 if (size >= 0x80000000U) {
82 struct m_ext2fs *fs = ip->i_e2fs;
83
84 if (fs->e2fs.e2fs_rev <= E2FS_REV0) {
85
86 return (EFBIG);
87 }
88 if (!(fs->e2fs.e2fs_features_rocompat
89 & EXT2F_ROCOMPAT_LARGEFILE)) {
90 fs->e2fs.e2fs_features_rocompat |=
91 EXT2F_ROCOMPAT_LARGEFILE;
92 fs->e2fs_fmod = 1;
93 }
94 }
95 } else if (size >= 0x80000000U)
96 return (EFBIG);
97
98 ip->i_e2fs_size = size;
99
100 return (0);
101 }
102
103
104
105
106
107 int
108 ext2fs_inactive(void *v)
109 {
110 struct vop_inactive_args *ap = v;
111 struct vnode *vp = ap->a_vp;
112 struct inode *ip = VTOI(vp);
113 struct proc *p = ap->a_p;
114 struct timespec ts;
115 int error = 0;
116 #ifdef DIAGNOSTIC
117 extern int prtactive;
118
119 if (prtactive && vp->v_usecount != 0)
120 vprint("ext2fs_inactive: pushing active", vp);
121 #endif
122
123
124 if (ip->i_e2din == NULL || ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime)
125 goto out;
126
127 error = 0;
128 if (ip->i_e2fs_nlink == 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
129 if (ext2fs_size(ip) != 0) {
130 error = ext2fs_truncate(ip, (off_t)0, 0, NOCRED);
131 }
132 getnanotime(&ts);
133 ip->i_e2fs_dtime = ts.tv_sec;
134 ip->i_flag |= IN_CHANGE | IN_UPDATE;
135 ext2fs_inode_free(ip, ip->i_number, ip->i_e2fs_mode);
136 }
137 if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
138 ext2fs_update(ip, NULL, NULL, 0);
139 }
140 out:
141 VOP_UNLOCK(vp, 0, p);
142
143
144
145
146 if (ip->i_e2din == NULL || ip->i_e2fs_dtime != 0)
147 vrecycle(vp, p);
148 return (error);
149 }
150
151
152
153
154
155
156
157
158
159
160
161 int
162 ext2fs_update(struct inode *ip, struct timespec *atime, struct timespec *mtime,
163 int waitfor)
164 {
165 struct m_ext2fs *fs;
166 struct buf *bp;
167 int error;
168 struct timespec ts;
169 caddr_t cp;
170
171 if (ITOV(ip)->v_mount->mnt_flag & MNT_RDONLY)
172 return (0);
173 getnanotime(&ts);
174 EXT2FS_ITIMES(ip,
175 atime ? atime : &ts,
176 mtime ? mtime : &ts);
177 if ((ip->i_flag & IN_MODIFIED) == 0)
178 return (0);
179 ip->i_flag &= ~IN_MODIFIED;
180 fs = ip->i_e2fs;
181 error = bread(ip->i_devvp,
182 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
183 (int)fs->e2fs_bsize, NOCRED, &bp);
184 if (error) {
185 brelse(bp);
186 return (error);
187 }
188 ip->i_flag &= ~(IN_MODIFIED);
189 cp = (caddr_t)bp->b_data +
190 (ino_to_fsbo(fs, ip->i_number) * EXT2_DINODE_SIZE);
191
192
193
194
195
196
197 ip->i_e2fs_uid_low = (u_int16_t)ip->i_e2fs_uid;
198 ip->i_e2fs_gid_low = (u_int16_t)ip->i_e2fs_gid;
199 ip->i_e2fs_uid_high = ip->i_e2fs_uid >> 16;
200 ip->i_e2fs_gid_high = ip->i_e2fs_gid >> 16;
201
202 e2fs_isave(ip->i_e2din, (struct ext2fs_dinode *)cp);
203 if (waitfor)
204 return (bwrite(bp));
205 else {
206 bdwrite(bp);
207 return (0);
208 }
209 }
210
211 #define SINGLE 0
212 #define DOUBLE 1
213 #define TRIPLE 2
214
215
216
217
218 int
219 ext2fs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred)
220 {
221 struct vnode *ovp = ITOV(oip);
222 int32_t lastblock;
223 int32_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
224 int32_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
225 struct m_ext2fs *fs;
226 struct buf *bp;
227 int offset, size, level;
228 long count, nblocks, vflags, blocksreleased = 0;
229 int i;
230 int aflags, error, allerror;
231 off_t osize;
232
233 if (length < 0)
234 return (EINVAL);
235
236 if (ovp->v_type != VREG &&
237 ovp->v_type != VDIR &&
238 ovp->v_type != VLNK)
239 return (0);
240
241 if (ovp->v_type == VLNK &&
242 (ext2fs_size(oip) < ovp->v_mount->mnt_maxsymlinklen ||
243 (ovp->v_mount->mnt_maxsymlinklen == 0 &&
244 oip->i_e2fs_nblock == 0))) {
245 #ifdef DIAGNOSTIC
246 if (length != 0)
247 panic("ext2fs_truncate: partial truncate of symlink");
248 #endif
249 bzero((char *)&oip->i_e2din->e2di_shortlink,
250 (u_int)ext2fs_size(oip));
251 (void)ext2fs_setsize(oip, 0);
252 oip->i_flag |= IN_CHANGE | IN_UPDATE;
253 return (ext2fs_update(oip, NULL, NULL, 1));
254 }
255
256 if (ext2fs_size(oip) == length) {
257 oip->i_flag |= IN_CHANGE | IN_UPDATE;
258 return (ext2fs_update(oip, NULL, NULL, 0));
259 }
260 fs = oip->i_e2fs;
261 osize = ext2fs_size(oip);
262
263
264
265
266
267 if (osize < length) {
268 #if 0
269 if (length > fs->fs_maxfilesize)
270 return (EFBIG);
271 #endif
272 offset = blkoff(fs, length - 1);
273 lbn = lblkno(fs, length - 1);
274 aflags = B_CLRBUF;
275 if (flags & IO_SYNC)
276 aflags |= B_SYNC;
277 error = ext2fs_buf_alloc(oip, lbn, offset + 1, cred, &bp,
278 aflags);
279 if (error)
280 return (error);
281 (void)ext2fs_setsize(oip, length);
282 uvm_vnp_setsize(ovp, length);
283 uvm_vnp_uncache(ovp);
284 if (aflags & B_SYNC)
285 bwrite(bp);
286 else
287 bawrite(bp);
288 oip->i_flag |= IN_CHANGE | IN_UPDATE;
289 return (ext2fs_update(oip, NULL, NULL, 1));
290 }
291
292
293
294
295
296
297
298 offset = blkoff(fs, length);
299 if (offset == 0) {
300 (void)ext2fs_setsize(oip, length);
301 } else {
302 lbn = lblkno(fs, length);
303 aflags = B_CLRBUF;
304 if (flags & IO_SYNC)
305 aflags |= B_SYNC;
306 error = ext2fs_buf_alloc(oip, lbn, offset, cred, &bp,
307 aflags);
308 if (error)
309 return (error);
310 (void)ext2fs_setsize(oip, length);
311 size = fs->e2fs_bsize;
312 uvm_vnp_setsize(ovp, length);
313 uvm_vnp_uncache(ovp);
314 bzero(bp->b_data + offset, (u_int)(size - offset));
315 bp->b_bcount = size;
316 if (aflags & B_SYNC)
317 bwrite(bp);
318 else
319 bawrite(bp);
320 }
321
322
323
324
325
326
327 lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1;
328 lastiblock[SINGLE] = lastblock - NDADDR;
329 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
330 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
331 nblocks = btodb(fs->e2fs_bsize);
332
333
334
335
336
337
338 memcpy((caddr_t)oldblks, (caddr_t)&oip->i_e2fs_blocks[0], sizeof oldblks);
339 for (level = TRIPLE; level >= SINGLE; level--)
340 if (lastiblock[level] < 0) {
341 oip->i_e2fs_blocks[NDADDR + level] = 0;
342 lastiblock[level] = -1;
343 }
344 for (i = NDADDR - 1; i > lastblock; i--)
345 oip->i_e2fs_blocks[i] = 0;
346 oip->i_flag |= IN_CHANGE | IN_UPDATE;
347 if ((error = ext2fs_update(oip, NULL, NULL, 1)) != 0)
348 allerror = error;
349
350
351
352
353
354
355 bcopy((caddr_t)&oip->i_e2fs_blocks[0], (caddr_t)newblks, sizeof newblks);
356 bcopy((caddr_t)oldblks, (caddr_t)&oip->i_e2fs_blocks[0], sizeof oldblks);
357 (void)ext2fs_setsize(oip, osize);
358 vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
359 allerror = vinvalbuf(ovp, vflags, cred, curproc, 0, 0);
360
361
362
363
364 indir_lbn[SINGLE] = -NDADDR;
365 indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) -1;
366 indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
367 for (level = TRIPLE; level >= SINGLE; level--) {
368 bn = fs2h32(oip->i_e2fs_blocks[NDADDR + level]);
369 if (bn != 0) {
370 error = ext2fs_indirtrunc(oip, indir_lbn[level],
371 fsbtodb(fs, bn), lastiblock[level], level, &count);
372 if (error)
373 allerror = error;
374 blocksreleased += count;
375 if (lastiblock[level] < 0) {
376 oip->i_e2fs_blocks[NDADDR + level] = 0;
377 ext2fs_blkfree(oip, bn);
378 blocksreleased += nblocks;
379 }
380 }
381 if (lastiblock[level] >= 0)
382 goto done;
383 }
384
385
386
387
388 for (i = NDADDR - 1; i > lastblock; i--) {
389 bn = fs2h32(oip->i_e2fs_blocks[i]);
390 if (bn == 0)
391 continue;
392 oip->i_e2fs_blocks[i] = 0;
393 ext2fs_blkfree(oip, bn);
394 blocksreleased += btodb(fs->e2fs_bsize);
395 }
396
397 done:
398 #ifdef DIAGNOSTIC
399 for (level = SINGLE; level <= TRIPLE; level++)
400 if (newblks[NDADDR + level] !=
401 oip->i_e2fs_blocks[NDADDR + level])
402 panic("ext2fs_truncate1");
403 for (i = 0; i < NDADDR; i++)
404 if (newblks[i] != oip->i_e2fs_blocks[i])
405 panic("ext2fs_truncate2");
406 if (length == 0 &&
407 (!LIST_EMPTY(&ovp->v_cleanblkhd) ||
408 !LIST_EMPTY(&ovp->v_dirtyblkhd)))
409 panic("ext2fs_truncate3");
410 #endif
411
412
413
414 (void)ext2fs_setsize(oip, length);
415 if (blocksreleased >= oip->i_e2fs_nblock)
416 oip->i_e2fs_nblock = 0;
417 else
418 oip->i_e2fs_nblock -= blocksreleased;
419 oip->i_flag |= IN_CHANGE;
420 return (allerror);
421 }
422
423
424
425
426
427
428
429
430
431
432 static int
433 ext2fs_indirtrunc(struct inode *ip, int32_t lbn, int32_t dbn, int32_t lastbn, int level, long *countp)
434 {
435 int i;
436 struct buf *bp;
437 struct m_ext2fs *fs = ip->i_e2fs;
438 int32_t *bap;
439 struct vnode *vp;
440 int32_t *copy = NULL, nb, nlbn, last;
441 long blkcount, factor;
442 int nblocks, blocksreleased = 0;
443 int error = 0, allerror = 0;
444
445
446
447
448
449
450 factor = 1;
451 for (i = SINGLE; i < level; i++)
452 factor *= NINDIR(fs);
453 last = lastbn;
454 if (lastbn > 0)
455 last /= factor;
456 nblocks = btodb(fs->e2fs_bsize);
457
458
459
460
461
462
463
464
465 vp = ITOV(ip);
466 bp = getblk(vp, lbn, (int)fs->e2fs_bsize, 0, 0);
467 if (!(bp->b_flags & (B_DONE | B_DELWRI))) {
468 curproc->p_stats->p_ru.ru_inblock++;
469 bp->b_flags |= B_READ;
470 if (bp->b_bcount > bp->b_bufsize)
471 panic("ext2fs_indirtrunc: bad buffer size");
472 bp->b_blkno = dbn;
473 VOP_STRATEGY(bp);
474 error = biowait(bp);
475 }
476 if (error) {
477 brelse(bp);
478 *countp = 0;
479 return (error);
480 }
481
482 bap = (int32_t *)bp->b_data;
483 if (lastbn >= 0) {
484 MALLOC(copy, int32_t *, fs->e2fs_bsize, M_TEMP, M_WAITOK);
485 memcpy((caddr_t)copy, (caddr_t)bap, (u_int)fs->e2fs_bsize);
486 memset((caddr_t)&bap[last + 1], 0,
487 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (u_int32_t));
488 error = bwrite(bp);
489 if (error)
490 allerror = error;
491 bap = copy;
492 }
493
494
495
496
497 for (i = NINDIR(fs) - 1,
498 nlbn = lbn + 1 - i * factor; i > last;
499 i--, nlbn += factor) {
500 nb = fs2h32(bap[i]);
501 if (nb == 0)
502 continue;
503 if (level > SINGLE) {
504 error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
505 (int32_t)-1, level - 1,
506 &blkcount);
507 if (error)
508 allerror = error;
509 blocksreleased += blkcount;
510 }
511 ext2fs_blkfree(ip, nb);
512 blocksreleased += nblocks;
513 }
514
515
516
517
518 if (level > SINGLE && lastbn >= 0) {
519 last = lastbn % factor;
520 nb = fs2h32(bap[i]);
521 if (nb != 0) {
522 error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
523 last, level - 1, &blkcount);
524 if (error)
525 allerror = error;
526 blocksreleased += blkcount;
527 }
528 }
529
530 if (copy != NULL) {
531 FREE(copy, M_TEMP);
532 } else {
533 bp->b_flags |= B_INVAL;
534 brelse(bp);
535 }
536
537 *countp = blocksreleased;
538 return (allerror);
539 }