Whamcloud - gitweb
git://git.whamcloud.com
/
fs
/
lustre-release.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
| inline |
side by side
land b_hd_remote_acl: support get/set ACL from remote client.
[fs/lustre-release.git]
/
lustre
/
llite
/
llite_gns.c
diff --git
a/lustre/llite/llite_gns.c
b/lustre/llite/llite_gns.c
index
b703532
..
0b88b4e
100644
(file)
--- a/
lustre/llite/llite_gns.c
+++ b/
lustre/llite/llite_gns.c
@@
-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,16
+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);
+ 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;
}
/*
@@
-77,7
+83,6
@@
ll_gns_wait_for_mount(struct dentry *dentry,
int
ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
{
- struct ll_dentry_data *lld = dentry->d_fsdata;
char *path, *pathpage, *datapage, *argv[4];
struct file *mntinfo_fd = NULL;
int cleanup_phase = 0, rc = 0;
@@
-85,38
+90,77
@@
ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
struct dentry *dchild;
ENTRY;
+ LASSERT(dentry->d_inode != NULL);
+
+ if (!S_ISDIR(dentry->d_inode->i_mode))
+ RETURN(-EINVAL);
+
+ sbi = ll_i2sbi(dentry->d_inode);
+
if (mnt == NULL) {
CERROR("suid directory found, but no "
"vfsmount available.\n");
RETURN(-EINVAL);
}
- CDEBUG(D_INODE, "mounting dentry %p\n", dentry);
-
- LASSERT(dentry->d_inode != NULL);
- LASSERT(S_ISDIR(dentry->d_inode->i_mode));
- LASSERT(lld != NULL);
-
- sbi = ll_i2sbi(dentry->d_inode);
- LASSERT(sbi != NULL);
+ 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.
*/
- spin_lock(&sbi->ll_gns_lock);
- 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.
+ */
+ 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);
+
+ /*
+ * waiting for GNS complete and check dentry again, it may be
+ * mounted already.
+ */
+ wait_for_completion(&sbi->ll_gns_mount_finished);
+ if (d_mountpoint(dentry))
+ RETURN(0);
+
+ /*
+ * 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);
- CDEBUG(D_INODE, "GNS is in progress now, throwing "
- "-ERESTARTSYS to restart syscall and let "
- "it finish.\n");
- RETURN(-ERESTARTSYS);
}
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 */
@@
-140,22
+184,20
@@
ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
* mount object name is taken from sbi, where it is set in mount time or
* via /proc/fs... tunable. It may be ".mntinfo" or so.
*/
- dchild = lookup_one_len(sbi->ll_gns_oname, dentry,
- strlen(sbi->ll_gns_oname));
+
+ /*
+ * 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().
+ */
+ dchild = ll_lookup_one_len(sbi->ll_gns_oname, dentry,
+ strlen(sbi->ll_gns_oname));
up(&sbi->ll_gns_sem);
cleanup_phase = 2;
if (IS_ERR(dchild)) {
rc = PTR_ERR(dchild);
-
- if (rc == -ERESTARTSYS) {
- CDEBUG(D_INODE, "possible endless loop is detected "
- "due to mount object is directory marked by "
- "SUID bit.\n");
- GOTO(cleanup, rc = -ELOOP);
- }
-
CERROR("can't find mount object %*s/%*s err = %d.\n",
(int)dentry->d_name.len, dentry->d_name.name,
strlen(sbi->ll_gns_oname), sbi->ll_gns_oname,
@@
-169,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 = -E
OPNOTSUPP
);
+ GOTO(cleanup, rc = -E
BADF
);
mntget(mnt);
@@
-236,29
+278,25
@@
ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
up(&sbi->ll_gns_sem);
- rc = USERMODEHELPER(argv[0], argv, NULL);
+ /* do not wait for helper complete here. */
+ rc = call_usermodehelper(argv[0], argv, NULL, 1);
if (rc) {
- CERROR("failed to call GNS upcall %s, err = %d\n",
- sbi->ll_gns_upcall, rc);
- GOTO(cleanup, rc);
+ CWARN("failed to call GNS upcall %s, err = %d, "
+ "checking for mount anyway\n", sbi->ll_gns_upcall, rc);
}
/*
- * wait for mount completion. This is actually not needed, because
- * USERMODEHELPER() returns only when usermode process finishes. But we
- * doing this just for case USERMODEHELPER() semantics will be changed
- * or usermode upcall program will start mounting in backgound and
- * return instantly. --umka
+ * waiting for dentry become mount point GNS_WAIT_ATTEMPTS times by 1
+ * 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);
@@
-279,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);
@@
-297,16
+337,15
@@
cleanup:
dput(dchild);
case 1:
free_page((unsigned long)pathpage);
-
- /*
- * waking up all waiters after gns state is set to
- * LL_GNS_MOUNTING
- */
- 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;
}