LINUX.ORG.RU
решено ФорумTalks

Про фрагментацию файлов на ФС, FreeBSD и iZEN'а


0

0

В недавней теме про дефрагментатор ext4 iZEN начал доказывать, что FreeBSD'шная UFS2 не подвержена фрагментации. Т.е. как-бы вообще. Я решил попробовать доказать обратное путём экспериментирования со свежескачанным LiveCD Frenzy (основан на FreeBSD 8.0). В результате эксперимента мне удалось выяснить, что FreeBSD'шный fsck заместо степени фрагментации показывает непонятно что...

Для начала надо определиться, что же такое фрагментация. (Далее идёт описание моего понимания этого термина, если что-то не так - поправьте меня). Допустим есть три файла - 1, 2 и 3, каждый из них имеет длину 10. При отсутствии фрагментации на блочном устройстве они должны быть расположены так: 111111111122222222223333333333. Если фрагментация имеет место, то может получиться что-то вроде: 123123123123123123123123123123. В худшем случае части файлов будут не только перепутаны между собой, но ещё и расположены в обратном порядке. Я думаю не надо объяснять почему это плохо - при последовательном чтении файла получается непоследовательное чтение блочного устройства. Задача дефрагментатора - расположить части файлов последовательно и в правильном порядке, т.е. сделать 123123123123123123123123123123 -> 111111111122222222223333333333. Надеюсь я правильно написал?

А теперь про эксперименты над Frenzy.

[root@frenzy ~]# uname -a
FreeBSD frenzy 8.0-RELEASE FreeBSD 8.0-RELEASE #0: Thu Jan  7 11:59:02 UTC 2010     root@frenzy.home.local:/buildscripts/frenzybuild/build/buildscripts/frenzybuild/src/sys/FRENZY  i386
Сначала создаём блочное устройство на 128МБ и на нём ФС:
[root@frenzy ~]# dd if=/dev/zero of=fsimage bs=1M count=128
128+0 records in
128+0 records out
134217728 bytes transferred in 1.333509 secs (100650038 bytes/sec)

[root@frenzy ~]# mdconfig -a -t vnode -f fsimage
md3

[root@frenzy ~]# newfs /dev/md3
/dev/md3: 128.0MB (262144 sectors) block size 16384, fragment size 2048
	using 4 cylinder groups of 32.02MB, 2049 blks, 4160 inodes.
super-block backups (for fsck -b #) at:
 160, 65728, 131296, 196864

[root@frenzy ~]# mkdir ufs2

[root@frenzy ~]# mount /dev/md3 ufs2

[root@frenzy ~]# fsck -n -t ufs md3 | grep fragmentation
2 files, 2 used, 63349 free (21 frags, 7916 blocks, 0.0% fragmentation)
Далее создаём кучу мелких файлов
[root@frenzy ~]# for ((i=0; i<1000; i++)); do dd if=/dev/zero of=/root/ufs2/test$i bs=1k count=120; done
... вывод пропущен ...

[root@frenzy ~]# df -h | grep ufs
/dev/md3                        124M    117M   -3.4M   103%    /root/ufs2

[root@frenzy ~]# fsck -n -t ufs md3 | grep fragmentation
1002 files, 60009 used, 3342 free (998 frags, 293 blocks, 1.6% fragmentation)
Сразу же вопрос: откуда взялись 1.6% фрагментации? Ну да ладно. Далее удаляем каждый десятый мелкий файл и на его место дозаписываем один большой («fragmented»):
[root@frenzy ~]# rm ufs2/test*0

[root@frenzy ~]# df -h | grep ufs2
/dev/md3                        124M    105M    8.3M    93%    /root/ufs2

[root@frenzy ~]# fsck -n -t ufs md3 | grep fragmentation
902 files, 54009 used, 9342 free (1206 frags, 1017 blocks, 1.9% fragmentation)

[root@frenzy ~]# cat /dev/zero >>ufs2/fragmented

/root/ufs2: write failed, filesystem is full
cat: stdout: No space left on device

[root@frenzy ~]# fsck -n -t ufs md3 | grep fragmentation
903 files, 61697 used, 1654 free (1206 frags, 56 blocks, 1.9% fragmentation)

[root@frenzy ~]# rm ufs2/test*1

[root@frenzy ~]# cat /dev/zero >>ufs2/fragmented

/root/ufs2: write failed, filesystem is full
cat: stdout: No space left on device

[root@frenzy ~]# fsck -n -t ufs md3 | grep fragmentation
803 files, 55697 used, 7654 free (982 frags, 834 blocks, 1.6% fragmentation)
И так далее, пока на разделе не останется один большой файл fragmented, занимающий всё место. По идее, если

  • UFS2 не обладает телепатией и не могла изначально расположить мелкие файлы так, чтобы при их непоследовательном удалении место на блочном устройстве освобождалось последовательно
  • UFS2 в фоне не перемещает части существующих файлов, т.е. не делает фоновую дефрагментацию

, то куски файла на блочном устройстве должны быть расположены не последовательно, т.е. он должен быть фрагментирован. Но что же мы видим:

[root@frenzy ~]# fsck -n -t ufs md3 | grep fragmentation
3 files, 63025 used, 326 free (14 frags, 39 blocks, 0.0% fragmentation)
Ага, щас, 0% =).

А теперь вопрос: чем же смотреть фрагментацию во FreeBSD? Под линуксом с помощью утилиты filefrag можно посмотреть на сколько частей разбило файл.

Deleted

Ответ на: комментарий от iZEN

>Большая.

Операционка работает с блочными устройствами транзакциями пересылаемых данных, кратными размеру блока. Для маленьких блоков будет несколько транзакций. Для больших блоков — транзакций меньше. Это влияет на общую пропускную способность интерфейса диск-память.

это в общем-то к теме никак не относится.

Если фрагментация на уровне фрагментов блоков, то все равно надо считывать больше блоков, чем можно было бы.

dikiy ★★☆☆☆
()
Ответ на: комментарий от dikiy

видимо фрагментацией называют сколько разрывов имеет файл.

Именно.

В данном случае - ни одного.

Нет. Всё проще: в терминах freebsd фрагментацией именуют совсем другое.

Deleted
()
Ответ на: комментарий от dikiy

Записывай в качестве большого файла просто последователность из нулей и единий. Допустим 20МБ 0xA0, а потом 20МБ 0x0F. Ну или в этом духе.

Я рассматривал и этот вариант. Но даже в этом случае для оценки степени фрагментации пришлось бы писать свою программу, причём с кучей костылей. Лучше разобраться в структуре ФС и написать нормальную утилиту. Чем и занимаюсь. В принципе уже разобрался как айноды адресуют блоки данных, думаю до вечера доделаю...

Deleted
()
Ответ на: комментарий от iZEN

ФС для больших файлов выставляет больший размер блока (максимум в 16 раз больше стандартного). Файлы будут писаться по возможности внутри одной группы цилиндров и в смежные группы цилиндров. Так что тут опять «опачки» — фрагментированности файлов на уровне блоков добиться очень трудно.

Изменить размер блока после создания ФС нельзя хотя бы потому, что карта занятых блоков данных имеет фиксированный размер, который не изменить безе перекройки всей ФС. Или я не понял что ты имеешь ввиду?

Про фрагментированность на уровне блоков - этого добиться очень легко. Как - я написал в первом посте.

Deleted
()
Ответ на: комментарий от iZEN

Большая.

Операционка работает с блочными устройствами транзакциями пересылаемых данных, кратными размеру блока. Для маленьких блоков будет несколько транзакций. Для больших блоков — транзакций меньше. Это влияет на общую пропускную способность интерфейса диск-память.

Фрагментированность на уровне фрагментов блоков не влияют на количество считанных в память блоков, так как вся обработка фрагментов (склеивание из них файла) осуществляется в памяти == блочное устройство лишний раз не дёргается.

Ну сколько же можно тебя отсылать к первому посту? Я же там на пальцах объяснил - что люди именуют фрагментацией и чем это плохо. А тебя постоянно уносит куда-то не туда...

Deleted
()
Ответ на: комментарий от Deleted

Изменить размер блока после создания ФС нельзя хотя бы потому, что карта занятых блоков данных имеет фиксированный размер, который не изменить безе перекройки всей ФС. Или я не понял что ты имеешь ввиду?

в inode добавлено поле, которое позволяет ФС использовать для конкретного файла больший размер блока. Для маленьких, слабо растущих или сильно фрагментированных файлов в этом поле устанавливается единица. А когда ФС обнаруживает большой непрерывный файл, она пишет сюда число от 2 до 16, на которое домножается размер блока ФС при работе с метаданными этого файла.

А тебя постоянно уносит куда-то не туда...

В Soft-Updates? ;)

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

В Soft-Updates? ;)

О б-же! А soft-updates то тут каким боком?! Похоже у тебя в голове какая-то каша.

Deleted
()
Ответ на: комментарий от Deleted

Итак, я всё-таки переписал утилиту под FreeBSD & UFS2. Код топорный, на больших файлов работает очень медленно, возможны баги. Но всё-таки он работает =). Вот:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/lock.h>
#include <sys/extattr.h>
#include <sys/acl.h>
#include <sys/param.h>

#include <ufs/ufs/quota.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ffs/fs.h>

#define LLD(x) ((long long int) x)
#define LLU(x) ((unsigned long long int) x)

#ifdef MONSTER_CAT
#	define printf(...) ((void) 0)
#endif

typedef struct
{
	int	fd;
	off_t	pos;
	char	buf[MAXBSIZE];
	off_t	buf_pos;
	off_t	buf_sz;
} Dev;

typedef struct
{
	Dev				*dev;

	const struct fs			*sb;
	const struct ufs2_dinode	*in;
	ufs2_daddr_t			cgbase;
	
	uint64_t			apb;
	
	int				ind_lvl;
	unsigned int			pos[NIADDR];
} AddrReaderState;

static void die(const char *message)
{
	fprintf(stderr, "ERROR: %s\n", message);
	exit(EXIT_FAILURE);
}

static void openDev(Dev *dev, const char *name)
{
	dev->fd = open(name, O_RDONLY);
	if (dev->fd == -1)
		die("open() error.");
	dev->pos = 0;
	dev->buf_pos = -1;
}

static void seekDev(Dev *dev, off_t pos)
{
	dev->pos = pos;
}

static void readDev(Dev *dev, void *buf, size_t size)
{
	size_t	n;
	char	*b = buf;
	ssize_t	readed;

	while (size) {
		if ((dev->pos >= dev->buf_pos) &&
				(dev->pos - dev->buf_pos < MAXBSIZE)) {
			n = MAXBSIZE - (dev->pos - dev->buf_pos);
			if (n > size)
				n = size;
			if (dev->pos - dev->buf_pos + n > dev->buf_sz)
				die("End of block device.");
			memcpy(b, dev->buf + (dev->pos - dev->buf_pos), n);
			size -= n;
			b += n;
			dev->pos += n;
		} else {
			dev->buf_pos = dev->pos - (dev->pos % MAXBSIZE);
			if (lseek(dev->fd, dev->buf_pos, SEEK_SET) == -1)
				die("lseek() error.");
				
			readed = read(dev->fd, dev->buf, MAXBSIZE);
			if (!readed)
				die("End of block device.");
			else if (readed == -1)
				die("read() error.");
			dev->buf_sz = (size_t) readed;
			
		}
	}
}

static void closeDev(const Dev *dev)
{
	if (close(dev->fd) == -1)
		die("close() error.");
}

static void findSuperBlock(Dev *dev, struct fs *sblock)
{
	const off_t	search_pos[] = SBLOCKSEARCH;
	
	for(int i = 0; search_pos[i] != -1; ++i) {
		seekDev(dev, search_pos[i]);
		readDev(dev, sblock, sizeof(*sblock));
		if (sblock->fs_magic == FS_UFS2_MAGIC)
			return;
	}
	
	die("Can't find valid UFS2 superblock.");
}

static void findDevice(char *namebuf, dev_t dev)
{
	DIR		*d;
	struct dirent	*de;
	struct stat	st;
	
	d = opendir("/dev");
	if (!d)
		die("opendir() error.");
	while ((de = readdir(d)) != NULL) {
		snprintf(namebuf, PATH_MAX, "/dev/%s", de->d_name);
		if (stat(namebuf, &st) == -1)
			die("stat() error.");
		if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
			continue;
		
		if (st.st_rdev == dev) {
			if (closedir(d) == -1)
				die("closedir() error.");
			return;
		}
	}
	die("Can't find block device.");
}

static void initAddrReader(AddrReaderState *ars, Dev *dev,
		const struct fs *sb, const struct ufs2_dinode *in,
		ufs2_daddr_t cgbase)
{
	ars->dev = dev;

	ars->sb = sb;
	ars->in = in;
	ars->cgbase = cgbase;
	
	ars->apb = sb->fs_bsize / sizeof(ufs2_daddr_t);
	
	ars->ind_lvl = -1;
	ars->pos[0] = 0;
}

static ufs2_daddr_t getBlockAddr(AddrReaderState *ars)
{
	ufs2_daddr_t	addr;
	
	if (ars->ind_lvl == -1) {
		addr = ars->in->di_db[ars->pos[0]];
		++ars->pos[0];
		if (ars->pos[0] == NDADDR) {
			ars->ind_lvl = 0;
			ars->pos[0] = 0;
		}
		
		return addr;
	} else {
		addr = ars->in->di_ib[ars->ind_lvl];
		for (int i = 0; i <= ars->ind_lvl; ++i) {
			addr = (addr + ars->cgbase) * ars->sb->fs_fsize +
					ars->pos[i] * sizeof(ufs2_daddr_t);
			seekDev(ars->dev, addr);
			readDev(ars->dev, &addr, sizeof(addr));
		}
		
		for (int i = ars->ind_lvl; i >= 0; --i) {
			++ars->pos[i];
			if (ars->pos[i] < ars->apb) {
				break;
			} else {
				ars->pos[i] = 0;
				if (!i) {
					++ars->ind_lvl;
					if (ars->ind_lvl == NIADDR)
						die("Out of indirect blocks.");
				}
				ars->pos[ars->ind_lvl] = 0;
			}
		}
		
		return addr;
	}
}

static void printGroup(int n, ufs2_daddr_t s, ufs2_daddr_t e)
{
#	ifdef MONSTER_CAT
		(void) n;
		(void) s;
		(void) e;
#	else
		if (s != e)
			printf("Group of fragments #%d: %lld - %lld (%lld)\n",
					n, LLD(s), LLD(e), LLD(e - s + 1));
		else
			printf("Single fragment #%d: %lld\n", n, LLD(s));
#	endif
}

static void showFragmentation(Dev *dev, const struct fs	*sb, ino_t in)
{
	off_t			inode_off;
	struct ufs2_dinode	inode;
	ufs2_daddr_t		start, lenf;
	off_t			len;
	AddrReaderState		ars;
	uint64_t		num_frags = 0, num_blocks = 0;
	uint64_t		num_groups = 0, num_reverse_groups = 0;
	double			fragmentation = 0.0;
	ufs2_daddr_t		old_start = -1, old_lenf = 0, group_start = -1;

	inode_off = lfragtosize(sb, ino_to_fsba(sb, in)) +
			ino_to_fsbo(sb, in) * sb->fs_bsize / sb->fs_inopb;
	seekDev(dev, inode_off);
	readDev(dev, &inode, sizeof(inode));
	printf("Size in bytes: %llu\n", LLU(inode.di_size));
	
	initAddrReader(&ars, dev, sb, &inode, cgbase(sb, ino_to_cg(sb, in)));
	while (inode.di_size) {
		start = getBlockAddr(&ars);
		lenf = sb->fs_frag - fragnum(sb, start);
		len = lfragtosize(sb, lenf);
		
		if ((uint64_t) len > inode.di_size)
			len = inode.di_size;
		inode.di_size -= len;
		
#		ifdef MONSTER_CAT
			char buf[len];
			seekDev(dev, lfragtosize(sb, start));
			readDev(dev, buf, len);
			if (fwrite(buf, len, 1, stdout) < 1)
				die("fwrite() error.");
#		endif

		++num_blocks;
		num_frags += lenf;
		
		if (start != old_start + old_lenf) {
			if (group_start >= 0) {
				printGroup(num_groups, group_start,
						old_start + old_lenf - 1);
			}
			group_start = start;

			++num_groups;

			if (old_start > start)
				++num_reverse_groups;
		}
		
		old_start = start;
		old_lenf = lenf;
	}
	if (group_start >= 0)
		printGroup(num_groups, group_start, old_start + old_lenf - 1);


	printf("Total number of fragments: %llu\n", LLU(num_blocks));
	printf("Total number of blocks: %llu\n", LLU(num_blocks));
	printf("Total number of groups: %llu\n", LLU(num_groups));
	printf("Total number of groups in reverse order: %llu\n", LLU(num_reverse_groups));

	if (num_blocks > 1)
		fragmentation = ((double) (num_groups - 1)) / ((double) (num_blocks - 1)) * 100.0;
	else
		fragmentation = 0.0;
	printf("Fragmentation: %f%%\n", fragmentation);
}

int main(int argc, char **argv) {
	struct stat	st;
	char		dev_name[PATH_MAX];
	Dev		dev_buf, *dev = &dev_buf;
	struct fs	sb;

	if (argc != 2) {
		fprintf(stderr, "Usage:\n\t%s filename\n", argv[0]);
		die("No file name in command line.");
	}

	if (stat(argv[1], &st) == -1)
		die("stat() error.");
	if (!S_ISREG(st.st_mode))
		die("Not regular file.");
	
	printf("File inode: %llu\n", LLU(st.st_ino));
	printf("Device: %d, %d\n", major(st.st_dev), minor(st.st_dev));
	findDevice(dev_name, st.st_dev);
	printf("Device name: \"%s\"\n", dev_name);
	
	openDev(dev, dev_name);
	findSuperBlock(dev, &sb);

	showFragmentation(dev, &sb, st.st_ino);

	closeDev(dev);

	return 0;
}
Собирается так же как и linux-версия:
$ gcc -Wall -Wextra -pedantic -std=c99 -o showfrag-ufs2 showfrag-ufs2.c

В качестве дополнения, можно собрать «тестовую» версию утилиты, которая будет представлять из себя этакую монструозную реализацию cat со встроенным драйвером ФС:

$ gcc -DMONSTER_CAT -Wall -Wextra -pedantic -std=c99 -o showfrag-ufs2 showfrag-ufs2.c

$ md5 /mnt/test/fragmented
MD5 (/mnt/test/fragmented) = 00a76c1799b9ff442fbd7ecaee9be8ab

$ ./showfrag-ufs2 /mnt/test/fragmented | md5
00a76c1799b9ff442fbd7ecaee9be8ab

Важно: перед использованием утилиты надо делать sync, чтобы все свежезаписанные данные точно сбросились из кешей на блочное устройство.

Deleted
()
Ответ на: комментарий от iZEN

А теперь вернёмся к нашим баранам, т.е. эксперименту из первого поста. После его проведения (правда на немного большем разделе, но не суть важно) я натравил на файл fragmented свою утилиту. Вот что вышло:

[root@ ~/showfrag]# ./showfrag-ufs2 /mnt/test/fragmented
File inode: 1004
Device: 0, 67
Device name: "/dev/md0"
Size in bytes: 258998272
Group of fragments #1: 64160 - 64223 (64)
Group of fragments #2: 64272 - 65551 (1280)
Group of fragments #3: 66648 - 81751 (15104)
Group of fragments #4: 81784 - 98199 (16416)
... пропущено ...
Group of fragments #1027: 59896 - 59959 (64)
Group of fragments #1028: 60496 - 60559 (64)
Group of fragments #1029: 61096 - 61159 (64)
Group of fragments #1030: 61696 - 61759 (64)
Group of fragments #1031: 62296 - 62303 (8)
Total number of fragments: 15808
Total number of blocks: 15808
Total number of groups: 1031
Total number of groups in reverse order: 20
Fragmentation: 6.516100%
Итого: файл расфигачило на 1031 кусок и размазало по разделу. Причём 20 кусков UFS2 расположила в неправильном порядке. Далее делаем «дефрагментацию»:
[root@ ~/showfrag]# mv /mnt/test/fragmented /var/tmp/

[root@ ~/showfrag]# mv /var/tmp/fragmented /mnt/test/                    

[root@ ~/showfrag]# sync
И пробуем снова:
[root@ ~/showfrag]# ./showfrag-ufs2 /mnt/test/fragmented
File inode: 4
Device: 0, 67
Device name: "/dev/md0"
Size in bytes: 258998272
Group of fragments #1: 1112 - 1175 (64)
Group of fragments #2: 1224 - 17639 (16416)
Group of fragments #3: 33872 - 50255 (16384)
Group of fragments #4: 66648 - 83031 (16384)
Group of fragments #5: 99424 - 115807 (16384)
Group of fragments #6: 50256 - 65551 (15296)
Group of fragments #7: 83032 - 98327 (15296)
Group of fragments #8: 115808 - 131071 (15264)
Group of fragments #9: 17640 - 20903 (3264)
Group of fragments #10: 20936 - 32647 (11712)
Total number of fragments: 15808
Total number of blocks: 15808
Total number of groups: 10
Total number of groups in reverse order: 2
Fragmentation: 0.056937%
Не идеально, но уже намного лучше - кусков получилось всего 10.

Вывод: UFS2 точно так же подвержена фрагментации, как и ext4 или любая другая ФС общего назначения.

Deleted
()
Ответ на: комментарий от Deleted

«fragmentation = ((double) (num_groups - 1)) / ((double) (num_blocks - 1)) * 100.0;»

Хорошая формула. Можно при форматировании сделать число групп равным 5-10 и в каждой группе по 1000 блоков. Как результат: фрагментация 0,5-1% на маленьких файлах и максимум 8-16% для очень больших файлов. ВСЕГДА. :)))

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

Чувак, у тебя похоже и с математикой плохо. Максимальная фрагментация по этой формуле ВСЕГДА будет равна 100%. Это возможно, если ФС все блоки файла расположит непоследовательно. Тебе рассказать как такой случай воспроизвести на реальной ФС или сам догадаешься?

Deleted
()
Ответ на: комментарий от Deleted

>Чувак, у тебя похоже и с математикой плохо. Максимальная фрагментация по этой формуле ВСЕГДА будет равна 100%.

:))

«fragmentation = ((double) (num_groups - 1)) / ((double) (num_blocks - 1)) * 100.0;»

Ага. При условии равенства num_groups == num_blocks, то есть при условии вырожденной ФС, которого никогда не случится на реальном устройстве.

Это возможно, если ФС все блоки файла расположит непоследовательно. Тебе рассказать как такой случай воспроизвести на реальной ФС или сам догадаешься?


Эта формула никак не учитывает относительное расположение блоков (один за другими или вперемешку). Так что чувачок, математику подтягивать надо тебе, раз вывел такую формулу.

iZEN ★★★★★
()
Ответ на: комментарий от bibi

на худой конец пошел в поход в горы

Что имеешь против походов в горы?

wfrr ★★☆
()
Ответ на: комментарий от iZEN

Эта формула никак не учитывает относительное расположение блоков (один за другими или вперемешку). Так что чувачок, математику подтягивать надо тебе, раз вывел такую формулу.

Тебе уже в пору официальную справку с печатью выписывать...

Эта формула только относительное расположение и учитывает. Если все блоки, из которых состоит файл, идут подряд и без разрывов, то фрагментация == 0%. Если после каждого блока файла идёт разрыв (т.е. пустое место, данные другого файла или блок другой части этого же файла, расположенной не по порядку), то фрагментация == 100%. Ты по номерам фрагментов то посмотри.

Deleted
()
Ответ на: комментарий от Deleted

> Эта формула только относительное расположение и учитывает.

Надо было давать вменяемые названия переменным, чтобы не путать их с терминологическими и не вводить в заблуждение пользователей.

Потому что: блоки делятся на фрагменты; группы состоят из блоков — это терминология ФС. А у тебя в выводе программы получается каша параметров из собственных воззрений с пересекающимися названиями слов из терминологии ФС.

Отчёт в виде:
«Total number of fragments: 15808
Total number of blocks: 15808
Total number of groups: 1031»
Полностью бессмысленен, если не вникать в текст программы.

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

Отчёт в виде:

«Total number of fragments: 15808

Total number of blocks: 15808

Total number of groups: 1031»

Полностью бессмысленен, если не вникать в текст программы.

Фрагменты - это фрагменты. Блоки - это блоки. Группы - это группы блоков (или фрагментов, в данном случае это одно и то же, так как блоки состоят из фрагментов), расположенных последовательно. Адреса выдаются во фрагментах от начала раздела, т.к. фрагмент - это минимальная адресуемая единица на UFS2.

Deleted
()
Ответ на: комментарий от Deleted

Я понял из вывода, что всего 1031 групп цилиндров, в каждом 15808 блоке остался один фрагмент (поэтому число блоков и фрагментов равно).
Так?

iZEN ★★★★★
()
Ответ на: комментарий от Deleted

> Вывод: UFS2 точно так же подвержена фрагментации, как и ext4 или любая другая ФС общего назначения.

Хорошо, вы научились считать из скольки фрагментов состоит файл в UFS2 на FreeBSD и убедились воочию, что чудес не бывает.

Впрочем, в обоих случаях результаты вполне себе удовлетворительные - группы блоков довольно большие - 128К и больше.

Но что дальше? Чем так плоха фрагментация, что вы так ею озабочены?

ZFSych
()
Ответ на: комментарий от iZEN

> Я понял из вывода, что всего 1031 групп цилиндров, в каждом 15808 блоке остался один фрагмент (поэтому число блоков и фрагментов равно). Так?

Не так. Количество фрагментов равно количеству блоков, то есть для хранения файла не используется ни одного фрагмента. Всего файл состоит из 1031 группы непрерывных блоков. Показанные размеры групп блоков говорят, что несмотря на то, что их довольно много, их размеры довольно велики (средний размер группы - около 15 блоков).

ZFSych
()
Ответ на: комментарий от iZEN

Я понял из вывода, что всего 1031 групп цилиндров, в каждом 15808 блоке остался один фрагмент (поэтому число блоков и фрагментов равно). Так?

Не групп цилиндров, а групп. Я группами обозвал последовательности непрерывно идущих блоков. Вот например файл на диске: 1111xxxx11111111x111111111111xxx1111. 1 - это блоки с данными файла, а x - это «чужие» блоки. В этом примере 4 группы и 25 блоков.

А число блоков и фрагментов равно из-за тупейшей ошибки копипаста, вместо

	printf("Total number of fragments: %llu\n", LLU(num_blocks));
	printf("Total number of blocks: %llu\n", LLU(num_blocks));
должно быть
	printf("Total number of fragments: %llu\n", LLU(num_frags));
	printf("Total number of blocks: %llu\n", LLU(num_blocks));
=)

Кстати есть и ещё как минимум один баг - на некоторых файлах неправильно читаются indirect-блоки с адресами. Впрочем если в тестовом режиме (-DMONSTER_CAT) md5-сумма совпадает с обычным чтением, то значит что всё читается правильно...

Deleted
()
Ответ на: комментарий от ZFSych

Но что дальше? Чем так плоха фрагментация, что вы так ею озабочены?

Меня фрагментация мало волнует. Меня волнует троллинг iZEN'а на тему того, что UFS2 вообще не подвержена фрагментации. Только и всего.

Deleted
()
Ответ на: комментарий от Deleted

> Меня фрагментация мало волнует. Меня волнует троллинг iZEN'а на тему того, что UFS2 вообще не подвержена фрагментации. Только и всего.

Дык выяснили вроде, что речь шла о разных фрагментациях. Так что получается, что правы обе стороны, каждая по-своему ;-)

ZFSych
()
Ответ на: комментарий от Deleted

Кстати есть и ещё как минимум один баг - на некоторых файлах неправильно читаются indirect-блоки с адресами

Fixed:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/lock.h>
#include <sys/extattr.h>
#include <sys/acl.h>
#include <sys/param.h>

#include <ufs/ufs/quota.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ffs/fs.h>

#define LLD(x) ((long long int) x)
#define LLU(x) ((unsigned long long int) x)

#ifdef MONSTER_CAT
#	define printf(...) ((void) 0)
#endif

typedef struct
{
	int	fd;
	off_t	pos;
	char	buf[MAXBSIZE];
	off_t	buf_pos;
	off_t	buf_sz;
} Dev;

typedef struct
{
	Dev				*dev;

	const struct fs			*sb;
	const struct ufs2_dinode	*in;
	
	uint64_t			apb;
	
	int				ind_lvl;
	unsigned int			pos[NIADDR];
} AddrReaderState;

static void die(const char *message)
{
	fprintf(stderr, "ERROR: %s\n", message);
	exit(EXIT_FAILURE);
}

static void openDev(Dev *dev, const char *name)
{
	dev->fd = open(name, O_RDONLY);
	if (dev->fd == -1)
		die("open() error.");
	dev->pos = 0;
	dev->buf_pos = -1;
}

static void seekDev(Dev *dev, off_t pos)
{
	dev->pos = pos;
}

static void readDev(Dev *dev, void *buf, size_t size)
{
	size_t	n;
	char	*b = buf;
	ssize_t	readed;

	while (size) {
		if ((dev->pos >= dev->buf_pos) &&
				(dev->pos - dev->buf_pos < MAXBSIZE)) {
			n = MAXBSIZE - (dev->pos - dev->buf_pos);
			if (n > size)
				n = size;
			if (dev->pos - dev->buf_pos + n > dev->buf_sz)
				die("End of block device.");
			memcpy(b, dev->buf + (dev->pos - dev->buf_pos), n);
			size -= n;
			b += n;
			dev->pos += n;
		} else {
			dev->buf_pos = dev->pos - (dev->pos % MAXBSIZE);
			if (lseek(dev->fd, dev->buf_pos, SEEK_SET) == -1)
				die("lseek() error.");
				
			readed = read(dev->fd, dev->buf, MAXBSIZE);
			if (!readed)
				die("End of block device.");
			else if (readed == -1)
				die("read() error.");
			dev->buf_sz = (size_t) readed;
			
		}
	}
}

static void closeDev(const Dev *dev)
{
	if (close(dev->fd) == -1)
		die("close() error.");
}

static void findSuperBlock(Dev *dev, struct fs *sblock)
{
	const off_t	search_pos[] = SBLOCKSEARCH;
	
	for(int i = 0; search_pos[i] != -1; ++i) {
		seekDev(dev, search_pos[i]);
		readDev(dev, sblock, sizeof(*sblock));
		if (sblock->fs_magic == FS_UFS2_MAGIC)
			return;
	}
	
	die("Can't find valid UFS2 superblock.");
}

static void findDevice(char *namebuf, dev_t dev)
{
	DIR		*d;
	struct dirent	*de;
	struct stat	st;
	
	d = opendir("/dev");
	if (!d)
		die("opendir() error.");
	while ((de = readdir(d)) != NULL) {
		snprintf(namebuf, PATH_MAX, "/dev/%s", de->d_name);
		if (stat(namebuf, &st) == -1)
			die("stat() error.");
		if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
			continue;
		
		if (st.st_rdev == dev) {
			if (closedir(d) == -1)
				die("closedir() error.");
			return;
		}
	}
	die("Can't find block device.");
}

static void initAddrReader(AddrReaderState *ars, Dev *dev,
		const struct fs *sb, const struct ufs2_dinode *in)
{
	ars->dev = dev;

	ars->sb = sb;
	ars->in = in;
	
	ars->apb = sb->fs_bsize / sizeof(ufs2_daddr_t);
	
	ars->ind_lvl = -1;
	ars->pos[0] = 0;
}

static ufs2_daddr_t getBlockAddr(AddrReaderState *ars)
{
	ufs2_daddr_t	addr;
	
	if (ars->ind_lvl == -1) {
		addr = ars->in->di_db[ars->pos[0]];
		++ars->pos[0];
		if (ars->pos[0] == NDADDR) {
			ars->ind_lvl = 0;
			ars->pos[0] = 0;
		}
		
		return addr;
	} else {
		addr = ars->in->di_ib[ars->ind_lvl];
		for (int i = 0; i <= ars->ind_lvl; ++i) {
			addr = addr * ars->sb->fs_fsize +
					ars->pos[i] * sizeof(ufs2_daddr_t);
			seekDev(ars->dev, addr);
			readDev(ars->dev, &addr, sizeof(addr));
		}
		
		for (int i = ars->ind_lvl; i >= 0; --i) {
			++ars->pos[i];
			if (ars->pos[i] < ars->apb) {
				break;
			} else {
				ars->pos[i] = 0;
				if (!i) {
					++ars->ind_lvl;
					if (ars->ind_lvl == NIADDR)
						die("Out of indirect blocks.");
				}
				ars->pos[ars->ind_lvl] = 0;
			}
		}
		
		return addr;
	}
}

static void printGroup(int n, ufs2_daddr_t s, ufs2_daddr_t e)
{
#	ifdef MONSTER_CAT
		(void) n;
		(void) s;
		(void) e;
#	else
		if (s != e)
			printf("Group of fragments #%d: %lld - %lld (%lld)\n",
					n, LLD(s), LLD(e), LLD(e - s + 1));
		else
			printf("Single fragment #%d: %lld\n", n, LLD(s));
#	endif
}

static void showFragmentation(Dev *dev, const struct fs	*sb, ino_t in)
{
	off_t			inode_off;
	struct ufs2_dinode	inode;
	ufs2_daddr_t		start, lenf;
	off_t			len;
	AddrReaderState		ars;
	uint64_t		num_frags = 0, num_blocks = 0;
	uint64_t		num_groups = 0, num_reverse_groups = 0;
	double			fragmentation = 0.0;
	ufs2_daddr_t		old_start = -1, old_lenf = 0, group_start = -1;

	inode_off = lfragtosize(sb, ino_to_fsba(sb, in)) +
			ino_to_fsbo(sb, in) * sb->fs_bsize / sb->fs_inopb;
	seekDev(dev, inode_off);
	readDev(dev, &inode, sizeof(inode));
	printf("Size in bytes: %llu\n", LLU(inode.di_size));
	
	initAddrReader(&ars, dev, sb, &inode);
	while (inode.di_size) {
		start = getBlockAddr(&ars);
		lenf = sb->fs_frag - fragnum(sb, start);
		len = lfragtosize(sb, lenf);
		
		if ((uint64_t) len > inode.di_size)
			len = inode.di_size;
		inode.di_size -= len;
		
#		ifdef MONSTER_CAT
			char buf[len];
			seekDev(dev, lfragtosize(sb, start));
			readDev(dev, buf, len);
			if (fwrite(buf, len, 1, stdout) < 1)
				die("fwrite() error.");
#		endif

		++num_blocks;
		num_frags += lenf;
		
		if (start != old_start + old_lenf) {
			if (group_start >= 0) {
				printGroup(num_groups, group_start,
						old_start + old_lenf - 1);
			}
			group_start = start;

			++num_groups;

			if (old_start > start)
				++num_reverse_groups;
		}
		
		old_start = start;
		old_lenf = lenf;
	}
	if (group_start >= 0)
		printGroup(num_groups, group_start, old_start + old_lenf - 1);


	printf("Total number of fragments: %llu\n", LLU(num_frags));
	printf("Total number of blocks: %llu\n", LLU(num_blocks));
	printf("Total number of groups: %llu\n", LLU(num_groups));
	printf("Total number of groups in reverse order: %llu\n", LLU(num_reverse_groups));

	if (num_blocks > 1)
		fragmentation = ((double) (num_groups - 1)) / ((double) (num_blocks - 1)) * 100.0;
	else
		fragmentation = 0.0;
	printf("Fragmentation: %f%%\n", fragmentation);
}

int main(int argc, char **argv) {
	struct stat	st;
	char		dev_name[PATH_MAX];
	Dev		dev_buf, *dev = &dev_buf;
	struct fs	sb;

	if (argc != 2) {
		fprintf(stderr, "Usage:\n\t%s filename\n", argv[0]);
		die("No file name in command line.");
	}

	if (stat(argv[1], &st) == -1)
		die("stat() error.");
	if (!S_ISREG(st.st_mode))
		die("Not regular file.");
	
	printf("File inode: %llu\n", LLU(st.st_ino));
	printf("Device: %d, %d\n", major(st.st_dev), minor(st.st_dev));
	findDevice(dev_name, st.st_dev);
	printf("Device name: \"%s\"\n", dev_name);
	
	openDev(dev, dev_name);
	findSuperBlock(dev, &sb);

	showFragmentation(dev, &sb, st.st_ino);

	closeDev(dev);

	return 0;
}
Оказывается адреса indirect-блоков задаются абсолютные, а не относительно начала группы цилиндров.

P.S. А не пора ли на ЛОРе пастебин сделать? =)

Deleted
()
Ответ на: комментарий от Deleted

Экий iZEN катализатор мыслей и энергии оказывается ;-)

ZFSych
()
Ответ на: комментарий от Deleted

> Не групп цилиндров, а групп. Я группами обозвал последовательности непрерывно идущих блоков.

Ну обозвал бы это своими словами, не трогая терминологию ФС.

Вот например файл на диске: 1111xxxx11111111x111111111111xxx1111. 1 - это блоки с данными файла, а x - это «чужие» блоки. В этом примере 4 группы и 25 блоков.


Хорошо. Из этого примера рассчитай степень фрагментации ФС с выкладками здесь.

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

Ну обозвал бы это своими словами, не трогая терминологию ФС.

В терминологии UFS2 вроде и нет никаких групп. Есть только группы цилиндров =).

Вот например файл на диске: 1111xxxx11111111x111111111111xxx1111. 1 - это блоки с данными файла, а x - это «чужие» блоки. В этом примере 4 группы и 25 блоков.

Хорошо. Из этого примера рассчитай степень фрагментации ФС с выкладками здесь.

1111xxxx11111111x111111111111xxx1 -> 25 блоков, 4 группы -> фрагментация == (4 - 1)/(25 - 1)*100% == 12.5%

Худший случай: 1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1x1 -> 25 блоков, 25 групп (в каждой один блок) -> фрагментация == (25 - 1)/(25 - 1)*100% == 100%

Лучший случай: x1111111111111111111111111x -> 25 блоков, 1 группа -> фрагментация == (1 - 1)/(25 - 1)*100% == 0%

Deleted
()
Ответ на: комментарий от Deleted

Спасибо.

Ещё один вопрос. Может ли блок UFS2 во фрагментах хранить части трёх и более файлов (по количеству незанятых фрагментов) или только максимум двух файлов?

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

Может ли блок UFS2 во фрагментах хранить части трёх и более файлов (по количеству незанятых фрагментов) или только максимум двух файлов?

Теоретически - да. Как на самом деле - хз.

Deleted
()
Ответ на: комментарий от Deleted
/*
 * Addresses stored in inodes are capable of addressing fragments
 * of `blocks'. File system blocks of at most size MAXBSIZE can
 * be optionally broken into 2, 4, or 8 pieces, each of which is
 * addressable; these pieces may be DEV_BSIZE, or some multiple of
 * a DEV_BSIZE unit.
 *
 * Large files consist of exclusively large data blocks.  To avoid
 * undue wasted disk space, the last data block of a small file may be
 * allocated as only as many fragments of a large block as are
 * necessary.  The filesystem format retains only a single pointer
 * to such a fragment, which is a piece of a single large block that
 * has been divided.  The size of such a fragment is determinable from
 * information in the inode, using the ``blksize(fs, ip, lbn)'' macro.
 *
 * The filesystem records space availability at the fragment level;
 * to determine block availability, aligned fragments are examined.
 */

из /usr/include/ufs/ffs/fs.h. Так что ответ - да.

Deleted
()
Ответ на: комментарий от Deleted

Пусть у нас есть два больших файла A и B, где каждый символ обозначает кусок размером скажем 1ГБ

1. ABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB

2. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

Вопрос - какой вариант взаимного расположения блоков файла на диске лучше?

ZFSych
()
Ответ на: комментарий от ZFSych

Вопрос - какой вариант взаимного расположения блоков файла на диске лучше?

В теории? Второй. На практике - зависит от свойств носителя, на котором это всё записано. Но в общем случае тоже второй.

Deleted
()
Ответ на: комментарий от iZEN

Тогда однофигственно. Кроме очень специфического случая, когда оба файла будут писаться с одинаковой скоростью. Тогда первый вариант. Но для этого нужно, чтобы ФС, кеш и контроллер жёсткого диска обладали искусственным интеллектом...

Deleted
()
Ответ на: комментарий от Deleted

> В теории? Второй. На практике - зависит от свойств носителя, на котором это всё записано. Но в общем случае тоже второй.

А если у нас два потока - первый последовательно читает файл A, а второй последовательно читает файл B?

Или у нас до сих пор MS-DOS и 1 процессор?

ZFSych
()
Ответ на: комментарий от ZFSych

А если у нас два потока - первый последовательно читает файл A, а второй последовательно читает файл B?

А если а если, то у нас получается куча разных факторов, которые невозможно учесть.

Если начать делать оптимизации под одно множество конкретных случаев, то получится гарантированная жопа на множестве остальных случаев. По этому всегда приходится искать некий компромисс.

Deleted
()
Ответ на: комментарий от Deleted

> А если а если, то у нас получается куча разных факторов, которые невозможно учесть.

Вот именно. Поэтому утверждать, что второй вариант лучше или хуже первого - нельзя. Потому как он однозначно лучше для последовательного чтения одного файла за другим в один поток и только.

Если начать делать оптимизации под одно множество конкретных случаев, то получится гарантированная жопа на множестве остальных случаев. По этому всегда приходится искать некий компромисс.

Поэтому в качестве компромисса предлагаю признать, что необходимость дефрагментации, в особенности когда фрагменты имеют размер 128К и более, несколько преувеличена :-)

Иначе, как вы сами утверждаете, оптимизация (дефрагментация) под одно множество из одного конкретного случая (последовательное чтение одного файла в один поток) приводит к гарантированной жопе на множестве всех остальных случаев...

ZFSych
()
Ответ на: комментарий от ZFSych

Поэтому в качестве компромисса предлагаю признать, что необходимость дефрагментации, в особенности когда фрагменты имеют размер 128К и более, несколько преувеличена :-)

Так и быть, соглашусь =).

Deleted
()
Ответ на: комментарий от Deleted

Я думаю, что фрагментация состоит в другом.

Нужно различать: 1) фрагментированность файловой системы и 2) фрагментированность отдельных файлов. Первое отнюдь не всегда соответствует второму.

В первом случае имеем: блоки одного и того же файла разбросаны по диску хаотическим образом == находятся в разных группах цилиндров — в терминологии UFS1/2, или группах блоков в терминологии Ext2/3. При этом для считывания такого файла головке диска приходится совершать массу радиальных перемещений, и передача всего файлов поблочно через интерфейс сильно медленная. Это мы наблюдаем на интенсивно используемой NTFS (и Ext2?).

Во втором случае мы имеем естественным образом разделённый на части файл, который записывается в блоки данных файловой системы определённым образом, с использованием адресации на уровне фрагментов и экстентов или без использования таковых.

Безусловно, драйвер файловой системы выбирает наилучшую политику размещения данных, а именно: с поочерёдным заполнением последовательно адресуемых блоков (фрагментов блоков), увеличивая там где надо размер блока (экстенты). Что мы имеем в этом случае: профит от экономичного использования дискового пространства! Будет ли скорость считывания размещённых таким образом файлов оптимальной? Несомненно. Куда уж быстрее, если их не перезаписывать новыми файлами всё меньшего и меньшего размера.

Размещение блоков одного и того же файла последовательно умеют делать все нормальные ФС, но только некоторые ФС могут локализовать задействованные блоки в группах (цилиндров), что оттягивает конец нефрагментированного пространства диска, а части файлов сосредоточиваются в логически (и, многие до сих пор надеются, что и физически) близких — «группах блоков», а не разбрасываются по всему диску, что уменьшает радиальные перемещения головки диска в узком секторе. FAT12/16/32 не умеет локализовать части файлов (кластера) в определённом месте дискового пространства — она тупо выделяет свободные кластеры из свободного пространства ВСЕГО диска, задействую самые старые из них.

Немногие ФС учитывать свободное пространство, остающееся в последнем блоке файла из-за того, что размер файла несовсем кратен количеству выделенных под него блоков. И тогда на куче файлов в не столь продвинутых ФС остаётся незадействованным множество свободного пространства, которое, фактически лежит мёртвым грузом и его невозможно задействовать, так как все блоки «заняты» (в лучшем случае наполовину).

Помните: была такая неприятная ситуация, например, которая возникала на FAT16 (размер кластера 32 кбайта): когда есть куча мелких файлов по 5-10 кбайт, суммарный размер которых чуть больше половины 1,2ГБ-диска, а записать новые файлы нельзя по причине отсутствия свободных целых кластеров. И, главное, дефрагментация раздела не спасает ситуацию! От этого избавились, перейдя на FAT32 с 4 кбайтным размером кластера и сведя потерю свободного пространства до 20% в самых тяжёлых случаях использования.

Я думаю, да и не только я, пространство неполностью задействованных блоков — ключ к фрагментированности файлов и, в конечном итоге, к степени фрагментированности самой ФС (хотя последнее сглаживается группами блоков). Ключ к использованию её свободного пространства, а после удаления файлов — и к последующей фрагментации новых файлов.

Как выход из положения: минимизировать размер блока. В идеале: 1 байт на блок — вот уж точно для абсолютно всех файлов их размер будет кратен этому значению. Но просто так это никому не нужно — метаинформация для поиска и учёта всех частей файла будет занимать место, превосходящее по размеру сам файл. :)

Вот поэтому в UFS2 сделали размер блока для 90% файлов одинаковым (16 килобайт) и позволили адресовать части файлов на уровне фрагментов блоков (2 кбайта), чтобы использовать дисковое пространство на 99% с минимумом «дыр» из незанятых фрагментов (2 кбайта). Файлы на полностью заполненном разделе, занимающие только оставшиеся фрагменты, я думаю, не внесут сколь-нибудь заметный вклад в скорость доступа к ним.

Для относительно больших файлов используются блоки с размером, превосходящим стандартный размер блока в 16 раз, — это уменьшает количество метаинформации для поиска всех частей таких файлов и увеличивает (за счёт экономии места под метаинформацию) количество доступного свободного пространства.

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

> В первом случае имеем: блоки одного и того же файла разбросаны по диску хаотическим образом == находятся в разных группах цилиндров — в терминологии UFS1/2, или группах блоков в терминологии Ext2/3. При этом для считывания такого файла головке диска приходится совершать массу радиальных перемещений, и передача всего файлов поблочно через интерфейс сильно медленная.

А некоторые ФС могут управлять и несколькими дисками одновременно...

Как выход из положения: минимизировать размер блока. В идеале: 1 байт на блок — вот уж точно для абсолютно всех файлов их размер будет кратен этому значению. Но просто так это никому не нужно — метаинформация для поиска и учёта всех частей файла будет занимать место, превосходящее по размеру сам файл. :)

Нет большого смысла делать минимальный размер блока меньшим, чем размер сектора на диске. А некоторые ФС умеют использовать блоки переменного (не фиксированного) расмера.

А еще есть такое понятие, как фрагментированность свободного пространства.

ZFSych
()
Ответ на: комментарий от iZEN

Я думаю, что фрагментация состоит в другом.

Тут не надо думать. Есть общепринятое понятие фрагментации: http://en.wikipedia.org/wiki/Fragmentation_(computer). С начала темы я говорю про фрагментацию данных. Так что большая просьба: давай ты перестанешь доказывать, что фрагментация это на самом деле совсем не фрагментация, красный цвет на самом деле синий, а вода не мокрая. Просто надоело уже.

Остальную часть поста комментировать нет смысла, так как в ней большей частью содержится бред. А вылавливать не бредовые высказывания и додумывать, что же именно ты имел ввиду, - мне просто надоело.

Тезис о том, что файлы в UFS2 фрагментируются точно так же, как и в ext4, я доказал экспериментальным путём. Тему можно считать закрытой.

Deleted
()
Ответ на: комментарий от Deleted

>Тезис о том, что файлы в UFS2 фрагментируются точно так же, как и в ext4, я доказал экспериментальным путём.

Нет, не доказал.

Ext4 не имеет фрагментов в блоках, поэтому у файлов на ней будет фрагментация значительно выше, чем у файлов на UFS2.

К тому же, на Ext4 будет потеря дискового пространства за счёт неиспользованного свободного места в «хвостах» файлов — недоконца заполненные завершающие блоки, а тем более блоки большого размера (экстенты) будут в Ext4 сжирать свободное пространство за милую душу. В UFS2 этого нет.

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

Ext4 не имеет фрагментов в блоках, поэтому у файлов на ней будет фрагментация значительно выше, чем у файлов на UFS2.

Ты совсем дурак, да? Фрагментация данных (см. статью на википедии) на UFS2 из-за использования фрагментах будет как раз таки выше. Почему? Потому что если в одном блоке будут лежать хвосты нескольких файлов, то в соседних блоках будут остальные части только одного из этих файлов.

К тому же, на Ext4 будет потеря дискового пространства за счёт неиспользованного свободного места в «хвостах» файлов — недоконца заполненные завершающие блоки, а тем более блоки большого размера (экстенты) будут в Ext4 сжирать свободное пространство за милую душу. В UFS2 этого нет.

Если в ext4 при форматировании указать размер блока, равный размеру фрагмента в UFS2, то получится ровно то же самое.

Deleted
()
Ответ на: комментарий от Deleted

Ты совсем дурак, да?

Попрошу не оскорблять.

Фрагментация данных (см. статью на википедии) на UFS2 из-за использования фрагментах будет как раз таки выше. Почему? Потому что если в одном блоке будут лежать хвосты нескольких файлов, то в соседних блоках будут остальные части только одного из этих файлов.

Э, нет. Политика размещения данных в блоках учитывает максимальную заполенность прежде всего блоков (выделяется кратное число блоков на файл), а потом уже заполняются фрагменты недоконца занятых блоков в той же или близкоотстоящей группе цилиндров. Таким образом, число недоконца заполненных блоков будет минимальным (примерно — остаток от деления размера файла на размер блока). Свободное пространство будет представлять из себя набор целых блоков с небольшим процентом адресуемого пространства во фрагментах недоконца заполненных блоков. И это не будет являться серьёзным фактором фрагментации ФС.

В Ext4 же всё наоборот: свободное пространство будет представлять из себя, КАК ПРАВИЛО, набор недоконца заполненных хвостами файлов блоков, которое невозможно использовать из-за отсутствия механизма адресации к «частям» таких блоков. Переменный размер блоков (кстати, каков минимальный и каков максимальный размер получающегося «блока»?) спасёт ситуацию в том случае, если минимальный размер блока будет 2-4 кбайта — и только в этом случае уровень фрагментации Ext4 и утилизации дискового пространства приблизится к UFS2.

Если в ext4 при форматировании указать размер блока, равный размеру фрагмента в UFS2, то получится ровно то же самое.

Именно.

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

Попрошу не оскорблять.

Это не оскорбление, это констатация. Диагноз, если угодно.

KRoN73 абсолютно правильно сказал в прошлой теме - у тебя мощный входной фильтр на логику.

P.S. Мне уже просто надоело доказывать тебе очевидные и общеизвестные вещи, так что можешь продолжать наслаждаться своими заблуждениями.

Deleted
()
Ответ на: комментарий от iZEN

> блоки большого размера (экстенты)

- это просто непрерывные последовательности блоков базового размера, а не какие-то абстрактные большие блоки. А возможные потери места в неиспользуемых полностью последних блоках в 4К (ну или сколько там базовый блок по умолчанию) и в мире, где настольные винчестеры перешагнули терабайтный размер, вряд ли могут считаться очень серьезными.

Пока разговор был про разные фрагментации, это было даже забавно. Теперь, когда все все уже поняли, и разговор идет об одной и той же фрагментации - это уже становится не смешно.

ZFSych
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.