|
@@ -75,21 +75,6 @@ static void uid_hash_remove(struct user_struct *up)
|
|
put_user_ns(up->user_ns);
|
|
put_user_ns(up->user_ns);
|
|
}
|
|
}
|
|
|
|
|
|
-static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
|
|
|
|
-{
|
|
|
|
- struct user_struct *user;
|
|
|
|
- struct hlist_node *h;
|
|
|
|
-
|
|
|
|
- hlist_for_each_entry(user, h, hashent, uidhash_node) {
|
|
|
|
- if (user->uid == uid) {
|
|
|
|
- atomic_inc(&user->__count);
|
|
|
|
- return user;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return NULL;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
#ifdef CONFIG_USER_SCHED
|
|
#ifdef CONFIG_USER_SCHED
|
|
|
|
|
|
static void sched_destroy_user(struct user_struct *up)
|
|
static void sched_destroy_user(struct user_struct *up)
|
|
@@ -119,6 +104,23 @@ static int sched_create_user(struct user_struct *up) { return 0; }
|
|
|
|
|
|
#if defined(CONFIG_USER_SCHED) && defined(CONFIG_SYSFS)
|
|
#if defined(CONFIG_USER_SCHED) && defined(CONFIG_SYSFS)
|
|
|
|
|
|
|
|
+static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
|
|
|
|
+{
|
|
|
|
+ struct user_struct *user;
|
|
|
|
+ struct hlist_node *h;
|
|
|
|
+
|
|
|
|
+ hlist_for_each_entry(user, h, hashent, uidhash_node) {
|
|
|
|
+ if (user->uid == uid) {
|
|
|
|
+ /* possibly resurrect an "almost deleted" object */
|
|
|
|
+ if (atomic_inc_return(&user->__count) == 1)
|
|
|
|
+ cancel_delayed_work(&user->work);
|
|
|
|
+ return user;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */
|
|
static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */
|
|
static DEFINE_MUTEX(uids_mutex);
|
|
static DEFINE_MUTEX(uids_mutex);
|
|
|
|
|
|
@@ -283,12 +285,12 @@ int __init uids_sysfs_init(void)
|
|
return uids_user_create(&root_user);
|
|
return uids_user_create(&root_user);
|
|
}
|
|
}
|
|
|
|
|
|
-/* work function to remove sysfs directory for a user and free up
|
|
|
|
|
|
+/* delayed work function to remove sysfs directory for a user and free up
|
|
* corresponding structures.
|
|
* corresponding structures.
|
|
*/
|
|
*/
|
|
static void cleanup_user_struct(struct work_struct *w)
|
|
static void cleanup_user_struct(struct work_struct *w)
|
|
{
|
|
{
|
|
- struct user_struct *up = container_of(w, struct user_struct, work);
|
|
|
|
|
|
+ struct user_struct *up = container_of(w, struct user_struct, work.work);
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
int remove_user = 0;
|
|
int remove_user = 0;
|
|
|
|
|
|
@@ -297,15 +299,12 @@ static void cleanup_user_struct(struct work_struct *w)
|
|
*/
|
|
*/
|
|
uids_mutex_lock();
|
|
uids_mutex_lock();
|
|
|
|
|
|
- local_irq_save(flags);
|
|
|
|
-
|
|
|
|
- if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
|
|
|
|
|
|
+ spin_lock_irqsave(&uidhash_lock, flags);
|
|
|
|
+ if (atomic_read(&up->__count) == 0) {
|
|
uid_hash_remove(up);
|
|
uid_hash_remove(up);
|
|
remove_user = 1;
|
|
remove_user = 1;
|
|
- spin_unlock_irqrestore(&uidhash_lock, flags);
|
|
|
|
- } else {
|
|
|
|
- local_irq_restore(flags);
|
|
|
|
}
|
|
}
|
|
|
|
+ spin_unlock_irqrestore(&uidhash_lock, flags);
|
|
|
|
|
|
if (!remove_user)
|
|
if (!remove_user)
|
|
goto done;
|
|
goto done;
|
|
@@ -331,16 +330,28 @@ done:
|
|
*/
|
|
*/
|
|
static void free_user(struct user_struct *up, unsigned long flags)
|
|
static void free_user(struct user_struct *up, unsigned long flags)
|
|
{
|
|
{
|
|
- /* restore back the count */
|
|
|
|
- atomic_inc(&up->__count);
|
|
|
|
spin_unlock_irqrestore(&uidhash_lock, flags);
|
|
spin_unlock_irqrestore(&uidhash_lock, flags);
|
|
-
|
|
|
|
- INIT_WORK(&up->work, cleanup_user_struct);
|
|
|
|
- schedule_work(&up->work);
|
|
|
|
|
|
+ INIT_DELAYED_WORK(&up->work, cleanup_user_struct);
|
|
|
|
+ schedule_delayed_work(&up->work, msecs_to_jiffies(1000));
|
|
}
|
|
}
|
|
|
|
|
|
#else /* CONFIG_USER_SCHED && CONFIG_SYSFS */
|
|
#else /* CONFIG_USER_SCHED && CONFIG_SYSFS */
|
|
|
|
|
|
|
|
+static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
|
|
|
|
+{
|
|
|
|
+ struct user_struct *user;
|
|
|
|
+ struct hlist_node *h;
|
|
|
|
+
|
|
|
|
+ hlist_for_each_entry(user, h, hashent, uidhash_node) {
|
|
|
|
+ if (user->uid == uid) {
|
|
|
|
+ atomic_inc(&user->__count);
|
|
|
|
+ return user;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
int uids_sysfs_init(void) { return 0; }
|
|
int uids_sysfs_init(void) { return 0; }
|
|
static inline int uids_user_create(struct user_struct *up) { return 0; }
|
|
static inline int uids_user_create(struct user_struct *up) { return 0; }
|
|
static inline void uids_mutex_lock(void) { }
|
|
static inline void uids_mutex_lock(void) { }
|