diff options
| author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2013-05-09 14:44:21 +0900 | 
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2013-05-09 20:11:48 -0400 | 
| commit | 3f2367ba7cbf13ec0f3f1e93b833a7eacd1ab4b8 (patch) | |
| tree | 81bac89b0b20458cb8505a3bdef4b9189ff4057e | |
| parent | f04f24fb7e48d446bd89a01c6056571f25972511 (diff) | |
| download | olio-linux-3.10-3f2367ba7cbf13ec0f3f1e93b833a7eacd1ab4b8.tar.xz olio-linux-3.10-3f2367ba7cbf13ec0f3f1e93b833a7eacd1ab4b8.zip  | |
ftrace: Cleanup regex_lock and ftrace_lock around hash updating
Cleanup regex_lock and ftrace_lock locking points around
ftrace_ops hash update code.
The new rule is that regex_lock protects ops->*_hash
read-update-write code for each ftrace_ops. Usually,
hash update is done by following sequence.
1. allocate a new local hash and copy the original hash.
2. update the local hash.
3. move(actually, copy) back the local hash to ftrace_ops.
4. update ftrace entries if needed.
5. release the local hash.
This makes regex_lock protect #1-#4, and ftrace_lock
to protect #3, #4 and adding and removing ftrace_ops from the
ftrace_ops_list. The ftrace_lock protects #3 as well because
the move functions update the entries too.
Link: http://lkml.kernel.org/r/20130509054421.30398.83411.stgit@mhiramat-M0-7522
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Tom Zanussi <tom.zanussi@intel.com>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
| -rw-r--r-- | kernel/trace/ftrace.c | 59 | 
1 files changed, 32 insertions, 27 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 827f2fe7bc3..cacf0856191 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2656,28 +2656,26 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,  		return -ENOMEM;  	} +	iter->ops = ops; +	iter->flags = flag; + +	mutex_lock(&ops->regex_lock); +  	if (flag & FTRACE_ITER_NOTRACE)  		hash = ops->notrace_hash;  	else  		hash = ops->filter_hash; -	iter->ops = ops; -	iter->flags = flag; -  	if (file->f_mode & FMODE_WRITE) { -		mutex_lock(&ftrace_lock);  		iter->hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, hash); -		mutex_unlock(&ftrace_lock); -  		if (!iter->hash) {  			trace_parser_put(&iter->parser);  			kfree(iter); -			return -ENOMEM; +			ret = -ENOMEM; +			goto out_unlock;  		}  	} -	mutex_lock(&ops->regex_lock); -  	if ((file->f_mode & FMODE_WRITE) &&  	    (file->f_flags & O_TRUNC))  		ftrace_filter_reset(iter->hash); @@ -2697,6 +2695,8 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,  		}  	} else  		file->private_data = iter; + + out_unlock:  	mutex_unlock(&ops->regex_lock);  	return ret; @@ -3012,7 +3012,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,  	if (WARN_ON(not))  		return -EINVAL; -	mutex_lock(&ftrace_lock); +	mutex_lock(&trace_probe_ops.regex_lock);  	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);  	if (!hash) { @@ -3070,14 +3070,16 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,  	} while_for_each_ftrace_rec(); +	mutex_lock(&ftrace_lock);  	ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);  	if (ret < 0)  		count = ret;  	__enable_ftrace_function_probe(); +	mutex_unlock(&ftrace_lock);   out_unlock: -	mutex_unlock(&ftrace_lock); +	mutex_unlock(&trace_probe_ops.regex_lock);  	free_ftrace_hash(hash);  	return count; @@ -3117,7 +3119,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,  			return;  	} -	mutex_lock(&ftrace_lock); +	mutex_lock(&trace_probe_ops.regex_lock);  	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);  	if (!hash) @@ -3155,6 +3157,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,  			list_add(&entry->free_list, &free_list);  		}  	} +	mutex_lock(&ftrace_lock);  	__disable_ftrace_function_probe();  	/*  	 * Remove after the disable is called. Otherwise, if the last @@ -3166,9 +3169,10 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,  		list_del(&entry->free_list);  		ftrace_free_entry(entry);  	} +	mutex_unlock(&ftrace_lock);   out_unlock: -	mutex_unlock(&ftrace_lock); +	mutex_unlock(&trace_probe_ops.regex_lock);  	free_ftrace_hash(hash);  } @@ -3284,11 +3288,10 @@ ftrace_regex_write(struct file *file, const char __user *ubuf,  	} else  		iter = file->private_data; -	mutex_lock(&iter->ops->regex_lock); - -	ret = -ENODEV;  	if (unlikely(ftrace_disabled)) -		goto out_unlock; +		return -ENODEV; + +	/* iter->hash is a local copy, so we don't need regex_lock */  	parser = &iter->parser;  	read = trace_get_user(parser, ubuf, cnt, ppos); @@ -3299,13 +3302,11 @@ ftrace_regex_write(struct file *file, const char __user *ubuf,  					   parser->idx, enable);  		trace_parser_clear(parser);  		if (ret < 0) -			goto out_unlock; +			goto out;  	}  	ret = read; -out_unlock: -	mutex_unlock(&iter->ops->regex_lock); - + out:  	return ret;  } @@ -3357,16 +3358,19 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,  	if (unlikely(ftrace_disabled))  		return -ENODEV; +	mutex_lock(&ops->regex_lock); +  	if (enable)  		orig_hash = &ops->filter_hash;  	else  		orig_hash = &ops->notrace_hash;  	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash); -	if (!hash) -		return -ENOMEM; +	if (!hash) { +		ret = -ENOMEM; +		goto out_regex_unlock; +	} -	mutex_lock(&ops->regex_lock);  	if (reset)  		ftrace_filter_reset(hash);  	if (buf && !ftrace_match_records(hash, buf, len)) { @@ -3584,8 +3588,6 @@ int ftrace_regex_release(struct inode *inode, struct file *file)  	} else  		iter = file->private_data; -	mutex_lock(&iter->ops->regex_lock); -  	parser = &iter->parser;  	if (trace_parser_loaded(parser)) {  		parser->buffer[parser->idx] = 0; @@ -3594,6 +3596,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file)  	trace_parser_put(parser); +	mutex_lock(&iter->ops->regex_lock); +  	if (file->f_mode & FMODE_WRITE) {  		filter_hash = !!(iter->flags & FTRACE_ITER_FILTER); @@ -3611,10 +3615,11 @@ int ftrace_regex_release(struct inode *inode, struct file *file)  		mutex_unlock(&ftrace_lock);  	} + +	mutex_unlock(&iter->ops->regex_lock);  	free_ftrace_hash(iter->hash);  	kfree(iter); -	mutex_unlock(&iter->ops->regex_lock);  	return 0;  }  |