From 42f834c3df4fbd9ca503942555d26ecf9d28e8f7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 14 Jan 2003 00:20:18 -0800 Subject: [PATCH] ext3 ino_t removal Patch from Andreas Dilger This patch against 2.5.53 removes my erronous use of ino_t in a couple of places in the ext3 code. This has been replaced with unsigned long (the same as is used for inode->i_ino). This patch matches the fix submitted to 2.4 for fixing 64-bit compiler warnings, and also replaces a couple of %ld with %lu to forestall output wierdness with filesystems with a few billion inodes. --- include/linux/ext3_fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index f909a967778e..0612ce8e8274 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -707,7 +707,7 @@ extern int ext3fs_dirhash(const char *name, int len, struct /* ialloc.c */ extern struct inode * ext3_new_inode (handle_t *, struct inode *, int); extern void ext3_free_inode (handle_t *, struct inode *); -extern struct inode * ext3_orphan_get (struct super_block *, ino_t); +extern struct inode * ext3_orphan_get (struct super_block *, unsigned long); extern unsigned long ext3_count_free_inodes (struct super_block *); extern unsigned long ext3_count_dirs (struct super_block *); extern void ext3_check_inodes_bitmap (struct super_block *); -- cgit v1.2.3 From daebe5ee58fa9985c257a1ce5df29fcb258f06d3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 14 Jan 2003 00:20:32 -0800 Subject: [PATCH] factor free memory into max_sane_readahead() max_sane_readahead() permits the user to readahead up to half-the-inactive-list's worth of pages. Which is totally wrong if most of memory is free. So make the limit be (nr_inactive + nr_free) / 2 --- fs/proc/proc_misc.c | 3 ++- include/linux/mmzone.h | 3 ++- mm/page_alloc.c | 8 ++++++-- mm/readahead.c | 5 +++-- 4 files changed, 13 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index fff23ee7ca2b..ba036340fcd1 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -140,9 +140,10 @@ static int meminfo_read_proc(char *page, char **start, off_t off, struct page_state ps; unsigned long inactive; unsigned long active; + unsigned long free; get_page_state(&ps); - get_zone_counts(&active, &inactive); + get_zone_counts(&active, &inactive, &free); /* * display in kilobytes. diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 14ce2049de71..bcb57ed21a8d 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -193,7 +193,8 @@ typedef struct pglist_data { extern int numnodes; extern struct pglist_data *pgdat_list; -void get_zone_counts(unsigned long *active, unsigned long *inactive); +void get_zone_counts(unsigned long *active, unsigned long *inactive, + unsigned long *free); void build_all_zonelists(void); void wakeup_kswapd(struct zone *zone); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 1c8015736d61..3969ad493b35 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -776,15 +776,18 @@ void get_full_page_state(struct page_state *ret) __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long)); } -void get_zone_counts(unsigned long *active, unsigned long *inactive) +void get_zone_counts(unsigned long *active, + unsigned long *inactive, unsigned long *free) { struct zone *zone; *active = 0; *inactive = 0; + *free = 0; for_each_zone(zone) { *active += zone->nr_active; *inactive += zone->nr_inactive; + *free += zone->free_pages; } } @@ -838,6 +841,7 @@ void show_free_areas(void) int cpu, temperature; unsigned long active; unsigned long inactive; + unsigned long free; struct zone *zone; for_each_zone(zone) { @@ -863,7 +867,7 @@ void show_free_areas(void) } get_page_state(&ps); - get_zone_counts(&active, &inactive); + get_zone_counts(&active, &inactive, &free); printk("\nFree pages: %11ukB (%ukB HighMem)\n", K(nr_free_pages()), diff --git a/mm/readahead.c b/mm/readahead.c index 00de3dcc2829..bd28c3b4f1ca 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -477,7 +477,8 @@ unsigned long max_sane_readahead(unsigned long nr) { unsigned long active; unsigned long inactive; + unsigned long free; - get_zone_counts(&active, &inactive); - return min(nr, inactive / 2); + get_zone_counts(&active, &inactive, &free); + return min(nr, (inactive + free) / 2); } -- cgit v1.2.3 From 2a6cb303d76059edf35254438375acd95862dc4c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 14 Jan 2003 00:20:46 -0800 Subject: [PATCH] fix ext3 memory leak This is the leak which Con found. Long story... - If a dirty page is fed into ext3_writepage() during truncate, block_write_full_page() will reutrn -EIO (it's outside i_size) and will leave the buffers dirty. In the expectation that discard_buffer() will clean them. - ext3_writepage() then adds the still-dirty buffers to the journal's "async data list". These are buffers which are known to have had IO started. All we need to do is to wait on them in commit. - meanwhile, truncate will chop the pages off the address_space. But truncate cannot invalidate the buffers (in journal_unmap_buffer()) because the buffers are attached to the committing transaction. (hm. This behaviour in journal_unmap_buffer() is bogus. We just never need to write these buffers.) - ext3 commit will "wait on writeout" of these writepage buffers (even though it was never started) and will then release them from the journalling system. So we end up with pages which are attached to no mapping, which are clean and which have dirty buffers. These are unreclaimable. Aside: ext3-ordered has two buffer lists: the "sync data list" and the "async data list". The sync list consists of probably-dirty buffers which were dirtied in commit_write(). Transaction commit must write all thee out and wait on them. The async list supposedly consists of clean buffers which were attached to the journal in ->writepage. These have had IO started (by writepage) so commit merely needs to wait on them. This is all designed for the 2.4 VM really. In 2.5, tons of writeback goes via writepage (instead of the buffer lru) and these buffers end up madly hpooing between the async and sync lists. Plus it's arguably incorrect to just wait on the writes in commit - if the buffers were set dirty again (say, by zap_pte_range()) then perhaps we should write them again before committing. So what the patch does is to remove the async list. All ordered-data buffers are now attached to the single "sync data list". So when we come to commit, those buffers which are dirty will have IO started and all buffers are waited upon. This means that the dirty buffers against a clean page which came about from block_write_full_page()'s -EIO will be written to disk in commit - this cleans them, and the page is now reclaimable. No leak. It seems bogus to write these buffers in commit, and indeed it is. But ext3 will not allow those blocks to be reused until the commit has ended so there is no corruption risk. And the amount of data involved is low - it only comes about as a race between truncate and writepage(). --- fs/ext3/inode.c | 36 +++++++++++++++++++----------------- fs/jbd/checkpoint.c | 1 - fs/jbd/commit.c | 33 --------------------------------- fs/jbd/transaction.c | 38 +++++++++----------------------------- include/linux/ext3_jbd.h | 12 ------------ include/linux/jbd.h | 28 +++++++++------------------- 6 files changed, 37 insertions(+), 111 deletions(-) (limited to 'include/linux') diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index a5e85ef29d2c..ccdb52c9cc77 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1098,20 +1098,14 @@ out: return ret; } -static int journal_dirty_sync_data(handle_t *handle, struct buffer_head *bh) -{ - return ext3_journal_dirty_data(handle, bh, 0); -} - -/* - * For ext3_writepage(). We also brelse() the buffer to account for - * the bget() which ext3_writepage() performs. - */ -static int journal_dirty_async_data(handle_t *handle, struct buffer_head *bh) +static int +ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) { - int ret = ext3_journal_dirty_data(handle, bh, 1); - __brelse(bh); - return ret; + int err = journal_dirty_data(handle, bh); + if (err) + ext3_journal_abort_handle(__FUNCTION__, __FUNCTION__, + bh, handle,err); + return err; } /* For commit_write() in data=journal mode */ @@ -1154,7 +1148,7 @@ static int ext3_commit_write(struct file *file, struct page *page, } else { if (ext3_should_order_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), - from, to, NULL, journal_dirty_sync_data); + from, to, NULL, ext3_journal_dirty_data); } /* Be careful here if generic_commit_write becomes a * required invocation after block_prepare_write. */ @@ -1228,7 +1222,13 @@ static sector_t ext3_bmap(struct address_space *mapping, sector_t block) static int bget_one(handle_t *handle, struct buffer_head *bh) { - atomic_inc(&bh->b_count); + get_bh(bh); + return 0; +} + +static int bput_one(handle_t *handle, struct buffer_head *bh) +{ + put_bh(bh); return 0; } @@ -1348,7 +1348,9 @@ static int ext3_writepage(struct page *page, struct writeback_control *wbc) /* And attach them to the current transaction */ if (order_data) { err = walk_page_buffers(handle, page_bufs, - 0, PAGE_CACHE_SIZE, NULL, journal_dirty_async_data); + 0, PAGE_CACHE_SIZE, NULL, ext3_journal_dirty_data); + walk_page_buffers(handle, page_bufs, 0, + PAGE_CACHE_SIZE, NULL, bput_one); if (!ret) ret = err; } @@ -1587,7 +1589,7 @@ static int ext3_block_truncate_page(handle_t *handle, err = ext3_journal_dirty_metadata(handle, bh); } else { if (ext3_should_order_data(inode)) - err = ext3_journal_dirty_data(handle, bh, 0); + err = ext3_journal_dirty_data(handle, bh); mark_buffer_dirty(bh); } diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index d640e23a1bf1..79b606822382 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -585,7 +585,6 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) J_ASSERT (transaction->t_ilist == NULL); J_ASSERT (transaction->t_buffers == NULL); J_ASSERT (transaction->t_sync_datalist == NULL); - J_ASSERT (transaction->t_async_datalist == NULL); J_ASSERT (transaction->t_forget == NULL); J_ASSERT (transaction->t_iobuf_list == NULL); J_ASSERT (transaction->t_shadow_list == NULL); diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index f61bce34d072..12d4a744f07f 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -264,37 +264,6 @@ write_out_data_locked: goto write_out_data_locked; sync_datalist_empty: - /* - * Wait for all the async writepage data. As they become unlocked - * in end_buffer_async_write(), the only place where they can be - * reaped is in try_to_free_buffers(), and we're locked against - * that. - */ - while ((jh = commit_transaction->t_async_datalist)) { - struct buffer_head *bh = jh2bh(jh); - if (buffer_locked(bh)) { - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); - wait_on_buffer(bh); - lock_journal(journal); - spin_lock(&journal_datalist_lock); - continue; /* List may have changed */ - } - if (jh->b_next_transaction) { - /* - * For writepage() buffers in journalled data mode: a - * later transaction may want the buffer for "metadata" - */ - __journal_refile_buffer(jh); - } else { - BUFFER_TRACE(bh, "finished async writeout: unfile"); - __journal_unfile_buffer(jh); - jh->b_transaction = NULL; - __journal_remove_journal_head(bh); - BUFFER_TRACE(bh, "finished async writeout: refile"); - __brelse(bh); - } - } spin_unlock(&journal_datalist_lock); /* @@ -304,7 +273,6 @@ sync_datalist_empty: * clean by now, so check that it is in fact empty. */ J_ASSERT (commit_transaction->t_sync_datalist == NULL); - J_ASSERT (commit_transaction->t_async_datalist == NULL); jbd_debug (3, "JBD: commit phase 3\n"); @@ -629,7 +597,6 @@ skip_commit: /* The journal should be unlocked by now. */ jbd_debug(3, "JBD: commit phase 7\n"); J_ASSERT(commit_transaction->t_sync_datalist == NULL); - J_ASSERT(commit_transaction->t_async_datalist == NULL); J_ASSERT(commit_transaction->t_buffers == NULL); J_ASSERT(commit_transaction->t_checkpoint_list == NULL); J_ASSERT(commit_transaction->t_iobuf_list == NULL); diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index f7e4c3a0c627..e62a542396a6 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -578,9 +578,6 @@ static void jbd_unexpected_dirty_buffer(struct journal_head *jh) * part of the transaction, that is). * * Returns an error code or 0 on success. - * - * In full data journalling mode the buffer may be of type BJ_AsyncData, - * because we're write()ing a buffer which is also part of a shared mapping. */ static int @@ -949,26 +946,16 @@ out: * The buffer is placed on the transaction's data list and is marked as * belonging to the transaction. * - * If `async' is set then the writebabk will be initiated by the caller - * using submit_bh -> end_buffer_async_write. We put the buffer onto - * t_async_datalist. - * * Returns error number or 0 on success. * * journal_dirty_data() can be called via page_launder->ext3_writepage * by kswapd. So it cannot block. Happily, there's nothing here * which needs lock_journal if `async' is set. - * - * When the buffer is on the current transaction we freely move it - * between BJ_AsyncData and BJ_SyncData according to who tried to - * change its state last. */ - -int journal_dirty_data (handle_t *handle, struct buffer_head *bh, int async) +int journal_dirty_data (handle_t *handle, struct buffer_head *bh) { journal_t *journal = handle->h_transaction->t_journal; int need_brelse = 0; - int wanted_jlist = async ? BJ_AsyncData : BJ_SyncData; struct journal_head *jh; if (is_handle_aborted(handle)) @@ -1046,8 +1033,7 @@ int journal_dirty_data (handle_t *handle, struct buffer_head *bh, int async) * the write() data. */ if (jh->b_jlist != BJ_None && - jh->b_jlist != BJ_SyncData && - jh->b_jlist != BJ_AsyncData) { + jh->b_jlist != BJ_SyncData) { JBUFFER_TRACE(jh, "Not stealing"); goto no_journal; } @@ -1058,7 +1044,7 @@ int journal_dirty_data (handle_t *handle, struct buffer_head *bh, int async) * again because that can cause the write-out loop in * commit to never terminate. */ - if (!async && buffer_dirty(bh)) { + if (buffer_dirty(bh)) { atomic_inc(&bh->b_count); spin_unlock(&journal_datalist_lock); need_brelse = 1; @@ -1084,18 +1070,18 @@ int journal_dirty_data (handle_t *handle, struct buffer_head *bh, int async) * committing transaction, so might still be left on that * transaction's metadata lists. */ - if (jh->b_jlist != wanted_jlist) { + if (jh->b_jlist != BJ_SyncData) { JBUFFER_TRACE(jh, "not on correct data list: unfile"); J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow); __journal_unfile_buffer(jh); jh->b_transaction = NULL; JBUFFER_TRACE(jh, "file as data"); __journal_file_buffer(jh, handle->h_transaction, - wanted_jlist); + BJ_SyncData); } } else { JBUFFER_TRACE(jh, "not on a transaction"); - __journal_file_buffer(jh, handle->h_transaction, wanted_jlist); + __journal_file_buffer(jh, handle->h_transaction, BJ_SyncData); } no_journal: spin_unlock(&journal_datalist_lock); @@ -1559,12 +1545,12 @@ __blist_del_buffer(struct journal_head **list, struct journal_head *jh) * Remove a buffer from the appropriate transaction list. * * Note that this function can *change* the value of - * bh->b_transaction->t_sync_datalist, t_async_datalist, t_buffers, t_forget, + * bh->b_transaction->t_sync_datalist, t_buffers, t_forget, * t_iobuf_list, t_shadow_list, t_log_list or t_reserved_list. If the caller * is holding onto a copy of one of thee pointers, it could go bad. * Generally the caller needs to re-read the pointer from the transaction_t. * - * If bh->b_jlist is BJ_SyncData or BJ_AsyncData then we may have been called + * If bh->b_jlist is BJ_SyncData then we may have been called * via journal_try_to_free_buffer() or journal_clean_data_list(). In that * case, journal_datalist_lock will be held, and the journal may not be locked. */ @@ -1590,9 +1576,6 @@ void __journal_unfile_buffer(struct journal_head *jh) case BJ_SyncData: list = &transaction->t_sync_datalist; break; - case BJ_AsyncData: - list = &transaction->t_async_datalist; - break; case BJ_Metadata: transaction->t_nr_buffers--; J_ASSERT_JH(jh, transaction->t_nr_buffers >= 0); @@ -1658,7 +1641,7 @@ static inline int __journal_try_to_free_buffer(struct buffer_head *bh) goto out; if (jh->b_transaction != 0 && jh->b_cp_transaction == 0) { - if (jh->b_jlist == BJ_SyncData || jh->b_jlist==BJ_AsyncData) { + if (jh->b_jlist == BJ_SyncData) { /* A written-back ordered data buffer */ JBUFFER_TRACE(jh, "release data"); __journal_unfile_buffer(jh); @@ -1994,9 +1977,6 @@ void __journal_file_buffer(struct journal_head *jh, case BJ_SyncData: list = &transaction->t_sync_datalist; break; - case BJ_AsyncData: - list = &transaction->t_async_datalist; - break; case BJ_Metadata: transaction->t_nr_buffers++; list = &transaction->t_buffers; diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h index 1985ecee6a3f..13508f6053b9 100644 --- a/include/linux/ext3_jbd.h +++ b/include/linux/ext3_jbd.h @@ -132,16 +132,6 @@ __ext3_journal_get_write_access(const char *where, return err; } -static inline int -__ext3_journal_dirty_data(const char *where, - handle_t *handle, struct buffer_head *bh, int async) -{ - int err = journal_dirty_data(handle, bh, async); - if (err) - ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); - return err; -} - static inline void ext3_journal_forget(handle_t *handle, struct buffer_head *bh) { @@ -183,8 +173,6 @@ __ext3_journal_dirty_metadata(const char *where, __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh)) #define ext3_journal_get_write_access(handle, bh) \ __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh)) -#define ext3_journal_dirty_data(handle, bh, async) \ - __ext3_journal_dirty_data(__FUNCTION__, (handle), (bh), (async)) #define ext3_journal_revoke(handle, blocknr, bh) \ __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh)) #define ext3_journal_get_create_access(handle, bh) \ diff --git a/include/linux/jbd.h b/include/linux/jbd.h index f3e44482a298..47a20ce63fa8 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -360,13 +360,6 @@ struct transaction_s */ struct journal_head * t_sync_datalist; - /* - * Doubly-linked circular list of all writepage data buffers - * still to be written before this transaction can be committed. - * Protected by journal_datalist_lock. - */ - struct journal_head * t_async_datalist; - /* Doubly-linked circular list of all forget buffers (superseded buffers which we can un-checkpoint once this transaction commits) */ @@ -654,8 +647,7 @@ extern int journal_extend (handle_t *, int nblocks); extern int journal_get_write_access (handle_t *, struct buffer_head *); extern int journal_get_create_access (handle_t *, struct buffer_head *); extern int journal_get_undo_access (handle_t *, struct buffer_head *); -extern int journal_dirty_data (handle_t *, - struct buffer_head *, int async); +extern int journal_dirty_data (handle_t *, struct buffer_head *); extern int journal_dirty_metadata (handle_t *, struct buffer_head *); extern void journal_release_buffer (handle_t *, struct buffer_head *); extern void journal_forget (handle_t *, struct buffer_head *); @@ -806,14 +798,13 @@ extern int journal_blocks_per_page(struct inode *inode); /* journaling buffer types */ #define BJ_None 0 /* Not journaled */ #define BJ_SyncData 1 /* Normal data: flush before commit */ -#define BJ_AsyncData 2 /* writepage data: wait on it before commit */ -#define BJ_Metadata 3 /* Normal journaled metadata */ -#define BJ_Forget 4 /* Buffer superseded by this transaction */ -#define BJ_IO 5 /* Buffer is for temporary IO use */ -#define BJ_Shadow 6 /* Buffer contents being shadowed to the log */ -#define BJ_LogCtl 7 /* Buffer contains log descriptors */ -#define BJ_Reserved 8 /* Buffer is reserved for access by journal */ -#define BJ_Types 9 +#define BJ_Metadata 2 /* Normal journaled metadata */ +#define BJ_Forget 3 /* Buffer superseded by this transaction */ +#define BJ_IO 4 /* Buffer is for temporary IO use */ +#define BJ_Shadow 5 /* Buffer contents being shadowed to the log */ +#define BJ_LogCtl 6 /* Buffer contains log descriptors */ +#define BJ_Reserved 7 /* Buffer is reserved for access by journal */ +#define BJ_Types 8 extern int jbd_blocks_per_page(struct inode *inode); @@ -860,8 +851,7 @@ static inline int buffer_jdirty(struct buffer_head *bh) static inline int buffer_jbd_data(struct buffer_head *bh) { return SPLICE_LOCK(buffer_jbd(bh), - bh2jh(bh)->b_jlist == BJ_SyncData || - bh2jh(bh)->b_jlist == BJ_AsyncData); + bh2jh(bh)->b_jlist == BJ_SyncData); } #ifdef CONFIG_SMP -- cgit v1.2.3 From e5b36baf5307d3d0987080b5304dbc01991324ae Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 14 Jan 2003 00:21:23 -0800 Subject: [PATCH] Create a per-cpu proces counter for /proc reporting proc_fill_super() simply wants a count of processes, not threads. This creates a per-cpu counter for it to use to determine that. --- fs/proc/inode.c | 7 +------ include/linux/sched.h | 3 +++ kernel/exit.c | 2 ++ kernel/fork.c | 16 ++++++++++++++++ 4 files changed, 22 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 089790f3b34a..62af20aecec2 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -221,7 +221,6 @@ out_fail: int proc_fill_super(struct super_block *s, void *data, int silent) { struct inode * root_inode; - struct task_struct *p; s->s_blocksize = 1024; s->s_blocksize_bits = 10; @@ -234,11 +233,7 @@ int proc_fill_super(struct super_block *s, void *data, int silent) /* * Fixup the root inode's nlink value */ - read_lock(&tasklist_lock); - for_each_process(p) - if (p->pid) - root_inode->i_nlink++; - read_unlock(&tasklist_lock); + root_inode->i_nlink += nr_processes(); s->s_root = d_alloc_root(root_inode); if (!s->s_root) goto out_no_root; diff --git a/include/linux/sched.h b/include/linux/sched.h index 1295d071376a..931cdf559eb2 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -27,6 +27,7 @@ #include #include #include +#include struct exec_domain; @@ -87,6 +88,8 @@ extern unsigned long avenrun[]; /* Load averages */ extern int nr_threads; extern int last_pid; +DECLARE_PER_CPU(unsigned long, process_counts); +extern int nr_processes(void); extern unsigned long nr_running(void); extern unsigned long nr_uninterruptible(void); extern unsigned long nr_iowait(void); diff --git a/kernel/exit.c b/kernel/exit.c index 1841978bfa4c..f5a9c5fbdd32 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -41,6 +41,8 @@ static struct dentry * __unhash_process(struct task_struct *p) if (thread_group_leader(p)) { detach_pid(p, PIDTYPE_PGID); detach_pid(p, PIDTYPE_SID); + if (p->pid) + per_cpu(process_counts, smp_processor_id())--; } REMOVE_LINKS(p); diff --git a/kernel/fork.c b/kernel/fork.c index 115a5eae0d6b..0ba9e64b5821 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -48,6 +48,8 @@ int nr_threads; int max_threads; unsigned long total_forks; /* Handle normal Linux uptimes. */ +DEFINE_PER_CPU(unsigned long, process_counts) = 0; + rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ /* @@ -57,6 +59,18 @@ rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ */ static task_t *task_cache[NR_CPUS] __cacheline_aligned; +int nr_processes(void) +{ + int cpu; + int total = 0; + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (cpu_online(cpu)) + total += per_cpu(process_counts, cpu); + } + return total; +} + void __put_task_struct(struct task_struct *tsk) { if (tsk != current) { @@ -931,6 +945,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, attach_pid(p, PIDTYPE_TGID, p->tgid); attach_pid(p, PIDTYPE_PGID, p->pgrp); attach_pid(p, PIDTYPE_SID, p->session); + if (p->pid) + per_cpu(process_counts, smp_processor_id())++; } else link_pid(p, p->pids + PIDTYPE_TGID, &p->group_leader->pids[PIDTYPE_TGID].pid); -- cgit v1.2.3 From e987ce0cfac3f9bb805e8913986cbf2f87c2158b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 14 Jan 2003 20:51:28 +0100 Subject: [XFS] update xattr.h copyright date --- include/linux/xattr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/xattr.h b/include/linux/xattr.h index a7eb1b4188bd..9e967b58ee2e 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -4,7 +4,7 @@ Extended attributes handling. Copyright (C) 2001 by Andreas Gruenbacher - Copyright (C) 2001 SGI - Silicon Graphics, Inc + Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _LINUX_XATTR_H #define _LINUX_XATTR_H -- cgit v1.2.3 From 2bff212cc091c42bfc1de6ea873b969978f9b1b9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 14 Jan 2003 20:53:24 +0100 Subject: [XFS] add dmapi miscdevice minor number This doesn't mean dmapi is scheduled for inclusion, just adding the reserved minor number to miscdevice.h for documentation purposes. --- include/linux/miscdevice.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 396d4178b14c..b7b3da409f8a 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -18,6 +18,7 @@ #define RTC_MINOR 135 #define EFI_RTC_MINOR 136 /* EFI Time services */ #define SUN_OPENPROM_MINOR 139 +#define DMAPI_MINOR 140 /* DMAPI */ #define NVRAM_MINOR 144 #define I2O_MINOR 166 #define MICROCODE_MINOR 184 -- cgit v1.2.3