1#!/bin/sh 2 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions 6# are met: 7# 1. Redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer. 9# 2. Redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution. 12# 13# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23# SUCH DAMAGE. 24# 25 26# The issue, found by Maxim, is that sometimes partial truncate could 27# create a UFS inode where the last byte is not populated. 28# Fixed by r295950. 29 30# Test scenario by Maxim Sobolev <sobomax@sippysoft.com> 31 32[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 33 34. ../default.cfg 35 36mount | grep -q "$mntpoint" && umount $mntpoint 37mdconfig -l | grep -q $mdstart && mdconfig -d -u $mdstart 38 39mdconfig -a -t swap -s 1g -u $mdstart 40 41if [ $# -eq 0 ]; then 42 newfs -n $newfs_flags md$mdstart > /dev/null 43else 44 newfs -n md$mdstart > /dev/null 45fi 46mount /dev/md$mdstart $mntpoint 47 48here=`pwd` 49cd /tmp 50sed '1,/^EOF/d' < $here/$0 > truncate6.c 51mycc -o truncate6 -Wall -Wextra -O2 truncate6.c -lutil 52rm -f truncate6.c 53 54cd $mntpoint 55 56/tmp/truncate6 57inode=$(ls -ail | awk '/file/ {print $1}') 58 59cd $here 60rm -f /tmp/truncate6 61 62while mount | grep -q md$rt; do 63 umount $mntpoint || sleep 1 64done 65 66full=$( 67fsdb -r /dev/md$mdstart <<QUOTE 68inode $inode 69blocks 70quit 71QUOTE 72) 73full=`echo "$full" | sed '/Last Mounted/,+6d'` 74r=`echo "$full" | tail -1` 75expect=" lbn 3 blkno 4712-4719" 76if [ "$r" != "$expect" ]; then 77 e=1 78 echo "FAIL Expected \"$expect\", got \"$r\"." 79 echo "$full" | tail -3 80else 81 e=0 82fi 83 84mdconfig -d -u $mdstart 85exit $e 86EOF 87#include <sys/types.h> 88#include <sys/stat.h> 89 90#include <err.h> 91#include <errno.h> 92#include <fcntl.h> 93#include <stdio.h> 94#include <stdlib.h> 95#include <unistd.h> 96 97int 98main(void) 99{ 100 off_t hole, data, pos; 101 int fd; 102 char tempname[] = "file"; 103 104 pos = 1024 * 128 + 1; // 131073 105 if ((fd = open(tempname, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE)) == 106 -1) 107 err(1, "open(%s)", tempname); 108 if (ftruncate(fd, pos) < 0) 109 err(1, "ftruncate()"); 110 hole = lseek(fd, 0, SEEK_HOLE); // 0 111 data = lseek(fd, 0, SEEK_DATA); // 131072 112 if (ftruncate(fd, data) < 0) 113 err(1, "ftruncate() 2"); 114 close(fd); 115 if (hole != 0 && data != 131072) { 116 printf("--> hole = %jd, data = %jd, pos = %jd\n", 117 (intmax_t)hole, (intmax_t)data, (intmax_t)pos); 118 exit (1); 119 } 120 121 return (0); 122} 123