aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2001-05-08 07:42:20 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2001-05-08 07:42:20 +0000
commit9ccb939ef0dd9c740a2486f2a982845b71c7076f (patch)
treefb504aff6a37ca8fb82f0f8c9fd384fdd81e5b16
parent27b047acf0fad617ac49504dfdeef8242bfc36f9 (diff)
downloadsrc-9ccb939ef0dd9c740a2486f2a982845b71c7076f.tar.gz
src-9ccb939ef0dd9c740a2486f2a982845b71c7076f.zip
When running with soft updates, track the number of blocks and files
that are committed to being freed and reflect these blocks in the counts returned by statfs (and thus also by the `df' command). This change allows programs such as those that do news expiration to know when to stop if they are trying to create a certain percentage of free space. Note that this change does not solve the much harder problem of making this to-be-freed space available to applications that want it (thus on a nearly full filesystem, you may still encounter out-of-space conditions even though the free space will show up eventually). Hopefully this harder problem will be the subject of a future enhancement.
Notes
Notes: svn path=/head/; revision=76357
-rw-r--r--sys/gnu/ext2fs/inode.h7
-rw-r--r--sys/gnu/fs/ext2fs/inode.h7
-rw-r--r--sys/ufs/ffs/ffs_inode.c2
-rw-r--r--sys/ufs/ffs/ffs_softdep.c59
-rw-r--r--sys/ufs/ffs/ffs_softdep_stub.c9
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c39
-rw-r--r--sys/ufs/ffs/fs.h4
-rw-r--r--sys/ufs/ffs/softdep.h7
-rw-r--r--sys/ufs/ufs/inode.h7
-rw-r--r--sys/ufs/ufs/ufs_extern.h1
-rw-r--r--sys/ufs/ufs/ufs_inode.c2
11 files changed, 125 insertions, 19 deletions
diff --git a/sys/gnu/ext2fs/inode.h b/sys/gnu/ext2fs/inode.h
index 3e7c67da8415..0fdaee2e93e9 100644
--- a/sys/gnu/ext2fs/inode.h
+++ b/sys/gnu/ext2fs/inode.h
@@ -125,10 +125,9 @@ struct inode {
#define IN_UPDATE 0x0004 /* Modification time update request. */
#define IN_MODIFIED 0x0008 /* Inode has been modified. */
#define IN_RENAME 0x0010 /* Inode is being renamed. */
-#define IN_SHLOCK 0x0020 /* File has shared lock. */
-#define IN_EXLOCK 0x0040 /* File has exclusive lock. */
-#define IN_HASHED 0x0080 /* Inode is on hash list */
-#define IN_LAZYMOD 0x0100 /* Modified, but don't write yet. */
+#define IN_HASHED 0x0020 /* Inode is on hash list */
+#define IN_LAZYMOD 0x0040 /* Modified, but don't write yet. */
+#define IN_SPACECOUNTED 0x0080 /* Blocks to be freed in free count. */
#ifdef _KERNEL
/*
diff --git a/sys/gnu/fs/ext2fs/inode.h b/sys/gnu/fs/ext2fs/inode.h
index 3e7c67da8415..0fdaee2e93e9 100644
--- a/sys/gnu/fs/ext2fs/inode.h
+++ b/sys/gnu/fs/ext2fs/inode.h
@@ -125,10 +125,9 @@ struct inode {
#define IN_UPDATE 0x0004 /* Modification time update request. */
#define IN_MODIFIED 0x0008 /* Inode has been modified. */
#define IN_RENAME 0x0010 /* Inode is being renamed. */
-#define IN_SHLOCK 0x0020 /* File has shared lock. */
-#define IN_EXLOCK 0x0040 /* File has exclusive lock. */
-#define IN_HASHED 0x0080 /* Inode is on hash list */
-#define IN_LAZYMOD 0x0100 /* Modified, but don't write yet. */
+#define IN_HASHED 0x0020 /* Inode is on hash list */
+#define IN_LAZYMOD 0x0040 /* Modified, but don't write yet. */
+#define IN_SPACECOUNTED 0x0080 /* Blocks to be freed in free count. */
#ifdef _KERNEL
/*
diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c
index 7a3c7eed0102..3af19b58e295 100644
--- a/sys/ufs/ffs/ffs_inode.c
+++ b/sys/ufs/ffs/ffs_inode.c
@@ -193,6 +193,8 @@ ffs_truncate(vp, length, flags, cred, p)
if ((error = VOP_FSYNC(ovp, cred, MNT_WAIT,
p)) != 0)
return (error);
+ if (oip->i_flag & IN_SPACECOUNTED)
+ fs->fs_pendingblocks -= oip->i_blocks;
} else {
#ifdef QUOTA
(void) chkdq(oip, -oip->i_blocks, NOCRED, 0);
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 2b88fe6b313e..d9503010889d 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -57,6 +57,7 @@
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/proc.h>
+#include <sys/stat.h>
#include <sys/syslog.h>
#include <sys/vnode.h>
#include <sys/conf.h>
@@ -1725,7 +1726,7 @@ softdep_setup_freeblocks(ip, length)
fs = ip->i_fs;
if (length != 0)
- panic("softde_setup_freeblocks: non-zero length");
+ panic("softdep_setup_freeblocks: non-zero length");
MALLOC(freeblks, struct freeblks *, sizeof(struct freeblks),
M_FREEBLKS, M_SOFTDEP_FLAGS|M_ZERO);
freeblks->fb_list.wk_type = D_FREEBLKS;
@@ -1747,6 +1748,13 @@ softdep_setup_freeblocks(ip, length)
ip->i_blocks = 0;
ip->i_size = 0;
/*
+ * If the file was removed, then the space being freed was
+ * accounted for then (see softdep_filereleased()). If the
+ * file is merely being truncated, then we account for it now.
+ */
+ if ((ip->i_flag & IN_SPACECOUNTED) == 0)
+ fs->fs_pendingblocks += freeblks->fb_chkcnt;
+ /*
* Push the zero'ed inode to to its disk buffer so that we are free
* to delete its dependencies below. Once the dependencies are gone
* the buffer can be safely released.
@@ -1986,6 +1994,8 @@ softdep_freefile(pvp, ino, mode)
freefile->fx_oldinum = ino;
freefile->fx_devvp = ip->i_devvp;
freefile->fx_mnt = ITOV(ip)->v_mount;
+ if ((ip->i_flag & IN_SPACECOUNTED) == 0)
+ ip->i_fs->fs_pendinginodes += 1;
/*
* If the inodedep does not exist, then the zero'ed inode has
@@ -2118,6 +2128,7 @@ handle_workitem_freeblocks(freeblks, flags)
baselbns[level], &blocksreleased)) == 0)
allerror = error;
ffs_blkfree(&tip, bn, fs->fs_bsize);
+ fs->fs_pendingblocks -= nblocks;
blocksreleased += nblocks;
}
/*
@@ -2128,6 +2139,7 @@ handle_workitem_freeblocks(freeblks, flags)
continue;
bsize = blksize(fs, &tip, i);
ffs_blkfree(&tip, bn, bsize);
+ fs->fs_pendingblocks -= btodb(bsize);
blocksreleased += btodb(bsize);
}
/*
@@ -2229,6 +2241,7 @@ indir_trunc(ip, dbn, level, lbn, countp)
allerror = error;
}
ffs_blkfree(ip, nb, fs->fs_bsize);
+ fs->fs_pendingblocks -= nblocks;
*countp += nblocks;
}
bp->b_flags |= B_INVAL | B_NOCACHE;
@@ -2780,6 +2793,47 @@ softdep_change_linkcnt(ip)
}
/*
+ * Called when the effective link count and the reference count
+ * on an inode drops to zero. At this point there are no names
+ * referencing the file in the filesystem and no active file
+ * references. The space associated with the file will be freed
+ * as soon as the necessary soft dependencies are cleared.
+ */
+void
+softdep_releasefile(ip)
+ struct inode *ip; /* inode with the zero effective link count */
+{
+ struct inodedep *inodedep;
+
+ if (ip->i_effnlink > 0)
+ panic("softdep_filerelease: file still referenced");
+ /*
+ * We may be called several times as the real reference count
+ * drops to zero. We only want to account for the space once.
+ */
+ if (ip->i_flag & IN_SPACECOUNTED)
+ return;
+ /*
+ * We have to deactivate a snapshot otherwise copyonwrites may
+ * add blocks and the cleanup may remove blocks after we have
+ * tried to account for them.
+ */
+ if ((ip->i_flags & SF_SNAPSHOT) != 0)
+ ffs_snapremove(ITOV(ip));
+ /*
+ * If we are tracking an nlinkdelta, we have to also remember
+ * whether we accounted for the freed space yet.
+ */
+ ACQUIRE_LOCK(&lk);
+ if ((inodedep_lookup(ip->i_fs, ip->i_number, 0, &inodedep)))
+ inodedep->id_state |= SPACECOUNTED;
+ FREE_LOCK(&lk);
+ ip->i_fs->fs_pendingblocks += ip->i_blocks;
+ ip->i_fs->fs_pendinginodes += 1;
+ ip->i_flag |= IN_SPACECOUNTED;
+}
+
+/*
* This workitem decrements the inode's link count.
* If the link count reaches zero, the file is removed.
*/
@@ -2905,6 +2959,7 @@ handle_workitem_freefile(freefile)
tip.i_devvp = freefile->fx_devvp;
tip.i_dev = freefile->fx_devvp->v_rdev;
tip.i_fs = fs;
+ fs->fs_pendinginodes -= 1;
if ((error = ffs_freefile(&tip, freefile->fx_oldinum, freefile->fx_mode)) != 0)
softdep_error("handle_workitem_freefile", error);
WORKITEM_FREE(freefile, D_FREEFILE);
@@ -3779,6 +3834,8 @@ softdep_load_inodeblock(ip)
return;
}
ip->i_effnlink -= inodedep->id_nlinkdelta;
+ if (inodedep->id_state & SPACECOUNTED)
+ ip->i_flag |= IN_SPACECOUNTED;
FREE_LOCK(&lk);
}
diff --git a/sys/ufs/ffs/ffs_softdep_stub.c b/sys/ufs/ffs/ffs_softdep_stub.c
index 95c947555661..3460b7c64967 100644
--- a/sys/ufs/ffs/ffs_softdep_stub.c
+++ b/sys/ufs/ffs/ffs_softdep_stub.c
@@ -270,6 +270,15 @@ int
softdep_slowdown(vp)
struct vnode *vp;
{
+
panic("softdep_slowdown called");
}
+
+void
+softdep_releasefile(ip)
+ struct inode *ip; /* inode with the zero effective link count */
+{
+
+ panic("softdep_releasefile called");
+}
#endif /* SOFTUPDATES not configured in */
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index b1fb0cfb2b3b..04ba155d4dee 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -192,6 +192,14 @@ ffs_mount(mp, path, data, ndp, p)
vn_finished_write(mp);
return (error);
}
+ if (fs->fs_pendingblocks != 0 ||
+ fs->fs_pendinginodes != 0) {
+ printf("%s: update error: blocks %d files %d\n",
+ fs->fs_fsmnt, fs->fs_pendingblocks,
+ fs->fs_pendinginodes);
+ fs->fs_pendingblocks = 0;
+ fs->fs_pendinginodes = 0;
+ }
fs->fs_ronly = 1;
if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
fs->fs_clean = 1;
@@ -433,6 +441,12 @@ ffs_reload(mp, cred, p)
fs->fs_avgfilesize = AVFILESIZ; /* XXX */
if (fs->fs_avgfpdir <= 0) /* XXX */
fs->fs_avgfpdir = AFPDIR; /* XXX */
+ if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
+ printf("%s: reload pending error: blocks %d files %d\n",
+ fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes);
+ fs->fs_pendingblocks = 0;
+ fs->fs_pendinginodes = 0;
+ }
/*
* Step 3: re-read summary information from disk.
@@ -609,6 +623,18 @@ ffs_mountfs(devvp, mp, p, malloctype)
error = EPERM;
goto out;
}
+ if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
+ printf("%s: lost blocks %d files %d\n", fs->fs_fsmnt,
+ fs->fs_pendingblocks, fs->fs_pendinginodes);
+ fs->fs_pendingblocks = 0;
+ fs->fs_pendinginodes = 0;
+ }
+ }
+ if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
+ printf("%s: mount pending error: blocks %d files %d\n",
+ fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes);
+ fs->fs_pendingblocks = 0;
+ fs->fs_pendinginodes = 0;
}
/* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
@@ -826,6 +852,12 @@ ffs_unmount(mp, mntflags, p)
fs->fs_cgsize = fs->fs_sparecon[0];
fs->fs_sparecon[0] = 0;
}
+ if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
+ printf("%s: unmount pending error: blocks %d files %d\n",
+ fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes);
+ fs->fs_pendingblocks = 0;
+ fs->fs_pendinginodes = 0;
+ }
if (fs->fs_ronly == 0) {
fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1;
error = ffs_sbupdate(ump, MNT_WAIT);
@@ -923,10 +955,11 @@ ffs_statfs(mp, sbp, p)
sbp->f_iosize = fs->fs_bsize;
sbp->f_blocks = fs->fs_dsize;
sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
- fs->fs_cstotal.cs_nffree;
- sbp->f_bavail = freespace(fs, fs->fs_minfree);
+ fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks);
+ sbp->f_bavail = freespace(fs, fs->fs_minfree) +
+ dbtofsb(fs, fs->fs_pendingblocks);
sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
- sbp->f_ffree = fs->fs_cstotal.cs_nifree;
+ sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
if (sbp != &mp->mnt_stat) {
sbp->f_type = mp->mnt_vfc->vfc_typenum;
bcopy((caddr_t)mp->mnt_stat.f_mntonname,
diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h
index b9cab9a826a4..0a3ad9685683 100644
--- a/sys/ufs/ffs/fs.h
+++ b/sys/ufs/ffs/fs.h
@@ -295,7 +295,9 @@ struct fs {
int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
int32_t fs_avgfilesize; /* expected average file size */
int32_t fs_avgfpdir; /* expected # of files per directory */
- int32_t fs_sparecon[28]; /* reserved for future constants */
+ int32_t fs_sparecon[26]; /* reserved for future constants */
+ int32_t fs_pendingblocks; /* blocks in process of being freed */
+ int32_t fs_pendinginodes; /* inodes in process of being freed */
int32_t fs_contigsumsize; /* size of cluster summary array */
int32_t fs_maxsymlinklen; /* max length of an internal symlink */
int32_t fs_inodefmt; /* format of on-disk inodes */
diff --git a/sys/ufs/ffs/softdep.h b/sys/ufs/ffs/softdep.h
index cf9cac8330cd..9a158c5dab19 100644
--- a/sys/ufs/ffs/softdep.h
+++ b/sys/ufs/ffs/softdep.h
@@ -82,8 +82,10 @@
* data structure is frozen from further change until its dependencies
* have been completed and its resources freed after which it will be
* discarded. The IOSTARTED flag prevents multiple calls to the I/O
- * start routine from doing multiple rollbacks. The ONWORKLIST flag
- * shows whether the structure is currently linked onto a worklist.
+ * start routine from doing multiple rollbacks. The SPACECOUNTED flag
+ * says that the files space has been accounted to the pending free
+ * space count. The ONWORKLIST flag shows whether the structure is
+ * currently linked onto a worklist.
*/
#define ATTACHED 0x0001
#define UNDONE 0x0002
@@ -95,6 +97,7 @@
#define DIRCHG 0x0080
#define GOINGAWAY 0x0100
#define IOSTARTED 0x0200
+#define SPACECOUNTED 0x0400
#define ONWORKLIST 0x8000
#define ALLCOMPLETE (ATTACHED | COMPLETE | DEPCOMPLETE)
diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h
index 3e7c67da8415..0fdaee2e93e9 100644
--- a/sys/ufs/ufs/inode.h
+++ b/sys/ufs/ufs/inode.h
@@ -125,10 +125,9 @@ struct inode {
#define IN_UPDATE 0x0004 /* Modification time update request. */
#define IN_MODIFIED 0x0008 /* Inode has been modified. */
#define IN_RENAME 0x0010 /* Inode is being renamed. */
-#define IN_SHLOCK 0x0020 /* File has shared lock. */
-#define IN_EXLOCK 0x0040 /* File has exclusive lock. */
-#define IN_HASHED 0x0080 /* Inode is on hash list */
-#define IN_LAZYMOD 0x0100 /* Modified, but don't write yet. */
+#define IN_HASHED 0x0020 /* Inode is on hash list */
+#define IN_LAZYMOD 0x0040 /* Modified, but don't write yet. */
+#define IN_SPACECOUNTED 0x0080 /* Blocks to be freed in free count. */
#ifdef _KERNEL
/*
diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h
index 2a98e9b6fe07..e08ee8d70c71 100644
--- a/sys/ufs/ufs/ufs_extern.h
+++ b/sys/ufs/ufs/ufs_extern.h
@@ -104,6 +104,7 @@ void softdep_setup_remove __P((struct buf *,struct inode *, struct inode *,
void softdep_setup_directory_change __P((struct buf *, struct inode *,
struct inode *, long, int));
void softdep_change_linkcnt __P((struct inode *));
+void softdep_releasefile __P((struct inode *));
int softdep_slowdown __P((struct vnode *));
#endif /* !_UFS_UFS_EXTERN_H_ */
diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c
index d4ed8b3efaad..4f4638d8bd91 100644
--- a/sys/ufs/ufs/ufs_inode.c
+++ b/sys/ufs/ufs/ufs_inode.c
@@ -77,6 +77,8 @@ ufs_inactive(ap)
*/
if (ip->i_mode == 0)
goto out;
+ if (ip->i_effnlink == 0 && DOINGSOFTDEP(vp))
+ softdep_releasefile(ip);
if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
#ifdef QUOTA