From nobody Mon May 01 08:10:27 2023 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Q8wr32Tfwz48DPW; Mon, 1 May 2023 08:10:27 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Q8wr32Bknz455p; Mon, 1 May 2023 08:10:27 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1682928627; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QjAg+FwGgRxALzJ9eDpNLvHgF+uAWB0A119a10DXzBo=; b=ePKLd+EObcm4dPIVEyO8O8ztiDNvpksf21hSIon+QojTo2P+t6moLXqgkQBX0be8UhrcuG hlEGnJQ+K6RfHgZjdQ9ruDqHFYqxxYCmmDq5vHZ+vfOZWbORviAvdbKDMp85UfiH0K28Md b8eCGv/GxiGuxBfb2lZiAxBsg6ReRmt+bu6MINNtfx4bRbtOLuAq4X0OGpIIqL+Tf2xd3J 7otZ3rFd+pVKXwrp97cfooYuD0auCE7fQZRyuhG2ibfn+L+Dqb9x4KtsyPteBLrgtQRe/w fCXr+nIQE9pgeY/Fz0+TThG+JLJi7EwpwJ3k4QBcxXvmwPOY3SyZ88Fncbag2w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1682928627; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QjAg+FwGgRxALzJ9eDpNLvHgF+uAWB0A119a10DXzBo=; b=wV0UUHi07nsqgGpsgX08vv69kti+MK9JYq2VOkbMzimSrBZLLGlahSD41sn+Il90/EcQXB 5/XqpLmdX1KQMh/tANrqbiNvnmHOxHXwtBLADfhj4uGuFhYUKyxYgahDC3MXyr4G+lvhyH aj0DRWOZNyV5vzlPhS1yikU9em2phqR30Oz8/yrlTMXMsHPc0VyJCdjv43X4yusZ+NwXXB p3jh9+6zGMsU7PpjjfnrPMwiPQtzqVQ0Gop7PZF12BaOkxqrx3bBIO1wJ8i0v5d2hOxN1c OdCwDXAtgwxhiFU4blkZIoKUXw+0x9R/0b7hVogHOvew7vA1N9xQyaNX9ENh9A== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1682928627; a=rsa-sha256; cv=none; b=WUI+y3Cl3/LPZs9N4Dtdq+0RxT1+oEMbEnv6ET1G6qqcNE2NYINIZFtr++k9DZwleUWj8/ gBmPee9lxZr2HKTENhN2Mgtw6W7OQikylUI0CSAhu7Rhc5AcBDDEFPQE8h4L+h5euM3Bzg b7zucoQRXp3H6rZ7pM0UPkuRzNgj9TA53ePV0+ixGJycL2pU+UdrzjDokxBvXgFR4UHdRh 254O5MZ3X7wg+SfOdgcaadXS9V8NOftle0KqnNafc6MlS1brhYjuaifBgRCFJI8JPBN4Gr OMy4tsd3D2hDTg5cUYFK2hZKHByWfQyVcCArLwvZZstLs20vAIDcjpLGo+QJ2A== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Q8wr31J6vzxj1; Mon, 1 May 2023 08:10:27 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 3418ARvq071778; Mon, 1 May 2023 08:10:27 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 3418ARVa071777; Mon, 1 May 2023 08:10:27 GMT (envelope-from git) Date: Mon, 1 May 2023 08:10:27 GMT Message-Id: <202305010810.3418ARVa071777@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: =?utf-8?Q?Stefan=20E=C3=9Fer?= Subject: git: d767bf361b3e - stable/13 - msdosfs: fix debug print format and parameter List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: se X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: d767bf361b3ebdb3955473cd378f8a8dcf9c85f0 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by se: URL: https://cgit.FreeBSD.org/src/commit/?id=d767bf361b3ebdb3955473cd378f8a8dcf9c85f0 commit d767bf361b3ebdb3955473cd378f8a8dcf9c85f0 Author: Stefan Eßer AuthorDate: 2023-03-08 16:58:00 +0000 Commit: Stefan Eßer CommitDate: 2023-05-01 08:09:33 +0000 msdosfs: fix debug print format and parameter Building with -DMSDOSFS_DEBUG failed due to a format mismatch and a variable that has been renamed but not updated in the printf() parameter list. (cherry picked from commit 2d8cf575d5778781928699f9b7cfb448bd2f1f8e) fs/msdosfs: add tracking of free root directory entries This update implements tallying of free directory entries during create, delete, or rename operations on FAT12 and FAT16 file systems. Prior to this change, the total number of root directory entries was reported as number of inodes, but 0 as the number of free inodes, causing system health monitoring software to warn about a suspected disk full issue. The FAT12 and FAT16 file systems provide a limited number of root directory entries, e.g. 512 on typical hard disk formats. The valid range of values is 1 to 65535, but the msdosfs code will effectively round up "odd" values to the next multiple of 16 (e.g. 513 would allow for 528 root directory entries). This update implements tracking of directory entries during create, delete, or rename operations, with initial values determined by scanning the directory when the file system is mounted. Total and free directory entries are reported in the f_files and f_ffree elements of struct statfs, despite differences in semantics of these values: - There is no limit on the number of files and directories that can be created on a FAT file system. Only the root directory of FAT12 and FAT16 file systems is limited, any number of files can still be created in sub-directories, even when 0 free "inodes" are reported. - A single file can require 1 to 21 directory entries, depending on the character set, structure, and length of the name. The DOS 8.3 style file name takes up 1 entry, and if the name does not comply with the syntax of a DOS 8.3 file name, 1 additional entry is used for each 13 characters of the file name. Since all these entries have to be contiguous, it is possible that a file or directory with a long name can not be created, despite a sufficient total number of free directory entries. - Renaming a file can require more directory entries than currently allocated to store its long name, which may prevent an in-place update of the name if more entries are needed. This may cause a rename operation to fail if no contiguous range of free entries for the new name can be found. - The volume label is stored in a directory entry. An empty FAT file system with a volume label will therefore show 1 used "inode" in df. - The perceentage of free inodes shown in df or monitoring tools does only represent the state of the root directory of a FAT12 or FAT16 file system. Neither does a reported value of 0% free inodes does prevent files from being created in sub-directories, nor does a value of 50% free inodes guarantee that even a single file with a "long" name can be created in the root directory (if every other directory entry is occupied and there are no 2 contiguous entries). The statfs(2) and df(1) man pages have been updated with a notice regarding the possibly different semantics of values reported as total and free inodes for non-Unix file systems. PR: 270053 Reported by: Ben Woods Approved by: mckusick Differential Revision: https://reviews.freebsd.org/D38987 (cherry picked from commit c33db74b5323480fba7adef58e8aa88f6091d134) fs/msdosfs: Fix potential panic and size calculations Some combinations of FAT12 file system parameters could cause a kernel panic due to an unmapped access if the size of the FAT was larger than the CPU page size. The reason is that FAT12 uses 3 bytes to store 2 FAT pointers, leading to partial FAT pointers at the end of buffers of a size that is not a multiple of 3. With a typical page size of 4 KB, this caused the FAT entry at byte offsets 4095 and 4096 to cross the page boundary, with only the first page mapped. This was fixed by adjusting the mapping to always cover both bytes of each FAT entry. Testing revealed 2 other inconsistencies that are fixed by this commit: 1) The calculation of the size of the data area did not take into account the fact that the first two data block numbers are reserved and that the data area starts with block 2. This could cause a FAT12 file system created with the maximum supported number of blocks to be incorrectly identified as FAT16. 2) The root directory does not take up space in the data area of a FAT12 or FAT16 file system, since it is placed into a reserved area outside of that data area. This commits makes stat() report the logical size of the root directory, but with 0 blocks allocated from the data area. PR: 270587 Reviewed by: mckusick Differential Revision: https://reviews.freebsd.org/D39386 (cherry picked from commit 0728695c63efda298feccefb3615c23cb6682929) --- bin/df/df.1 | 13 ++++- lib/libc/sys/statfs.2 | 18 +++++- sys/fs/msdosfs/msdosfs_denode.c | 2 +- sys/fs/msdosfs/msdosfs_fat.c | 12 +++- sys/fs/msdosfs/msdosfs_lookup.c | 5 +- sys/fs/msdosfs/msdosfs_vfsops.c | 120 +++++++++++++++++++++++++++++++++++++--- sys/fs/msdosfs/msdosfs_vnops.c | 7 ++- sys/fs/msdosfs/msdosfsmount.h | 17 ++++++ 8 files changed, 177 insertions(+), 17 deletions(-) diff --git a/bin/df/df.1 b/bin/df/df.1 index 64e471fedc42..aa35318c2c65 100644 --- a/bin/df/df.1 +++ b/bin/df/df.1 @@ -29,7 +29,7 @@ .\" @(#)df.1 8.3 (Berkeley) 5/8/95 .\" $FreeBSD$ .\" -.Dd March 11, 2022 +.Dd March 29, 2023 .Dt DF 1 .Os .Sh NAME @@ -246,6 +246,17 @@ $ df -h /dev/ada1p2 Filesystem Size Used Avail Capacity Mounted on /dev/ada1p2 213G 152G 44G 78% / .Ed +.Sh NOTES +For non-Unix file systems, the reported values of used and free inodes +may have a different meaning than that of used and available files and +directories. +An example is msdosfs, which in the case of FAT12 or FAT16 file systems +reports the number of available and free root directory entries instead +of inodes +.Po +where 1 to 21 such directory entries are required to store +each file or directory name or disk label +.Pc . .Sh SEE ALSO .Xr lsvfs 1 , .Xr quota 1 , diff --git a/lib/libc/sys/statfs.2 b/lib/libc/sys/statfs.2 index a865652022bd..4df0e801e418 100644 --- a/lib/libc/sys/statfs.2 +++ b/lib/libc/sys/statfs.2 @@ -28,7 +28,7 @@ .\" @(#)statfs.2 8.5 (Berkeley) 5/24/95 .\" $FreeBSD$ .\" -.Dd March 30, 2020 +.Dd March 29, 2023 .Dt STATFS 2 .Os .Sh NAME @@ -230,6 +230,22 @@ error occurred while reading from or writing to the file system. .It Bq Er EINTEGRITY Corrupted data was detected while reading from the file system. .El +.Sh NOTES +The fields in the +.Vt statfs +structure have been defined to provide the parameters relevant for +traditional +.Tm UNIX +file systems. +For some other file systems, values that have similar, but not +identical, semantics to those described above may be returned. +An example is msdosfs, which in case of FAT12 or FAT13 file systems +reports the number of available and of free root directory entries +instead of inodes +.Po +where 1 to 21 such directory entries are required to store +each file or directory name or disk label +.Pc . .Sh SEE ALSO .Xr fhstatfs 2 , .Xr getfsstat 2 diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c index 51c2e3beaf39..59107a6ca2ea 100644 --- a/sys/fs/msdosfs/msdosfs_denode.c +++ b/sys/fs/msdosfs/msdosfs_denode.c @@ -110,7 +110,7 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, #ifdef MSDOSFS_DEBUG printf("deget(pmp %p, dirclust %lu, diroffset %lx, flags %#x, " "depp %p)\n", - pmp, dirclust, diroffset, flags, depp); + pmp, dirclust, diroffset, lkflags, depp); #endif MPASS((lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE); diff --git a/sys/fs/msdosfs/msdosfs_fat.c b/sys/fs/msdosfs/msdosfs_fat.c index e6d9b671e7d7..2d50d30f33b3 100644 --- a/sys/fs/msdosfs/msdosfs_fat.c +++ b/sys/fs/msdosfs/msdosfs_fat.c @@ -89,11 +89,17 @@ static void fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp, u_long *sizep, u_long *bop) { - u_long bn, size; + u_long bn, size, fatblocksec; + fatblocksec = pmp->pm_fatblocksec; + if (FAT12(pmp) && fatblocksec % 3 != 0) { + fatblocksec *= 3; + if (fatblocksec % 6 == 0) + fatblocksec /= 2; + } bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec; - size = min(pmp->pm_fatblocksec, pmp->pm_FATsecs - bn) - * DEV_BSIZE; + size = roundup(min(fatblocksec, pmp->pm_FATsecs - bn) * DEV_BSIZE, + pmp->pm_BlkPerSec * DEV_BSIZE); bn += pmp->pm_fatblk + pmp->pm_curfat * pmp->pm_FATsecs; if (bnp) diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c index 291f923d79fe..9d98bae86596 100644 --- a/sys/fs/msdosfs/msdosfs_lookup.c +++ b/sys/fs/msdosfs/msdosfs_lookup.c @@ -335,7 +335,7 @@ msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname continue; } #ifdef MSDOSFS_DEBUG - printf("msdosfs_lookup(): match blkoff %d, diroff %d\n", + printf("msdosfs_lookup(): match blkoff %lu, diroff %d\n", blkoff, diroff); #endif /* @@ -688,6 +688,7 @@ createde(struct denode *dep, struct denode *ddep, struct denode **depp, return error; } ndep = bptoep(pmp, bp, ddep->de_fndoffset); + rootde_alloced(ddep); DE_EXTERNALIZE(ndep, dep); @@ -725,6 +726,7 @@ createde(struct denode *dep, struct denode *ddep, struct denode **depp, ndep--; ddep->de_fndoffset -= sizeof(struct direntry); } + rootde_alloced(ddep); if (!unix2winfn(un, unlen, (struct winentry *)ndep, cnt++, chksum, pmp)) break; @@ -1019,6 +1021,7 @@ removede(struct denode *pdep, struct denode *dep) */ offset -= sizeof(struct direntry); ep--->deName[0] = SLOT_DELETED; + rootde_freed(pdep); if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) || !(offset & pmp->pm_crbomask) || ep->deAttributes != ATTR_WIN95) diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c index d7efa103581b..480d278a5a45 100644 --- a/sys/fs/msdosfs/msdosfs_vfsops.c +++ b/sys/fs/msdosfs/msdosfs_vfsops.c @@ -409,6 +409,97 @@ msdosfs_mount(struct mount *mp) return (0); } +/* + * The FAT12 and FAT16 file systems use a limited size root directory that + * can be created with 1 to 65535 entries for files, directories, or a disk + * label (but DOS or Windows creates at most 512 root directory entries). + * This function calculates the number of free root directory entries by + * counting the non-deleted entries (not starting with 0xE5) and by adding + * the amount of never used entries (with the position indicated by an + * entry that starts with 0x00). + */ +static int +rootdir_free(struct msdosfsmount* pmp) +{ + struct buf *bp; + struct direntry *dep; + u_long readsize; + int dirclu; + int diridx; + int dirmax; + int dirleft; + int ffree; + + dirclu = pmp->pm_rootdirblk; + + /* + * The msdosfs code ignores pm_RootDirEnts and uses pm_rootdirsize + * (measured in DEV_BSIZE) to prevent excess root dir allocations. + */ + dirleft = howmany(pmp->pm_rootdirsize * DEV_BSIZE, + sizeof(struct direntry)); + + /* Read in chunks of default maximum root directory size */ + readsize = 512 * sizeof(struct direntry); + +#ifdef MSDOSFS_DEBUG + printf("rootdir_free: blkpersec=%lu fatblksize=%lu dirsize=%lu " + "firstclu=%lu dirclu=%d entries=%d rootdirsize=%lu " + "bytespersector=%hu bytepercluster=%lu\n", + pmp->pm_BlkPerSec, pmp->pm_fatblocksize, readsize, + pmp->pm_firstcluster, dirclu, dirleft, pmp->pm_rootdirsize, + pmp->pm_BytesPerSec, pmp->pm_bpcluster); +#endif + ffree = dirleft; + while (dirleft > 0 && ffree > 0) { + if (readsize > dirleft * sizeof(struct direntry)) + readsize = dirleft * sizeof(struct direntry); +#ifdef MSDOSFS_DEBUG + printf("rootdir_free: dirclu=%d dirleft=%d readsize=%lu\n", + dirclu, dirleft, readsize); +#endif + if (bread(pmp->pm_devvp, dirclu, readsize, NOCRED, &bp) != 0) { + printf("rootdir_free: read error\n"); + if (bp != NULL) + brelse(bp); + return (-1); + } + dirmax = readsize / sizeof(struct direntry); + for (diridx = 0; diridx < dirmax && dirleft > 0; + diridx++, dirleft--) { + dep = (struct direntry*)bp->b_data + diridx; +#ifdef MSDOSFS_DEBUG + if (dep->deName[0] == SLOT_DELETED) + printf("rootdir_free: idx=%d \n", + diridx); + else if (dep->deName[0] == SLOT_EMPTY) + printf("rootdir_free: idx=%d \n", + diridx); + else if (dep->deAttributes == ATTR_WIN95) + printf("rootdir_free: idx=%d \n", + diridx, (dep->deName[0] & 0x1f) + 1); + else if (dep->deAttributes & ATTR_VOLUME) + printf("rootdir_free: idx=%d label='%11.11s'\n", + diridx, dep->deName); + else if (dep->deAttributes & ATTR_DIRECTORY) + printf("rootdir_free: idx=%d dir='%11.11s'\n", + diridx, dep->deName); + else + printf("rootdir_free: idx=%d file='%11.11s'\n", + diridx, dep->deName); +#endif + if (dep->deName[0] == SLOT_EMPTY) + dirleft = 0; + else if (dep->deName[0] != SLOT_DELETED) + ffree--; + } + brelse(bp); + bp = NULL; + dirclu += readsize / DEV_BSIZE; + } + return (ffree); +} + static int mountmsdosfs(struct vnode *odevvp, struct mount *mp) { @@ -611,11 +702,14 @@ mountmsdosfs(struct vnode *odevvp, struct mount *mp) } pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / SecPerClust + 1; - pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; /* XXX not used? */ + pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE; if (pmp->pm_fatmask == 0) { - if (pmp->pm_maxcluster <= ((CLUST_RSRVD - CLUST_FIRST) & - FAT12_MASK)) { + /* + * The last 10 (or 16?) clusters are reserved and must not + * be allocated for data. + */ + if (pmp->pm_maxcluster < (CLUST_RSRVD & FAT12_MASK)) { /* * This will usually be a floppy disk. This size makes * sure that one FAT entry will not be split across @@ -631,11 +725,11 @@ mountmsdosfs(struct vnode *odevvp, struct mount *mp) } } - clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv; + clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv ; if (pmp->pm_maxcluster >= clusters) { #ifdef MSDOSFS_DEBUG printf("Warning: number of clusters (%ld) exceeds FAT " - "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters); + "capacity (%ld)\n", pmp->pm_maxcluster - 1, clusters); #endif pmp->pm_maxcluster = clusters - 1; } @@ -749,6 +843,15 @@ mountmsdosfs(struct vnode *odevvp, struct mount *mp) goto error_exit; pmp->pm_fmod = 1; } + + if (FAT32(pmp)) { + pmp->pm_rootdirfree = 0; + } else { + pmp->pm_rootdirfree = rootdir_free(pmp); + if (pmp->pm_rootdirfree < 0) + goto error_exit; + } + mp->mnt_data = pmp; mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; @@ -947,11 +1050,12 @@ msdosfs_statfs(struct mount *mp, struct statfs *sbp) pmp = VFSTOMSDOSFS(mp); sbp->f_bsize = pmp->pm_bpcluster; sbp->f_iosize = pmp->pm_bpcluster; - sbp->f_blocks = pmp->pm_maxcluster + 1; + sbp->f_blocks = pmp->pm_maxcluster - CLUST_FIRST + 1; sbp->f_bfree = pmp->pm_freeclustercount; sbp->f_bavail = pmp->pm_freeclustercount; - sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ - sbp->f_ffree = 0; /* what to put in here? */ + sbp->f_files = howmany(pmp->pm_rootdirsize * DEV_BSIZE, + sizeof(struct direntry)); + sbp->f_ffree = pmp->pm_rootdirfree; return (0); } diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c index 94af83b5a0a6..c9263fe977d4 100644 --- a/sys/fs/msdosfs/msdosfs_vnops.c +++ b/sys/fs/msdosfs/msdosfs_vnops.c @@ -318,8 +318,11 @@ msdosfs_getattr(struct vop_getattr_args *ap) vap->va_flags |= UF_SYSTEM; vap->va_gen = 0; vap->va_blocksize = pmp->pm_bpcluster; - vap->va_bytes = - (dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask; + if (dep->de_StartCluster != MSDOSFSROOT) + vap->va_bytes = + (dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask; + else + vap->va_bytes = 0; /* FAT12/FAT16 root dir in reserved area */ vap->va_type = ap->a_vp->v_type; vap->va_filerev = dep->de_modrev; return (0); diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h index 5caa40f2b648..5afbfc44dc0a 100644 --- a/sys/fs/msdosfs/msdosfsmount.h +++ b/sys/fs/msdosfs/msdosfsmount.h @@ -108,6 +108,7 @@ struct msdosfsmount { u_int pm_fatmult; /* these 2 values are used in FAT */ u_int pm_fatdiv; /* offset computation */ u_int pm_curfat; /* current FAT for FAT32 (0 otherwise) */ + int pm_rootdirfree; /* number of free slots in FAT12/16 root directory */ u_int *pm_inusemap; /* ptr to bitmap of in-use clusters */ uint64_t pm_flags; /* see below */ void *pm_u2w; /* Local->Unicode iconv handle */ @@ -222,6 +223,22 @@ struct msdosfs_fileno { ? roottobn((pmp), (dirofs)) \ : cntobn((pmp), (dirclu))) +/* + * Increment the number of used entries in a fixed size FAT12/16 root + * directory + */ +#define rootde_alloced(dep) \ + if ((dep)->de_StartCluster == MSDOSFSROOT) \ + (dep)->de_pmp->pm_rootdirfree--; + +/* + * Decrement the number of used entries in a fixed size FAT12/16 root + * directory + */ +#define rootde_freed(dep) \ + if ((dep)->de_StartCluster == MSDOSFSROOT) \ + (dep)->de_pmp->pm_rootdirfree++; + #define MSDOSFS_LOCK_MP(pmp) \ lockmgr(&(pmp)->pm_fatlock, LK_EXCLUSIVE, NULL) #define MSDOSFS_UNLOCK_MP(pmp) \