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
add a branch and its table named "b_iam" for "Index API Module" from #colibri
[fs/lustre-release.git]
/
lustre
/
llite
/
llite_gns.c
diff --git
a/lustre/llite/llite_gns.c
b/lustre/llite/llite_gns.c
index
0e37b51
..
d9affef
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,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;
}
/*
@@
-95,11
+83,11
@@
ll_gns_send_signal(void)
int
ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
{
- char *path, *pathpage, *datapage, *argv[4];
+ char *path, *pathpage, *datapage
= NULL
, *argv[4];
struct file *mntinfo_fd = NULL;
int cleanup_phase = 0, rc = 0;
struct ll_sb_info *sbi;
- struct dentry *dchild;
+ struct dentry *dchild
= NULL
;
ENTRY;
LASSERT(dentry->d_inode != NULL);
@@
-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 */
@@
-173,8
+173,8
@@
ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
path = d_path(dentry, mnt, pathpage, PAGE_SIZE);
if (IS_ERR(path)) {
CERROR("can't build mount object path, err %d\n",
- (int)PTR_ERR(
dchild
));
- GOTO(cleanup, rc = PTR_ERR(
dchild
));
+ (int)PTR_ERR(
path
));
+ GOTO(cleanup, rc = PTR_ERR(
path
));
}
/* synchronizing with possible /proc/fs/...write */
@@
-188,15
+188,12
@@
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));
up(&sbi->ll_gns_sem);
- cleanup_phase = 2;
-
if (IS_ERR(dchild)) {
rc = PTR_ERR(dchild);
CERROR("can't find mount object %*s/%*s err = %d.\n",
@@
-207,26
+204,39
@@
ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
}
/* mount object is not found */
- if (!dchild->d_inode)
+ if (!dchild->d_inode) {
+ dput(dchild);
GOTO(cleanup, rc = -ENOENT);
+ }
/* check if found child is regular file */
- if (!S_ISREG(dchild->d_inode->i_mode))
-
GOTO(cleanup, rc = -EOPNOTSUPP
);
-
- mntget(mnt);
+ if (!S_ISREG(dchild->d_inode->i_mode))
{
+
dput(dchild
);
+ GOTO(cleanup, rc = -EBADF);
+ }
/* ok, mount object if found, opening it. */
- mntinfo_fd = dentry_open(dchild, mnt, 0);
+ mntinfo_fd = dentry_open(dchild, mnt
get(mnt)
, 0);
if (IS_ERR(mntinfo_fd)) {
CERROR("can't open 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,
(int)PTR_ERR(mntinfo_fd));
mntput(mnt);
+ dput(dchild);
GOTO(cleanup, rc = PTR_ERR(mntinfo_fd));
}
- cleanup_phase = 3;
+ cleanup_phase = 2;
+
+ /* make sure that inode size is up-to-date */
+ rc = ll_inode_revalidate_it(mntinfo_fd->f_dentry);
+ if (rc < 0) {
+ CERROR("can't revalidate 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,
+ rc);
+ GOTO(cleanup, rc);
+ }
if (mntinfo_fd->f_dentry->d_inode->i_size > PAGE_SIZE - 1) {
CERROR("mount object %*s/%*s is too big (%Ld)\n",
@@
-240,7
+250,7
@@
ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
if (!datapage)
GOTO(cleanup, rc = -ENOMEM);
- cleanup_phase =
4
;
+ cleanup_phase =
3
;
/* read data from mount object. */
rc = kernel_read(mntinfo_fd, 0, datapage, PAGE_SIZE - 1);
@@
-280,7
+290,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
+301,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
+328,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);
@@
-327,21
+338,24
@@
ll_gns_mount_object(struct dentry *dentry, struct vfsmount *mnt)
EXIT;
cleanup:
switch (cleanup_phase) {
- case 4:
- free_page((unsigned long)datapage);
case 3:
- if (mntinfo_fd != NULL)
- fput(mntinfo_fd);
+ free_page((unsigned long)datapage);
case 2:
- if (dchild != NULL)
- dput(dchild);
+ if (mntinfo_fd != NULL) {
+ fput(mntinfo_fd);
+ dchild = NULL;
+ }
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;
}
@@
-449,7
+463,7
@@
static int inline ll_gns_check_stop(void)
}
/* GNS control thread function. */
-static int ll_gns_thread
_main
(void *arg)
+static int ll_gns_thread(void *arg)
{
struct ll_gns_ctl *ctl = arg;
unsigned long flags;
@@
-518,7
+532,7
@@
void ll_gns_del_timer(struct ll_sb_info *sbi)
* starts GNS control thread and waits for a signal it is up and work may be
* continued.
*/
-int ll_gns_
start_thread
(void)
+int ll_gns_
thread_start
(void)
{
int rc;
ENTRY;
@@
-528,7
+542,7
@@
int ll_gns_start_thread(void)
init_completion(&gns_ctl.gc_finishing);
init_waitqueue_head(&gns_thread.t_ctl_waitq);
- rc = kernel_thread(ll_gns_thread
_main
, &gns_ctl,
+ rc = kernel_thread(ll_gns_thread, &gns_ctl,
(CLONE_VM | CLONE_FILES));
if (rc < 0) {
CERROR("cannot start GNS control thread, "
@@
-541,7
+555,7
@@
int ll_gns_start_thread(void)
}
/* stops GNS control thread and waits its actual stop. */
-void ll_gns_
stop_thread
(void)
+void ll_gns_
thread_stop
(void)
{
ENTRY;
gns_thread.t_flags = SVC_STOPPING;