|
@@ -134,19 +134,39 @@ static int notifier_chain_unregister(struct notifier_block **nl,
|
|
|
return -ENOENT;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * notifier_call_chain - Informs the registered notifiers about an event.
|
|
|
+ * @nl: Pointer to head of the blocking notifier chain
|
|
|
+ * @val: Value passed unmodified to notifier function
|
|
|
+ * @v: Pointer passed unmodified to notifier function
|
|
|
+ * @nr_to_call: Number of notifier functions to be called. Don't care
|
|
|
+ * value of this parameter is -1.
|
|
|
+ * @nr_calls: Records the number of notifications sent. Don't care
|
|
|
+ * value of this field is NULL.
|
|
|
+ * @returns: notifier_call_chain returns the value returned by the
|
|
|
+ * last notifier function called.
|
|
|
+ */
|
|
|
+
|
|
|
static int __kprobes notifier_call_chain(struct notifier_block **nl,
|
|
|
- unsigned long val, void *v)
|
|
|
+ unsigned long val, void *v,
|
|
|
+ int nr_to_call, int *nr_calls)
|
|
|
{
|
|
|
int ret = NOTIFY_DONE;
|
|
|
struct notifier_block *nb, *next_nb;
|
|
|
|
|
|
nb = rcu_dereference(*nl);
|
|
|
- while (nb) {
|
|
|
+
|
|
|
+ while (nb && nr_to_call) {
|
|
|
next_nb = rcu_dereference(nb->next);
|
|
|
ret = nb->notifier_call(nb, val, v);
|
|
|
+
|
|
|
+ if (nr_calls)
|
|
|
+ (*nr_calls)++;
|
|
|
+
|
|
|
if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
|
|
|
break;
|
|
|
nb = next_nb;
|
|
|
+ nr_to_call--;
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
@@ -205,10 +225,12 @@ int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
|
|
|
EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
|
|
|
|
|
|
/**
|
|
|
- * atomic_notifier_call_chain - Call functions in an atomic notifier chain
|
|
|
+ * __atomic_notifier_call_chain - Call functions in an atomic notifier chain
|
|
|
* @nh: Pointer to head of the atomic notifier chain
|
|
|
* @val: Value passed unmodified to notifier function
|
|
|
* @v: Pointer passed unmodified to notifier function
|
|
|
+ * @nr_to_call: See the comment for notifier_call_chain.
|
|
|
+ * @nr_calls: See the comment for notifier_call_chain.
|
|
|
*
|
|
|
* Calls each function in a notifier chain in turn. The functions
|
|
|
* run in an atomic context, so they must not block.
|
|
@@ -222,19 +244,27 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
|
|
|
* of the last notifier function called.
|
|
|
*/
|
|
|
|
|
|
-int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
|
|
|
- unsigned long val, void *v)
|
|
|
+int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
|
|
|
+ unsigned long val, void *v,
|
|
|
+ int nr_to_call, int *nr_calls)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- ret = notifier_call_chain(&nh->head, val, v);
|
|
|
+ ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
|
|
|
rcu_read_unlock();
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
|
|
|
+EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain);
|
|
|
+
|
|
|
+int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
|
|
|
+ unsigned long val, void *v)
|
|
|
+{
|
|
|
+ return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
|
|
|
+}
|
|
|
|
|
|
+EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
|
|
|
/*
|
|
|
* Blocking notifier chain routines. All access to the chain is
|
|
|
* synchronized by an rwsem.
|
|
@@ -304,10 +334,12 @@ int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
|
|
|
EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
|
|
|
|
|
|
/**
|
|
|
- * blocking_notifier_call_chain - Call functions in a blocking notifier chain
|
|
|
+ * __blocking_notifier_call_chain - Call functions in a blocking notifier chain
|
|
|
* @nh: Pointer to head of the blocking notifier chain
|
|
|
* @val: Value passed unmodified to notifier function
|
|
|
* @v: Pointer passed unmodified to notifier function
|
|
|
+ * @nr_to_call: See comment for notifier_call_chain.
|
|
|
+ * @nr_calls: See comment for notifier_call_chain.
|
|
|
*
|
|
|
* Calls each function in a notifier chain in turn. The functions
|
|
|
* run in a process context, so they are allowed to block.
|
|
@@ -320,8 +352,9 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
|
|
|
* of the last notifier function called.
|
|
|
*/
|
|
|
|
|
|
-int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
|
|
|
- unsigned long val, void *v)
|
|
|
+int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
|
|
|
+ unsigned long val, void *v,
|
|
|
+ int nr_to_call, int *nr_calls)
|
|
|
{
|
|
|
int ret = NOTIFY_DONE;
|
|
|
|
|
@@ -332,12 +365,19 @@ int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
|
|
|
*/
|
|
|
if (rcu_dereference(nh->head)) {
|
|
|
down_read(&nh->rwsem);
|
|
|
- ret = notifier_call_chain(&nh->head, val, v);
|
|
|
+ ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
|
|
|
+ nr_calls);
|
|
|
up_read(&nh->rwsem);
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain);
|
|
|
|
|
|
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
|
|
|
+ unsigned long val, void *v)
|
|
|
+{
|
|
|
+ return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
|
|
|
+}
|
|
|
EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
|
|
|
|
|
|
/*
|
|
@@ -383,10 +423,12 @@ int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
|
|
|
EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
|
|
|
|
|
|
/**
|
|
|
- * raw_notifier_call_chain - Call functions in a raw notifier chain
|
|
|
+ * __raw_notifier_call_chain - Call functions in a raw notifier chain
|
|
|
* @nh: Pointer to head of the raw notifier chain
|
|
|
* @val: Value passed unmodified to notifier function
|
|
|
* @v: Pointer passed unmodified to notifier function
|
|
|
+ * @nr_to_call: See comment for notifier_call_chain.
|
|
|
+ * @nr_calls: See comment for notifier_call_chain
|
|
|
*
|
|
|
* Calls each function in a notifier chain in turn. The functions
|
|
|
* run in an undefined context.
|
|
@@ -400,10 +442,19 @@ EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
|
|
|
* of the last notifier function called.
|
|
|
*/
|
|
|
|
|
|
+int __raw_notifier_call_chain(struct raw_notifier_head *nh,
|
|
|
+ unsigned long val, void *v,
|
|
|
+ int nr_to_call, int *nr_calls)
|
|
|
+{
|
|
|
+ return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
|
|
|
+}
|
|
|
+
|
|
|
+EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);
|
|
|
+
|
|
|
int raw_notifier_call_chain(struct raw_notifier_head *nh,
|
|
|
unsigned long val, void *v)
|
|
|
{
|
|
|
- return notifier_call_chain(&nh->head, val, v);
|
|
|
+ return __raw_notifier_call_chain(nh, val, v, -1, NULL);
|
|
|
}
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
|
|
@@ -478,10 +529,12 @@ int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
|
|
|
EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
|
|
|
|
|
|
/**
|
|
|
- * srcu_notifier_call_chain - Call functions in an SRCU notifier chain
|
|
|
+ * __srcu_notifier_call_chain - Call functions in an SRCU notifier chain
|
|
|
* @nh: Pointer to head of the SRCU notifier chain
|
|
|
* @val: Value passed unmodified to notifier function
|
|
|
* @v: Pointer passed unmodified to notifier function
|
|
|
+ * @nr_to_call: See comment for notifier_call_chain.
|
|
|
+ * @nr_calls: See comment for notifier_call_chain
|
|
|
*
|
|
|
* Calls each function in a notifier chain in turn. The functions
|
|
|
* run in a process context, so they are allowed to block.
|
|
@@ -494,18 +547,25 @@ EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
|
|
|
* of the last notifier function called.
|
|
|
*/
|
|
|
|
|
|
-int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
|
|
|
- unsigned long val, void *v)
|
|
|
+int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
|
|
|
+ unsigned long val, void *v,
|
|
|
+ int nr_to_call, int *nr_calls)
|
|
|
{
|
|
|
int ret;
|
|
|
int idx;
|
|
|
|
|
|
idx = srcu_read_lock(&nh->srcu);
|
|
|
- ret = notifier_call_chain(&nh->head, val, v);
|
|
|
+ ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
|
|
|
srcu_read_unlock(&nh->srcu, idx);
|
|
|
return ret;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain);
|
|
|
|
|
|
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
|
|
|
+ unsigned long val, void *v)
|
|
|
+{
|
|
|
+ return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
|
|
|
+}
|
|
|
EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
|
|
|
|
|
|
/**
|