VOP_TRUNCATE now takes a cred argument
[unix-history] / usr / src / sys / ufs / lfs / lfs_vnops.c
CommitLineData
da7c5cc6 1/*
d9f5f868 2 * Copyright (c) 1986, 1989, 1991 Regents of the University of California.
7188ac27 3 * All rights reserved.
da7c5cc6 4 *
b702c21d 5 * %sccs.include.redist.c%
7188ac27 6 *
422c9c21 7 * @(#)lfs_vnops.c 7.79 (Berkeley) %G%
da7c5cc6 8 */
6459ebe0 9
c7e94c3a
KB
10#include <sys/param.h>
11#include <sys/systm.h>
12#include <sys/namei.h>
13#include <sys/resourcevar.h>
14#include <sys/kernel.h>
15#include <sys/file.h>
16#include <sys/stat.h>
17#include <sys/buf.h>
18#include <sys/proc.h>
19#include <sys/conf.h>
20#include <sys/mount.h>
21#include <sys/vnode.h>
22#include <sys/specdev.h>
23#include <sys/fifo.h>
24#include <sys/malloc.h>
25
d9f5f868
KB
26#include <ufs/ufs/quota.h>
27#include <ufs/ufs/inode.h>
28#include <ufs/ufs/dir.h>
29#include <ufs/ufs/ufs_extern.h>
c7e94c3a 30
d9f5f868
KB
31#include <ufs/lfs/lfs.h>
32#include <ufs/lfs/lfs_extern.h>
c7e94c3a
KB
33
34/* Global vfs data structures for lfs. */
35struct vnodeops lfs_vnodeops = {
36 ufs_lookup, /* lookup */
37 ufs_create, /* create */
38 ufs_mknod, /* mknod */
39 ufs_open, /* open */
40 ufs_close, /* close */
41 ufs_access, /* access */
42 ufs_getattr, /* getattr */
43 ufs_setattr, /* setattr */
44 lfs_read, /* read */
45 lfs_write, /* write */
46 ufs_ioctl, /* ioctl */
47 ufs_select, /* select */
48 ufs_mmap, /* mmap */
49 lfs_fsync, /* fsync */
50 ufs_seek, /* seek */
51 ufs_remove, /* remove */
52 ufs_link, /* link */
53 ufs_rename, /* rename */
54 ufs_mkdir, /* mkdir */
55 ufs_rmdir, /* rmdir */
56 ufs_symlink, /* symlink */
57 ufs_readdir, /* readdir */
58 ufs_readlink, /* readlink */
59 ufs_abortop, /* abortop */
a2d9885d 60 lfs_inactive, /* inactive */
c7e94c3a
KB
61 ufs_reclaim, /* reclaim */
62 ufs_lock, /* lock */
63 ufs_unlock, /* unlock */
a2d9885d 64 lfs_bmap, /* bmap */
c7e94c3a
KB
65 ufs_strategy, /* strategy */
66 ufs_print, /* print */
67 ufs_islocked, /* islocked */
68 ufs_advlock, /* advlock */
a2d9885d
KM
69 lfs_blkatoff, /* blkatoff */
70 lfs_vget, /* vget */
71 lfs_valloc, /* valloc */
72 lfs_vfree, /* vfree */
73 lfs_truncate, /* truncate */
74 lfs_update, /* update */
75 lfs_bwrite, /* bwrite */
c7e94c3a 76};
528f664c 77
a2d9885d
KM
78struct vnodeops lfs_specops = {
79 spec_lookup, /* lookup */
80 spec_create, /* create */
81 spec_mknod, /* mknod */
82 spec_open, /* open */
83 ufsspec_close, /* close */
84 ufs_access, /* access */
85 ufs_getattr, /* getattr */
86 ufs_setattr, /* setattr */
87 ufsspec_read, /* read */
88 ufsspec_write, /* write */
89 spec_ioctl, /* ioctl */
90 spec_select, /* select */
91 spec_mmap, /* mmap */
92 spec_fsync, /* fsync */
93 spec_seek, /* seek */
94 spec_remove, /* remove */
95 spec_link, /* link */
96 spec_rename, /* rename */
97 spec_mkdir, /* mkdir */
98 spec_rmdir, /* rmdir */
99 spec_symlink, /* symlink */
100 spec_readdir, /* readdir */
101 spec_readlink, /* readlink */
102 spec_abortop, /* abortop */
103 lfs_inactive, /* inactive */
104 ufs_reclaim, /* reclaim */
105 ufs_lock, /* lock */
106 ufs_unlock, /* unlock */
107 spec_bmap, /* bmap */
108 spec_strategy, /* strategy */
109 ufs_print, /* print */
110 ufs_islocked, /* islocked */
111 spec_advlock, /* advlock */
112 spec_blkatoff, /* blkatoff */
113 spec_vget, /* vget */
114 spec_valloc, /* valloc */
115 spec_vfree, /* vfree */
116 spec_truncate, /* truncate */
117 lfs_update, /* update */
118 lfs_bwrite, /* bwrite */
119};
120
121#ifdef FIFO
122struct vnodeops lfs_fifoops = {
123 fifo_lookup, /* lookup */
124 fifo_create, /* create */
125 fifo_mknod, /* mknod */
126 fifo_open, /* open */
127 ufsfifo_close, /* close */
128 ufs_access, /* access */
129 ufs_getattr, /* getattr */
130 ufs_setattr, /* setattr */
131 ufsfifo_read, /* read */
132 ufsfifo_write, /* write */
133 fifo_ioctl, /* ioctl */
134 fifo_select, /* select */
135 fifo_mmap, /* mmap */
136 fifo_fsync, /* fsync */
137 fifo_seek, /* seek */
138 fifo_remove, /* remove */
139 fifo_link, /* link */
140 fifo_rename, /* rename */
141 fifo_mkdir, /* mkdir */
142 fifo_rmdir, /* rmdir */
143 fifo_symlink, /* symlink */
144 fifo_readdir, /* readdir */
145 fifo_readlink, /* readlink */
146 fifo_abortop, /* abortop */
147 lfs_inactive, /* inactive */
148 ufs_reclaim, /* reclaim */
149 ufs_lock, /* lock */
150 ufs_unlock, /* unlock */
151 fifo_bmap, /* bmap */
152 fifo_strategy, /* strategy */
153 ufs_print, /* print */
154 ufs_islocked, /* islocked */
155 fifo_advlock, /* advlock */
156 fifo_blkatoff, /* blkatoff */
157 fifo_vget, /* vget */
158 fifo_valloc, /* valloc */
159 fifo_vfree, /* vfree */
160 fifo_truncate, /* truncate */
161 lfs_update, /* update */
162 lfs_bwrite, /* bwrite */
163};
164#endif /* FIFO */
165
b373e060
KM
166/*
167 * Vnode op for reading.
168 */
169/* ARGSUSED */
a8c062c5 170lfs_read(vp, uio, ioflag, cred)
b373e060
KM
171 struct vnode *vp;
172 register struct uio *uio;
173 int ioflag;
174 struct ucred *cred;
175{
176 register struct inode *ip = VTOI(vp);
d9f5f868 177 register struct lfs *fs; /* LFS */
b373e060
KM
178 struct buf *bp;
179 daddr_t lbn, bn, rablock;
0308fc84 180 int size, error = 0;
b373e060 181 long n, on, type;
0308fc84 182 off_t diff;
b373e060 183
c6a63814
KB
184#ifdef VERBOSE
185 printf("lfs_read: ino %d\n", ip->i_number);
186#endif
5b169cb7 187#ifdef DIAGNOSTIC
b373e060
KM
188 if (uio->uio_rw != UIO_READ)
189 panic("ufs_read mode");
190 type = ip->i_mode & IFMT;
191 if (type != IFDIR && type != IFREG && type != IFLNK)
192 panic("ufs_read type");
5b169cb7 193#endif
b373e060
KM
194 if (uio->uio_resid == 0)
195 return (0);
196 if (uio->uio_offset < 0)
197 return (EINVAL);
198 ip->i_flag |= IACC;
0b4d6502
KB
199
200 fs = ip->i_lfs; /* LFS */
b373e060
KM
201 do {
202 lbn = lblkno(fs, uio->uio_offset);
203 on = blkoff(fs, uio->uio_offset);
0b4d6502 204 n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid);
b373e060
KM
205 diff = ip->i_size - uio->uio_offset;
206 if (diff <= 0)
207 return (0);
208 if (diff < n)
209 n = diff;
0b4d6502 210 size = blksize(fs); /* LFS */
e16fa59e 211 rablock = lbn + 1;
20aa076b
KM
212 if (vp->v_lastr + 1 == lbn &&
213 lblktosize(fs, rablock) < ip->i_size)
38f21582
KM
214 error = breadn(ITOV(ip), lbn, size, &rablock,
215 &size, 1, NOCRED, &bp);
b373e060 216 else
e16fa59e 217 error = bread(ITOV(ip), lbn, size, NOCRED, &bp);
de67eefc 218 vp->v_lastr = lbn;
b373e060
KM
219 n = MIN(n, size - bp->b_resid);
220 if (error) {
221 brelse(bp);
222 return (error);
223 }
224 error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
0b4d6502 225 if (n + on == fs->lfs_bsize || uio->uio_offset == ip->i_size)
b373e060
KM
226 bp->b_flags |= B_AGE;
227 brelse(bp);
228 } while (error == 0 && uio->uio_resid > 0 && n != 0);
229 return (error);
230}
231
232/*
233 * Vnode op for writing.
234 */
a8c062c5 235lfs_write(vp, uio, ioflag, cred)
b373e060
KM
236 register struct vnode *vp;
237 struct uio *uio;
238 int ioflag;
239 struct ucred *cred;
240{
5b169cb7 241 struct proc *p = uio->uio_procp;
b373e060 242 register struct inode *ip = VTOI(vp);
a418dc41 243 register struct lfs *fs;
b373e060 244 struct buf *bp;
a418dc41 245 daddr_t lbn;
0308fc84 246 off_t osize;
a418dc41 247 int n, on, flags, newblock;
8986c97c 248 int size, resid, error = 0;
b373e060 249
c6a63814
KB
250#ifdef VERBOSE
251 printf("lfs_write ino %d\n", ip->i_number);
252#endif
5b169cb7 253#ifdef DIAGNOSTIC
b373e060 254 if (uio->uio_rw != UIO_WRITE)
a418dc41 255 panic("lfs_write mode");
5b169cb7 256#endif
b373e060
KM
257 switch (vp->v_type) {
258 case VREG:
259 if (ioflag & IO_APPEND)
260 uio->uio_offset = ip->i_size;
261 /* fall through */
262 case VLNK:
263 break;
264
265 case VDIR:
a418dc41 266 /* XXX This may not be correct for LFS. */
b373e060 267 if ((ioflag & IO_SYNC) == 0)
a418dc41 268 panic("lfs_write nonsync dir write");
b373e060
KM
269 break;
270
271 default:
a418dc41 272 panic("lfs_write type");
b373e060
KM
273 }
274 if (uio->uio_offset < 0)
275 return (EINVAL);
276 if (uio->uio_resid == 0)
277 return (0);
278 /*
279 * Maybe this should be above the vnode op call, but so long as
280 * file servers have no limits, i don't think it matters
281 */
b326e282 282 if (vp->v_type == VREG && p &&
b373e060 283 uio->uio_offset + uio->uio_resid >
c6f5111d
MK
284 p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
285 psignal(p, SIGXFSZ);
b373e060
KM
286 return (EFBIG);
287 }
288 resid = uio->uio_resid;
289 osize = ip->i_size;
d5075120 290 fs = ip->i_lfs; /* LFS */
e16fa59e 291 flags = 0;
d5075120 292#ifdef NOTLFS
e16fa59e
KM
293 if (ioflag & IO_SYNC)
294 flags = B_SYNC;
d5075120 295#endif
b373e060
KM
296 do {
297 lbn = lblkno(fs, uio->uio_offset);
cb1fb5d7 298 on = blkoff(fs, uio->uio_offset);
d5075120 299 n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid);
a418dc41 300 if (error = lfs_balloc(vp, n, lbn, &bp))
b373e060 301 break;
8986c97c 302 if (uio->uio_offset + n > ip->i_size) {
b373e060 303 ip->i_size = uio->uio_offset + n;
e738d0da 304 vnode_pager_setsize(vp, (u_long)ip->i_size);
8986c97c 305 }
d5075120 306 size = blksize(fs);
8986c97c 307 (void) vnode_pager_uncache(vp);
b373e060 308 n = MIN(n, size - bp->b_resid);
b373e060 309 error = uiomove(bp->b_un.b_addr + on, n, uio);
d5075120 310#ifdef NOTLFS /* LFS */
b373e060
KM
311 if (ioflag & IO_SYNC)
312 (void) bwrite(bp);
313 else if (n + on == fs->fs_bsize) {
314 bp->b_flags |= B_AGE;
315 bawrite(bp);
316 } else
317 bdwrite(bp);
a418dc41 318 ip->i_flag |= IUPD|ICHG;
d5075120 319#else
a418dc41
KB
320 /* XXX This doesn't handle IO_SYNC. */
321 LFS_UBWRITE(bp);
d5075120 322#endif
b373e060
KM
323 if (cred->cr_uid != 0)
324 ip->i_mode &= ~(ISUID|ISGID);
325 } while (error == 0 && uio->uio_resid > 0 && n != 0);
326 if (error && (ioflag & IO_UNIT)) {
422c9c21 327 (void)lfs_truncate(vp, osize, ioflag & IO_SYNC, cred);
b373e060
KM
328 uio->uio_offset -= resid - uio->uio_resid;
329 uio->uio_resid = resid;
330 }
1c05ecaf 331 if (!error && (ioflag & IO_SYNC))
cb1fb5d7 332 error = lfs_update(vp, &time, &time, 1);
b373e060
KM
333 return (error);
334}
335
4f083fd7 336/*
7188ac27 337 * Synch an open file.
4f083fd7 338 */
7188ac27 339/* ARGSUSED */
a8c062c5 340lfs_fsync(vp, fflags, cred, waitfor, p)
7188ac27
KM
341 struct vnode *vp;
342 int fflags;
343 struct ucred *cred;
86cdabf6 344 int waitfor;
5b169cb7 345 struct proc *p;
528f664c 346{
c6a63814 347 struct inode *ip;
7188ac27 348
c6a63814
KB
349#ifdef VERBOSE
350 printf("lfs_fsync\n");
351#endif
352 ip = VTOI(vp);
5b169cb7 353 if (fflags & FWRITE)
7188ac27 354 ip->i_flag |= ICHG;
6f68ec4a 355 return (lfs_update(vp, &time, &time, waitfor == MNT_WAIT));
88a7a62a 356}
a2d9885d
KM
357
358/*
359 * Last reference to an inode, write the inode out and if necessary,
360 * truncate and deallocate the file.
361 */
362int
363lfs_inactive(vp, p)
364 struct vnode *vp;
365 struct proc *p;
366{
c6a63814 367 extern int prtactive;
a2d9885d
KM
368 register struct inode *ip;
369 int mode, error;
a2d9885d 370
c6a63814
KB
371#ifdef VERBOSE
372 printf("lfs_inactive\n");
373#endif
a2d9885d
KM
374 if (prtactive && vp->v_usecount != 0)
375 vprint("lfs_inactive: pushing active", vp);
376
377 /* Get rid of inodes related to stale file handles. */
378 ip = VTOI(vp);
379 if (ip->i_mode == 0) {
380 if ((vp->v_flag & VXLOCK) == 0)
381 vgone(vp);
382 return (0);
383 }
384
385 error = 0;
386 ILOCK(ip);
387 if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
388#ifdef QUOTA
389 if (!getinoquota(ip))
390 (void)chkiq(ip, -1, NOCRED, 0);
391#endif
422c9c21 392 error = lfs_truncate(vp, (off_t)0, 0, NOCRED);
a2d9885d
KM
393 mode = ip->i_mode;
394 ip->i_mode = 0;
395 ip->i_rdev = 0;
396 ip->i_flag |= IUPD|ICHG;
397 lfs_vfree(vp, ip->i_number, mode);
398 }
399 if (ip->i_flag&(IUPD|IACC|ICHG|IMOD))
400 lfs_update(vp, &time, &time, 0);
401 IUNLOCK(ip);
402 ip->i_flag = 0;
403 /*
404 * If we are done with the inode, reclaim it
405 * so that it can be reused immediately.
406 */
407 if (vp->v_usecount == 0 && ip->i_mode == 0)
408 vgone(vp);
409 return (error);
410}