ufs: fix the logics for tail relocation
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 17 Jun 2017 19:44:06 +0000 (15:44 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 17 Jun 2017 21:22:42 +0000 (17:22 -0400)
* original hysteresis loop got broken by typo back in 2002; now
it never switches out of OPTTIME state.  Fixed.
* critical levels for switching from OPTTIME to OPTSPACE and back
ought to be calculated once, at mount time.
* we should use mul_u64_u32_div() for those calculations, now that
->s_dsize is 64bit.
* to quote Kirk McKusick (in 1995 FreeBSD commit message):
    The threshold for switching from time-space and space-time is too small
    when minfree is 5%...so make it stay at space in this case.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/ufs/balloc.c
fs/ufs/super.c
fs/ufs/ufs_fs.h

index 0315fea1d589e104ac4f10bf4db3f9f705c3f7ad..f80be4c5df9d13b7009602dd5be2f4c58a5de1ac 100644 (file)
@@ -455,24 +455,14 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,
        /*
         * allocate new block and move data
         */
-       switch (fs32_to_cpu(sb, usb1->fs_optim)) {
-           case UFS_OPTSPACE:
+       if (fs32_to_cpu(sb, usb1->fs_optim) == UFS_OPTSPACE) {
                request = newcount;
-               if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree
-                   > uspi->s_dsize * uspi->s_minfree / (2 * 100))
-                       break;
-               usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
-               break;
-           default:
-               usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
-       
-           case UFS_OPTTIME:
+               if (uspi->cs_total.cs_nffree < uspi->s_space_to_time)
+                       usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
+       } else {
                request = uspi->s_fpb;
-               if (uspi->cs_total.cs_nffree < uspi->s_dsize *
-                   (uspi->s_minfree - 2) / 100)
-                       break;
-               usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
-               break;
+               if (uspi->cs_total.cs_nffree > uspi->s_time_to_space)
+                       usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTSPACE);
        }
        result = ufs_alloc_fragments (inode, cgno, goal, request, err);
        if (result) {
index 34656c7a8e2276bfdc98a25e784c8f1cf2bb9e75..f211b662dd92a6203d7c588d2d469d30dc8821af 100644 (file)
@@ -1211,6 +1211,15 @@ magic_found:
 
        uspi->s_root_blocks = mul_u64_u32_div(uspi->s_dsize,
                                              uspi->s_minfree, 100);
+       if (uspi->s_minfree <= 5) {
+               uspi->s_time_to_space = ~0ULL;
+               uspi->s_space_to_time = 0;
+               usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTSPACE);
+       } else {
+               uspi->s_time_to_space = (uspi->s_root_blocks / 2) + 1;
+               uspi->s_space_to_time = mul_u64_u32_div(uspi->s_dsize,
+                                             uspi->s_minfree - 2, 100) - 1;
+       }
 
        /*
         * Compute another frequently used values
index 823d55a37586037f7ed02f9be5e1dbee890123d4..150eef6f12331a034dab0c48bee530fdc73c821e 100644 (file)
@@ -792,6 +792,8 @@ struct ufs_sb_private_info {
        __s32   fs_magic;       /* filesystem magic */
        unsigned int s_dirblksize;
        __u64   s_root_blocks;
+       __u64   s_time_to_space;
+       __u64   s_space_to_time;
 };
 
 /*