[systemd-devel] [PATCH 3/3] logind: differentiate between user state opening and closing

Djalal Harouni tixxdz at opendz.org
Wed Jan 22 01:25:53 PST 2014


To get the state of the user, the user_get_state() is used.
This function will check if the user->slice_job or the user->service_job
are set then it will automatically return USER_OPENING. This is buggy
in the context of user closing:

At logout or D-Bus TerminateUser() calls user_stop()
user_stop()
  => session_stop() on sessions
     => session_stop_scope() on sessions

  =>  user_get_state() == USER_CLOSING or USER_ACTIVE or USER_ONLINE
                                                        (incorrect)

    (depends on session closing execution and if we have finished the
     session scope jobs or not, if all the scopes are being queued
     then their session->scope_job will be set which means all
     sessions are in the OPENING_STATE, so user state will be
     USER_ONLINE).

     The previous patch improves session_get_state() logic, and if
     scopes are being queued then sessions are in SESSION_CLOSING state
     which makes user_get_state() return USER_CLOSING.

At user_stop()
user_stop_slice() queues the slice and sets user->slice_job
user_stop_service() queue the service and sets user->service_job

  =>  user_get_state() == USER_OPENING  (incorrect)

After the slice and service jobs are removed the state will be again
correct.

  =>  user_get_state() == USER_CLOSING  (correct)

To fix this and make sure that the state will always be USER_CLOSING
we add a flag that is used to differentiate between USER_OPENING and
USER_CLOSING when 'slice_job' and 'service_job' are set.

The 'slice_opening' flag for 'user->slice_job' and 'service_opening'
for 'user->service_job' are set to true only during real user opening.
During user closing they are already in the false state.

Update user_get_state() to check if they are set if so this is
USER_OPENING, otherwise we are in the USER_CLOSING.
---
 src/login/logind-dbus.c | 2 ++
 src/login/logind-user.c | 5 ++++-
 src/login/logind-user.h | 2 ++
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 0123a34..a7452b1 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -2000,11 +2000,13 @@ int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_b
                         /* Clean this up after session_send_create_reply() */
                         free(user->service_job);
                         user->service_job = NULL;
+                        user->service_opening = false;
                 }
 
                 if (streq_ptr(path, user->slice_job)) {
                         free(user->slice_job);
                         user->slice_job = NULL;
+                        user->slice_opening = false;
                 }
 
                 user_save(user);
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 0e46560..200763d 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -352,6 +352,7 @@ static int user_start_slice(User *u) {
 
                         free(u->slice_job);
                         u->slice_job = job;
+                        u->slice_opening = true;
                 }
         }
 
@@ -385,6 +386,7 @@ static int user_start_service(User *u) {
 
                         free(u->service_job);
                         u->service_job = job;
+                        u->service_opening = true;
                 }
         }
 
@@ -637,7 +639,8 @@ UserState user_get_state(User *u) {
 
         assert(u);
 
-        if (u->slice_job || u->service_job)
+        if ((u->slice_job && u->slice_opening) ||
+        (u->service_job && u->service_opening))
                 return USER_OPENING;
 
         LIST_FOREACH(sessions_by_user, i, u->sessions) {
diff --git a/src/login/logind-user.h b/src/login/logind-user.h
index 0062880..ac43361 100644
--- a/src/login/logind-user.h
+++ b/src/login/logind-user.h
@@ -61,6 +61,8 @@ struct User {
 
         bool in_gc_queue:1;
         bool started:1;
+        bool service_opening:1; /* User service is being created */
+        bool slice_opening:1; /* User slice is being created */
 
         LIST_HEAD(Session, sessions);
         LIST_FIELDS(User, gc_queue);
-- 
1.8.3.1



More information about the systemd-devel mailing list