Whamcloud - gitweb
land b_hd_remote_acl: support get/set ACL from remote client.
[fs/lustre-release.git] / lustre / llite / llite_gns.c
index 0e37b51..0b88b4e 100644 (file)
@@ -50,6 +50,7 @@ ll_gns_wait_for_mount(struct dentry *dentry,
 {
         struct l_wait_info lwi;
         struct ll_sb_info *sbi;
+       int rc = 0;
         ENTRY;
 
         LASSERT(dentry != NULL);
@@ -57,34 +58,21 @@ ll_gns_wait_for_mount(struct dentry *dentry,
         sbi = ll_s2sbi(dentry->d_sb);
         
         lwi = LWI_TIMEOUT(timeout * HZ, NULL, NULL);
-        for (; !d_mountpoint(dentry) && tries > 0; tries--)
+        for (; !d_mountpoint(dentry) && tries > 0; tries--) {
                 l_wait_event(sbi->ll_gns_waitq, d_mountpoint(dentry), &lwi);
-
-        if (d_mountpoint(dentry)) {
-                spin_lock(&sbi->ll_gns_lock);
-                sbi->ll_gns_state = LL_GNS_FINISHED;
-                spin_unlock(&sbi->ll_gns_lock);
-                RETURN(0);
-        }
-        RETURN(-ETIME);
-}
-
-/* 
- * sending a signal known to be ignored to cause restarting syscall if GNS mount
- * function returns -ERESTARTSYS.
- */
-static void
-ll_gns_send_signal(void)
-{
-        struct task_struct *task = current;
-        int signal = SIGCONT;
-
-        read_lock(&tasklist_lock);
-        spin_lock_irq(&task->sighand->siglock);
-        sigaddset(&task->pending.signal, signal);
-        spin_unlock_irq(&task->sighand->siglock);
-        read_unlock(&tasklist_lock);
-        set_tsk_thread_flag(task, TIF_SIGPENDING);
+               if (signal_pending(current))
+                       GOTO(out, rc = -EINTR);
+       }
+
+        if (!d_mountpoint(dentry))
+               rc = -ETIME;
+       
+       EXIT;
+out:   
+        spin_lock(&sbi->ll_gns_lock);
+        sbi->ll_gns_state = LL_GNS_FINISHED;
+        spin_unlock(&sbi->ll_gns_lock);
+        return rc;
 }
 
 /*
@@ -108,14 +96,6 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
                 RETURN(-EINVAL);
 
         sbi = ll_i2sbi(dentry->d_inode);
-        LASSERT(sbi != NULL);
-
-        spin_lock(&sbi->ll_gns_lock);
-
-        if (sbi->ll_gns_state == LL_GNS_DISABLED) {
-                spin_unlock(&sbi->ll_gns_lock);
-                RETURN(-EINVAL);
-        }
         
         if (mnt == NULL) {
                 CERROR("suid directory found, but no "
@@ -123,18 +103,23 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
                 RETURN(-EINVAL);
         }
 
+        if (atomic_read(&sbi->ll_gns_enabled) == 0)
+                RETURN(-EINVAL);
+
+        spin_lock(&sbi->ll_gns_lock);
+       
         /* 
          * another thead is in progress or just finished mounting the
          * dentry. Handling that.
          */
-        if (sbi->ll_gns_state == LL_GNS_MOUNTING ||
-            sbi->ll_gns_state == LL_GNS_FINISHED) {
+        if (sbi->ll_gns_state != LL_GNS_IDLE) {
                 /* 
                  * another thread is trying to mount GNS dentry. We'd like to
                  * handling that.
                  */
                 spin_unlock(&sbi->ll_gns_lock);
 
+        restart:
                 /* 
                  * check if dentry is mount point already, if so, do not restart
                  * syscal.
@@ -142,25 +127,40 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
                 if (d_mountpoint(dentry))
                         RETURN(0);
 
+                spin_lock(&sbi->ll_gns_lock);
+               if (sbi->ll_gns_pending_dentry && 
+                   is_subdir(sbi->ll_gns_pending_dentry, dentry)) {
+                       spin_unlock(&sbi->ll_gns_lock);
+                       RETURN(-EAGAIN);
+               }
+                spin_unlock(&sbi->ll_gns_lock);
+
                 /* 
-                 * causing syscall to restart and find this dentry already
-                 * mounted.
+                 * waiting for GNS complete and check dentry again, it may be
+                 * mounted already.
                  */
-                ll_gns_send_signal();
-                RETURN(-ERESTARTSYS);
-
-#if 0
                 wait_for_completion(&sbi->ll_gns_mount_finished);
                 if (d_mountpoint(dentry))
                         RETURN(0);
-#endif
+
+                /* 
+                 * check for he case when there are few waiters and all they are
+                 * awakened, but only one will find GNS state LL_GNS_IDLE, and
+                 * the rest will face with LL_GNS_MOUNTING.  --umka
+                 */
+                spin_lock(&sbi->ll_gns_lock);
+                if (sbi->ll_gns_state != LL_GNS_IDLE) {
+                        spin_unlock(&sbi->ll_gns_lock);
+                        goto restart;
+                }
+                spin_unlock(&sbi->ll_gns_lock);
         }
         LASSERT(sbi->ll_gns_state == LL_GNS_IDLE);
-
         CDEBUG(D_INODE, "mounting dentry %p\n", dentry);
 
         /* mounting started */
         sbi->ll_gns_state = LL_GNS_MOUNTING;
+       sbi->ll_gns_pending_dentry = dentry;
         spin_unlock(&sbi->ll_gns_lock);
 
         /* we need to build an absolute pathname to pass to mount */
@@ -188,8 +188,7 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
         /* 
          * recursive lookup with trying to mount SUID bit marked directories on
          * the way is not possible here, as lookup_one_len() does not pass @nd
-         * to ->lookup() and this is checked in ll_lookup_it(). So, do not
-         * handle possible -EAGAIN here.
+         * to ->lookup() and this is checked in ll_lookup_it().
          */
         dchild = ll_lookup_one_len(sbi->ll_gns_oname, dentry,
                                    strlen(sbi->ll_gns_oname));
@@ -212,7 +211,7 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
 
         /* check if found child is regular file */
         if (!S_ISREG(dchild->d_inode->i_mode))
-                GOTO(cleanup, rc = -EOPNOTSUPP);
+                GOTO(cleanup, rc = -EBADF);
 
         mntget(mnt);
 
@@ -280,7 +279,7 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
         up(&sbi->ll_gns_sem);
 
         /* do not wait for helper complete here. */
-        rc = call_usermodehelper(argv[0], argv, NULL, 0);
+        rc = call_usermodehelper(argv[0], argv, NULL, 1);
         if (rc) {
                 CWARN("failed to call GNS upcall %s, err = %d, "
                       "checking for mount anyway\n", sbi->ll_gns_upcall, rc);
@@ -291,14 +290,13 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
          * second.
          */
         rc = ll_gns_wait_for_mount(dentry, 1, GNS_WAIT_ATTEMPTS);
-        complete_all(&sbi->ll_gns_mount_finished);
-        if (rc == 0) {
+        LASSERT(sbi->ll_gns_state == LL_GNS_FINISHED);
+       
+       /* checking for mount point anyway to not loss mounts */
+        if (d_mountpoint(dentry)) {
                 struct dentry *rdentry;
                 struct vfsmount *rmnt;
-                
-                /* mount is successful */
-                LASSERT(sbi->ll_gns_state == LL_GNS_FINISHED);
-
+               
                 rmnt = mntget(mnt);
                 rdentry = dget(dentry);
                 
@@ -319,6 +317,8 @@ ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
                         mntput(mnt);
                         dput(dentry);
                 }
+               
+               rc = 0;
         } else {
                 CERROR("usermode upcall %s failed to mount %s, err %d\n",
                        sbi->ll_gns_upcall, path, rc);
@@ -337,11 +337,15 @@ cleanup:
                         dput(dchild);
         case 1:
                 free_page((unsigned long)pathpage);
-                complete_all(&sbi->ll_gns_mount_finished);
         case 0:
                 spin_lock(&sbi->ll_gns_lock);
                 sbi->ll_gns_state = LL_GNS_IDLE;
+               sbi->ll_gns_pending_dentry = NULL;
                 spin_unlock(&sbi->ll_gns_lock);
+
+                /* waking up all waiters after GNS state is LL_GNS_IDLE */
+                complete_all(&sbi->ll_gns_mount_finished);
+                init_completion(&sbi->ll_gns_mount_finished);
         }
         return rc;
 }