aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Elischer <julian@FreeBSD.org>1998-05-19 21:05:09 +0000
committerJulian Elischer <julian@FreeBSD.org>1998-05-19 21:05:09 +0000
commit9d346aefad3080fd4c4d7c5784d7fae403a9e5e8 (patch)
tree6f20569b21818530ffc7db1a2c8ca578a57a49b3
parent8e95b94dec7d6dfc60ba1a344bf1e41bb75db5b1 (diff)
downloadsrc-vendor/softdep/Feb11-98-ALPHA.tar.gz
src-vendor/softdep/Feb11-98-ALPHA.zip
Import changes from kirk which will appear in the Feb 13 snapshot.vendor/softdep/Feb11-98-ALPHA
-rw-r--r--sys/ufs/ffs/ffs_softdep.c36
-rw-r--r--sys/ufs/ffs/softdep.h50
2 files changed, 57 insertions, 29 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 44d29454d156..70c4cfe45799 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -52,8 +52,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- *
- * from: @(#)ffs_softdep.c 9.14 (McKusick) 1/15/98
+ * @(#)ffs_softdep.c 9.17 (McKusick) 2/11/98
*/
/*
@@ -691,6 +690,7 @@ top:
inodedep->id_buf = NULL;
LIST_INIT(&inodedep->id_pendinghd);
LIST_INIT(&inodedep->id_inowait);
+ LIST_INIT(&inodedep->id_bufwait);
TAILQ_INIT(&inodedep->id_inoupdt);
TAILQ_INIT(&inodedep->id_newinoupdt);
ACQUIRE_LOCK(&lk);
@@ -1457,7 +1457,7 @@ softdep_setup_freeblocks(ip, length)
* Add the freeblks structure to the list of operations that
* must await the zero'ed inode being written to disk.
*/
- WORKLIST_INSERT(&inodedep->id_inowait, &freeblks->fb_list);
+ WORKLIST_INSERT(&inodedep->id_bufwait, &freeblks->fb_list);
/*
* Because the file length has been truncated to zero, any
* pending block allocation dependency structures associated
@@ -1713,6 +1713,7 @@ free_inodedep(inodedep)
if ((inodedep->id_state & ONWORKLIST) != 0 ||
(inodedep->id_state & ALLCOMPLETE) != ALLCOMPLETE ||
LIST_FIRST(&inodedep->id_pendinghd) != NULL ||
+ LIST_FIRST(&inodedep->id_bufwait) != NULL ||
LIST_FIRST(&inodedep->id_inowait) != NULL ||
TAILQ_FIRST(&inodedep->id_inoupdt) != NULL ||
TAILQ_FIRST(&inodedep->id_newinoupdt) != NULL ||
@@ -2322,12 +2323,8 @@ handle_workitem_remove(dirrem)
*/
if ((dirrem->dm_state & RMDIR) == 0) {
ip->i_nlink--;
- if (ip->i_nlink < ip->i_effnlink) {
-#ifdef DIAGNOSTIC
- vprint("handle_workitem_remove: bad file delta", vp);
-#endif
- ip->i_effnlink = ip->i_nlink;
- }
+ if (ip->i_nlink < ip->i_effnlink)
+ panic("handle_workitem_remove: bad file delta");
ip->i_flag |= IN_CHANGE;
vput(vp);
WORKITEM_FREE(dirrem, M_DIRREM);
@@ -2982,7 +2979,7 @@ handle_written_inodeblock(inodedep, bp)
* before the old ones have been deleted.
*/
filefree = NULL;
- while ((wk = LIST_FIRST(&inodedep->id_inowait)) != NULL) {
+ while ((wk = LIST_FIRST(&inodedep->id_bufwait)) != NULL) {
WORKLIST_REMOVE(wk);
switch (wk->wk_type) {
@@ -3029,8 +3026,12 @@ handle_written_inodeblock(inodedep, bp)
/* NOTREACHED */
}
}
- if (filefree != NULL)
+ if (filefree != NULL) {
+ if (free_inodedep(inodedep) == 0)
+ panic("handle_written_inodeblock: live inodedep");
add_to_worklist(filefree);
+ return (0);
+ }
/*
* If no outstanding dependencies, free it.
@@ -3189,6 +3190,7 @@ softdep_load_inodeblock(ip)
}
if (inodedep->id_nlinkdelta != 0) {
ip->i_effnlink -= inodedep->id_nlinkdelta;
+ ip->i_flag |= IN_MODIFIED;
inodedep->id_nlinkdelta = 0;
(void) free_inodedep(inodedep);
}
@@ -3212,6 +3214,7 @@ softdep_update_inodeblock(ip, bp, waitfor)
int waitfor; /* 1 => update must be allowed */
{
struct inodedep *inodedep;
+ struct worklist *wk;
int error, gotit;
/*
@@ -3258,6 +3261,16 @@ softdep_update_inodeblock(ip, bp, waitfor)
if (TAILQ_FIRST(&inodedep->id_inoupdt) != NULL)
handle_allocdirect_partdone(TAILQ_FIRST(&inodedep->id_inoupdt));
/*
+ * Now that the inode has been pushed into the buffer, the
+ * operations dependent on the inode being written to disk
+ * can be moved to the id_bufwait so that they will be
+ * processed when the buffer I/O completes.
+ */
+ while ((wk = LIST_FIRST(&inodedep->id_inowait)) != NULL) {
+ WORKLIST_REMOVE(wk);
+ WORKLIST_INSERT(&inodedep->id_bufwait, wk);
+ }
+ /*
* Newly allocated inodes cannot be written until the bitmap
* that allocates them have been written (indicated by
* DEPCOMPLETE being set in id_state). If we are doing a
@@ -3338,6 +3351,7 @@ softdep_fsync(vp)
if (inodedep_lookup(fs, ip->i_number, 0, &inodedep) == 0)
break;
if (LIST_FIRST(&inodedep->id_inowait) != NULL ||
+ LIST_FIRST(&inodedep->id_bufwait) != NULL ||
TAILQ_FIRST(&inodedep->id_inoupdt) != NULL ||
TAILQ_FIRST(&inodedep->id_newinoupdt) != NULL)
panic("softdep_fsync: pending ops");
diff --git a/sys/ufs/ffs/softdep.h b/sys/ufs/ffs/softdep.h
index 16c8aea068ff..3435f6304173 100644
--- a/sys/ufs/ffs/softdep.h
+++ b/sys/ufs/ffs/softdep.h
@@ -52,8 +52,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- *
- * from: @(#)softdep.h 9.4 (McKusick) 1/15/98
+ * @(#)softdep.h 9.5 (McKusick) 2/11/98
*/
#include <sys/queue.h>
@@ -202,31 +201,45 @@ struct pagedep {
/*
* The "inodedep" structure tracks the set of dependencies associated
- * with an inode. Each block that is allocated is represented by an
+ * with an inode. One task that it must manage is delayed operations
+ * (i.e., work requests that must be held until the inodedep's associated
+ * inode has been written to disk). Getting an inode from its incore
+ * state to the disk requires two steps to be taken by the filesystem
+ * in this order: first the inode must be copied to its disk buffer by
+ * the VOP_UPDATE operation; second the inode's buffer must be written
+ * to disk. To ensure that both operations have happened in the required
+ * order, the inodedep maintains two lists. Delayed operations are
+ * placed on the id_inowait list. When the VOP_UPDATE is done, all
+ * operations on the id_inowait list are moved to the id_bufwait list.
+ * When the buffer is written, the items on the id_bufwait list can be
+ * safely moved to the work queue to be processed. A second task of the
+ * inodedep structure is to track the status of block allocation within
+ * the inode. Each block that is allocated is represented by an
* "allocdirect" structure (see below). It is linked onto the id_newinoupdt
* list until both its contents and its allocation in the cylinder
- * group map have been written to disk. Once the dependencies have been
+ * group map have been written to disk. Once these dependencies have been
* satisfied, it is removed from the id_newinoupdt list and any followup
* actions such as releasing the previous block or fragment are placed
- * on the id_inowait list. When an inode is updated (copied from the
- * in-core inode structure to a disk buffer containing its on-disk
- * copy), the "inodedep" structure is linked onto the buffer through
- * its worklist. Thus it will be notified when the buffer is about
+ * on the id_inowait list. When an inode is updated (a VOP_UPDATE is
+ * done), the "inodedep" structure is linked onto the buffer through
+ * its worklist. Thus, it will be notified when the buffer is about
* to be written and when it is done. At the update time, all the
* elements on the id_newinoupdt list are moved to the id_inoupdt list
* since those changes are now relevant to the copy of the inode in the
- * buffer. When the buffer containing the inode is written to disk, any
- * updates listed on the id_inoupdt list are rolled back as they are
- * not yet safe. Following the write, the changes are once again rolled
- * forward and any actions on the id_inowait list are processed (since
- * the previously allocated blocks are no longer claimed on the disk).
+ * buffer. Also at update time, the tasks on the id_inowait list are
+ * moved to the id_bufwait list so that they will be executed when
+ * the updated inode has been written to disk. When the buffer containing
+ * the inode is written to disk, any updates listed on the id_inoupdt
+ * list are rolled back as they are not yet safe. Following the write,
+ * the changes are once again rolled forward and any actions on the
+ * id_bufwait list are processed (since those actions are now safe).
* The entries on the id_inoupdt and id_newinoupdt lists must be kept
* sorted by logical block number to speed the calculation of the size
* of the rolled back inode (see explanation in initiate_write_inodeblock).
* When a directory entry is created, it is represented by a diradd.
- * The diradd is added to the id_inowait list and is not permitted to be
- * written to disk until the inode that it represents is written. After
- * the inode is written, the id_inowait list is processed and the diradd
+ * The diradd is added to the id_inowait list as it cannot be safely
+ * written to disk until the inode that it represents is on disk. After
+ * the inode is written, the id_bufwait list is processed and the diradd
* entries are moved to the id_pendinghd list where they remain until
* the directory block containing the name has been written to disk.
* The purpose of keeping the entries on the id_pendinghd list is so that
@@ -245,7 +258,8 @@ struct inodedep {
struct buf *id_buf; /* related bmsafemap (if pending) */
off_t id_savedsize; /* file size saved during rollback */
struct workhead id_pendinghd; /* entries awaiting directory write */
- struct workhead id_inowait; /* operations after inode written */
+ struct workhead id_bufwait; /* operations after inode written */
+ struct workhead id_inowait; /* operations waiting inode update */
struct allocdirectlst id_inoupdt; /* updates before inode written */
struct allocdirectlst id_newinoupdt; /* updates when inode written */
};
@@ -461,7 +475,7 @@ struct freefile {
* if appropriate and is never cleared.
*/
struct diradd {
- struct worklist da_list; /* id_inowait and id_pendinghd list */
+ struct worklist da_list; /* id_inowait or id_pendinghd list */
# define da_state da_list.wk_state /* state of the new directory entry */
LIST_ENTRY(diradd) da_pdlist; /* pagedep holding directory block */
doff_t da_offset; /* offset of new dir entry in dir blk */