Example #1
0
static int
zpl_rmdir(struct inode * dir, struct dentry *dentry)
{
	cred_t *cr = CRED();
	int error;
	fstrans_cookie_t cookie;
	zfs_sb_t *zsb = dentry->d_sb->s_fs_info;

	crhold(cr);
	cookie = spl_fstrans_mark();
	error = -zfs_rmdir(dir, dname(dentry), NULL, cr, 0);

	/*
	 * For a CI FS we must invalidate the dentry to prevent the
	 * creation of negative entries.
	 */
	if (error == 0 && zsb->z_case == ZFS_CASE_INSENSITIVE)
		d_invalidate(dentry);

	spl_fstrans_unmark(cookie);
	crfree(cr);
	ASSERT3S(error, <=, 0);

	return (error);
}
Example #2
0
static int autofs4_dir_open(struct inode *inode, struct file *file)
{
    struct dentry *dentry = file->f_dentry;
    struct vfsmount *mnt = file->f_vfsmnt;
    struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
    int status;

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

    if (autofs4_oz_mode(sbi))
        goto out;

    if (autofs4_ispending(dentry)) {
        DPRINTK("dentry busy");
        return -EBUSY;
    }

    if (!d_mountpoint(dentry) && dentry->d_op && dentry->d_op->d_revalidate) {
        struct nameidata nd;
        int empty;

        /* In case there are stale directory dentrys from a failed mount */
        spin_lock(&dcache_lock);
        empty = list_empty(&dentry->d_subdirs);
        spin_unlock(&dcache_lock);

        if (!empty)
            d_invalidate(dentry);

        nd.flags = LOOKUP_DIRECTORY;
        status = (dentry->d_op->d_revalidate)(dentry, &nd);

        if (!status)
            return -ENOENT;
    }

    if (d_mountpoint(dentry)) {
        struct file *fp = NULL;
        struct vfsmount *fp_mnt = mntget(mnt);
        struct dentry *fp_dentry = dget(dentry);

        while (follow_down(&fp_mnt, &fp_dentry) && d_mountpoint(fp_dentry));

        fp = dentry_open(fp_dentry, fp_mnt, file->f_flags);
        status = PTR_ERR(fp);
        if (IS_ERR(fp)) {
            file->private_data = NULL;
            return status;
        }
        file->private_data = fp;
    }
out:
    return 0;
}
Example #3
0
/*
 * Attempt to preload the dcache with the results from the FIND_FIRST/NEXT
 *
 * Find the dentry that matches "name". If there isn't one, create one. If it's
 * a negative dentry or the uniqueid changed, then drop it and recreate it.
 */
static void
cifs_prime_dcache(struct dentry *parent, struct qstr *name,
		    struct cifs_fattr *fattr)
{
	struct dentry *dentry, *alias;
	struct inode *inode;
	struct super_block *sb = parent->d_inode->i_sb;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);

	cFYI(1, "%s: for %s", __func__, name->name);

	dentry = d_hash_and_lookup(parent, name);
	if (unlikely(IS_ERR(dentry)))
		return;

	if (dentry) {
		int err;

		inode = dentry->d_inode;
		if (inode) {
			/*
			 * If we're generating inode numbers, then we don't
			 * want to clobber the existing one with the one that
			 * the readdir code created.
			 */
			if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
				fattr->cf_uniqueid = CIFS_I(inode)->uniqueid;

			/* update inode in place if i_ino didn't change */
			if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) {
				cifs_fattr_to_inode(inode, fattr);
				goto out;
			}
		}
		err = d_invalidate(dentry);
		dput(dentry);
		if (err)
			return;
	}

	dentry = d_alloc(parent, name);
	if (!dentry)
		return;

	inode = cifs_iget(sb, fattr);
	if (!inode)
		goto out;

	alias = d_materialise_unique(dentry, inode);
	if (alias && !IS_ERR(alias))
		dput(alias);
out:
	dput(dentry);
}
static int autofs4_tree_busy(struct vfsmount *mnt,
	       		     struct dentry *top,
			     unsigned long timeout,
			     int do_now)
{
	struct autofs_info *top_ino = autofs4_dentry_ino(top);
	struct dentry *p;

	DPRINTK("top %p %.*s",
		top, (int)top->d_name.len, top->d_name.name);

	
	if (!simple_positive(top))
		return 1;

	p = NULL;
	while ((p = get_next_positive_dentry(p, top))) {
		DPRINTK("dentry %p %.*s",
			p, (int) p->d_name.len, p->d_name.name);

		if (d_mountpoint(p)) {
			if (autofs4_mount_busy(mnt, p)) {
				top_ino->last_used = jiffies;
				dput(p);
				return 1;
			}
		} else {
			struct autofs_info *ino = autofs4_dentry_ino(p);
			unsigned int ino_count = atomic_read(&ino->count);

			d_invalidate(p);

			
			if (p == top)
				ino_count += 2;
			else
				ino_count++;

			if (p->d_count > ino_count) {
				top_ino->last_used = jiffies;
				dput(p);
				return 1;
			}
		}
	}

	
	if (!autofs4_can_expire(top, timeout, do_now))
		return 1;

	return 0;
}
STATIC int
xfs_vn_unlink(
	struct inode	*dir,
	struct dentry	*dentry)
{
	struct xfs_name	name;
	int		error;

	xfs_dentry_to_name(&name, dentry);

	error = -xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode));
	if (error)
		return error;

	if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb))
		d_invalidate(dentry);
	return 0;
}
Example #6
0
extern int
vnode_shadow_dop_revalidate(
    DENT_T *dentry_p,
    struct nameidata *nd
)
{
    int err;
    DENT_T *real_dentry;
    VNODE_T *cvp;

    real_dentry = REALDENTRY_LOCKED(dentry_p, &cvp);
    if ((!real_dentry) || d_unhashed(real_dentry)) {
        err = FALSE;
 	if (real_dentry)
            /* drop the real entry, it's stale */
            REALDENTRY_UNLOCK_DETACH(dentry_p, cvp);
    } else {
        VNODE_DGET(real_dentry);
        err = TRUE;
        if (real_dentry->d_op && real_dentry->d_op->d_revalidate) {
            err = (*real_dentry->d_op->d_revalidate)(real_dentry, nd);
            /* Recreate what cached lookup would do to the real dentry.
             * Note that d_invalidate only returns non-zero if it is
             * called for a directory still in use.  We should never
             * have a directory here.
             */
            if (!err) {
                d_invalidate(real_dentry);
            }
        }
        /* if the dentry is still valid, we need to update the shadow
         * inode to match the values in the real inode.
         */
        if (err && dentry_p->d_inode && real_dentry->d_inode) {
            /* The dentry is valid, update the inode in case it has
             * changed since the last time we looked.
             */
            SHADOW_CP_INODAT(real_dentry->d_inode, dentry_p->d_inode);
        }
        VNODE_DPUT(real_dentry);
        REALDENTRY_UNLOCK(dentry_p, cvp);
    }
    return(err);
}
Example #7
0
int
osi_TryEvictVCache(struct vcache *avc, int *slept, int defersleep) {
    int code;
    struct dentry *dentry;
    struct list_head *cur, *head;

    /* First, see if we can evict the inode from the dcache */
    if (defersleep && avc != afs_globalVp && VREFCOUNT(avc) > 1 && avc->opens == 0) {
	*slept = 1;
	ReleaseWriteLock(&afs_xvcache);
        AFS_GUNLOCK();
	afs_linux_lock_dcache();
	head = &(AFSTOV(avc))->i_dentry;

restart:
        cur = head;
	while ((cur = cur->next) != head) {
	    dentry = list_entry(cur, struct dentry, d_alias);

	    if (d_unhashed(dentry))
		continue;

	    dget_locked(dentry);

	    afs_linux_unlock_dcache();

	    if (d_invalidate(dentry) == -EBUSY) {
		dput(dentry);
		/* perhaps lock and try to continue? (use cur as head?) */
		goto inuse;
	    }
	    dput(dentry);
	    afs_linux_lock_dcache();
	    goto restart;
	}
	afs_linux_unlock_dcache();
inuse:
	AFS_GLOCK();
        ObtainWriteLock(&afs_xvcache, 733);
    }
Example #8
0
File: super.c Project: cshzc/linux
static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
{
	struct ovl_entry *oe = dentry->d_fsdata;
	unsigned int i;
	int ret = 1;

	for (i = 0; i < oe->numlower; i++) {
		struct dentry *d = oe->lowerstack[i].dentry;

		if (d->d_flags & DCACHE_OP_REVALIDATE) {
			ret = d->d_op->d_revalidate(d, flags);
			if (ret < 0)
				return ret;
			if (!ret) {
				if (!(flags & LOOKUP_RCU))
					d_invalidate(d);
				return -ESTALE;
			}
		}
	}
	return 1;
}
Example #9
0
STATIC int
xfs_vn_unlink(
	struct inode	*dir,
	struct dentry	*dentry)
{
	struct xfs_name	name;
	int		error;

	xfs_dentry_to_name(&name, dentry);

	error = -xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode));
	if (error)
		return error;

	/*
	 * With unlink, the VFS makes the dentry "negative": no inode,
	 * but still hashed. This is incompatible with case-insensitive
	 * mode, so invalidate (unhash) the dentry in CI-mode.
	 */
	if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb))
		d_invalidate(dentry);
	return 0;
}
Example #10
0
/*
 * Same as fuse_invalidate_entry_cache(), but also try to remove the
 * dentry from the hash
 */
static void fuse_invalidate_entry(struct dentry *entry)
{
	d_invalidate(entry);
	fuse_invalidate_entry_cache(entry);
}
Example #11
0
static int fuse_direntplus_link(struct file *file,
				struct fuse_direntplus *direntplus,
				u64 attr_version)
{
	int err;
	struct fuse_entry_out *o = &direntplus->entry_out;
	struct fuse_dirent *dirent = &direntplus->dirent;
	struct dentry *parent = file->f_path.dentry;
	struct qstr name = QSTR_INIT(dirent->name, dirent->namelen);
	struct dentry *dentry;
	struct dentry *alias;
	struct inode *dir = parent->d_inode;
	struct fuse_conn *fc;
	struct inode *inode;

	if (!o->nodeid) {
		/*
		 * Unlike in the case of fuse_lookup, zero nodeid does not mean
		 * ENOENT. Instead, it only means the userspace filesystem did
		 * not want to return attributes/handle for this entry.
		 *
		 * So do nothing.
		 */
		return 0;
	}

	if (name.name[0] == '.') {
		/*
		 * We could potentially refresh the attributes of the directory
		 * and its parent?
		 */
		if (name.len == 1)
			return 0;
		if (name.name[1] == '.' && name.len == 2)
			return 0;
	}

	if (invalid_nodeid(o->nodeid))
		return -EIO;
	if (!fuse_valid_type(o->attr.mode))
		return -EIO;

	fc = get_fuse_conn(dir);

	name.hash = full_name_hash(name.name, name.len);
	dentry = d_lookup(parent, &name);
	if (dentry) {
		inode = dentry->d_inode;
		if (!inode) {
			d_drop(dentry);
		} else if (get_node_id(inode) != o->nodeid ||
			   ((o->attr.mode ^ inode->i_mode) & S_IFMT)) {
			err = d_invalidate(dentry);
			if (err)
				goto out;
		} else if (is_bad_inode(inode)) {
			err = -EIO;
			goto out;
		} else {
			struct fuse_inode *fi;
			fi = get_fuse_inode(inode);
			spin_lock(&fc->lock);
			fi->nlookup++;
			spin_unlock(&fc->lock);

			fuse_change_attributes(inode, &o->attr,
					       entry_attr_timeout(o),
					       attr_version);

			/*
			 * The other branch to 'found' comes via fuse_iget()
			 * which bumps nlookup inside
			 */
			goto found;
		}
		dput(dentry);
	}

	dentry = d_alloc(parent, &name);
	err = -ENOMEM;
	if (!dentry)
		goto out;

	inode = fuse_iget(dir->i_sb, o->nodeid, o->generation,
			  &o->attr, entry_attr_timeout(o), attr_version);
	if (!inode)
		goto out;

	alias = fuse_materialise_dentry(dentry, inode);
	err = PTR_ERR(alias);
	if (IS_ERR(alias))
		goto out;

	if (alias) {
		dput(dentry);
		dentry = alias;
	}

found:
	fuse_change_entry_timeout(dentry, o);

	err = 0;
out:
	dput(dentry);
	return err;
}
Example #12
0
File: dir.c Project: mkrufky/linux
static int fuse_direntplus_link(struct file *file,
				struct fuse_direntplus *direntplus,
				u64 attr_version)
{
	struct fuse_entry_out *o = &direntplus->entry_out;
	struct fuse_dirent *dirent = &direntplus->dirent;
	struct dentry *parent = file->f_path.dentry;
	struct qstr name = QSTR_INIT(dirent->name, dirent->namelen);
	struct dentry *dentry;
	struct dentry *alias;
	struct inode *dir = d_inode(parent);
	struct fuse_conn *fc;
	struct inode *inode;
	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);

	if (!o->nodeid) {
		/*
		 * Unlike in the case of fuse_lookup, zero nodeid does not mean
		 * ENOENT. Instead, it only means the userspace filesystem did
		 * not want to return attributes/handle for this entry.
		 *
		 * So do nothing.
		 */
		return 0;
	}

	if (name.name[0] == '.') {
		/*
		 * We could potentially refresh the attributes of the directory
		 * and its parent?
		 */
		if (name.len == 1)
			return 0;
		if (name.name[1] == '.' && name.len == 2)
			return 0;
	}

	if (invalid_nodeid(o->nodeid))
		return -EIO;
	if (!fuse_valid_type(o->attr.mode))
		return -EIO;

	fc = get_fuse_conn(dir);

	name.hash = full_name_hash(parent, name.name, name.len);
	dentry = d_lookup(parent, &name);
	if (!dentry) {
retry:
		dentry = d_alloc_parallel(parent, &name, &wq);
		if (IS_ERR(dentry))
			return PTR_ERR(dentry);
	}
	if (!d_in_lookup(dentry)) {
		struct fuse_inode *fi;
		inode = d_inode(dentry);
		if (!inode ||
		    get_node_id(inode) != o->nodeid ||
		    ((o->attr.mode ^ inode->i_mode) & S_IFMT)) {
			d_invalidate(dentry);
			dput(dentry);
			goto retry;
		}
		if (is_bad_inode(inode)) {
			dput(dentry);
			return -EIO;
		}

		fi = get_fuse_inode(inode);
		spin_lock(&fc->lock);
		fi->nlookup++;
		spin_unlock(&fc->lock);

		forget_all_cached_acls(inode);
		fuse_change_attributes(inode, &o->attr,
				       entry_attr_timeout(o),
				       attr_version);
		/*
		 * The other branch comes via fuse_iget()
		 * which bumps nlookup inside
		 */
	} else {
		inode = fuse_iget(dir->i_sb, o->nodeid, o->generation,
				  &o->attr, entry_attr_timeout(o),
				  attr_version);
		if (!inode)
			inode = ERR_PTR(-ENOMEM);

		alias = d_splice_alias(inode, dentry);
		d_lookup_done(dentry);
		if (alias) {
			dput(dentry);
			dentry = alias;
		}
		if (IS_ERR(dentry))
			return PTR_ERR(dentry);
	}
	if (fc->readdirplus_auto)
		set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state);
	fuse_change_entry_timeout(dentry, o);

	dput(dentry);
	return 0;
}
Example #13
0
/*
 * Attempt to preload the dcache with the results from the FIND_FIRST/NEXT
 *
 * Find the dentry that matches "name". If there isn't one, create one. If it's
 * a negative dentry or the uniqueid or filetype(mode) changed,
 * then drop it and recreate it.
 */
static void
cifs_prime_dcache(struct dentry *parent, struct qstr *name,
		    struct cifs_fattr *fattr)
{
	struct dentry *dentry, *alias;
	struct inode *inode;
	struct super_block *sb = parent->d_inode->i_sb;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);

	cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);

	dentry = d_hash_and_lookup(parent, name);
	if (unlikely(IS_ERR(dentry)))
		return;

	if (dentry) {
		inode = dentry->d_inode;
		if (inode) {
			/*
			 * If we're generating inode numbers, then we don't
			 * want to clobber the existing one with the one that
			 * the readdir code created.
			 */
			if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
				fattr->cf_uniqueid = CIFS_I(inode)->uniqueid;

			/* update inode in place
			 * if both i_ino and i_mode didn't change */
			if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid &&
			    (inode->i_mode & S_IFMT) ==
			    (fattr->cf_mode & S_IFMT)) {
				cifs_fattr_to_inode(inode, fattr);
				goto out;
			}
		}
		d_invalidate(dentry);
		dput(dentry);
	}

	/*
	 * If we know that the inode will need to be revalidated immediately,
	 * then don't create a new dentry for it. We'll end up doing an on
	 * the wire call either way and this spares us an invalidation.
	 */
	if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
		return;

	dentry = d_alloc(parent, name);
	if (!dentry)
		return;

	inode = cifs_iget(sb, fattr);
	if (!inode)
		goto out;

	alias = d_splice_alias(inode, dentry);
	if (alias && !IS_ERR(alias))
		dput(alias);
out:
	dput(dentry);
}
static int fuse_direntplus_link(struct file *file,
				struct fuse_direntplus *direntplus,
				u64 attr_version)
{
	int err;
	struct fuse_entry_out *o = &direntplus->entry_out;
	struct fuse_dirent *dirent = &direntplus->dirent;
	struct dentry *parent = file->f_path.dentry;
	struct qstr name = { .len = dirent->namelen, .name = dirent->name };
	struct dentry *dentry;
	struct dentry *alias;
	struct inode *dir = parent->d_inode;
	struct fuse_conn *fc;
	struct inode *inode;

	if (!o->nodeid) {
		/*
		 * Unlike in the case of fuse_lookup, zero nodeid does not mean
		 * ENOENT. Instead, it only means the userspace filesystem did
		 * not want to return attributes/handle for this entry.
		 *
		 * So do nothing.
		 */
		return 0;
	}

	if (name.name[0] == '.') {
		/*
		 * We could potentially refresh the attributes of the directory
		 * and its parent?
		 */
		if (name.len == 1)
			return 0;
		if (name.name[1] == '.' && name.len == 2)
			return 0;
	}

	if (invalid_nodeid(o->nodeid))
		return -EIO;
	if (!fuse_valid_type(o->attr.mode))
		return -EIO;

	fc = get_fuse_conn(dir);

	name.hash = full_name_hash(name.name, name.len);
	dentry = d_lookup(parent, &name);
	if (dentry) {
		inode = dentry->d_inode;
		if (!inode) {
			d_drop(dentry);
		} else if (get_node_id(inode) != o->nodeid ||
			   ((o->attr.mode ^ inode->i_mode) & S_IFMT)) {
			err = d_invalidate(dentry);
			if (err)
				goto out;
		} else if (is_bad_inode(inode)) {
			err = -EIO;
			goto out;
		} else {
			struct fuse_inode *fi;
			fi = get_fuse_inode(inode);
			spin_lock(&fc->lock);
			fi->nlookup++;
			spin_unlock(&fc->lock);

			fuse_change_attributes(inode, &o->attr,
					       entry_attr_timeout(o),
					       attr_version);

			/*
			 * The other branch to 'found' comes via fuse_iget()
			 * which bumps nlookup inside
			 */
			goto found;
		}
		dput(dentry);
	}

	dentry = d_alloc(parent, &name);
	err = -ENOMEM;
	if (!dentry)
		goto out;
	dentry->d_op = &fuse_dentry_operations;

	inode = fuse_iget(dir->i_sb, o->nodeid, o->generation,
			  &o->attr, entry_attr_timeout(o), attr_version);
	if (!inode)
		goto out;

	alias = fuse_materialise_dentry(dentry, inode);
	err = PTR_ERR(alias);
	if (IS_ERR(alias))
		goto out;

	if (alias) {
		dput(dentry);
		dentry = alias;
	}

found:
	fuse_change_entry_timeout(dentry, o);

	err = 0;
out:
	dput(dentry);
	return err;
}

static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
			     void *dstbuf, filldir_t filldir, u64 attr_version)
{
	struct fuse_direntplus *direntplus;
	struct fuse_dirent *dirent;
	size_t reclen;
	int over = 0;
	int ret;

	while (nbytes >= FUSE_NAME_OFFSET_DIRENTPLUS) {
		direntplus = (struct fuse_direntplus *) buf;
		dirent = &direntplus->dirent;
		reclen = FUSE_DIRENTPLUS_SIZE(direntplus);

		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
			return -EIO;
		if (reclen > nbytes)
			break;
		if (memchr(dirent->name, '/', dirent->namelen) != NULL)
			return -EIO;

		if (!over) {
			/* We fill entries into dstbuf only as much as
			   it can hold. But we still continue iterating
			   over remaining entries to link them. If not,
			   we need to send a FORGET for each of those
			   which we did not link.
			*/
			over = filldir(dstbuf, dirent->name, dirent->namelen,
				       file->f_pos, dirent->ino,
				       dirent->type);
			file->f_pos = dirent->off;
		}

		buf += reclen;
		nbytes -= reclen;

		ret = fuse_direntplus_link(file, direntplus, attr_version);
		if (ret)
			fuse_force_forget(file, direntplus->entry_out.nodeid);
	}

	return 0;
}

static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
{
	int plus, err;
	size_t nbytes;
	struct page *page;
	struct inode *inode = file->f_path.dentry->d_inode;
	struct fuse_conn *fc = get_fuse_conn(inode);
	struct fuse_req *req;
	u64 attr_version = 0;

	if (is_bad_inode(inode))
		return -EIO;

	req = fuse_get_req(fc, 1);
	if (IS_ERR(req))
		return PTR_ERR(req);

	page = alloc_page(GFP_KERNEL);
	if (!page) {
		fuse_put_request(fc, req);
		return -ENOMEM;
	}

	plus = fuse_use_readdirplus(inode, file);
	req->out.argpages = 1;
	req->num_pages = 1;
	req->pages[0] = page;
	req->page_descs[0].length = PAGE_SIZE;
	if (plus) {
		attr_version = fuse_get_attr_version(fc);
		fuse_read_fill(req, file, file->f_pos, PAGE_SIZE,
			       FUSE_READDIRPLUS);
	} else {
		fuse_read_fill(req, file, file->f_pos, PAGE_SIZE,
			       FUSE_READDIR);
	}
	fuse_request_send(fc, req);
	nbytes = req->out.args[0].size;
	err = req->out.h.error;
	fuse_put_request(fc, req);
	if (!err) {
		if (plus) {
			err = parse_dirplusfile(page_address(page), nbytes,
						file, dstbuf, filldir,
						attr_version);
		} else {
			err = parse_dirfile(page_address(page), nbytes, file,
					    dstbuf, filldir);
		}
	}

	__free_page(page);
	fuse_invalidate_attr(inode); /* atime changed */
	return err;
}
/* Check a directory tree of mount points for busyness
 * The tree is not busy iff no mountpoints are busy
 */
static int autofs4_tree_busy(struct vfsmount *mnt,
	       		     struct dentry *top,
			     unsigned long timeout,
			     int do_now)
{
	struct autofs_info *top_ino = autofs4_dentry_ino(top);
	struct dentry *p;

	DPRINTK("top %p %.*s",
		top, (int)top->d_name.len, top->d_name.name);

	/* Negative dentry - give up */
	if (!simple_positive(top))
		return 1;

	p = NULL;
	while ((p = get_next_positive_dentry(p, top))) {
		DPRINTK("dentry %p %.*s",
			p, (int) p->d_name.len, p->d_name.name);

		/*
		 * Is someone visiting anywhere in the subtree ?
		 * If there's no mount we need to check the usage
		 * count for the autofs dentry.
		 * If the fs is busy update the expiry counter.
		 */
		if (d_mountpoint(p)) {
			if (autofs4_mount_busy(mnt, p)) {
				top_ino->last_used = jiffies;
				dput(p);
				return 1;
			}
		} else {
			struct autofs_info *ino = autofs4_dentry_ino(p);
			unsigned int ino_count = atomic_read(&ino->count);

			/*
			 * Clean stale dentries below that have not been
			 * invalidated after a mount fail during lookup
			 */
			d_invalidate(p);

			/* allow for dget above and top is already dgot */
			if (p == top)
				ino_count += 2;
			else
				ino_count++;

			if (p->d_count > ino_count) {
				top_ino->last_used = jiffies;
				dput(p);
				return 1;
			}
		}
	}

	/* Timeout of a tree mount is ultimately determined by its top dentry */
	if (!autofs4_can_expire(top, timeout, do_now))
		return 1;

	return 0;
}
Example #16
0
int
osi_TryEvictVCache(struct vcache *avc, int *slept, int defersleep) {
    int code;

    struct dentry *dentry;
    struct inode *inode = AFSTOV(avc);
    struct list_head *cur, *head;

    /* First, see if we can evict the inode from the dcache */
    if (defersleep && avc != afs_globalVp && VREFCOUNT(avc) > 1 && avc->opens == 0) {
	*slept = 1;
	ReleaseWriteLock(&afs_xvcache);
        AFS_GUNLOCK();

#if defined(HAVE_DCACHE_LOCK)
        spin_lock(&dcache_lock);
	head = &inode->i_dentry;

restart:
        cur = head;
	while ((cur = cur->next) != head) {
	    dentry = list_entry(cur, struct dentry, d_alias);

	    if (d_unhashed(dentry))
		continue;
	    dget_locked(dentry);

	    spin_unlock(&dcache_lock);
	    if (d_invalidate(dentry) == -EBUSY) {
		dput(dentry);
		/* perhaps lock and try to continue? (use cur as head?) */
		goto inuse;
	    }
	    dput(dentry);
	    spin_lock(&dcache_lock);
	    goto restart;
	}
	spin_unlock(&dcache_lock);
#else /* HAVE_DCACHE_LOCK */
	spin_lock(&inode->i_lock);
	head = &inode->i_dentry;

restart:
	cur = head;
	while ((cur = cur->next) != head) {
	    dentry = list_entry(cur, struct dentry, d_alias);

	    spin_lock(&dentry->d_lock);
	    if (d_unhashed(dentry)) {
		spin_unlock(&dentry->d_lock);
		continue;
	    }
	    spin_unlock(&dentry->d_lock);
	    dget(dentry);

	    spin_unlock(&inode->i_lock);
	    if (d_invalidate(dentry) == -EBUSY) {
		dput(dentry);
		/* perhaps lock and try to continue? (use cur as head?) */
		goto inuse;
	    }
	    dput(dentry);
	    spin_lock(&inode->i_lock);
	    goto restart;
	}
	spin_unlock(&inode->i_lock);
#endif /* HAVE_DCACHE_LOCK */
inuse:
	AFS_GLOCK();
	ObtainWriteLock(&afs_xvcache, 733);
    }
Example #17
0
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
                         struct inode *new_dir_i, struct dentry *new_dentry)
{
    int ret;
    struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
    struct jffs2_inode_info *victim_f = NULL;
    uint8_t type;
    uint32_t now;

    /* The VFS will check for us and prevent trying to rename a
     * file over a directory and vice versa, but if it's a directory,
     * the VFS can't check whether the victim is empty. The filesystem
     * needs to do that for itself.
     */
    if (d_really_is_positive(new_dentry)) {
        victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
        if (d_is_dir(new_dentry)) {
            struct jffs2_full_dirent *fd;

            mutex_lock(&victim_f->sem);
            for (fd = victim_f->dents; fd; fd = fd->next) {
                if (fd->ino) {
                    mutex_unlock(&victim_f->sem);
                    return -ENOTEMPTY;
                }
            }
            mutex_unlock(&victim_f->sem);
        }
    }

    /* XXX: We probably ought to alloc enough space for
       both nodes at the same time. Writing the new link,
       then getting -ENOSPC, is quite bad :)
    */

    /* Make a hard link */

    /* XXX: This is ugly */
    type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12;
    if (!type) type = DT_REG;

    now = get_seconds();
    ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
                        d_inode(old_dentry)->i_ino, type,
                        new_dentry->d_name.name, new_dentry->d_name.len, now);

    if (ret)
        return ret;

    if (victim_f) {
        /* There was a victim. Kill it off nicely */
        if (d_is_dir(new_dentry))
            clear_nlink(d_inode(new_dentry));
        else
            drop_nlink(d_inode(new_dentry));
        /* Don't oops if the victim was a dirent pointing to an
           inode which didn't exist. */
        if (victim_f->inocache) {
            mutex_lock(&victim_f->sem);
            if (d_is_dir(new_dentry))
                victim_f->inocache->pino_nlink = 0;
            else
                victim_f->inocache->pino_nlink--;
            mutex_unlock(&victim_f->sem);
        }
    }

    /* If it was a directory we moved, and there was no victim,
       increase i_nlink on its new parent */
    if (d_is_dir(old_dentry) && !victim_f)
        inc_nlink(new_dir_i);

    /* Unlink the original */
    ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
                          old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);

    /* We don't touch inode->i_nlink */

    if (ret) {
        /* Oh shit. We really ought to make a single node which can do both atomically */
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry));
        mutex_lock(&f->sem);
        inc_nlink(d_inode(old_dentry));
        if (f->inocache && !d_is_dir(old_dentry))
            f->inocache->pino_nlink++;
        mutex_unlock(&f->sem);

        pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n",
                  __func__, ret);
        /*
         * We can't keep the target in dcache after that.
         * For one thing, we can't afford dentry aliases for directories.
         * For another, if there was a victim, we _can't_ set new inode
         * for that sucker and we have to trigger mount eviction - the
         * caller won't do it on its own since we are returning an error.
         */
        d_invalidate(new_dentry);
        new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
        return ret;
    }

    if (d_is_dir(old_dentry))
        drop_nlink(old_dir_i);

    new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);

    return 0;
}