void quota2_create_blk0(uint64_t bsize, void *bp, int q2h_hash_shift, int type, int ns) { struct quota2_header *q2h; const int quota2_hash_size = 1 << q2h_hash_shift; const int quota2_full_header_size = sizeof(struct quota2_header) + sizeof(q2h->q2h_entries[0]) * quota2_hash_size; int i; memset(bp, 0, bsize); q2h = bp; q2h->q2h_magic_number = ufs_rw32(Q2_HEAD_MAGIC, ns); q2h->q2h_type = type; q2h->q2h_hash_shift = q2h_hash_shift; q2h->q2h_hash_size = ufs_rw16(quota2_hash_size, ns); /* setup defaut entry: unlimited, 7 days grace */ for (i = 0; i < N_QL; i++) { q2h->q2h_defentry.q2e_val[i].q2v_hardlimit = q2h->q2h_defentry.q2e_val[i].q2v_softlimit = ufs_rw64(UQUAD_MAX, ns); q2h->q2h_defentry.q2e_val[i].q2v_grace = ufs_rw64(7ULL * 24ULL * 3600ULL, ns); } /* first quota entry, after the hash table */ quota2_addfreeq2e(q2h, bp, quota2_full_header_size, bsize, ns); }
int ufs_mkdir(void *v) { struct vop_mkdir_v3_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; } */ *ap = v; struct vnode *dvp = ap->a_dvp, *tvp; struct vattr *vap = ap->a_vap; struct componentname *cnp = ap->a_cnp; struct inode *ip, *dp = VTOI(dvp); struct buf *bp; struct dirtemplate dirtemplate; struct direct *newdir; int error, dmode; struct ufsmount *ump = dp->i_ump; int dirblksiz = ump->um_dirblksiz; struct ufs_lookup_results *ulr; fstrans_start(dvp->v_mount, FSTRANS_SHARED); /* XXX should handle this material another way */ ulr = &dp->i_crap; UFS_CHECK_CRAPCOUNTER(dp); if ((nlink_t)dp->i_nlink >= LINK_MAX) { error = EMLINK; goto out; } dmode = vap->va_mode & ACCESSPERMS; dmode |= IFDIR; /* * Must simulate part of ufs_makeinode here to acquire the inode, * but not have it entered in the parent directory. The entry is * made later after writing "." and ".." entries. */ if ((error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, ap->a_vpp)) != 0) goto out; tvp = *ap->a_vpp; ip = VTOI(tvp); error = UFS_WAPBL_BEGIN(ap->a_dvp->v_mount); if (error) { UFS_VFREE(tvp, ip->i_number, dmode); vput(tvp); goto out; } ip->i_uid = kauth_cred_geteuid(cnp->cn_cred); DIP_ASSIGN(ip, uid, ip->i_uid); ip->i_gid = dp->i_gid; DIP_ASSIGN(ip, gid, ip->i_gid); #if defined(QUOTA) || defined(QUOTA2) if ((error = chkiq(ip, 1, cnp->cn_cred, 0))) { UFS_VFREE(tvp, ip->i_number, dmode); UFS_WAPBL_END(dvp->v_mount); fstrans_done(dvp->v_mount); vput(tvp); return (error); } #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = dmode; DIP_ASSIGN(ip, mode, dmode); tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ ip->i_nlink = 2; DIP_ASSIGN(ip, nlink, 2); if (cnp->cn_flags & ISWHITEOUT) { ip->i_flags |= UF_OPAQUE; DIP_ASSIGN(ip, flags, ip->i_flags); } /* * Bump link count in parent directory to reflect work done below. * Should be done before reference is created so cleanup is * possible if we crash. */ dp->i_nlink++; DIP_ASSIGN(dp, nlink, dp->i_nlink); dp->i_flag |= IN_CHANGE; if ((error = UFS_UPDATE(dvp, NULL, NULL, UPDATE_DIROP)) != 0) goto bad; /* * Initialize directory with "." and ".." from static template. */ dirtemplate = mastertemplate; dirtemplate.dotdot_reclen = dirblksiz - dirtemplate.dot_reclen; dirtemplate.dot_ino = ufs_rw32(ip->i_number, UFS_MPNEEDSWAP(ump)); dirtemplate.dotdot_ino = ufs_rw32(dp->i_number, UFS_MPNEEDSWAP(ump)); dirtemplate.dot_reclen = ufs_rw16(dirtemplate.dot_reclen, UFS_MPNEEDSWAP(ump)); dirtemplate.dotdot_reclen = ufs_rw16(dirtemplate.dotdot_reclen, UFS_MPNEEDSWAP(ump)); if (ump->um_maxsymlinklen <= 0) { #if BYTE_ORDER == LITTLE_ENDIAN if (UFS_MPNEEDSWAP(ump) == 0) #else if (UFS_MPNEEDSWAP(ump) != 0) #endif { dirtemplate.dot_type = dirtemplate.dot_namlen; dirtemplate.dotdot_type = dirtemplate.dotdot_namlen; dirtemplate.dot_namlen = dirtemplate.dotdot_namlen = 0; } else dirtemplate.dot_type = dirtemplate.dotdot_type = 0; } if ((error = UFS_BALLOC(tvp, (off_t)0, dirblksiz, cnp->cn_cred, B_CLRBUF, &bp)) != 0) goto bad; ip->i_size = dirblksiz; DIP_ASSIGN(ip, size, dirblksiz); ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; uvm_vnp_setsize(tvp, ip->i_size); memcpy((void *)bp->b_data, (void *)&dirtemplate, sizeof dirtemplate); /* * Directory set up, now install its entry in the parent directory. * We must write out the buffer containing the new directory body * before entering the new name in the parent. */ if ((error = VOP_BWRITE(bp->b_vp, bp)) != 0) goto bad; if ((error = UFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0) { goto bad; } newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK); ufs_makedirentry(ip, cnp, newdir); error = ufs_direnter(dvp, ulr, tvp, newdir, cnp, bp); pool_cache_put(ufs_direct_cache, newdir); bad: if (error == 0) { VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); VOP_UNLOCK(tvp); UFS_WAPBL_END(dvp->v_mount); } else { dp->i_nlink--; DIP_ASSIGN(dp, nlink, dp->i_nlink); dp->i_flag |= IN_CHANGE; UFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP); /* * No need to do an explicit UFS_TRUNCATE here, vrele will * do this for us because we set the link count to 0. */ ip->i_nlink = 0; DIP_ASSIGN(ip, nlink, 0); ip->i_flag |= IN_CHANGE; UFS_WAPBL_UPDATE(tvp, NULL, NULL, UPDATE_DIROP); UFS_WAPBL_END(dvp->v_mount); vput(tvp); } out: fstrans_done(dvp->v_mount); return (error); }
/* * Vnode op for reading directories. * * This routine handles converting from the on-disk directory format * "struct direct" to the in-memory format "struct dirent" as well as * byte swapping the entries if necessary. */ int ufs_readdir(void *v) { struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; kauth_cred_t a_cred; int *a_eofflag; off_t **a_cookies; int *ncookies; } */ *ap = v; struct vnode *vp = ap->a_vp; struct direct *cdp, *ecdp; struct dirent *ndp; char *cdbuf, *ndbuf, *endp; struct uio auio, *uio; struct iovec aiov; int error; size_t count, ccount, rcount, cdbufsz, ndbufsz; off_t off, *ccp; off_t startoff; size_t skipbytes; struct ufsmount *ump = VFSTOUFS(vp->v_mount); int nswap = UFS_MPNEEDSWAP(ump); #if BYTE_ORDER == LITTLE_ENDIAN int needswap = ump->um_maxsymlinklen <= 0 && nswap == 0; #else int needswap = ump->um_maxsymlinklen <= 0 && nswap != 0; #endif uio = ap->a_uio; count = uio->uio_resid; rcount = count - ((uio->uio_offset + count) & (ump->um_dirblksiz - 1)); if (rcount < _DIRENT_MINSIZE(cdp) || count < _DIRENT_MINSIZE(ndp)) return EINVAL; startoff = uio->uio_offset & ~(ump->um_dirblksiz - 1); skipbytes = uio->uio_offset - startoff; rcount += skipbytes; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = startoff; auio.uio_resid = rcount; UIO_SETUP_SYSSPACE(&auio); auio.uio_rw = UIO_READ; cdbufsz = rcount; cdbuf = kmem_alloc(cdbufsz, KM_SLEEP); aiov.iov_base = cdbuf; aiov.iov_len = rcount; error = VOP_READ(vp, &auio, 0, ap->a_cred); if (error != 0) { kmem_free(cdbuf, cdbufsz); return error; } rcount -= auio.uio_resid; cdp = (struct direct *)(void *)cdbuf; ecdp = (struct direct *)(void *)&cdbuf[rcount]; ndbufsz = count; ndbuf = kmem_alloc(ndbufsz, KM_SLEEP); ndp = (struct dirent *)(void *)ndbuf; endp = &ndbuf[count]; off = uio->uio_offset; if (ap->a_cookies) { ccount = rcount / _DIRENT_RECLEN(cdp, 1); ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp), M_TEMP, M_WAITOK); } else { /* XXX: GCC */ ccount = 0; ccp = NULL; } while (cdp < ecdp) { cdp->d_reclen = ufs_rw16(cdp->d_reclen, nswap); if (skipbytes > 0) { if (cdp->d_reclen <= skipbytes) { skipbytes -= cdp->d_reclen; cdp = _DIRENT_NEXT(cdp); continue; } /* * invalid cookie. */ error = EINVAL; goto out; } if (cdp->d_reclen == 0) { struct dirent *ondp = ndp; ndp->d_reclen = _DIRENT_MINSIZE(ndp); ndp = _DIRENT_NEXT(ndp); ondp->d_reclen = 0; cdp = ecdp; break; } if (needswap) { ndp->d_type = cdp->d_namlen; ndp->d_namlen = cdp->d_type; } else { ndp->d_type = cdp->d_type; ndp->d_namlen = cdp->d_namlen; } ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen); if ((char *)(void *)ndp + ndp->d_reclen + _DIRENT_MINSIZE(ndp) > endp) break; ndp->d_fileno = ufs_rw32(cdp->d_ino, nswap); (void)memcpy(ndp->d_name, cdp->d_name, ndp->d_namlen); memset(&ndp->d_name[ndp->d_namlen], 0, ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen); off += cdp->d_reclen; if (ap->a_cookies) { KASSERT(ccp - *(ap->a_cookies) < ccount); *(ccp++) = off; } ndp = _DIRENT_NEXT(ndp); cdp = _DIRENT_NEXT(cdp); } count = ((char *)(void *)ndp - ndbuf); error = uiomove(ndbuf, count, uio); out: if (ap->a_cookies) { if (error) { free(*(ap->a_cookies), M_TEMP); *(ap->a_cookies) = NULL; *(ap->a_ncookies) = 0; } else { *ap->a_ncookies = ccp - *(ap->a_cookies); } } uio->uio_offset = off; kmem_free(ndbuf, ndbufsz); kmem_free(cdbuf, cdbufsz); *ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset; return error; }