* remove everybody - which includes ourselves - fill in the return
* value, and then complete the operation.
*/
-static void idempotent_complete(struct idempotent *u, int ret)
+static int idempotent_complete(struct idempotent *u, int ret)
{
const void *cookie = u->cookie;
int hash = hash_ptr(cookie, IDEM_HASH_BITS);
complete(&pos->complete);
}
spin_unlock(&idem_lock);
+ return ret;
}
static int init_module_from_file(struct file *f, const char __user * uargs, int flags)
{
- struct idempotent idem;
struct load_info info = { };
void *buf = NULL;
- int len, ret;
-
- if (!f || !(f->f_mode & FMODE_READ))
- return -EBADF;
-
- if (idempotent(&idem, file_inode(f))) {
- wait_for_completion(&idem.complete);
- return idem.ret;
- }
+ int len;
len = kernel_read_file(f, 0, &buf, INT_MAX, NULL, READING_MODULE);
if (len < 0) {
mod_stat_inc(&failed_kreads);
- mod_stat_add_long(len, &invalid_kread_bytes);
return len;
}
info.len = len;
}
- ret = load_module(&info, uargs, flags);
- idempotent_complete(&idem, ret);
- return ret;
+ return load_module(&info, uargs, flags);
+}
+
+static int idempotent_init_module(struct file *f, const char __user * uargs, int flags)
+{
+ struct idempotent idem;
+
+ if (!f || !(f->f_mode & FMODE_READ))
+ return -EBADF;
+
+ /* See if somebody else is doing the operation? */
+ if (idempotent(&idem, file_inode(f))) {
+ wait_for_completion(&idem.complete);
+ return idem.ret;
+ }
+
+ /* Otherwise, we'll do it and complete others */
+ return idempotent_complete(&idem,
+ init_module_from_file(f, uargs, flags));
}
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
return -EINVAL;
f = fdget(fd);
- err = init_module_from_file(f.file, uargs, flags);
+ err = idempotent_init_module(f.file, uargs, flags);
fdput(f);
return err;
}