static int auto_rmdir( vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cred, caller_context_t *ct, int flags) { vnode_t *newvp; int error; AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp, nm)); if (error = auto_trigger_mount(dvp, cred, &newvp)) goto done; if (newvp != NULL) { /* * Node is now mounted on. */ if (vn_is_readonly(newvp)) error = EROFS; else error = VOP_RMDIR(newvp, nm, cdir, cred, ct, flags); VN_RELE(newvp); } else error = ENOSYS; done: AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error)); return (error); }
/*ARGSUSED4*/ static int auto_setattr( vnode_t *vp, struct vattr *vap, int flags, cred_t *cred, caller_context_t *ct) { vnode_t *newvp; int error; AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp)); if (error = auto_trigger_mount(vp, cred, &newvp)) goto done; if (newvp != NULL) { /* * Node is mounted on. */ if (vn_is_readonly(newvp)) error = EROFS; else error = VOP_SETATTR(newvp, vap, flags, cred, ct); VN_RELE(newvp); } else error = ENOSYS; done: AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error)); return (error); }
/* * Unhook an attribute directory from a parent file/dir * Only do so, if we are the only user of the vnode. */ void ufs_unhook_shadow(struct inode *ip, struct inode *sip) { struct vnode *datavp = ITOV(ip); struct vnode *dirvp = ITOV(sip); int hno; kmutex_t *ihm; ASSERT(RW_WRITE_HELD(&sip->i_contents)); ASSERT(RW_WRITE_HELD(&ip->i_contents)); if (vn_is_readonly(ITOV(ip))) return; if (ip->i_ufsvfs == NULL || sip->i_ufsvfs == NULL) return; hno = INOHASH(ip->i_number); ihm = &ih_lock[hno]; mutex_enter(ihm); mutex_enter(&datavp->v_lock); mutex_enter(&dirvp->v_lock); if (dirvp->v_count != 1 && datavp->v_count != 1) { mutex_exit(&dirvp->v_lock); mutex_exit(&datavp->v_lock); mutex_exit(ihm); return; } /* * Delete shadow from ip */ sip->i_nlink -= 2; ufs_setreclaim(sip); TRANS_INODE(sip->i_ufsvfs, sip); sip->i_flag |= ICHG; sip->i_seq++; ITIMES_NOLOCK(sip); /* * Update src file */ ip->i_oeftflag = 0; TRANS_INODE(ip->i_ufsvfs, ip); ip->i_flag |= ICHG; ip->i_seq++; ufs_iupdat(ip, 1); mutex_exit(&dirvp->v_lock); mutex_exit(&datavp->v_lock); mutex_exit(ihm); }
static int auto_link( vnode_t *tdvp, vnode_t *svp, char *nm, cred_t *cred, caller_context_t *ct, int flags) { vnode_t *newvp; int error; AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp, (void *)svp, nm)); if (error = auto_trigger_mount(tdvp, cred, &newvp)) goto done; if (newvp == NULL) { /* * an autonode can not be a link to another node */ error = ENOSYS; goto done; } if (vn_is_readonly(newvp)) { error = EROFS; VN_RELE(newvp); goto done; } if (vn_matchops(svp, auto_vnodeops)) { /* * source vp can't be an autonode */ error = ENOSYS; VN_RELE(newvp); goto done; } error = VOP_LINK(newvp, svp, nm, cred, ct, flags); VN_RELE(newvp); done: AUTOFS_DPRINT((5, "auto_link error=%d\n", error)); return (error); }
/* ARGSUSED */ void acl2_setacl(SETACL2args *args, SETACL2res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr) { int error; vnode_t *vp; vattr_t va; vp = nfs_fhtovp(&args->fh, exi); if (vp == NULL) { resp->status = NFSERR_STALE; return; } if (rdonly(exi, req) || vn_is_readonly(vp)) { VN_RELE(vp); resp->status = NFSERR_ROFS; return; } (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); error = VOP_SETSECATTR(vp, &args->acl, 0, cr); if (error) { VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); VN_RELE(vp); resp->status = puterrno(error); return; } va.va_mask = AT_ALL; error = rfs4_delegated_getattr(vp, &va, 0, cr); VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); VN_RELE(vp); /* check for overflowed values */ if (!error) { error = vattr_to_nattr(&va, &resp->resok.attr); } if (error) { resp->status = puterrno(error); return; } resp->status = NFS_OK; }
static int auto_create( vnode_t *dvp, char *nm, vattr_t *va, vcexcl_t excl, int mode, vnode_t **vpp, cred_t *cred, int flag, caller_context_t *ct, vsecattr_t *vsecp) { vnode_t *newvp; int error; AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp, nm)); if (error = auto_trigger_mount(dvp, cred, &newvp)) goto done; if (newvp != NULL) { /* * Node is now mounted on. */ if (vn_is_readonly(newvp)) error = EROFS; else error = VOP_CREATE(newvp, nm, va, excl, mode, vpp, cred, flag, ct, vsecp); VN_RELE(newvp); } else error = ENOSYS; done: AUTOFS_DPRINT((5, "auto_create: error=%d\n", error)); return (error); }
static int auto_symlink( vnode_t *dvp, char *lnknm, /* new entry */ vattr_t *tva, char *tnm, /* existing entry */ cred_t *cred, caller_context_t *ct, int flags) { vnode_t *newvp; int error; AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n", (void *)dvp, lnknm, tnm)); if (error = auto_trigger_mount(dvp, cred, &newvp)) goto done; if (newvp != NULL) { /* * Node is mounted on. */ if (vn_is_readonly(newvp)) error = EROFS; else error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred, ct, flags); VN_RELE(newvp); } else error = ENOSYS; done: AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error)); return (error); }
static int auto_rename( vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, caller_context_t *ct, int flags) { vnode_t *o_newvp, *n_newvp; int error; AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n", (void *)odvp, onm, (void *)ndvp, nnm)); /* * we know odvp is an autonode, otherwise this function * could not have ever been called. */ ASSERT(vn_matchops(odvp, auto_vnodeops)); if (error = auto_trigger_mount(odvp, cr, &o_newvp)) goto done; if (o_newvp == NULL) { /* * can't rename an autonode */ error = ENOSYS; goto done; } if (vn_matchops(ndvp, auto_vnodeops)) { /* * directory is AUTOFS, need to trigger the * mount of the real filesystem. */ if (error = auto_trigger_mount(ndvp, cr, &n_newvp)) { VN_RELE(o_newvp); goto done; } if (n_newvp == NULL) { /* * target can't be an autonode */ error = ENOSYS; VN_RELE(o_newvp); goto done; } } else { /* * destination directory mount had been * triggered prior to the call to this function. */ n_newvp = ndvp; } ASSERT(!vn_matchops(n_newvp, auto_vnodeops)); if (vn_is_readonly(n_newvp)) { error = EROFS; VN_RELE(o_newvp); if (n_newvp != ndvp) VN_RELE(n_newvp); goto done; } error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr, ct, flags); VN_RELE(o_newvp); if (n_newvp != ndvp) VN_RELE(n_newvp); done: AUTOFS_DPRINT((5, "auto_rename error=%d\n", error)); return (error); }
static int cfutimesat(int fd, char *fname, int nmflag, vattr_t *vap, int flags, int follow) { file_t *fp; vnode_t *startvp, *vp; int error; char startchar; if (fd == AT_FDCWD && fname == NULL) return (set_errno(EFAULT)); if (nmflag == 1 || (nmflag == 2 && fname != NULL)) { if (copyin(fname, &startchar, sizeof (char))) return (set_errno(EFAULT)); } else { startchar = '\0'; } if (fd == AT_FDCWD) { startvp = NULL; } else { /* * is this absolute path? */ if (startchar != '/') { if ((fp = getf(fd)) == NULL) return (set_errno(EBADF)); startvp = fp->f_vnode; VN_HOLD(startvp); releasef(fd); } else { startvp = NULL; } } if ((nmflag == 1) || ((nmflag == 2) && (fname != NULL))) { if (AU_AUDITING() && startvp != NULL) audit_setfsat_path(1); if ((error = lookupnameat(fname, UIO_USERSPACE, follow, NULLVPP, &vp, startvp)) != 0) { if (startvp != NULL) VN_RELE(startvp); return (set_errno(error)); } } else { vp = startvp; VN_HOLD(vp); } if (startvp != NULL) { VN_RELE(startvp); } if (vn_is_readonly(vp)) { error = EROFS; } else { error = VOP_SETATTR(vp, vap, flags, CRED(), NULL); } VN_RELE(vp); if (error != 0) return (set_errno(error)); return (0); }
/* ARGSUSED */ void acl3_setacl(SETACL3args *args, SETACL3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr) { int error; vnode_t *vp; vattr_t *vap; vattr_t va; vap = NULL; vp = nfs3_fhtovp(&args->fh, exi); if (vp == NULL) { error = ESTALE; goto out1; } (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); #ifdef DEBUG if (rfs3_do_post_op_attr) { va.va_mask = AT_ALL; vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; } else vap = NULL; #else va.va_mask = AT_ALL; vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; #endif if (rdonly(exi, req) || vn_is_readonly(vp)) { resp->status = NFS3ERR_ROFS; goto out1; } error = VOP_SETSECATTR(vp, &args->acl, 0, cr); #ifdef DEBUG if (rfs3_do_post_op_attr) { va.va_mask = AT_ALL; vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; } else vap = NULL; #else va.va_mask = AT_ALL; vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; #endif if (error) goto out; VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); VN_RELE(vp); resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.attr); return; out: if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: if (vp != NULL) { VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); VN_RELE(vp); } vattr_to_post_op_attr(vap, &resp->resfail.attr); }
/* * nmflag has the following values * * 1 - Always do lookup. i.e. chown, lchown. * 2 - Name is optional i.e. fchownat * 0 - Don't lookup name, vp is in file_p. i.e. fchown * */ int cfchownat(int fd, char *name, int nmflag, uid_t uid, gid_t gid, int flags) { vnode_t *startvp, *vp; file_t *filefp; struct vattr vattr; int error = 0; char startchar; if (uid < -1 || uid > MAXUID || gid < -1 || gid > MAXUID) return (set_errno(EINVAL)); vattr.va_uid = uid; vattr.va_gid = gid; vattr.va_mask = 0; if (vattr.va_uid != -1) vattr.va_mask |= AT_UID; if (vattr.va_gid != -1) vattr.va_mask |= AT_GID; if (fd == AT_FDCWD && name == NULL) return (set_errno(EFAULT)); if (nmflag == 1 || (nmflag == 2 && name != NULL)) { if (copyin(name, &startchar, sizeof (char))) return (set_errno(EFAULT)); } else startchar = '\0'; if (fd == AT_FDCWD) startvp = NULL; else { /* * only get fd if not doing absolute lookup */ if (startchar != '/' || nmflag == 0) { if ((filefp = getf(fd)) == NULL) { return (set_errno(EBADF)); } startvp = filefp->f_vnode; VN_HOLD(startvp); releasef(fd); } else { startvp = NULL; } } #if C2_AUDIT if ((nmflag == 2) && audit_active) audit_setfsat_path(1); #endif /* C2_AUDIT */ /* * Do lookups for chown, lchown and fchownat when name not NULL */ if ((nmflag == 2 && name != NULL) || nmflag == 1) { if (error = lookupnameat(name, UIO_USERSPACE, (flags == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW, NULLVPP, &vp, startvp)) { if (startvp != NULL) VN_RELE(startvp); return (set_errno(error)); } } else { vp = startvp; ASSERT(vp); VN_HOLD(vp); } if (vn_is_readonly(vp)) { error = EROFS; } else { error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL); } if (startvp != NULL) VN_RELE(startvp); if (vp != NULL) VN_RELE(vp); if (error != 0) return (set_errno(error)); else return (error); }
/* * Flush all vnodes in this (or every) vfs. * Used by nfs_sync and by nfs_unmount. */ void r4flush(struct vfs *vfsp, cred_t *cr) { int index; rnode4_t *rp; vnode_t *vp, **vplist; long num, cnt; /* * Check to see whether there is anything to do. */ num = rnode4_new; if (num == 0) return; /* * Allocate a slot for all currently active rnodes on the * supposition that they all may need flushing. */ vplist = kmem_alloc(num * sizeof (*vplist), KM_SLEEP); cnt = 0; /* * Walk the hash queues looking for rnodes with page * lists associated with them. Make a list of these * files. */ for (index = 0; index < rtable4size; index++) { rw_enter(&rtable4[index].r_lock, RW_READER); for (rp = rtable4[index].r_hashf; rp != (rnode4_t *)(&rtable4[index]); rp = rp->r_hashf) { vp = RTOV4(rp); /* * Don't bother sync'ing a vp if it * is part of virtual swap device or * if VFS is read-only */ if (IS_SWAPVP(vp) || vn_is_readonly(vp)) continue; /* * If flushing all mounted file systems or * the vnode belongs to this vfs, has pages * and is marked as either dirty or mmap'd, * hold and add this vnode to the list of * vnodes to flush. */ if ((vfsp == NULL || vp->v_vfsp == vfsp) && nfs4_has_pages(vp) && ((rp->r_flags & R4DIRTY) || rp->r_mapcnt > 0)) { VN_HOLD(vp); vplist[cnt++] = vp; if (cnt == num) { rw_exit(&rtable4[index].r_lock); goto toomany; } } } rw_exit(&rtable4[index].r_lock); } toomany: /* * Flush and release all of the files on the list. */ while (cnt-- > 0) { vp = vplist[cnt]; (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_ASYNC, cr, NULL); VN_RELE(vp); } /* * Free the space allocated to hold the list. */ kmem_free(vplist, num * sizeof (*vplist)); }