- Move softdep from using a global worklist to per-mount worklists. This
has many positive effects including improved smp locking, reducing interdependencies between mounts that can lead to deadlocks, etc. - Add the softdep worklist and various counters to the ufsmnt structure. - Add a mount pointer to the workitem and remove mount pointers from the various structures derived from the workitem as they are now redundant. - Remove the poor-man's semaphore protecting softdep_process_worklist and softdep_flushworklist. Several threads may now process the list simultaneously. - Add softdep_waitidle() to block the thread until all pending dependencies being operated on by other threads have been flushed. - Use softdep_waitidle() in unmount and snapshots to block either operation until the fs is stable. - Remove softdep worklist processing from the syncer and move it into the softdep_flush() thread. This thread processes all softdep mounts once each second and when it is called via the new softdep_speedup() when there is a resource shortage. This removes the softdep hook from the kernel and various hacks in header files to support it. Reviewed by/Discussed with: tegge, truckman, mckusick Tested by: kris
This commit is contained in:
parent
420239c773
commit
eb2ea10590
@ -270,9 +270,6 @@ static int vnlru_nowhere;
|
||||
SYSCTL_INT(_debug, OID_AUTO, vnlru_nowhere, CTLFLAG_RW,
|
||||
&vnlru_nowhere, 0, "Number of times the vnlru process ran without success");
|
||||
|
||||
/* Hook for calling soft updates. */
|
||||
int (*softdep_process_worklist_hook)(struct mount *);
|
||||
|
||||
/*
|
||||
* Macros to control when a vnode is freed and recycled. All require
|
||||
* the vnode interlock.
|
||||
@ -1675,13 +1672,6 @@ sched_sync(void)
|
||||
if (syncer_state == SYNCER_FINAL_DELAY && syncer_final_iter > 0)
|
||||
syncer_final_iter--;
|
||||
mtx_unlock(&sync_mtx);
|
||||
|
||||
/*
|
||||
* Do soft update processing.
|
||||
*/
|
||||
if (softdep_process_worklist_hook != NULL)
|
||||
(*softdep_process_worklist_hook)(NULL);
|
||||
|
||||
/*
|
||||
* The variable rushjob allows the kernel to speed up the
|
||||
* processing of the filesystem syncer process. A rushjob
|
||||
|
@ -683,10 +683,6 @@ vfs_uninit_t vfs_stduninit;
|
||||
vfs_extattrctl_t vfs_stdextattrctl;
|
||||
vfs_sysctl_t vfs_stdsysctl;
|
||||
|
||||
/* XXX - these should be indirect functions!!! */
|
||||
int softdep_fsync(struct vnode *);
|
||||
int softdep_process_worklist(struct mount *);
|
||||
|
||||
#else /* !_KERNEL */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
@ -555,7 +555,6 @@ struct vattr;
|
||||
struct vnode;
|
||||
|
||||
extern int (*lease_check_hook)(struct vop_lease_args *);
|
||||
extern int (*softdep_process_worklist_hook)(struct mount *);
|
||||
|
||||
/* cache_* may belong in namei.h. */
|
||||
void cache_enter(struct vnode *dvp, struct vnode *vp,
|
||||
|
@ -1348,7 +1348,7 @@ ffs_fragextend(ip, cg, bprev, osize, nsize)
|
||||
ACTIVECLEAR(fs, cg);
|
||||
UFS_UNLOCK(ump);
|
||||
if (DOINGSOFTDEP(ITOV(ip)))
|
||||
softdep_setup_blkmapdep(bp, fs, bprev);
|
||||
softdep_setup_blkmapdep(bp, UFSTOVFS(ump), bprev);
|
||||
bdwrite(bp);
|
||||
return (bprev);
|
||||
|
||||
@ -1454,7 +1454,7 @@ ffs_alloccg(ip, cg, bpref, size)
|
||||
ACTIVECLEAR(fs, cg);
|
||||
UFS_UNLOCK(ump);
|
||||
if (DOINGSOFTDEP(ITOV(ip)))
|
||||
softdep_setup_blkmapdep(bp, fs, blkno);
|
||||
softdep_setup_blkmapdep(bp, UFSTOVFS(ump), blkno);
|
||||
bdwrite(bp);
|
||||
return (blkno);
|
||||
|
||||
@ -1523,7 +1523,7 @@ gotit:
|
||||
/* XXX Fixme. */
|
||||
UFS_UNLOCK(ump);
|
||||
if (DOINGSOFTDEP(ITOV(ip)))
|
||||
softdep_setup_blkmapdep(bp, fs, blkno);
|
||||
softdep_setup_blkmapdep(bp, UFSTOVFS(ump), blkno);
|
||||
UFS_LOCK(ump);
|
||||
return (blkno);
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ void softdep_freefile(struct vnode *, ino_t, int);
|
||||
int softdep_request_cleanup(struct fs *, struct vnode *);
|
||||
void softdep_setup_freeblocks(struct inode *, off_t, int);
|
||||
void softdep_setup_inomapdep(struct buf *, struct inode *, ino_t);
|
||||
void softdep_setup_blkmapdep(struct buf *, struct fs *, ufs2_daddr_t);
|
||||
void softdep_setup_blkmapdep(struct buf *, struct mount *, ufs2_daddr_t);
|
||||
void softdep_setup_allocdirect(struct inode *, ufs_lbn_t, ufs2_daddr_t,
|
||||
ufs2_daddr_t, long, long, struct buf *);
|
||||
void softdep_setup_allocext(struct inode *, ufs_lbn_t, ufs2_daddr_t,
|
||||
@ -118,9 +118,8 @@ void softdep_setup_allocindir_page(struct inode *, ufs_lbn_t,
|
||||
struct buf *, int, ufs2_daddr_t, ufs2_daddr_t, struct buf *);
|
||||
void softdep_fsync_mountdev(struct vnode *);
|
||||
int softdep_sync_metadata(struct vnode *);
|
||||
/* XXX incorrectly moved to mount.h - should be indirect function */
|
||||
#if 0
|
||||
int softdep_fsync(struct vnode *vp);
|
||||
#endif
|
||||
int softdep_process_worklist(struct mount *, int);
|
||||
int softdep_fsync(struct vnode *);
|
||||
int softdep_waitidle(struct mount *);
|
||||
|
||||
#endif /* !_UFS_FFS_EXTERN_H */
|
||||
|
@ -401,7 +401,14 @@ restart:
|
||||
break;
|
||||
vn_start_write(NULL, &wrtmp, V_WAIT);
|
||||
}
|
||||
/*
|
||||
* Wait for all dependency processing to finish after the sync
|
||||
* triggered by vfs_write_suspend().
|
||||
*/
|
||||
error = softdep_waitidle(vp->v_mount);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
if (error)
|
||||
goto out1;
|
||||
if (collectsnapstats)
|
||||
nanotime(&starttime);
|
||||
/*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -135,6 +135,7 @@
|
||||
* and the macros below changed to use it.
|
||||
*/
|
||||
struct worklist {
|
||||
struct mount *wk_mp; /* Mount we live in */
|
||||
LIST_ENTRY(worklist) wk_list; /* list of work requests */
|
||||
unsigned short wk_type; /* type of request */
|
||||
unsigned short wk_state; /* state flags */
|
||||
@ -142,7 +143,6 @@ struct worklist {
|
||||
#define WK_DATA(wk) ((void *)(wk))
|
||||
#define WK_PAGEDEP(wk) ((struct pagedep *)(wk))
|
||||
#define WK_INODEDEP(wk) ((struct inodedep *)(wk))
|
||||
#define WK_NEWBLK(wk) ((struct newblk *)(wk))
|
||||
#define WK_BMSAFEMAP(wk) ((struct bmsafemap *)(wk))
|
||||
#define WK_ALLOCDIRECT(wk) ((struct allocdirect *)(wk))
|
||||
#define WK_INDIRDEP(wk) ((struct indirdep *)(wk))
|
||||
@ -190,7 +190,6 @@ struct pagedep {
|
||||
struct worklist pd_list; /* page buffer */
|
||||
# define pd_state pd_list.wk_state /* check for multiple I/O starts */
|
||||
LIST_ENTRY(pagedep) pd_hash; /* hashed lookup */
|
||||
struct mount *pd_mnt; /* associated mount point */
|
||||
ino_t pd_ino; /* associated file */
|
||||
ufs_lbn_t pd_lbn; /* block within file */
|
||||
struct dirremhd pd_dirremhd; /* dirrem's waiting for page */
|
||||
@ -415,7 +414,6 @@ struct allocindir {
|
||||
struct freefrag {
|
||||
struct worklist ff_list; /* id_inowait or delayed worklist */
|
||||
# define ff_state ff_list.wk_state /* owning user; should be uid_t */
|
||||
struct mount *ff_mnt; /* associated mount point */
|
||||
ufs2_daddr_t ff_blkno; /* fragment physical block number */
|
||||
long ff_fragsize; /* size of fragment being deleted */
|
||||
ino_t ff_inum; /* owning inode number */
|
||||
@ -433,7 +431,6 @@ struct freeblks {
|
||||
ino_t fb_previousinum; /* inode of previous owner of blocks */
|
||||
uid_t fb_uid; /* uid of previous owner of blocks */
|
||||
struct vnode *fb_devvp; /* filesystem device vnode */
|
||||
struct mount *fb_mnt; /* associated mount point */
|
||||
long fb_oldextsize; /* previous ext data size */
|
||||
off_t fb_oldsize; /* previous file size */
|
||||
ufs2_daddr_t fb_chkcnt; /* used to check cnt of blks released */
|
||||
@ -453,7 +450,6 @@ struct freefile {
|
||||
mode_t fx_mode; /* mode of inode */
|
||||
ino_t fx_oldinum; /* inum of the unlinked file */
|
||||
struct vnode *fx_devvp; /* filesystem device vnode */
|
||||
struct mount *fx_mnt; /* associated mount point */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -555,7 +551,6 @@ struct dirrem {
|
||||
struct worklist dm_list; /* delayed worklist */
|
||||
# define dm_state dm_list.wk_state /* state of the old directory entry */
|
||||
LIST_ENTRY(dirrem) dm_next; /* pagedep's list of dirrem's */
|
||||
struct mount *dm_mnt; /* associated mount point */
|
||||
ino_t dm_oldinum; /* inum of the removed dir entry */
|
||||
union {
|
||||
struct pagedep *dmu_pagedep; /* pagedep dependency for remove */
|
||||
|
@ -33,6 +33,8 @@
|
||||
#ifndef _UFS_UFS_UFSMOUNT_H_
|
||||
#define _UFS_UFS_UFSMOUNT_H_
|
||||
|
||||
#include <sys/buf.h> /* XXX For struct workhead. */
|
||||
|
||||
/*
|
||||
* Arguments to mount UFS-based filesystems
|
||||
*/
|
||||
@ -71,6 +73,11 @@ struct ufsmount {
|
||||
u_long um_seqinc; /* inc between seq blocks */
|
||||
struct mtx um_lock; /* Protects ufsmount & fs */
|
||||
long um_numindirdeps; /* outstanding indirdeps */
|
||||
struct workhead softdep_workitem_pending; /* softdep work queue */
|
||||
struct worklist *softdep_worklist_tail; /* Tail pointer for above */
|
||||
int softdep_on_worklist; /* Items on the worklist */
|
||||
int softdep_deps; /* Total dependency count */
|
||||
int softdep_req; /* Wakeup when deps hits 0. */
|
||||
struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */
|
||||
struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */
|
||||
time_t um_btime[MAXQUOTAS]; /* block quota time limit */
|
||||
@ -112,6 +119,7 @@ struct ufsmount {
|
||||
|
||||
/* Convert mount ptr to ufsmount ptr. */
|
||||
#define VFSTOUFS(mp) ((struct ufsmount *)((mp)->mnt_data))
|
||||
#define UFSTOVFS(ump) (ump)->um_mountp
|
||||
|
||||
/*
|
||||
* Macros to access filesystem parameters in the ufsmount structure.
|
||||
|
Loading…
x
Reference in New Issue
Block a user