⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 root.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		ino = list_entry(p, struct autofs_info, rehash);		dentry = ino->dentry;		spin_lock(&dentry->d_lock);		/* Bad luck, we've already been dentry_iput */		if (!dentry->d_inode)			goto next;		qstr = &dentry->d_name;		if (dentry->d_name.hash != hash)			goto next;		if (dentry->d_parent != parent)			goto next;		if (qstr->len != len)			goto next;		if (memcmp(qstr->name, str, len))			goto next;		if (d_unhashed(dentry)) {			struct autofs_info *ino = autofs4_dentry_ino(dentry);			struct inode *inode = dentry->d_inode;			list_del_init(&ino->rehash);			dget(dentry);			/*			 * Make the rehashed dentry negative so the VFS			 * behaves as it should.			 */			if (inode) {				dentry->d_inode = NULL;				list_del_init(&dentry->d_alias);				spin_unlock(&dentry->d_lock);				spin_unlock(&sbi->rehash_lock);				spin_unlock(&dcache_lock);				iput(inode);				return dentry;			}			spin_unlock(&dentry->d_lock);			spin_unlock(&sbi->rehash_lock);			spin_unlock(&dcache_lock);			return dentry;		}next:		spin_unlock(&dentry->d_lock);	}	spin_unlock(&sbi->rehash_lock);	spin_unlock(&dcache_lock);	return NULL;}/* Lookups in the root directory */static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){	struct autofs_sb_info *sbi;	struct dentry *unhashed;	int oz_mode;	DPRINTK("name = %.*s",		dentry->d_name.len, dentry->d_name.name);	/* File name too long to exist */	if (dentry->d_name.len > NAME_MAX)		return ERR_PTR(-ENAMETOOLONG);	sbi = autofs4_sbi(dir->i_sb);	oz_mode = autofs4_oz_mode(sbi);	DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",		 current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode);	unhashed = autofs4_lookup_unhashed(sbi, dentry->d_parent, &dentry->d_name);	if (!unhashed) {		/*		 * Mark the dentry incomplete but don't hash it. We do this		 * to serialize our inode creation operations (symlink and		 * mkdir) which prevents deadlock during the callback to		 * the daemon. Subsequent user space lookups for the same		 * dentry are placed on the wait queue while the daemon		 * itself is allowed passage unresticted so the create		 * operation itself can then hash the dentry. Finally,		 * we check for the hashed dentry and return the newly		 * hashed dentry.		 */		dentry->d_op = &autofs4_root_dentry_operations;		dentry->d_fsdata = NULL;		d_instantiate(dentry, NULL);	} else {		struct autofs_info *ino = autofs4_dentry_ino(unhashed);		DPRINTK("rehash %p with %p", dentry, unhashed);		/*		 * If we are racing with expire the request might not		 * be quite complete but the directory has been removed		 * so it must have been successful, so just wait for it.		 * We need to ensure the AUTOFS_INF_EXPIRING flag is clear		 * before continuing as revalidate may fail when calling		 * try_to_fill_dentry (returning EAGAIN) if we don't.		 */		while (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {			DPRINTK("wait for incomplete expire %p name=%.*s",				unhashed, unhashed->d_name.len,				unhashed->d_name.name);			autofs4_wait(sbi, unhashed, NFY_NONE);			DPRINTK("request completed");		}		dentry = unhashed;	}	if (!oz_mode) {		spin_lock(&dentry->d_lock);		dentry->d_flags |= DCACHE_AUTOFS_PENDING;		spin_unlock(&dentry->d_lock);	}	if (dentry->d_op && dentry->d_op->d_revalidate) {		mutex_unlock(&dir->i_mutex);		(dentry->d_op->d_revalidate)(dentry, nd);		mutex_lock(&dir->i_mutex);	}	/*	 * 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) {		/* See if we were interrupted */		if (signal_pending(current)) {			sigset_t *sigset = &current->pending.signal;			if (sigismember (sigset, SIGKILL) ||			    sigismember (sigset, SIGQUIT) ||			    sigismember (sigset, SIGINT)) {			    if (unhashed)				dput(unhashed);			    return ERR_PTR(-ERESTARTNOINTR);			}		}		spin_lock(&dentry->d_lock);		dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;		spin_unlock(&dentry->d_lock);	}	/*	 * If this dentry is unhashed, then we shouldn't honour this	 * lookup.  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 (!oz_mode && d_unhashed(dentry)) {		/*		 * A user space application can (and has done in the past)		 * remove and re-create this directory during the callback.		 * This can leave us with an unhashed dentry, but a		 * successful mount!  So we need to perform another		 * cached lookup in case the dentry now exists.		 */		struct dentry *parent = dentry->d_parent;		struct dentry *new = d_lookup(parent, &dentry->d_name);		if (new != NULL)			dentry = new;		else			dentry = ERR_PTR(-ENOENT);		if (unhashed)			dput(unhashed);		return dentry;	}	if (unhashed)		return dentry;	return NULL;}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 autofs_info *p_ino;	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_add(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);	atomic_inc(&ino->count);	p_ino = autofs4_dentry_ino(dentry->d_parent);	if (p_ino && dentry->d_parent != dentry)		atomic_inc(&p_ino->count);	ino->inode = inode;	dir->i_mtime = CURRENT_TIME;	return 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 the unlink is probably the result of an expire. * We simply d_drop it and add it to a rehash candidates list in the * super block, which allows the dentry lookup to reuse it retaining * the flags, such as expire in progress, in case we're racing with expire. * * 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);	struct autofs_info *p_ino;		/* This allows root to remove symlinks */	if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))		return -EACCES;	if (atomic_dec_and_test(&ino->count)) {		p_ino = autofs4_dentry_ino(dentry->d_parent);		if (p_ino && dentry->d_parent != dentry)			atomic_dec(&p_ino->count);	}	dput(ino->dentry);	dentry->d_inode->i_size = 0;	clear_nlink(dentry->d_inode);	dir->i_mtime = CURRENT_TIME;	spin_lock(&dcache_lock);	spin_lock(&sbi->rehash_lock);	list_add(&ino->rehash, &sbi->rehash_list);	spin_unlock(&sbi->rehash_lock);	spin_lock(&dentry->d_lock);	__d_drop(dentry);	spin_unlock(&dentry->d_lock);	spin_unlock(&dcache_lock);	return 0;}static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry){	struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);	struct autofs_info *ino = autofs4_dentry_ino(dentry);	struct autofs_info *p_ino;		DPRINTK("dentry %p, removing %.*s",		dentry, dentry->d_name.len, dentry->d_name.name);	if (!autofs4_oz_mode(sbi))		return -EACCES;	spin_lock(&dcache_lock);	if (!list_empty(&dentry->d_subdirs)) {		spin_unlock(&dcache_lock);		return -ENOTEMPTY;	}	spin_lock(&sbi->rehash_lock);	list_add(&ino->rehash, &sbi->rehash_list);	spin_unlock(&sbi->rehash_lock);	spin_lock(&dentry->d_lock);	__d_drop(dentry);	spin_unlock(&dentry->d_lock);	spin_unlock(&dcache_lock);	if (atomic_dec_and_test(&ino->count)) {		p_ino = autofs4_dentry_ino(dentry->d_parent);		if (p_ino && dentry->d_parent != dentry)			atomic_dec(&p_ino->count);	}	dput(ino->dentry);	dentry->d_inode->i_size = 0;	clear_nlink(dentry->d_inode);	if (dir->i_nlink)		drop_nlink(dir);	return 0;}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 autofs_info *p_ino;	struct inode *inode;	if (!autofs4_oz_mode(sbi))		return -EACCES;	DPRINTK("dentry %p, creating %.*s",		dentry, dentry->d_name.len, dentry->d_name.name);	ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555);	if (ino == NULL)		return -ENOSPC;	inode = autofs4_get_inode(dir->i_sb, ino);	d_add(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);	atomic_inc(&ino->count);	p_ino = autofs4_dentry_ino(dentry->d_parent);	if (p_ino && dentry->d_parent != dentry)		atomic_inc(&p_ino->count);	ino->inode = inode;	inc_nlink(dir);	dir->i_mtime = CURRENT_TIME;	return 0;}/* Get/set timeout ioctl() operation */static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi,					 unsigned long __user *p){	int rv;	unsigned long ntimeout;	if ((rv = get_user(ntimeout, p)) ||	     (rv = put_user(sbi->exp_timeout/HZ, p)))		return rv;	if (ntimeout > ULONG_MAX/HZ)		sbi->exp_timeout = 0;	else		sbi->exp_timeout = ntimeout * HZ;	return 0;}/* Return protocol version */static inline int autofs4_get_protover(struct autofs_sb_info *sbi, int __user *p){	return put_user(sbi->version, p);}/* Return protocol sub version */static inline int autofs4_get_protosubver(struct autofs_sb_info *sbi, int __user *p){	return put_user(sbi->sub_version, p);}/* * Tells the daemon whether we need to reghost or not. Also, clears * the reghost_needed flag. */static inline int autofs4_ask_reghost(struct autofs_sb_info *sbi, int __user *p){	int status;	DPRINTK("returning %d", sbi->needs_reghost);	status = put_user(sbi->needs_reghost, p);	if (status)		return status;	sbi->needs_reghost = 0;	return 0;}/* * Enable / Disable reghosting ioctl() operation */static inline int autofs4_toggle_reghost(struct autofs_sb_info *sbi, int __user *p){	int status;	int val;	status = get_user(val, p);	DPRINTK("reghost = %d", val);	if (status)		return status;	/* turn on/off reghosting, with the val */	sbi->reghost_enabled = val;	return 0;}/** Tells the daemon whether it can umount the autofs mount.*/static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p){	int status = 0;	if (may_umount(mnt))		status = 1;	DPRINTK("returning %d", status);	status = put_user(status, p);	return status;}/* Identify autofs4_dentries - this is so we can tell if there's   an extra dentry refcount or not.  We only hold a refcount on the   dentry if its non-negative (ie, d_inode != NULL)*/int is_autofs4_dentry(struct dentry *dentry){	return dentry && dentry->d_inode &&		(dentry->d_op == &autofs4_root_dentry_operations ||		 dentry->d_op == &autofs4_dentry_operations) &&		dentry->d_fsdata != NULL;}/* * 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);	void __user *p = (void __user *)arg;	DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u",		cmd,arg,sbi,task_pgrp_nr(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, p);	case AUTOFS_IOC_PROTOSUBVER: /* Get protocol sub version */		return autofs4_get_protosubver(sbi, p);	case AUTOFS_IOC_SETTIMEOUT:		return autofs4_get_set_timeout(sbi, p);	case AUTOFS_IOC_TOGGLEREGHOST:		return autofs4_toggle_reghost(sbi, p);	case AUTOFS_IOC_ASKREGHOST:		return autofs4_ask_reghost(sbi, p);	case AUTOFS_IOC_ASKUMOUNT:		return autofs4_ask_umount(filp->f_path.mnt, p);	/* return a single thing to expire */	case AUTOFS_IOC_EXPIRE:		return autofs4_expire_run(inode->i_sb,filp->f_path.mnt,sbi, p);	/* same as above, but can send multiple expires through pipe */	case AUTOFS_IOC_EXPIRE_MULTI:		return autofs4_expire_multi(inode->i_sb,filp->f_path.mnt,sbi, p);	default:		return -ENOSYS;	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -