final version
[unix-history] / usr / src / sys / kern / vfs_vnops.c
CommitLineData
da7c5cc6 1/*
eb668bc6
KM
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
dbf0c423 5 * %sccs.include.redist.c%
eb668bc6 6 *
e39dd239 7 * @(#)vfs_vnops.c 7.40 (Berkeley) %G%
da7c5cc6 8 */
961945a8 9
94368568
JB
10#include "param.h"
11#include "systm.h"
eb668bc6 12#include "kernel.h"
94368568 13#include "file.h"
eb668bc6
KM
14#include "stat.h"
15#include "buf.h"
16#include "proc.h"
eb668bc6 17#include "mount.h"
a9194d51 18#include "namei.h"
eb668bc6 19#include "vnode.h"
eb668bc6
KM
20#include "ioctl.h"
21#include "tty.h"
8b4f20bf 22#include <vm/vm.h>
fc96c615 23
eb668bc6 24struct fileops vnops =
97f761d2 25 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
d301d150 26
fc96c615 27/*
eb668bc6
KM
28 * Common code for vnode open operations.
29 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
fc96c615 30 */
35dccb0f 31vn_open(ndp, fmode, cmode)
eb668bc6
KM
32 register struct nameidata *ndp;
33 int fmode, cmode;
34{
9342689a
JH
35 USES_VOP_ABORTOP;
36 USES_VOP_ACCESS;
37 USES_VOP_CREATE;
38 USES_VOP_OPEN;
39 USES_VOP_SETATTR;
eb668bc6 40 register struct vnode *vp;
35dccb0f 41 register struct proc *p = ndp->ni_cnd.cn_proc;
9b808fbd 42 register struct ucred *cred = p->p_ucred;
eb668bc6
KM
43 struct vattr vat;
44 struct vattr *vap = &vat;
45 int error;
46
63992c37 47 if (fmode & O_CREAT) {
35dccb0f
KM
48 ndp->ni_cnd.cn_nameiop = CREATE;
49 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
63992c37 50 if ((fmode & O_EXCL) == 0)
35dccb0f
KM
51 ndp->ni_cnd.cn_flags |= FOLLOW;
52 if (error = namei(ndp))
eb668bc6
KM
53 return (error);
54 if (ndp->ni_vp == NULL) {
3ee1461b 55 VATTR_NULL(vap);
eb668bc6
KM
56 vap->va_type = VREG;
57 vap->va_mode = cmode;
73019d79 58 LEASE_CHECK(ndp->ni_dvp, p, cred, LEASE_WRITE);
35dccb0f
KM
59 if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
60 &ndp->ni_cnd, vap))
eb668bc6 61 return (error);
63992c37 62 fmode &= ~O_TRUNC;
eb668bc6
KM
63 vp = ndp->ni_vp;
64 } else {
cfef4373 65 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
3f530a7b
KM
66 if (ndp->ni_dvp == ndp->ni_vp)
67 vrele(ndp->ni_dvp);
7341981c 68 else
3f530a7b
KM
69 vput(ndp->ni_dvp);
70 ndp->ni_dvp = NULL;
eb668bc6 71 vp = ndp->ni_vp;
63992c37 72 if (fmode & O_EXCL) {
eb668bc6
KM
73 error = EEXIST;
74 goto bad;
75 }
63992c37 76 fmode &= ~O_CREAT;
eb668bc6
KM
77 }
78 } else {
35dccb0f
KM
79 ndp->ni_cnd.cn_nameiop = LOOKUP;
80 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
81 if (error = namei(ndp))
eb668bc6
KM
82 return (error);
83 vp = ndp->ni_vp;
84 }
85 if (vp->v_type == VSOCK) {
86 error = EOPNOTSUPP;
87 goto bad;
88 }
63992c37 89 if ((fmode & O_CREAT) == 0) {
eb668bc6 90 if (fmode & FREAD) {
a9194d51 91 if (error = VOP_ACCESS(vp, VREAD, cred, p))
eb668bc6
KM
92 goto bad;
93 }
63992c37 94 if (fmode & (FWRITE | O_TRUNC)) {
eb668bc6
KM
95 if (vp->v_type == VDIR) {
96 error = EISDIR;
97 goto bad;
98 }
cd811e9a 99 if ((error = vn_writechk(vp)) ||
a9194d51 100 (error = VOP_ACCESS(vp, VWRITE, cred, p)))
cd811e9a 101 goto bad;
eb668bc6
KM
102 }
103 }
63992c37 104 if (fmode & O_TRUNC) {
3ee1461b 105 VATTR_NULL(vap);
eb668bc6 106 vap->va_size = 0;
73019d79 107 LEASE_CHECK(vp, p, cred, LEASE_WRITE);
a9194d51 108 if (error = VOP_SETATTR(vp, vap, cred, p))
eb668bc6
KM
109 goto bad;
110 }
cb3e538f
KM
111 if (error = VOP_OPEN(vp, fmode, cred, p))
112 goto bad;
113 if (fmode & FWRITE)
114 vp->v_writecount++;
115 return (0);
eb668bc6
KM
116bad:
117 vput(vp);
ccee3c59 118 return (error);
eb668bc6
KM
119}
120
121/*
cd811e9a
KM
122 * Check for write permissions on the specified vnode.
123 * The read-only status of the file system is checked.
124 * Also, prototype text segments cannot be written.
eb668bc6 125 */
cd811e9a 126vn_writechk(vp)
eb668bc6 127 register struct vnode *vp;
fc96c615 128{
fc96c615 129
cd811e9a
KM
130 /*
131 * Disallow write attempts on read-only file systems;
132 * unless the file is a socket or a block or character
133 * device resident on the file system.
134 */
5216fbe4
KM
135 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
136 switch (vp->v_type) {
137 case VREG: case VDIR: case VLNK:
138 return (EROFS);
139 }
140 }
cd811e9a
KM
141 /*
142 * If there's shared text associated with
143 * the vnode, try to free it up once. If
144 * we fail, we can't allow writing.
145 */
9db58063 146 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
cd811e9a
KM
147 return (ETXTBSY);
148 return (0);
eb668bc6
KM
149}
150
151/*
97f761d2
KM
152 * Vnode close call
153 */
154vn_close(vp, flags, cred, p)
155 register struct vnode *vp;
156 int flags;
157 struct ucred *cred;
158 struct proc *p;
159{
9342689a 160 USES_VOP_CLOSE;
97f761d2
KM
161 int error;
162
163 if (flags & FWRITE)
164 vp->v_writecount--;
165 error = VOP_CLOSE(vp, flags, cred, p);
166 vrele(vp);
167 return (error);
168}
169
170/*
171 * Package up an I/O request on a vnode into a uio and do it.
eb668bc6 172 */
a9194d51 173vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
eb668bc6
KM
174 enum uio_rw rw;
175 struct vnode *vp;
176 caddr_t base;
177 int len;
178 off_t offset;
179 enum uio_seg segflg;
180 int ioflg;
181 struct ucred *cred;
182 int *aresid;
a9194d51 183 struct proc *p;
eb668bc6 184{
9342689a
JH
185 USES_VOP_LOCK;
186 USES_VOP_READ;
187 USES_VOP_UNLOCK;
188 USES_VOP_WRITE;
eb668bc6
KM
189 struct uio auio;
190 struct iovec aiov;
191 int error;
192
cde34f67
KM
193 if ((ioflg & IO_NODELOCKED) == 0)
194 VOP_LOCK(vp);
eb668bc6
KM
195 auio.uio_iov = &aiov;
196 auio.uio_iovcnt = 1;
197 aiov.iov_base = base;
198 aiov.iov_len = len;
199 auio.uio_resid = len;
200 auio.uio_offset = offset;
201 auio.uio_segflg = segflg;
202 auio.uio_rw = rw;
a9194d51 203 auio.uio_procp = p;
73019d79
KM
204 if (rw == UIO_READ) {
205 LEASE_CHECK(vp, p, cred, LEASE_READ);
cde34f67 206 error = VOP_READ(vp, &auio, ioflg, cred);
73019d79
KM
207 } else {
208 LEASE_CHECK(vp, p, cred, LEASE_WRITE);
cde34f67 209 error = VOP_WRITE(vp, &auio, ioflg, cred);
73019d79 210 }
eb668bc6
KM
211 if (aresid)
212 *aresid = auio.uio_resid;
213 else
214 if (auio.uio_resid && error == 0)
215 error = EIO;
cde34f67
KM
216 if ((ioflg & IO_NODELOCKED) == 0)
217 VOP_UNLOCK(vp);
eb668bc6
KM
218 return (error);
219}
220
97f761d2
KM
221/*
222 * File table vnode read routine.
223 */
eb668bc6
KM
224vn_read(fp, uio, cred)
225 struct file *fp;
226 struct uio *uio;
227 struct ucred *cred;
228{
9342689a
JH
229 USES_VOP_LOCK;
230 USES_VOP_READ;
231 USES_VOP_UNLOCK;
cde34f67
KM
232 register struct vnode *vp = (struct vnode *)fp->f_data;
233 int count, error;
eb668bc6 234
cde34f67
KM
235 VOP_LOCK(vp);
236 uio->uio_offset = fp->f_offset;
237 count = uio->uio_resid;
73019d79 238 LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_READ);
63992c37
KM
239 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
240 cred);
cde34f67
KM
241 fp->f_offset += count - uio->uio_resid;
242 VOP_UNLOCK(vp);
243 return (error);
eb668bc6
KM
244}
245
97f761d2
KM
246/*
247 * File table vnode write routine.
248 */
eb668bc6
KM
249vn_write(fp, uio, cred)
250 struct file *fp;
251 struct uio *uio;
252 struct ucred *cred;
253{
9342689a
JH
254 USES_VOP_LOCK;
255 USES_VOP_UNLOCK;
256 USES_VOP_WRITE;
eb668bc6 257 register struct vnode *vp = (struct vnode *)fp->f_data;
cde34f67 258 int count, error, ioflag = 0;
eb668bc6 259
63992c37 260 if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
eb668bc6 261 ioflag |= IO_APPEND;
63992c37 262 if (fp->f_flag & FNONBLOCK)
eb668bc6 263 ioflag |= IO_NDELAY;
cde34f67
KM
264 VOP_LOCK(vp);
265 uio->uio_offset = fp->f_offset;
266 count = uio->uio_resid;
73019d79 267 LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_WRITE);
cde34f67
KM
268 error = VOP_WRITE(vp, uio, ioflag, cred);
269 if (ioflag & IO_APPEND)
270 fp->f_offset = uio->uio_offset;
271 else
272 fp->f_offset += count - uio->uio_resid;
273 VOP_UNLOCK(vp);
274 return (error);
eb668bc6
KM
275}
276
277/*
97f761d2 278 * File table vnode stat routine.
eb668bc6 279 */
a9194d51 280vn_stat(vp, sb, p)
eb668bc6
KM
281 struct vnode *vp;
282 register struct stat *sb;
a9194d51 283 struct proc *p;
eb668bc6 284{
9342689a 285 USES_VOP_GETATTR;
eb668bc6
KM
286 struct vattr vattr;
287 register struct vattr *vap;
288 int error;
289 u_short mode;
290
291 vap = &vattr;
a9194d51 292 error = VOP_GETATTR(vp, vap, p->p_ucred, p);
eb668bc6
KM
293 if (error)
294 return (error);
295 /*
296 * Copy from vattr table
297 */
298 sb->st_dev = vap->va_fsid;
299 sb->st_ino = vap->va_fileid;
300 mode = vap->va_mode;
301 switch (vp->v_type) {
302 case VREG:
2e3baa4b 303 mode |= S_IFREG;
eb668bc6
KM
304 break;
305 case VDIR:
2e3baa4b 306 mode |= S_IFDIR;
eb668bc6
KM
307 break;
308 case VBLK:
2e3baa4b 309 mode |= S_IFBLK;
eb668bc6
KM
310 break;
311 case VCHR:
2e3baa4b 312 mode |= S_IFCHR;
eb668bc6
KM
313 break;
314 case VLNK:
2e3baa4b 315 mode |= S_IFLNK;
eb668bc6
KM
316 break;
317 case VSOCK:
2e3baa4b 318 mode |= S_IFSOCK;
eb668bc6 319 break;
0099f400
KM
320 case VFIFO:
321 mode |= S_IFIFO;
322 break;
eb668bc6
KM
323 default:
324 return (EBADF);
325 };
326 sb->st_mode = mode;
327 sb->st_nlink = vap->va_nlink;
328 sb->st_uid = vap->va_uid;
329 sb->st_gid = vap->va_gid;
330 sb->st_rdev = vap->va_rdev;
331 sb->st_size = vap->va_size;
e39dd239
KM
332 sb->st_atimespec.ts_sec = vap->va_atime.tv_sec;
333 sb->st_atimespec.ts_nsec = vap->va_atime.tv_usec * 1000;
334 sb->st_mtimespec.ts_sec = vap->va_mtime.tv_sec;
335 sb->st_mtimespec.ts_nsec = vap->va_mtime.tv_usec * 1000;
336 sb->st_ctimespec.ts_sec = vap->va_ctime.tv_sec;
337 sb->st_ctimespec.ts_nsec = vap->va_ctime.tv_usec * 1000;
eb668bc6 338 sb->st_blksize = vap->va_blocksize;
2ff0b8da
KM
339 sb->st_flags = vap->va_flags;
340 sb->st_gen = vap->va_gen;
366f2ef0 341 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
eb668bc6
KM
342 return (0);
343}
344
345/*
97f761d2 346 * File table vnode ioctl routine.
eb668bc6 347 */
a9194d51 348vn_ioctl(fp, com, data, p)
eb668bc6
KM
349 struct file *fp;
350 int com;
351 caddr_t data;
a9194d51 352 struct proc *p;
eb668bc6 353{
9342689a
JH
354 USES_VOP_GETATTR;
355 USES_VOP_IOCTL;
eb668bc6
KM
356 register struct vnode *vp = ((struct vnode *)fp->f_data);
357 struct vattr vattr;
358 int error;
359
360 switch (vp->v_type) {
361
362 case VREG:
363 case VDIR:
364 if (com == FIONREAD) {
a9194d51 365 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
eb668bc6
KM
366 return (error);
367 *(off_t *)data = vattr.va_size - fp->f_offset;
368 return (0);
369 }
370 if (com == FIONBIO || com == FIOASYNC) /* XXX */
371 return (0); /* XXX */
372 /* fall into ... */
373
374 default:
375 return (ENOTTY);
376
0099f400 377 case VFIFO:
eb668bc6
KM
378 case VCHR:
379 case VBLK:
a9194d51 380 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
1665da5a 381 if (error == 0 && com == TIOCSCTTY) {
8429d022 382 p->p_session->s_ttyvp = vp;
1665da5a
MT
383 VREF(vp);
384 }
385 return (error);
fc96c615 386 }
eb668bc6
KM
387}
388
389/*
97f761d2 390 * File table vnode select routine.
eb668bc6 391 */
a9194d51 392vn_select(fp, which, p)
eb668bc6
KM
393 struct file *fp;
394 int which;
a9194d51 395 struct proc *p;
eb668bc6 396{
9342689a 397 USES_VOP_SELECT;
8429d022 398
ccee3c59 399 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
97f761d2 400 fp->f_cred, p));
eb668bc6
KM
401}
402
403/*
97f761d2 404 * File table vnode close routine.
eb668bc6 405 */
97f761d2
KM
406vn_closefile(fp, p)
407 struct file *fp;
a9194d51 408 struct proc *p;
eb668bc6 409{
eb668bc6 410
97f761d2
KM
411 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
412 fp->f_cred, p));
eb668bc6
KM
413}
414
eb668bc6
KM
415/*
416 * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked)
417 * - look up fsid in mount list (if not found ret error)
418 * - get vp by calling VFS_FHTOVP() macro
419 * - if lockflag lock it with VOP_LOCK()
420 */
421vn_fhtovp(fhp, lockflag, vpp)
422 fhandle_t *fhp;
423 int lockflag;
424 struct vnode **vpp;
425{
9342689a 426 USES_VOP_UNLOCK;
eb668bc6 427 register struct mount *mp;
eb668bc6
KM
428
429 if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
430 return (ESTALE);
73019d79 431 if (VFS_FHTOVP(mp, &fhp->fh_fid, 0, vpp))
a2f658f9
KM
432 return (ESTALE);
433 if (!lockflag)
434 VOP_UNLOCK(*vpp);
eb668bc6
KM
435 return (0);
436}