Subject: EMM: Fixup return value handling of emm_notify() Right now we stop calling additional subsystems if one callback returned an error. That has the potential for causing additional trouble with the subsystems that do not receive the callbacks they expect if one has failed. So change the handling of error code to continue callbacks to other subsystems but return the first error code encountered. If a callback returns a positive return value then add up all the value from all the calls. That can be used to establish how many references exist (xpmem may want this feature at some point) or ensure that the aging works the way Andrea wants it to (KVM, XPmem so far do not care too much). Signed-off-by: Christoph Lameter --- mm/rmap.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) Index: linux-2.6/mm/rmap.c =================================================================== --- linux-2.6.orig/mm/rmap.c 2008-04-02 18:16:07.906032549 -0700 +++ linux-2.6/mm/rmap.c 2008-04-04 14:52:45.383453580 -0700 @@ -299,27 +299,45 @@ void emm_notifier_register(struct emm_no } EXPORT_SYMBOL_GPL(emm_notifier_register); -/* Perform a callback */ +/* + * Perform a callback + * + * The return of this function is either a negative error of the first + * callback that failed or a consolidated count of all the positive + * values that were returned by the callbacks. + */ int __emm_notify(struct mm_struct *mm, enum emm_operation op, unsigned long start, unsigned long end) { struct emm_notifier *e = rcu_dereference(mm->emm_notifier); int x; + int result = 0; while (e) { - if (e->callback) { x = e->callback(e, mm, op, start, end); - if (x) - return x; + + /* + * Callback may return a positive value to indicate a count + * or a negative error code. We keep the first error code + * but continue to perform callbacks to other subscribed + * subsystems. + */ + if (x && result >= 0) { + if (x >= 0) + result += x; + else + result = x; + } } + /* * emm_notifier contents (e) must be fetched after * the retrival of the pointer to the notifier. */ e = rcu_dereference(e->next); } - return 0; + return result; } EXPORT_SYMBOL_GPL(__emm_notify); #endif