예제 #1
0
static const char *autofs4_get_link(struct dentry *dentry,
				    struct inode *inode,
				    struct delayed_call *done)
{
	struct autofs_sb_info *sbi;
	struct autofs_info *ino;

	if (!dentry)
		return ERR_PTR(-ECHILD);
	sbi = autofs4_sbi(dentry->d_sb);
	ino = autofs4_dentry_ino(dentry);
	if (ino && !autofs4_oz_mode(sbi))
		ino->last_used = jiffies;
	return d_inode(dentry)->i_private;
}
예제 #2
0
static int autofs4_dir_symlink(struct inode *dir,
                               struct dentry *dentry,
                               const char *symname)
{
    struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
    struct autofs_info *ino = autofs4_dentry_ino(dentry);
    struct inode *inode;
    char *cp;

    DPRINTK("%s <- %.*s", symname,
            dentry->d_name.len, dentry->d_name.name);

    if (!autofs4_oz_mode(sbi))
        return -EACCES;

    ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555);
    if (ino == NULL)
        return -ENOSPC;

    ino->size = strlen(symname);
    ino->u.symlink = cp = kmalloc(ino->size + 1, GFP_KERNEL);

    if (cp == NULL) {
        kfree(ino);
        return -ENOSPC;
    }

    strcpy(cp, symname);

    inode = autofs4_get_inode(dir->i_sb, ino);
    d_instantiate(dentry, inode);

    if (dir == dir->i_sb->s_root->d_inode)
        dentry->d_op = &autofs4_root_dentry_operations;
    else
        dentry->d_op = &autofs4_dentry_operations;

    dentry->d_fsdata = ino;
    ino->dentry = dget(dentry);
    ino->inode = inode;

    dir->i_mtime = CURRENT_TIME;

    return 0;
}
예제 #3
0
/*
 * NOTE!
 *
 * Normal filesystems would do a "d_delete()" to tell the VFS dcache
 * that the file no longer exists. However, doing that means that the
 * VFS layer can turn the dentry into a negative dentry.  We don't want
 * this, because since the unlink is probably the result of an expire.
 * We simply d_drop it, which allows the dentry lookup to remount it
 * if necessary.
 *
 * If a process is blocked on the dentry waiting for the expire to finish,
 * it will invalidate the dentry and try to mount with a new one.
 *
 * Also see autofs4_dir_rmdir()..
 */
static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
{
    struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
    struct autofs_info *ino = autofs4_dentry_ino(dentry);

    /* This allows root to remove symlinks */
    if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
        return -EACCES;

    dput(ino->dentry);

    dentry->d_inode->i_size = 0;
    dentry->d_inode->i_nlink = 0;

    dir->i_mtime = CURRENT_TIME;

    d_drop(dentry);

    return 0;
}
예제 #4
0
파일: root.c 프로젝트: xricson/knoppix
/*
 * ioctl()'s on the root directory is the chief method for the daemon to
 * generate kernel reactions
 */
static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
			     unsigned int cmd, unsigned long arg)
{
	struct autofs_sb_info *sbi = autofs4_sbi(inode->i_sb);

	DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",
		 cmd,arg,sbi,process_group(current)));

	if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
	     _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
		return -ENOTTY;
	
	if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
		return -EPERM;
	
	switch(cmd) {
	case AUTOFS_IOC_READY:	/* Wait queue: go ahead and retry */
		return autofs4_wait_release(sbi,(autofs_wqt_t)arg,0);
	case AUTOFS_IOC_FAIL:	/* Wait queue: fail with ENOENT */
		return autofs4_wait_release(sbi,(autofs_wqt_t)arg,-ENOENT);
	case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */
		autofs4_catatonic_mode(sbi);
		return 0;
	case AUTOFS_IOC_PROTOVER: /* Get protocol version */
		return autofs4_get_protover(sbi, (int *)arg);
	case AUTOFS_IOC_SETTIMEOUT:
		return autofs4_get_set_timeout(sbi,(unsigned long *)arg);

	/* return a single thing to expire */
	case AUTOFS_IOC_EXPIRE:
		return autofs4_expire_run(inode->i_sb,filp->f_vfsmnt,sbi,
					  (struct autofs_packet_expire *)arg);
	/* same as above, but can send multiple expires through pipe */
	case AUTOFS_IOC_EXPIRE_MULTI:
		return autofs4_expire_multi(inode->i_sb,filp->f_vfsmnt,sbi,
					    (int *)arg);

	default:
		return -ENOSYS;
	}
}
예제 #5
0
static int autofs4_root_readdir(struct file *file, void *dirent,
                                filldir_t filldir)
{
    struct autofs_sb_info *sbi = autofs4_sbi(file->f_dentry->d_sb);
    int oz_mode = autofs4_oz_mode(sbi);

    DPRINTK("called, filp->f_pos = %lld", file->f_pos);

    /*
     * Don't set reghost flag if:
     * 1) f_pos is larger than zero -- we've already been here.
     * 2) we haven't even enabled reghosting in the 1st place.
     * 3) this is the daemon doing a readdir
     */
    if (oz_mode && file->f_pos == 0 && sbi->reghost_enabled)
        sbi->needs_reghost = 1;

    DPRINTK("needs_reghost = %d", sbi->needs_reghost);

    return autofs4_dcache_readdir(file, dirent, filldir);
}
예제 #6
0
/*
 * Revalidate is called on every cache lookup.  Some of those
 * cache lookups may actually happen while the dentry is not
 * yet completely filled in, and revalidate has to delay such
 * lookups..
 */
static int autofs4_revalidate(struct dentry * dentry, struct nameidata *nd)
{
    struct inode * dir = dentry->d_parent->d_inode;
    struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
    int oz_mode = autofs4_oz_mode(sbi);
    int flags = nd ? nd->flags : 0;
    int status = 1;

    /* Pending dentry */
    if (autofs4_ispending(dentry)) {
        if (!oz_mode)
            status = try_to_fill_dentry(dentry, dir->i_sb, sbi, flags);
        return status;
    }

    /* Negative dentry.. invalidate if "old" */
    if (dentry->d_inode == NULL)
        return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);

    /* Check for a non-mountpoint directory with no contents */
    spin_lock(&dcache_lock);
    if (S_ISDIR(dentry->d_inode->i_mode) &&
            !d_mountpoint(dentry) &&
            list_empty(&dentry->d_subdirs)) {
        DPRINTK("dentry=%p %.*s, emptydir",
                dentry, dentry->d_name.len, dentry->d_name.name);
        spin_unlock(&dcache_lock);
        if (!oz_mode)
            status = try_to_fill_dentry(dentry, dir->i_sb, sbi, flags);
        return status;
    }
    spin_unlock(&dcache_lock);

    /* Update the usage list */
    if (!oz_mode)
        autofs4_update_usage(dentry);

    return 1;
}
예제 #7
0
파일: root.c 프로젝트: xricson/knoppix
static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
	struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
	struct autofs_info *ino = autofs4_dentry_ino(dentry);
	struct inode *inode;

	lock_kernel();
	if ( !autofs4_oz_mode(sbi) ) {
		unlock_kernel();
		return -EACCES;
	}

	DPRINTK(("autofs_dir_mkdir: dentry %p, creating %.*s\n",
		 dentry, dentry->d_name.len, dentry->d_name.name));

	ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555);
	if (ino == NULL) {
		unlock_kernel();
		return -ENOSPC;
	}

	inode = autofs4_get_inode(dir->i_sb, ino);
	d_instantiate(dentry, inode);

	if (dir == dir->i_sb->s_root->d_inode)
		dentry->d_op = &autofs4_root_dentry_operations;
	else
		dentry->d_op = &autofs4_dentry_operations;

	dentry->d_fsdata = ino;
	ino->dentry = dget(dentry);
	ino->inode = inode;
	dir->i_nlink++;
	dir->i_mtime = CURRENT_TIME;

	unlock_kernel();
	return 0;
}
예제 #8
0
/* ioctl dispatcher */
static int _autofs_dev_ioctl(unsigned int command, struct autofs_dev_ioctl __user *user)
{
	struct autofs_dev_ioctl *param;
	struct file *fp;
	struct autofs_sb_info *sbi;
	unsigned int cmd_first, cmd;
	ioctl_fn fn = NULL;
	int err = 0;

	/* only root can play with this */
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	cmd_first = _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST);
	cmd = _IOC_NR(command);

	if (_IOC_TYPE(command) != _IOC_TYPE(AUTOFS_DEV_IOCTL_IOC_FIRST) ||
	    cmd - cmd_first >= AUTOFS_DEV_IOCTL_IOC_COUNT) {
		return -ENOTTY;
	}

	/* Copy the parameters into kernel space. */
	param = copy_dev_ioctl(user);
	if (IS_ERR(param))
		return PTR_ERR(param);

	err = validate_dev_ioctl(command, param);
	if (err)
		goto out;

	/* The validate routine above always sets the version */
	if (cmd == AUTOFS_DEV_IOCTL_VERSION_CMD)
		goto done;

	fn = lookup_dev_ioctl(cmd);
	if (!fn) {
		AUTOFS_WARN("unknown command 0x%08x", command);
		return -ENOTTY;
	}

	fp = NULL;
	sbi = NULL;

	/*
	 * For obvious reasons the openmount can't have a file
	 * descriptor yet. We don't take a reference to the
	 * file during close to allow for immediate release.
	 */
	if (cmd != AUTOFS_DEV_IOCTL_OPENMOUNT_CMD &&
	    cmd != AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD) {
		fp = fget(param->ioctlfd);
		if (!fp) {
			if (cmd == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD)
				goto cont;
			err = -EBADF;
			goto out;
		}

		if (!fp->f_op) {
			err = -ENOTTY;
			fput(fp);
			goto out;
		}

		sbi = autofs_dev_ioctl_sbi(fp);
		if (!sbi || sbi->magic != AUTOFS_SBI_MAGIC) {
			err = -EINVAL;
			fput(fp);
			goto out;
		}

		/*
		 * Admin needs to be able to set the mount catatonic in
		 * order to be able to perform the re-open.
		 */
		if (!autofs4_oz_mode(sbi) &&
		    cmd != AUTOFS_DEV_IOCTL_CATATONIC_CMD) {
			err = -EACCES;
			fput(fp);
			goto out;
		}
	}
cont:
	err = fn(fp, sbi, param);

	if (fp)
		fput(fp);
done:
	if (err >= 0 && copy_to_user(user, param, AUTOFS_DEV_IOCTL_SIZE))
		err = -EFAULT;
out:
	free_dev_ioctl(param);
	return err;
}
예제 #9
0
파일: root.c 프로젝트: xricson/knoppix
static int try_to_fill_dentry(struct dentry *dentry, 
			      struct super_block *sb,
			      struct autofs_sb_info *sbi)
{
	struct autofs_info *de_info = autofs4_dentry_ino(dentry);
	int status = 0;

	/* Block on any pending expiry here; invalidate the dentry
           when expiration is done to trigger mount request with a new
           dentry */
	if (de_info && (de_info->flags & AUTOFS_INF_EXPIRING)) {
		DPRINTK(("try_to_fill_entry: waiting for expire %p name=%.*s, flags&PENDING=%s de_info=%p de_info->flags=%x\n",
			 dentry, dentry->d_name.len, dentry->d_name.name, 
			 dentry->d_flags & DCACHE_AUTOFS_PENDING?"t":"f",
			 de_info, de_info?de_info->flags:0));
		status = autofs4_wait(sbi, &dentry->d_name, NFY_NONE);
		
		DPRINTK(("try_to_fill_entry: expire done status=%d\n", status));
		
		return 0;
	}

	DPRINTK(("try_to_fill_entry: dentry=%p %.*s ino=%p\n", 
		 dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode));

	/* Wait for a pending mount, triggering one if there isn't one already */
	while(dentry->d_inode == NULL) {
		DPRINTK(("try_to_fill_entry: waiting for mount name=%.*s, de_info=%p de_info->flags=%x\n",
			 dentry->d_name.len, dentry->d_name.name, 
			 de_info, de_info?de_info->flags:0));
		status = autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT);
		 
		DPRINTK(("try_to_fill_entry: mount done status=%d\n", status));

		if (status && dentry->d_inode)
			return 0; /* Try to get the kernel to invalidate this dentry */
		
		/* Turn this into a real negative dentry? */
		if (status == -ENOENT) {
			dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
			dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
			return 1;
		} else if (status) {
			/* Return a negative dentry, but leave it "pending" */
			return 1;
		}
	}

	/* If this is an unused directory that isn't a mount point,
	   bitch at the daemon and fix it in user space */
	spin_lock(&dcache_lock);
	if (S_ISDIR(dentry->d_inode->i_mode) &&
	    !d_mountpoint(dentry) && 
	    list_empty(&dentry->d_subdirs)) {
		DPRINTK(("try_to_fill_entry: mounting existing dir\n"));
		spin_unlock(&dcache_lock);
		return autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT) == 0;
	}
	spin_unlock(&dcache_lock);

	/* We don't update the usages for the autofs daemon itself, this
	   is necessary for recursive autofs mounts */
	if (!autofs4_oz_mode(sbi))
		autofs4_update_usage(dentry);

	dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
	return 1;
}
예제 #10
0
파일: root.c 프로젝트: xricson/knoppix
/* Lookups in the root directory */
static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
	struct autofs_sb_info *sbi;
	int oz_mode;

	DPRINTK(("autofs_root_lookup: name = %.*s\n", 
		 dentry->d_name.len, dentry->d_name.name));

	if (dentry->d_name.len > NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */

	sbi = autofs4_sbi(dir->i_sb);

	lock_kernel();
	oz_mode = autofs4_oz_mode(sbi);
	DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n",
		 current->pid, process_group(current), sbi->catatonic, oz_mode));

	/*
	 * Mark the dentry incomplete, but add it. This is needed so
	 * that the VFS layer knows about the dentry, and we can count
	 * on catching any lookups through the revalidate.
	 *
	 * Let all the hard work be done by the revalidate function that
	 * needs to be able to do this anyway..
	 *
	 * We need to do this before we release the directory semaphore.
	 */
	dentry->d_op = &autofs4_root_dentry_operations;

	if (!oz_mode)
		dentry->d_flags |= DCACHE_AUTOFS_PENDING;
	dentry->d_fsdata = NULL;
	d_add(dentry, NULL);

	if (dentry->d_op && dentry->d_op->d_revalidate) {
		up(&dir->i_sem);
		(dentry->d_op->d_revalidate)(dentry, nd);
		down(&dir->i_sem);
	}

	/*
	 * If we are still pending, check if we had to handle
	 * a signal. If so we can force a restart..
	 */
	if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
		if (signal_pending(current)) {
			unlock_kernel();
			return ERR_PTR(-ERESTARTNOINTR);
		}
	}
	unlock_kernel();

	/*
	 * If this dentry is unhashed, then we shouldn't honour this
	 * lookup even if the dentry is positive.  Returning ENOENT here
	 * doesn't do the right thing for all system calls, but it should
	 * be OK for the operations we permit from an autofs.
	 */
	if ( dentry->d_inode && d_unhashed(dentry) )
		return ERR_PTR(-ENOENT);

	return NULL;
}
예제 #11
0
static int try_to_fill_dentry(struct dentry *dentry,
                              struct super_block *sb,
                              struct autofs_sb_info *sbi, int flags)
{
    struct autofs_info *de_info = autofs4_dentry_ino(dentry);
    int status = 0;

    /* Block on any pending expiry here; invalidate the dentry
           when expiration is done to trigger mount request with a new
           dentry */
    if (de_info && (de_info->flags & AUTOFS_INF_EXPIRING)) {
        DPRINTK("waiting for expire %p name=%.*s",
                dentry, dentry->d_name.len, dentry->d_name.name);

        status = autofs4_wait(sbi, dentry, NFY_NONE);

        DPRINTK("expire done status=%d", status);

        return 0;
    }

    DPRINTK("dentry=%p %.*s ino=%p",
            dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);

    /* Wait for a pending mount, triggering one if there isn't one already */
    if (dentry->d_inode == NULL) {
        DPRINTK("waiting for mount name=%.*s",
                dentry->d_name.len, dentry->d_name.name);

        status = autofs4_wait(sbi, dentry, NFY_MOUNT);

        DPRINTK("mount done status=%d", status);

        if (status && dentry->d_inode)
            return 0; /* Try to get the kernel to invalidate this dentry */

        /* Turn this into a real negative dentry? */
        if (status == -ENOENT) {
            dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
            spin_lock(&dentry->d_lock);
            dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
            spin_unlock(&dentry->d_lock);
            return 1;
        } else if (status) {
            /* Return a negative dentry, but leave it "pending" */
            return 1;
        }
        /* Trigger mount for path component or follow link */
    } else if (flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) ||
               current->link_count) {
        DPRINTK("waiting for mount name=%.*s",
                dentry->d_name.len, dentry->d_name.name);

        spin_lock(&dentry->d_lock);
        dentry->d_flags |= DCACHE_AUTOFS_PENDING;
        spin_unlock(&dentry->d_lock);
        status = autofs4_wait(sbi, dentry, NFY_MOUNT);

        DPRINTK("mount done status=%d", status);

        if (status) {
            spin_lock(&dentry->d_lock);
            dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
            spin_unlock(&dentry->d_lock);
            return 0;
        }
    }

    /* We don't update the usages for the autofs daemon itself, this
       is necessary for recursive autofs mounts */
    if (!autofs4_oz_mode(sbi))
        autofs4_update_usage(dentry);

    spin_lock(&dentry->d_lock);
    dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
    spin_unlock(&dentry->d_lock);
    return 1;
}