From 9c864e1093b3fd8e7572856387466c049c401fd2 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 19 Nov 2009 18:10:23 +0000 Subject: [PATCH] --- yaml --- r: 168814 b: refs/heads/master c: 3d7a641e544e428191667e8b1f83f96fa46dbd65 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/.gitignore | 1 - trunk/Documentation/filesystems/ocfs2.txt | 6 +- trunk/Documentation/slow-work.txt | 13 ++- trunk/Makefile | 2 +- trunk/arch/parisc/kernel/unwind.c | 2 +- trunk/arch/parisc/kernel/vmlinux.lds.S | 6 +- trunk/drivers/char/vt_ioctl.c | 6 +- trunk/drivers/i2c/busses/i2c-pnx.c | 5 - trunk/drivers/pci/dmar.c | 3 - trunk/fs/fscache/main.c | 6 +- trunk/fs/fscache/object.c | 1 + trunk/fs/fscache/operation.c | 1 + trunk/fs/gfs2/main.c | 4 +- trunk/fs/gfs2/recovery.c | 1 + trunk/fs/nfs/nfs4proc.c | 2 +- trunk/fs/ocfs2/file.c | 3 +- trunk/fs/ocfs2/ocfs2.h | 7 +- trunk/fs/ocfs2/refcounttree.c | 69 +---------- trunk/fs/ocfs2/super.c | 20 ++-- trunk/fs/ocfs2/uptodate.c | 5 + trunk/include/linux/i2c-pnx.h | 2 +- trunk/include/linux/slow-work.h | 8 +- trunk/include/linux/vt.h | 4 +- trunk/kernel/slow-work.c | 132 +++++++++++++++++++++- trunk/net/sunrpc/addr.c | 18 +-- 26 files changed, 200 insertions(+), 129 deletions(-) diff --git a/[refs] b/[refs] index bfaaf76ae632..94dfcc1904dc 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: e3a41d7b99e7f97d9a50bec2a8f4eb237ce1d504 +refs/heads/master: 3d7a641e544e428191667e8b1f83f96fa46dbd65 diff --git a/trunk/.gitignore b/trunk/.gitignore index 946c7ec5c922..b93fb7eff942 100644 --- a/trunk/.gitignore +++ b/trunk/.gitignore @@ -25,7 +25,6 @@ *.elf *.bin *.gz -*.bz2 *.lzma *.patch *.gcno diff --git a/trunk/Documentation/filesystems/ocfs2.txt b/trunk/Documentation/filesystems/ocfs2.txt index c58b9f5ba002..c2a0871280a0 100644 --- a/trunk/Documentation/filesystems/ocfs2.txt +++ b/trunk/Documentation/filesystems/ocfs2.txt @@ -20,16 +20,15 @@ Lots of code taken from ext3 and other projects. Authors in alphabetical order: Joel Becker Zach Brown -Mark Fasheh +Mark Fasheh Kurt Hackel -Tao Ma Sunil Mushran Manish Singh -Tiger Yang Caveats ======= Features which OCFS2 does not support yet: + - quotas - Directory change notification (F_NOTIFY) - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease) @@ -71,6 +70,7 @@ commit=nrsec (*) Ocfs2 can be told to sync all its data and metadata performance. localalloc=8(*) Allows custom localalloc size in MB. If the value is too large, the fs will silently revert it to the default. + Localalloc is not enabled for local mounts. localflocks This disables cluster aware flock. inode64 Indicates that Ocfs2 is allowed to create inodes at any location in the filesystem, including those which diff --git a/trunk/Documentation/slow-work.txt b/trunk/Documentation/slow-work.txt index ebc50f808ea4..f12fda31dcdc 100644 --- a/trunk/Documentation/slow-work.txt +++ b/trunk/Documentation/slow-work.txt @@ -64,9 +64,11 @@ USING SLOW WORK ITEMS Firstly, a module or subsystem wanting to make use of slow work items must register its interest: - int ret = slow_work_register_user(); + int ret = slow_work_register_user(struct module *module); -This will return 0 if successful, or a -ve error upon failure. +This will return 0 if successful, or a -ve error upon failure. The module +pointer should be the module interested in using this facility (almost +certainly THIS_MODULE). Slow work items may then be set up by: @@ -110,7 +112,12 @@ operation. When all a module's slow work items have been processed, and the module has no further interest in the facility, it should unregister its interest: - slow_work_unregister_user(); + slow_work_unregister_user(struct module *module); + +The module pointer is used to wait for all outstanding work items for that +module before completing the unregistration. This prevents the put_ref() code +from being taken away before it completes. module should almost certainly be +THIS_MODULE. =============== diff --git a/trunk/Makefile b/trunk/Makefile index ad8260102f64..aa3e13a7e353 100644 --- a/trunk/Makefile +++ b/trunk/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 32 -EXTRAVERSION = -rc8 +EXTRAVERSION = -rc7 NAME = Man-Eating Seals of Antiquity # *DOCUMENTATION* diff --git a/trunk/arch/parisc/kernel/unwind.c b/trunk/arch/parisc/kernel/unwind.c index a36799e85693..69dad5a850a8 100644 --- a/trunk/arch/parisc/kernel/unwind.c +++ b/trunk/arch/parisc/kernel/unwind.c @@ -28,7 +28,7 @@ #define dbg(x...) #endif -#define KERNEL_START (KERNEL_BINARY_TEXT_START) +#define KERNEL_START (KERNEL_BINARY_TEXT_START - 0x1000) extern struct unwind_table_entry __start___unwind[]; extern struct unwind_table_entry __stop___unwind[]; diff --git a/trunk/arch/parisc/kernel/vmlinux.lds.S b/trunk/arch/parisc/kernel/vmlinux.lds.S index 9dab4a4e09f7..fda4baa059b5 100644 --- a/trunk/arch/parisc/kernel/vmlinux.lds.S +++ b/trunk/arch/parisc/kernel/vmlinux.lds.S @@ -78,6 +78,9 @@ SECTIONS */ . = ALIGN(PAGE_SIZE); data_start = .; + EXCEPTION_TABLE(16) + + NOTES /* unwind info */ .PARISC.unwind : { @@ -86,9 +89,6 @@ SECTIONS __stop___unwind = .; } - EXCEPTION_TABLE(16) - NOTES - /* Data */ RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) diff --git a/trunk/drivers/char/vt_ioctl.c b/trunk/drivers/char/vt_ioctl.c index 6aa10284104a..ed86d3bf249a 100644 --- a/trunk/drivers/char/vt_ioctl.c +++ b/trunk/drivers/char/vt_ioctl.c @@ -103,8 +103,8 @@ void vt_event_post(unsigned int event, unsigned int old, unsigned int new) ve->event.event = event; /* kernel view is consoles 0..n-1, user space view is console 1..n with 0 meaning current, so we must bias */ - ve->event.oldev = old + 1; - ve->event.newev = new + 1; + ve->event.old = old + 1; + ve->event.new = new + 1; wake = 1; ve->done = 1; } @@ -186,7 +186,7 @@ int vt_waitactive(int n) vt_event_wait(&vw); if (vw.done == 0) return -EINTR; - } while (vw.event.newev != n); + } while (vw.event.new != n); return 0; } diff --git a/trunk/drivers/i2c/busses/i2c-pnx.c b/trunk/drivers/i2c/busses/i2c-pnx.c index 1fca59077949..6ff6c20f1e78 100644 --- a/trunk/drivers/i2c/busses/i2c-pnx.c +++ b/trunk/drivers/i2c/busses/i2c-pnx.c @@ -19,9 +19,7 @@ #include #include #include -#include #include -#include #include #include @@ -56,9 +54,6 @@ static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap) struct timer_list *timer = &data->mif.timer; int expires = I2C_PNX_TIMEOUT / (1000 / HZ); - if (expires <= 1) - expires = 2; - del_timer_sync(timer); dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n", diff --git a/trunk/drivers/pci/dmar.c b/trunk/drivers/pci/dmar.c index b952ebc7a78b..e5f8fc164fd3 100644 --- a/trunk/drivers/pci/dmar.c +++ b/trunk/drivers/pci/dmar.c @@ -609,9 +609,6 @@ int __init check_zero_address(void) dmi_get_system_info(DMI_BIOS_VENDOR), dmi_get_system_info(DMI_BIOS_VERSION), dmi_get_system_info(DMI_PRODUCT_VERSION)); -#ifdef CONFIG_DMAR - dmar_disabled = 1; -#endif return 0; } break; diff --git a/trunk/fs/fscache/main.c b/trunk/fs/fscache/main.c index 4de41b597499..add6bdb53f04 100644 --- a/trunk/fs/fscache/main.c +++ b/trunk/fs/fscache/main.c @@ -48,7 +48,7 @@ static int __init fscache_init(void) { int ret; - ret = slow_work_register_user(); + ret = slow_work_register_user(THIS_MODULE); if (ret < 0) goto error_slow_work; @@ -80,7 +80,7 @@ static int __init fscache_init(void) error_cookie_jar: fscache_proc_cleanup(); error_proc: - slow_work_unregister_user(); + slow_work_unregister_user(THIS_MODULE); error_slow_work: return ret; } @@ -97,7 +97,7 @@ static void __exit fscache_exit(void) kobject_put(fscache_root); kmem_cache_destroy(fscache_cookie_jar); fscache_proc_cleanup(); - slow_work_unregister_user(); + slow_work_unregister_user(THIS_MODULE); printk(KERN_NOTICE "FS-Cache: Unloaded\n"); } diff --git a/trunk/fs/fscache/object.c b/trunk/fs/fscache/object.c index 392a41b1b79d..d236eb1d6f37 100644 --- a/trunk/fs/fscache/object.c +++ b/trunk/fs/fscache/object.c @@ -45,6 +45,7 @@ static void fscache_enqueue_dependents(struct fscache_object *); static void fscache_dequeue_object(struct fscache_object *); const struct slow_work_ops fscache_object_slow_work_ops = { + .owner = THIS_MODULE, .get_ref = fscache_object_slow_work_get_ref, .put_ref = fscache_object_slow_work_put_ref, .execute = fscache_object_slow_work_execute, diff --git a/trunk/fs/fscache/operation.c b/trunk/fs/fscache/operation.c index e7f8d53b8b6b..f1a2857b2ff5 100644 --- a/trunk/fs/fscache/operation.c +++ b/trunk/fs/fscache/operation.c @@ -453,6 +453,7 @@ static void fscache_op_execute(struct slow_work *work) } const struct slow_work_ops fscache_op_slow_work_ops = { + .owner = THIS_MODULE, .get_ref = fscache_op_get_ref, .put_ref = fscache_op_put_ref, .execute = fscache_op_execute, diff --git a/trunk/fs/gfs2/main.c b/trunk/fs/gfs2/main.c index eacd78a5d082..5b31f7741a8f 100644 --- a/trunk/fs/gfs2/main.c +++ b/trunk/fs/gfs2/main.c @@ -114,7 +114,7 @@ static int __init init_gfs2_fs(void) if (error) goto fail_unregister; - error = slow_work_register_user(); + error = slow_work_register_user(THIS_MODULE); if (error) goto fail_slow; @@ -163,7 +163,7 @@ static void __exit exit_gfs2_fs(void) gfs2_unregister_debugfs(); unregister_filesystem(&gfs2_fs_type); unregister_filesystem(&gfs2meta_fs_type); - slow_work_unregister_user(); + slow_work_unregister_user(THIS_MODULE); kmem_cache_destroy(gfs2_quotad_cachep); kmem_cache_destroy(gfs2_rgrpd_cachep); diff --git a/trunk/fs/gfs2/recovery.c b/trunk/fs/gfs2/recovery.c index 59d2695509d3..b2bb779f09ed 100644 --- a/trunk/fs/gfs2/recovery.c +++ b/trunk/fs/gfs2/recovery.c @@ -593,6 +593,7 @@ static void gfs2_recover_work(struct slow_work *work) } struct slow_work_ops gfs2_recover_ops = { + .owner = THIS_MODULE, .get_ref = gfs2_recover_get_ref, .put_ref = gfs2_recover_put_ref, .execute = gfs2_recover_work, diff --git a/trunk/fs/nfs/nfs4proc.c b/trunk/fs/nfs/nfs4proc.c index 741a562177fc..ff37454fa783 100644 --- a/trunk/fs/nfs/nfs4proc.c +++ b/trunk/fs/nfs/nfs4proc.c @@ -2767,7 +2767,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, .pages = &page, .pgbase = 0, .count = count, - .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, + .bitmask = NFS_SERVER(dentry->d_inode)->cache_consistency_bitmask, }; struct nfs4_readdir_res res; struct rpc_message msg = { diff --git a/trunk/fs/ocfs2/file.c b/trunk/fs/ocfs2/file.c index de059f490586..89fc8ee1f5a5 100644 --- a/trunk/fs/ocfs2/file.c +++ b/trunk/fs/ocfs2/file.c @@ -1712,8 +1712,7 @@ int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos, struct super_block *sb = inode->i_sb; if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)) || - !(OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) || - OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) + !(OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)) return 0; cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits; diff --git a/trunk/fs/ocfs2/ocfs2.h b/trunk/fs/ocfs2/ocfs2.h index d963d8638709..eae404602424 100644 --- a/trunk/fs/ocfs2/ocfs2.h +++ b/trunk/fs/ocfs2/ocfs2.h @@ -35,7 +35,12 @@ #include #include #include -#include +#ifndef CONFIG_OCFS2_COMPAT_JBD +# include +#else +# include +# include "ocfs2_jbd_compat.h" +#endif /* For union ocfs2_dlm_lksb */ #include "stackglue.h" diff --git a/trunk/fs/ocfs2/refcounttree.c b/trunk/fs/ocfs2/refcounttree.c index 3a0df7a1b810..60287fc56bcb 100644 --- a/trunk/fs/ocfs2/refcounttree.c +++ b/trunk/fs/ocfs2/refcounttree.c @@ -3743,9 +3743,6 @@ static int ocfs2_attach_refcount_tree(struct inode *inode, goto out; } - if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) - goto attach_xattr; - ocfs2_init_dinode_extent_tree(&di_et, INODE_CACHE(inode), di_bh); size = i_size_read(inode); @@ -3772,7 +3769,6 @@ static int ocfs2_attach_refcount_tree(struct inode *inode, cpos += num_clusters; } -attach_xattr: if (oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) { ret = ocfs2_xattr_attach_refcount_tree(inode, di_bh, &ref_tree->rf_ci, @@ -3862,49 +3858,6 @@ static int ocfs2_add_refcounted_extent(struct inode *inode, return ret; } -static int ocfs2_duplicate_inline_data(struct inode *s_inode, - struct buffer_head *s_bh, - struct inode *t_inode, - struct buffer_head *t_bh) -{ - int ret; - handle_t *handle; - struct ocfs2_super *osb = OCFS2_SB(s_inode->i_sb); - struct ocfs2_dinode *s_di = (struct ocfs2_dinode *)s_bh->b_data; - struct ocfs2_dinode *t_di = (struct ocfs2_dinode *)t_bh->b_data; - - BUG_ON(!(OCFS2_I(s_inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)); - - handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - mlog_errno(ret); - goto out; - } - - ret = ocfs2_journal_access_di(handle, INODE_CACHE(t_inode), t_bh, - OCFS2_JOURNAL_ACCESS_WRITE); - if (ret) { - mlog_errno(ret); - goto out_commit; - } - - t_di->id2.i_data.id_count = s_di->id2.i_data.id_count; - memcpy(t_di->id2.i_data.id_data, s_di->id2.i_data.id_data, - le16_to_cpu(s_di->id2.i_data.id_count)); - spin_lock(&OCFS2_I(t_inode)->ip_lock); - OCFS2_I(t_inode)->ip_dyn_features |= OCFS2_INLINE_DATA_FL; - t_di->i_dyn_features = cpu_to_le16(OCFS2_I(t_inode)->ip_dyn_features); - spin_unlock(&OCFS2_I(t_inode)->ip_lock); - - ocfs2_journal_dirty(handle, t_bh); - -out_commit: - ocfs2_commit_trans(osb, handle); -out: - return ret; -} - static int ocfs2_duplicate_extent_list(struct inode *s_inode, struct inode *t_inode, struct buffer_head *t_bh, @@ -4044,14 +3997,6 @@ static int ocfs2_create_reflink_node(struct inode *s_inode, goto out; } - if (OCFS2_I(s_inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { - ret = ocfs2_duplicate_inline_data(s_inode, s_bh, - t_inode, t_bh); - if (ret) - mlog_errno(ret); - goto out; - } - ret = ocfs2_lock_refcount_tree(osb, le64_to_cpu(di->i_refcount_loc), 1, &ref_tree, &ref_root_bh); if (ret) { @@ -4068,6 +4013,10 @@ static int ocfs2_create_reflink_node(struct inode *s_inode, goto out_unlock_refcount; } + ret = ocfs2_complete_reflink(s_inode, s_bh, t_inode, t_bh, preserve); + if (ret) + mlog_errno(ret); + out_unlock_refcount: ocfs2_unlock_refcount_tree(osb, ref_tree, 1); brelse(ref_root_bh); @@ -4119,17 +4068,9 @@ static int __ocfs2_reflink(struct dentry *old_dentry, ret = ocfs2_reflink_xattrs(inode, old_bh, new_inode, new_bh, preserve); - if (ret) { + if (ret) mlog_errno(ret); - goto inode_unlock; - } } - - ret = ocfs2_complete_reflink(inode, old_bh, - new_inode, new_bh, preserve); - if (ret) - mlog_errno(ret); - inode_unlock: ocfs2_inode_unlock(new_inode, 1); brelse(new_bh); diff --git a/trunk/fs/ocfs2/super.c b/trunk/fs/ocfs2/super.c index 14f47d2bfe02..c0e48aeebb1c 100644 --- a/trunk/fs/ocfs2/super.c +++ b/trunk/fs/ocfs2/super.c @@ -773,20 +773,18 @@ static int ocfs2_sb_probe(struct super_block *sb, if (tmpstat < 0) { status = tmpstat; mlog_errno(status); - break; + goto bail; } di = (struct ocfs2_dinode *) (*bh)->b_data; memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats)); spin_lock_init(&stats->b_lock); - tmpstat = ocfs2_verify_volume(di, *bh, blksize, stats); - if (tmpstat < 0) { - brelse(*bh); - *bh = NULL; - } - if (tmpstat != -EAGAIN) { - status = tmpstat; + status = ocfs2_verify_volume(di, *bh, blksize, stats); + if (status >= 0) + goto bail; + brelse(*bh); + *bh = NULL; + if (status != -EAGAIN) break; - } } bail: @@ -1647,10 +1645,6 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_bavail = buf->f_bfree; buf->f_files = numbits; buf->f_ffree = freebits; - buf->f_fsid.val[0] = crc32_le(0, osb->uuid_str, OCFS2_VOL_UUID_LEN) - & 0xFFFFFFFFUL; - buf->f_fsid.val[1] = crc32_le(0, osb->uuid_str + OCFS2_VOL_UUID_LEN, - OCFS2_VOL_UUID_LEN) & 0xFFFFFFFFUL; brelse(bh); diff --git a/trunk/fs/ocfs2/uptodate.c b/trunk/fs/ocfs2/uptodate.c index c61369342a27..b6284f235d2f 100644 --- a/trunk/fs/ocfs2/uptodate.c +++ b/trunk/fs/ocfs2/uptodate.c @@ -53,6 +53,11 @@ #include #include #include +#ifndef CONFIG_OCFS2_COMPAT_JBD +# include +#else +# include +#endif #define MLOG_MASK_PREFIX ML_UPTODATE diff --git a/trunk/include/linux/i2c-pnx.h b/trunk/include/linux/i2c-pnx.h index 9eb07bbc6522..f13255e06406 100644 --- a/trunk/include/linux/i2c-pnx.h +++ b/trunk/include/linux/i2c-pnx.h @@ -21,7 +21,7 @@ struct i2c_pnx_mif { int mode; /* Interface mode */ struct completion complete; /* I/O completion */ struct timer_list timer; /* Timeout */ - u8 * buf; /* Data buffer */ + char * buf; /* Data buffer */ int len; /* Length of data buffer */ }; diff --git a/trunk/include/linux/slow-work.h b/trunk/include/linux/slow-work.h index b65c8881f07a..9adb2b30754f 100644 --- a/trunk/include/linux/slow-work.h +++ b/trunk/include/linux/slow-work.h @@ -24,6 +24,9 @@ struct slow_work; * The operations used to support slow work items */ struct slow_work_ops { + /* owner */ + struct module *owner; + /* get a ref on a work item * - return 0 if successful, -ve if not */ @@ -42,6 +45,7 @@ struct slow_work_ops { * queued */ struct slow_work { + struct module *owner; /* the owning module */ unsigned long flags; #define SLOW_WORK_PENDING 0 /* item pending (further) execution */ #define SLOW_WORK_EXECUTING 1 /* item currently executing */ @@ -84,8 +88,8 @@ static inline void vslow_work_init(struct slow_work *work, } extern int slow_work_enqueue(struct slow_work *work); -extern int slow_work_register_user(void); -extern void slow_work_unregister_user(void); +extern int slow_work_register_user(struct module *owner); +extern void slow_work_unregister_user(struct module *owner); #ifdef CONFIG_SYSCTL extern ctl_table slow_work_sysctls[]; diff --git a/trunk/include/linux/vt.h b/trunk/include/linux/vt.h index 7ffa11f06232..7afca0d72139 100644 --- a/trunk/include/linux/vt.h +++ b/trunk/include/linux/vt.h @@ -70,8 +70,8 @@ struct vt_event { #define VT_EVENT_UNBLANK 0x0004 /* Screen unblank */ #define VT_EVENT_RESIZE 0x0008 /* Resize display */ #define VT_MAX_EVENT 0x000F - unsigned int oldev; /* Old console */ - unsigned int newev; /* New console (if changing) */ + unsigned int old; /* Old console */ + unsigned int new; /* New console (if changing) */ unsigned int pad[4]; /* Padding for expansion */ }; diff --git a/trunk/kernel/slow-work.c b/trunk/kernel/slow-work.c index 0d31135efbf4..dd08f376e406 100644 --- a/trunk/kernel/slow-work.c +++ b/trunk/kernel/slow-work.c @@ -22,6 +22,8 @@ #define SLOW_WORK_OOM_TIMEOUT (5 * HZ) /* can't start new threads for 5s after * OOM */ +#define SLOW_WORK_THREAD_LIMIT 255 /* abs maximum number of slow-work threads */ + static void slow_work_cull_timeout(unsigned long); static void slow_work_oom_timeout(unsigned long); @@ -46,7 +48,7 @@ static unsigned vslow_work_proportion = 50; /* % of threads that may process #ifdef CONFIG_SYSCTL static const int slow_work_min_min_threads = 2; -static int slow_work_max_max_threads = 255; +static int slow_work_max_max_threads = SLOW_WORK_THREAD_LIMIT; static const int slow_work_min_vslow = 1; static const int slow_work_max_vslow = 99; @@ -97,6 +99,23 @@ static DEFINE_TIMER(slow_work_cull_timer, slow_work_cull_timeout, 0, 0); static DEFINE_TIMER(slow_work_oom_timer, slow_work_oom_timeout, 0, 0); static struct slow_work slow_work_new_thread; /* new thread starter */ +/* + * slow work ID allocation (use slow_work_queue_lock) + */ +static DECLARE_BITMAP(slow_work_ids, SLOW_WORK_THREAD_LIMIT); + +/* + * Unregistration tracking to prevent put_ref() from disappearing during module + * unload + */ +#ifdef CONFIG_MODULES +static struct module *slow_work_thread_processing[SLOW_WORK_THREAD_LIMIT]; +static struct module *slow_work_unreg_module; +static struct slow_work *slow_work_unreg_work_item; +static DECLARE_WAIT_QUEUE_HEAD(slow_work_unreg_wq); +static DEFINE_MUTEX(slow_work_unreg_sync_lock); +#endif + /* * The queues of work items and the lock governing access to them. These are * shared between all the CPUs. It doesn't make sense to have per-CPU queues @@ -149,8 +168,11 @@ static unsigned slow_work_calc_vsmax(void) * Attempt to execute stuff queued on a slow thread. Return true if we managed * it, false if there was nothing to do. */ -static bool slow_work_execute(void) +static bool slow_work_execute(int id) { +#ifdef CONFIG_MODULES + struct module *module; +#endif struct slow_work *work = NULL; unsigned vsmax; bool very_slow; @@ -186,6 +208,12 @@ static bool slow_work_execute(void) } else { very_slow = false; /* avoid the compiler warning */ } + +#ifdef CONFIG_MODULES + if (work) + slow_work_thread_processing[id] = work->owner; +#endif + spin_unlock_irq(&slow_work_queue_lock); if (!work) @@ -219,7 +247,18 @@ static bool slow_work_execute(void) spin_unlock_irq(&slow_work_queue_lock); } + /* sort out the race between module unloading and put_ref() */ work->ops->put_ref(work); + +#ifdef CONFIG_MODULES + module = slow_work_thread_processing[id]; + slow_work_thread_processing[id] = NULL; + smp_mb(); + if (slow_work_unreg_work_item == work || + slow_work_unreg_module == module) + wake_up_all(&slow_work_unreg_wq); +#endif + return true; auto_requeue: @@ -232,6 +271,7 @@ static bool slow_work_execute(void) else list_add_tail(&work->link, &slow_work_queue); spin_unlock_irq(&slow_work_queue_lock); + slow_work_thread_processing[id] = NULL; return true; } @@ -368,13 +408,22 @@ static inline bool slow_work_available(int vsmax) */ static int slow_work_thread(void *_data) { - int vsmax; + int vsmax, id; DEFINE_WAIT(wait); set_freezable(); set_user_nice(current, -5); + /* allocate ourselves an ID */ + spin_lock_irq(&slow_work_queue_lock); + id = find_first_zero_bit(slow_work_ids, SLOW_WORK_THREAD_LIMIT); + BUG_ON(id < 0 || id >= SLOW_WORK_THREAD_LIMIT); + __set_bit(id, slow_work_ids); + spin_unlock_irq(&slow_work_queue_lock); + + sprintf(current->comm, "kslowd%03u", id); + for (;;) { vsmax = vslow_work_proportion; vsmax *= atomic_read(&slow_work_thread_count); @@ -395,7 +444,7 @@ static int slow_work_thread(void *_data) vsmax *= atomic_read(&slow_work_thread_count); vsmax /= 100; - if (slow_work_available(vsmax) && slow_work_execute()) { + if (slow_work_available(vsmax) && slow_work_execute(id)) { cond_resched(); if (list_empty(&slow_work_queue) && list_empty(&vslow_work_queue) && @@ -412,6 +461,10 @@ static int slow_work_thread(void *_data) break; } + spin_lock_irq(&slow_work_queue_lock); + __clear_bit(id, slow_work_ids); + spin_unlock_irq(&slow_work_queue_lock); + if (atomic_dec_and_test(&slow_work_thread_count)) complete_and_exit(&slow_work_last_thread_exited, 0); return 0; @@ -475,6 +528,7 @@ static void slow_work_new_thread_execute(struct slow_work *work) } static const struct slow_work_ops slow_work_new_thread_ops = { + .owner = THIS_MODULE, .get_ref = slow_work_new_thread_get_ref, .put_ref = slow_work_new_thread_put_ref, .execute = slow_work_new_thread_execute, @@ -546,12 +600,13 @@ static int slow_work_max_threads_sysctl(struct ctl_table *table, int write, /** * slow_work_register_user - Register a user of the facility + * @module: The module about to make use of the facility * * Register a user of the facility, starting up the initial threads if there * aren't any other users at this point. This will return 0 if successful, or * an error if not. */ -int slow_work_register_user(void) +int slow_work_register_user(struct module *module) { struct task_struct *p; int loop; @@ -598,14 +653,79 @@ int slow_work_register_user(void) } EXPORT_SYMBOL(slow_work_register_user); +/* + * wait for all outstanding items from the calling module to complete + * - note that more items may be queued whilst we're waiting + */ +static void slow_work_wait_for_items(struct module *module) +{ + DECLARE_WAITQUEUE(myself, current); + struct slow_work *work; + int loop; + + mutex_lock(&slow_work_unreg_sync_lock); + add_wait_queue(&slow_work_unreg_wq, &myself); + + for (;;) { + spin_lock_irq(&slow_work_queue_lock); + + /* first of all, we wait for the last queued item in each list + * to be processed */ + list_for_each_entry_reverse(work, &vslow_work_queue, link) { + if (work->owner == module) { + set_current_state(TASK_UNINTERRUPTIBLE); + slow_work_unreg_work_item = work; + goto do_wait; + } + } + list_for_each_entry_reverse(work, &slow_work_queue, link) { + if (work->owner == module) { + set_current_state(TASK_UNINTERRUPTIBLE); + slow_work_unreg_work_item = work; + goto do_wait; + } + } + + /* then we wait for the items being processed to finish */ + slow_work_unreg_module = module; + smp_mb(); + for (loop = 0; loop < SLOW_WORK_THREAD_LIMIT; loop++) { + if (slow_work_thread_processing[loop] == module) + goto do_wait; + } + spin_unlock_irq(&slow_work_queue_lock); + break; /* okay, we're done */ + + do_wait: + spin_unlock_irq(&slow_work_queue_lock); + schedule(); + slow_work_unreg_work_item = NULL; + slow_work_unreg_module = NULL; + } + + remove_wait_queue(&slow_work_unreg_wq, &myself); + mutex_unlock(&slow_work_unreg_sync_lock); +} + /** * slow_work_unregister_user - Unregister a user of the facility + * @module: The module whose items should be cleared * * Unregister a user of the facility, killing all the threads if this was the * last one. + * + * This waits for all the work items belonging to the nominated module to go + * away before proceeding. */ -void slow_work_unregister_user(void) +void slow_work_unregister_user(struct module *module) { + /* first of all, wait for all outstanding items from the calling module + * to complete */ + if (module) + slow_work_wait_for_items(module); + + /* then we can actually go about shutting down the facility if need + * be */ mutex_lock(&slow_work_user_lock); BUG_ON(slow_work_user_count <= 0); diff --git a/trunk/net/sunrpc/addr.c b/trunk/net/sunrpc/addr.c index c7450c8f0a7c..22e8fd89477f 100644 --- a/trunk/net/sunrpc/addr.c +++ b/trunk/net/sunrpc/addr.c @@ -306,25 +306,24 @@ EXPORT_SYMBOL_GPL(rpc_sockaddr2uaddr); * @sap: buffer into which to plant socket address * @salen: size of buffer * - * @uaddr does not have to be '\0'-terminated, but strict_strtoul() and - * rpc_pton() require proper string termination to be successful. - * * Returns the size of the socket address if successful; otherwise * zero is returned. */ size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, struct sockaddr *sap, const size_t salen) { - char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')]; + char *c, buf[RPCBIND_MAXUADDRLEN]; unsigned long portlo, porthi; unsigned short port; - if (uaddr_len > RPCBIND_MAXUADDRLEN) + if (uaddr_len > sizeof(buf)) return 0; memcpy(buf, uaddr, uaddr_len); - buf[uaddr_len] = '\0'; + buf[uaddr_len] = '\n'; + buf[uaddr_len + 1] = '\0'; + c = strrchr(buf, '.'); if (unlikely(c == NULL)) return 0; @@ -333,7 +332,9 @@ size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, if (unlikely(portlo > 255)) return 0; - *c = '\0'; + c[0] = '\n'; + c[1] = '\0'; + c = strrchr(buf, '.'); if (unlikely(c == NULL)) return 0; @@ -344,7 +345,8 @@ size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, port = (unsigned short)((porthi << 8) | portlo); - *c = '\0'; + c[0] = '\0'; + if (rpc_pton(buf, strlen(buf), sap, salen) == 0) return 0;