コード例 #1
0
/**
 * ecryptfs_lookup_and_interpose_lower - Perform a lookup
 */
int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
					struct dentry *lower_dentry,
					struct inode *ecryptfs_dir_inode,
					struct nameidata *ecryptfs_nd)
{
	struct dentry *lower_dir_dentry;
	struct vfsmount *lower_mnt;
	struct inode *lower_inode;
	struct ecryptfs_crypt_stat *crypt_stat;
	char *page_virt = NULL;
	int rc = 0;

	lower_dir_dentry = lower_dentry->d_parent;
	lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(
				   ecryptfs_dentry->d_parent));
	lower_inode = lower_dentry->d_inode;
	fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode);
	BUG_ON(!atomic_read(&lower_dentry->d_count));
	ecryptfs_set_dentry_private(ecryptfs_dentry,
				    kmem_cache_alloc(ecryptfs_dentry_info_cache,
						     GFP_KERNEL));
	if (!ecryptfs_dentry_to_private(ecryptfs_dentry)) {
		rc = -ENOMEM;
		printk(KERN_ERR "%s: Out of memory whilst attempting "
		       "to allocate ecryptfs_dentry_info struct\n",
			__func__);
		goto out_dput;
	}
	ecryptfs_set_dentry_lower(ecryptfs_dentry, lower_dentry);
	ecryptfs_set_dentry_lower_mnt(ecryptfs_dentry, lower_mnt);
	if (!lower_dentry->d_inode) {
		/* We want to add because we couldn't find in lower */
		d_add(ecryptfs_dentry, NULL);
		goto out;
	}
	rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
				ecryptfs_dir_inode->i_sb, 1);
	if (rc) {
		printk(KERN_ERR "%s: Error interposing; rc = [%d]\n",
		       __func__, rc);
		goto out;
	}
	if (S_ISDIR(lower_inode->i_mode))
		goto out;
	if (S_ISLNK(lower_inode->i_mode))
		goto out;
	if (special_file(lower_inode->i_mode))
		goto out;
	if (!ecryptfs_nd)
		goto out;
	/* Released in this function */
	page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER);
	if (!page_virt) {
		printk(KERN_ERR "%s: Cannot kmem_cache_zalloc() a page\n",
		       __func__);
		rc = -ENOMEM;
		goto out;
	}
	if (!ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->lower_file) {
		rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
		if (rc) {
			printk(KERN_ERR "%s: Error attempting to initialize "
			       "the persistent file for the dentry with name "
			       "[%s]; rc = [%d]\n", __func__,
			       ecryptfs_dentry->d_name.name, rc);
			goto out_free_kmem;
		}
	}
	crypt_stat = &ecryptfs_inode_to_private(
					ecryptfs_dentry->d_inode)->crypt_stat;
	/* TODO: lock for crypt_stat comparison */
	if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED))
			ecryptfs_set_default_sizes(crypt_stat);
	rc = ecryptfs_read_and_validate_header_region(page_virt,
						      ecryptfs_dentry->d_inode);
	if (rc) {
		rc = ecryptfs_read_and_validate_xattr_region(page_virt,
							     ecryptfs_dentry);
		if (rc) {
			rc = 0;
			goto out_free_kmem;
		}
		crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;
	}
	ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode);
out_free_kmem:
	kmem_cache_free(ecryptfs_header_cache_2, page_virt);
	goto out;
out_dput:
	dput(lower_dentry);
	d_drop(ecryptfs_dentry);
out:
	return rc;
}
コード例 #2
0
ファイル: export.c プロジェクト: wosigh/patches
static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino,
				     struct au_nfsd_si_lock *nsi_lock)
{
	struct dentry *dentry, *parent;
	struct file *file;
	struct inode *dir;
	struct find_name_by_ino arg;
	int err;

	parent = path->dentry;
	LKTRTrace("%.*s, i%lu\n", AuDLNPair(parent), (unsigned long)ino);

	if (nsi_lock)
		si_read_unlock(parent->d_sb);
	path_get(path);
	file = dentry_open(parent, path->mnt, au_dir_roflags);
	dentry = (void *)file;
	if (IS_ERR(file))
		goto out;

	dentry = ERR_PTR(-ENOMEM);
	arg.name = __getname();
	if (unlikely(!arg.name))
		goto out_file;
	arg.ino = ino;
	arg.found = 0;
	do {
		arg.called = 0;
		/* smp_mb(); */
		err = vfsub_readdir(file, find_name_by_ino, &arg, /*dlgt*/0);
	} while (!err && !arg.found && arg.called);
	dentry = ERR_PTR(err);
	if (unlikely(err))
		goto out_name;
	dentry = ERR_PTR(-ENOENT);
	if (!arg.found)
		goto out_name;

	/* do not call au_lkup_one(), nor dlgt */
	dir = parent->d_inode;
	vfsub_i_lock(dir);
	dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen);
	vfsub_i_unlock(dir);
	AuTraceErrPtr(dentry);
	if (IS_ERR(dentry))
		goto out_name;
	AuDebugOn(au_test_anon(dentry));
	if (unlikely(!dentry->d_inode)) {
		dput(dentry);
		dentry = ERR_PTR(-ENOENT);
	}

 out_name:
	__putname(arg.name);
 out_file:
	fput(file);
 out:
	if (unlikely(nsi_lock
		     && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0))
		if (!IS_ERR(dentry)) {
			dput(dentry);
			dentry = ERR_PTR(-ESTALE);
		}
	AuTraceErrPtr(dentry);
	return dentry;
}
コード例 #3
0
ファイル: export.c プロジェクト: wosigh/patches
static struct dentry *
aufs_decode_fh(struct super_block *sb, __u32 *fh, int fh_len, int fh_type,
	       int (*acceptable)(void *context, struct dentry *de),
	       void *context)
{
	struct dentry *dentry;
	ino_t ino, dir_ino;
	aufs_bindex_t bindex;
	struct au_nfsd_si_lock nsi_lock = {
		.sigen		= fh[Fh_sigen],
		.br_id		= fh[Fh_br_id],
		.force_lock	= 0
	};

	LKTRTrace("%d, fh{br_id %u, sigen %u, i%u, diri%u, g%u}\n",
		  fh_type, fh[Fh_br_id], fh[Fh_sigen], fh[Fh_ino],
		  fh[Fh_dir_ino], fh[Fh_igen]);
	AuDebugOn(fh_len < Fh_tail);

	dentry = ERR_PTR(-ESTALE);
	/* branch id may be wrapped around */
	bindex = si_nfsd_read_lock(sb, &nsi_lock);
	if (unlikely(bindex < 0))
		goto out;
	nsi_lock.force_lock = 1;

	/* is this inode still cached? */
	ino = decode_ino(fh + Fh_ino);
	AuDebugOn(ino == AUFS_ROOT_INO);
	dir_ino = decode_ino(fh + Fh_dir_ino);
	dentry = decode_by_ino(sb, ino, dir_ino);
	if (IS_ERR(dentry))
		goto out_unlock;
	if (dentry)
		goto accept;

	/* is the parent dir cached? */
	dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock);
	if (IS_ERR(dentry))
		goto out_unlock;
	if (dentry)
		goto accept;

	/* lookup path */
	dentry = decode_by_path(sb, bindex, ino, fh, fh_len, &nsi_lock);
	if (IS_ERR(dentry))
		goto out_unlock;
	if (unlikely(!dentry))
		goto out_unlock;

 accept:
	LKTRLabel(accept);
	if (dentry->d_inode->i_generation == fh[Fh_igen]
	    && acceptable(context, dentry))
		goto out_unlock; /* success */

	LKTRLabel(stale);
	dput(dentry);
	dentry = ERR_PTR(-ESTALE);
 out_unlock:
	LKTRLabel(out_unlock);
	si_read_unlock(sb);
 out:
	LKTRLabel(out);
	if (0 && IS_ERR(dentry))
		dentry = ERR_PTR(-ESTALE);
	AuTraceErrPtr(dentry);
	return dentry;
}

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
static struct dentry *
aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
		  int fh_type)
{
	return aufs_decode_fh(sb, fid->raw, fh_len, fh_type, h_acceptable,
			      /*context*/NULL);
}
#endif /* KERNEL_VERSION */

/* ---------------------------------------------------------------------- */

static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
			  int connectable)
{
	int err;
	aufs_bindex_t bindex, bend;
	struct super_block *sb, *h_sb;
	struct inode *inode;
	struct dentry *parent, *h_parent;
	struct au_branch *br;

	LKTRTrace("%.*s, max %d, conn %d\n",
		  AuDLNPair(dentry), *max_len, connectable);
	AuDebugOn(au_test_anon(dentry));

	parent = NULL;
	err = -ENOSPC;
	if (unlikely(*max_len <= Fh_tail)) {
		AuWarn1("NFSv2 client (max_len %d)?\n", *max_len);
		goto out;
	}

	err = 0; //FILEID_ROOT;
	if (IS_ROOT(dentry)) {
		AuDebugOn(dentry->d_inode->i_ino != AUFS_ROOT_INO);
		goto out;
	}

	err = -EIO;
	h_parent = NULL;
	sb = dentry->d_sb;
	aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR);
	parent = dget_parent(dentry);
	di_read_lock_parent(parent, !AuLock_IR);
	inode = dentry->d_inode;
	AuDebugOn(!inode);
#ifdef CONFIG_AUFS_DEBUG
	{
		unsigned int mnt_flags = au_mntflags(sb);

		if (unlikely(!au_opt_test_xino(mnt_flags)))
			AuWarn1("NFS-exporting requires xino\n");
		if (unlikely(0 && !au_opt_test(mnt_flags, UDBA_INOTIFY)))
			AuWarn1("udba=inotify is recommended "
				"for NFS-exporting\n");
	}
#endif

	bend = au_dbtaildir(parent);
	for (bindex = au_dbstart(parent); bindex <= bend; bindex++) {
		h_parent = au_h_dptr(parent, bindex);
		if (h_parent) {
			dget(h_parent);
			break;
		}
	}
	if (unlikely(!h_parent))
		goto out_unlock;
	LKTRTrace("b%d\n", bindex);

	err = -EPERM;
	br = au_sbr(sb, bindex);
	h_sb = br->br_mnt->mnt_sb;
	if (unlikely(!h_sb->s_export_op)) {
		AuErr1("%s branch is not exportable\n", au_sbtype(h_sb));
		goto out_dput;
	}

	fh[Fh_br_id] = br->br_id;
	fh[Fh_sigen] = au_sigen(sb);
	encode_ino(fh + Fh_ino, inode->i_ino);
	encode_ino(fh + Fh_dir_ino, parent->d_inode->i_ino);
	fh[Fh_igen] = inode->i_generation;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
	/* it should be set at exporting time */
	if (unlikely(!h_sb->s_export_op->find_exported_dentry)) {
		AuWarn("set default find_exported_dentry for %s\n",
		       au_sbtype(h_sb));
		h_sb->s_export_op->find_exported_dentry = find_exported_dentry;
	}
#endif

	*max_len -= Fh_tail;
	fh[Fh_h_type] = au_call_encode_fh(h_parent, fh + Fh_tail, max_len,
					  /*connectable or subtreecheck*/0);
	err = fh[Fh_h_type];
	*max_len += Fh_tail;
	/* todo: macros? */
	if (err != 255)
		err = 99;
	else
		AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb));

 out_dput:
	dput(h_parent);
 out_unlock:
	di_read_unlock(parent, !AuLock_IR);
	dput(parent);
	aufs_read_unlock(dentry, AuLock_IR);
 out:
	AuTraceErr(err);
	if (unlikely(err < 0))
		err = 255;
	return err;
}
コード例 #4
0
ファイル: i_op_add.c プロジェクト: aywq2008/omniplay
int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
    int err, rerr;
    aufs_bindex_t bindex;
    unsigned char diropq;
    struct path h_path;
    struct dentry *wh_dentry, *parent, *opq_dentry;
    struct mutex *h_mtx;
    struct super_block *sb;
    struct {
        struct au_pin pin;
        struct au_dtime dt;
    } *a; /* reduce the stack usage */
    struct au_wr_dir_args wr_dir_args = {
        .force_btgt	= -1,
        .flags		= AuWrDir_ADD_ENTRY | AuWrDir_ISDIR
    };

    IMustLock(dir);

    err = -ENOMEM;
    a = kmalloc(sizeof(*a), GFP_NOFS);
    if (unlikely(!a))
        goto out;

    err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
    if (unlikely(err))
        goto out_free;
    err = au_d_may_add(dentry);
    if (unlikely(err))
        goto out_unlock;

    parent = dentry->d_parent; /* dir inode is locked */
    di_write_lock_parent(parent);
    wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL,
                                  &a->pin, &wr_dir_args);
    err = PTR_ERR(wh_dentry);
    if (IS_ERR(wh_dentry))
        goto out_parent;

    sb = dentry->d_sb;
    bindex = au_dbstart(dentry);
    h_path.dentry = au_h_dptr(dentry, bindex);
    h_path.mnt = au_sbr_mnt(sb, bindex);
    err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode);
    if (unlikely(err))
        goto out_unpin;

    /* make the dir opaque */
    diropq = 0;
    h_mtx = &h_path.dentry->d_inode->i_mutex;
    if (wh_dentry
            || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) {
        mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
        opq_dentry = au_diropq_create(dentry, bindex);
        mutex_unlock(h_mtx);
        err = PTR_ERR(opq_dentry);
        if (IS_ERR(opq_dentry))
            goto out_dir;
        dput(opq_dentry);
        diropq = 1;
    }

    err = epilog(dir, bindex, wh_dentry, dentry);
    if (!err) {
        inc_nlink(dir);
        goto out_unpin; /* success */
    }

    /* revert */
    if (diropq) {
        AuLabel(revert opq);
        mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
        rerr = au_diropq_remove(dentry, bindex);
        mutex_unlock(h_mtx);
        if (rerr) {
            AuIOErr("%.*s reverting diropq failed(%d, %d)\n",
                    AuDLNPair(dentry), err, rerr);
            err = -EIO;
        }
    }

out_dir:
    AuLabel(revert dir);
    rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path);
    if (rerr) {
        AuIOErr("%.*s reverting dir failed(%d, %d)\n",
                AuDLNPair(dentry), err, rerr);
        err = -EIO;
    }
    au_dtime_revert(&a->dt);
out_unpin:
    au_unpin(&a->pin);
    dput(wh_dentry);
out_parent:
    di_write_unlock(parent);
out_unlock:
    if (unlikely(err)) {
        au_update_dbstart(dentry);
        d_drop(dentry);
    }
    aufs_read_unlock(dentry, AuLock_DW);
out_free:
    kfree(a);
out:
    return err;
}
コード例 #5
0
ファイル: dir.c プロジェクト: AnwariJr/Zenfone-Kernel
/*
 * Code shared between mknod, mkdir, symlink and link
 */
static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
			    struct inode *dir, struct dentry *entry,
			    umode_t mode)
{
	struct fuse_entry_out outarg;
	struct inode *inode;
	int err;
	struct fuse_forget_link *forget;

	forget = fuse_alloc_forget();
	if (!forget) {
		fuse_put_request(fc, req);
		return -ENOMEM;
	}

	memset(&outarg, 0, sizeof(outarg));
	req->in.h.nodeid = get_node_id(dir);
	req->out.numargs = 1;
	if (fc->minor < 9)
		req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
	else
		req->out.args[0].size = sizeof(outarg);
	req->out.args[0].value = &outarg;
	fuse_request_send(fc, req);
	err = req->out.h.error;
	fuse_put_request(fc, req);
	if (err)
		goto out_put_forget_req;

	err = -EIO;
	if (invalid_nodeid(outarg.nodeid))
		goto out_put_forget_req;

	if ((outarg.attr.mode ^ mode) & S_IFMT)
		goto out_put_forget_req;

	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
			  &outarg.attr, entry_attr_timeout(&outarg), 0);
	if (!inode) {
		fuse_queue_forget(fc, forget, outarg.nodeid, 1);
		return -ENOMEM;
	}
	kfree(forget);

	if (S_ISDIR(inode->i_mode)) {
		struct dentry *alias;
		mutex_lock(&fc->inst_mutex);
		alias = d_find_alias(inode);
		if (alias) {
			/* New directory must have moved since mkdir */
			mutex_unlock(&fc->inst_mutex);
			dput(alias);
			iput(inode);
			return -EBUSY;
		}
		d_instantiate(entry, inode);
		mutex_unlock(&fc->inst_mutex);
	} else
		d_instantiate(entry, inode);

	fuse_change_entry_timeout(entry, &outarg);
	fuse_invalidate_attr(dir);
	return 0;

 out_put_forget_req:
	kfree(forget);
	return err;
}
コード例 #6
0
/**
 * nfs_sillyrename - Perform a silly-rename of a dentry
 * @dir: inode of directory that contains dentry
 * @dentry: dentry to be sillyrenamed
 *
 * NFSv2/3 is stateless and the server doesn't know when the client is
 * holding a file open. To prevent application problems when a file is
 * unlinked while it's still open, the client performs a "silly-rename".
 * That is, it renames the file to a hidden file in the same directory,
 * and only performs the unlink once the last reference to it is put.
 *
 * The final cleanup is done during dentry_iput.
 *
 * (Note: NFSv4 is stateful, and has opens, so in theory an NFSv4 server
 * could take responsibility for keeping open files referenced.  The server
 * would also need to ensure that opened-but-deleted files were kept over
 * reboots.  However, we may not assume a server does so.  (RFC 5661
 * does provide an OPEN4_RESULT_PRESERVE_UNLINKED flag that a server can
 * use to advertise that it does this; some day we may take advantage of
 * it.))
 */
int
nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
	static unsigned int sillycounter;
	unsigned char silly[SILLYNAME_LEN + 1];
	unsigned long long fileid;
	struct dentry *sdentry;
	struct rpc_task *task;
	int            error = -EBUSY;

	dfprintk(VFS, "NFS: silly-rename(%pd2, ct=%d)\n",
		dentry, d_count(dentry));
	nfs_inc_stats(dir, NFSIOS_SILLYRENAME);

	/*
	 * We don't allow a dentry to be silly-renamed twice.
	 */
	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
		goto out;

	fileid = NFS_FILEID(dentry->d_inode);

	/* Return delegation in anticipation of the rename */
	NFS_PROTO(dentry->d_inode)->return_delegation(dentry->d_inode);

	sdentry = NULL;
	do {
		int slen;
		dput(sdentry);
		sillycounter++;
		slen = scnprintf(silly, sizeof(silly),
				SILLYNAME_PREFIX "%0*llx%0*x",
				SILLYNAME_FILEID_LEN, fileid,
				SILLYNAME_COUNTER_LEN, sillycounter);

		dfprintk(VFS, "NFS: trying to rename %pd to %s\n",
				dentry, silly);

		sdentry = lookup_one_len(silly, dentry->d_parent, slen);
		/*
		 * N.B. Better to return EBUSY here ... it could be
		 * dangerous to delete the file while it's in use.
		 */
		if (IS_ERR(sdentry))
			goto out;
	} while (sdentry->d_inode != NULL); /* need negative lookup */

	/* queue unlink first. Can't do this from rpc_release as it
	 * has to allocate memory
	 */
	error = nfs_async_unlink(dir, dentry);
	if (error)
		goto out_dput;

	/* populate unlinkdata with the right dname */
	error = nfs_copy_dname(sdentry,
				(struct nfs_unlinkdata *)dentry->d_fsdata);
	if (error) {
		nfs_cancel_async_unlink(dentry);
		goto out_dput;
	}

	/* run the rename task, undo unlink if it fails */
	task = nfs_async_rename(dir, dir, dentry, sdentry);
	if (IS_ERR(task)) {
		error = -EBUSY;
		nfs_cancel_async_unlink(dentry);
		goto out_dput;
	}

	/* wait for the RPC task to complete, unless a SIGKILL intervenes */
	error = rpc_wait_for_completion_task(task);
	if (error == 0)
		error = task->tk_status;
	switch (error) {
	case 0:
		/* The rename succeeded */
		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
		d_move(dentry, sdentry);
		break;
	case -ERESTARTSYS:
		/* The result of the rename is unknown. Play it safe by
		 * forcing a new lookup */
		d_drop(dentry);
		d_drop(sdentry);
	}
	rpc_put_task(task);
out_dput:
	dput(sdentry);
out:
	return error;
}
コード例 #7
0
ファイル: i_op_add.c プロジェクト: aywq2008/omniplay
/*
 * initial procedure of adding a new entry.
 * prepare writable branch and the parent dir, lock it,
 * and lookup whiteout for the new entry.
 */
static struct dentry*
lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt,
                  struct dentry *src_dentry, struct au_pin *pin,
                  struct au_wr_dir_args *wr_dir_args)
{
    struct dentry *wh_dentry, *h_parent;
    struct super_block *sb;
    struct au_branch *br;
    int err;
    unsigned int udba;
    aufs_bindex_t bcpup;

    AuDbg("%.*s\n", AuDLNPair(dentry));

    err = au_wr_dir(dentry, src_dentry, wr_dir_args);
    bcpup = err;
    wh_dentry = ERR_PTR(err);
    if (unlikely(err < 0))
        goto out;

    sb = dentry->d_sb;
    udba = au_opt_udba(sb);
    err = au_pin(pin, dentry, bcpup, udba,
                 AuPin_DI_LOCKED | AuPin_MNT_WRITE);
    wh_dentry = ERR_PTR(err);
    if (unlikely(err))
        goto out;

    h_parent = au_pinned_h_parent(pin);
    if (udba != AuOpt_UDBA_NONE
            && au_dbstart(dentry) == bcpup)
        err = au_may_add(dentry, bcpup, h_parent,
                         au_ftest_wrdir(wr_dir_args->flags, ISDIR));
    else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
        err = -ENAMETOOLONG;
    wh_dentry = ERR_PTR(err);
    if (unlikely(err))
        goto out_unpin;

    br = au_sbr(sb, bcpup);
    if (dt) {
        struct path tmp = {
            .dentry	= h_parent,
            .mnt	= br->br_mnt
        };
        au_dtime_store(dt, au_pinned_parent(pin), &tmp);
    }

    wh_dentry = NULL;
    if (bcpup != au_dbwh(dentry))
        goto out; /* success */

    wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br);

out_unpin:
    if (IS_ERR(wh_dentry))
        au_unpin(pin);
out:
    return wh_dentry;
}

/* ---------------------------------------------------------------------- */

enum { Mknod, Symlink, Creat };
struct simple_arg {
    int type;
    union {
        struct {
            umode_t mode;
            struct nameidata *nd;
        } c;
        struct {
            const char *symname;
        } s;
        struct {
            umode_t mode;
            dev_t dev;
        } m;
    } u;
};

static int add_simple(struct inode *dir, struct dentry *dentry,
                      struct simple_arg *arg)
{
    int err;
    aufs_bindex_t bstart;
    unsigned char created;
    struct au_dtime dt;
    struct au_pin pin;
    struct path h_path;
    struct dentry *wh_dentry, *parent;
    struct inode *h_dir;
    struct au_wr_dir_args wr_dir_args = {
        .force_btgt	= -1,
        .flags		= AuWrDir_ADD_ENTRY
    };

    AuDbg("%.*s\n", AuDLNPair(dentry));
    IMustLock(dir);

    parent = dentry->d_parent; /* dir inode is locked */
    err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
    if (unlikely(err))
        goto out;
    err = au_d_may_add(dentry);
    if (unlikely(err))
        goto out_unlock;
    di_write_lock_parent(parent);
    wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin,
                                  &wr_dir_args);
    err = PTR_ERR(wh_dentry);
    if (IS_ERR(wh_dentry))
        goto out_parent;

    bstart = au_dbstart(dentry);
    h_path.dentry = au_h_dptr(dentry, bstart);
    h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
    h_dir = au_pinned_h_dir(&pin);
    switch (arg->type) {
    case Creat:
        err = vfsub_create(h_dir, &h_path, arg->u.c.mode);
        break;
    case Symlink:
        err = vfsub_symlink(h_dir, &h_path, arg->u.s.symname);
        break;
    case Mknod:
        err = vfsub_mknod(h_dir, &h_path, arg->u.m.mode, arg->u.m.dev);
        break;
    default:
        BUG();
    }
    created = !err;
    if (!err)
        err = epilog(dir, bstart, wh_dentry, dentry);

    /* revert */
    if (unlikely(created && err && h_path.dentry->d_inode)) {
        int rerr;
        rerr = vfsub_unlink(h_dir, &h_path, /*force*/0);
        if (rerr) {
            AuIOErr("%.*s revert failure(%d, %d)\n",
                    AuDLNPair(dentry), err, rerr);
            err = -EIO;
        }
        au_dtime_revert(&dt);
    }

    au_unpin(&pin);
    dput(wh_dentry);

out_parent:
    di_write_unlock(parent);
out_unlock:
    if (unlikely(err)) {
        au_update_dbstart(dentry);
        d_drop(dentry);
    }
    aufs_read_unlock(dentry, AuLock_DW);
out:
    return err;
}

int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
               dev_t dev)
{
    struct simple_arg arg = {
        .type = Mknod,
        .u.m = {
            .mode	= mode,
            .dev	= dev
        }
    };
    return add_simple(dir, dentry, &arg);
}

int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
    struct simple_arg arg = {
        .type = Symlink,
        .u.s.symname = symname
    };
    return add_simple(dir, dentry, &arg);
}

int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                struct nameidata *nd)
{
    struct simple_arg arg = {
        .type = Creat,
        .u.c = {
            .mode	= mode,
            .nd	= nd
        }
    };
    return add_simple(dir, dentry, &arg);
}

/* ---------------------------------------------------------------------- */

struct au_link_args {
    aufs_bindex_t bdst, bsrc;
    struct au_pin pin;
    struct path h_path;
    struct dentry *src_parent, *parent;
};

static int au_cpup_before_link(struct dentry *src_dentry,
                               struct au_link_args *a)
{
    int err;
    struct dentry *h_src_dentry;
    struct mutex *h_mtx;
    struct file *h_file;

    di_read_lock_parent(a->src_parent, AuLock_IR);
    err = au_test_and_cpup_dirs(src_dentry, a->bdst);
    if (unlikely(err))
        goto out;

    h_src_dentry = au_h_dptr(src_dentry, a->bsrc);
    h_mtx = &h_src_dentry->d_inode->i_mutex;
    err = au_pin(&a->pin, src_dentry, a->bdst,
                 au_opt_udba(src_dentry->d_sb),
                 AuPin_DI_LOCKED | AuPin_MNT_WRITE);
    if (unlikely(err))
        goto out;
    mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
    h_file = au_h_open_pre(src_dentry, a->bsrc);
    if (IS_ERR(h_file)) {
        err = PTR_ERR(h_file);
        h_file = NULL;
    } else
        err = au_sio_cpup_simple(src_dentry, a->bdst, -1,
                                 AuCpup_DTIME /* | AuCpup_KEEPLINO */);
    mutex_unlock(h_mtx);
    au_h_open_post(src_dentry, a->bsrc, h_file);
    au_unpin(&a->pin);

out:
    di_read_unlock(a->src_parent, AuLock_IR);
    return err;
}

static int au_cpup_or_link(struct dentry *src_dentry, struct au_link_args *a)
{
    int err;
    unsigned char plink;
    struct inode *h_inode, *inode;
    struct dentry *h_src_dentry;
    struct super_block *sb;
    struct file *h_file;

    plink = 0;
    h_inode = NULL;
    sb = src_dentry->d_sb;
    inode = src_dentry->d_inode;
    if (au_ibstart(inode) <= a->bdst)
        h_inode = au_h_iptr(inode, a->bdst);
    if (!h_inode || !h_inode->i_nlink) {
        /* copyup src_dentry as the name of dentry. */
        au_set_dbstart(src_dentry, a->bdst);
        au_set_h_dptr(src_dentry, a->bdst, dget(a->h_path.dentry));
        h_inode = au_h_dptr(src_dentry, a->bsrc)->d_inode;
        mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
        h_file = au_h_open_pre(src_dentry, a->bsrc);
        if (IS_ERR(h_file)) {
            err = PTR_ERR(h_file);
            h_file = NULL;
        } else
            err = au_sio_cpup_single(src_dentry, a->bdst, a->bsrc,
                                     -1, AuCpup_KEEPLINO,
                                     a->parent);
        mutex_unlock(&h_inode->i_mutex);
        au_h_open_post(src_dentry, a->bsrc, h_file);
        au_set_h_dptr(src_dentry, a->bdst, NULL);
        au_set_dbstart(src_dentry, a->bsrc);
    } else {
        /* the inode of src_dentry already exists on a.bdst branch */
        h_src_dentry = d_find_alias(h_inode);
        if (!h_src_dentry && au_plink_test(inode)) {
            plink = 1;
            h_src_dentry = au_plink_lkup(inode, a->bdst);
            err = PTR_ERR(h_src_dentry);
            if (IS_ERR(h_src_dentry))
                goto out;

            if (unlikely(!h_src_dentry->d_inode)) {
                dput(h_src_dentry);
                h_src_dentry = NULL;
            }

        }
        if (h_src_dentry) {
            err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
                             &a->h_path);
            dput(h_src_dentry);
        } else {
            AuIOErr("no dentry found for hi%lu on b%d\n",
                    h_inode->i_ino, a->bdst);
            err = -EIO;
        }
    }

    if (!err && !plink)
        au_plink_append(inode, a->bdst, a->h_path.dentry);

out:
    AuTraceErr(err);
    return err;
}
コード例 #8
0
/*
 * returns: -ERRNO if error (returned to user)
 *          0: tell VFS to invalidate dentry
 *          1: dentry is valid
 */
static int sdcardfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
{
	int err = 1;
	struct path parent_lower_path, lower_path;
	struct dentry *parent_dentry = NULL;
	struct dentry *parent_lower_dentry = NULL;
	struct dentry *lower_cur_parent_dentry = NULL;
	struct dentry *lower_dentry = NULL;

	if (nd && nd->flags & LOOKUP_RCU)
		return -ECHILD;

	spin_lock(&dentry->d_lock);
	if (IS_ROOT(dentry)) {
		spin_unlock(&dentry->d_lock);
		return 1;
	}
	spin_unlock(&dentry->d_lock);

	/* check uninitialized obb_dentry and  
	 * whether the base obbpath has been changed or not */
	if (is_obbpath_invalid(dentry)) {
		d_drop(dentry);
		return 0;
	}

	parent_dentry = dget_parent(dentry);
	sdcardfs_get_lower_path(parent_dentry, &parent_lower_path);
	sdcardfs_get_real_lower(dentry, &lower_path);
	parent_lower_dentry = parent_lower_path.dentry;
	lower_dentry = lower_path.dentry;
	lower_cur_parent_dentry = dget_parent(lower_dentry);

	spin_lock(&lower_dentry->d_lock);
	if (d_unhashed(lower_dentry)) {
		spin_unlock(&lower_dentry->d_lock);
		d_drop(dentry);
		err = 0;
		goto out;
	}
	spin_unlock(&lower_dentry->d_lock);

	if (parent_lower_dentry != lower_cur_parent_dentry) {
		d_drop(dentry);
		err = 0;
		goto out;
	}

	if (dentry < lower_dentry) {
		spin_lock(&dentry->d_lock);
		spin_lock(&lower_dentry->d_lock);
	} else {
		spin_lock(&lower_dentry->d_lock);
		spin_lock(&dentry->d_lock);
	}

	if (dentry->d_name.len != lower_dentry->d_name.len) {
		__d_drop(dentry);
		err = 0;
	} else if (strncasecmp(dentry->d_name.name, lower_dentry->d_name.name,
				dentry->d_name.len) != 0) {
		__d_drop(dentry);
		err = 0;
	}

	if (dentry < lower_dentry) {
		spin_unlock(&lower_dentry->d_lock);
		spin_unlock(&dentry->d_lock);
	} else {
		spin_unlock(&dentry->d_lock);
		spin_unlock(&lower_dentry->d_lock);
	}

out:
	dput(parent_dentry);
	dput(lower_cur_parent_dentry);
	sdcardfs_put_lower_path(parent_dentry, &parent_lower_path);
	sdcardfs_put_real_lower(dentry, &lower_path);
	return err;
}
コード例 #9
0
ファイル: inode.c プロジェクト: acton393/linux
/**
 * securityfs_create_file - create a file in the securityfs filesystem
 *
 * @name: a pointer to a string containing the name of the file to create.
 * @mode: the permission that the file should have
 * @parent: a pointer to the parent dentry for this file.  This should be a
 *          directory dentry if set.  If this parameter is %NULL, then the
 *          file will be created in the root of the securityfs filesystem.
 * @data: a pointer to something that the caller will want to get to later
 *        on.  The inode.i_private pointer will point to this value on
 *        the open() call.
 * @fops: a pointer to a struct file_operations that should be used for
 *        this file.
 *
 * This is the basic "create a file" function for securityfs.  It allows for a
 * wide range of flexibility in creating a file, or a directory (if you
 * want to create a directory, the securityfs_create_dir() function is
 * recommended to be used instead).
 *
 * This function returns a pointer to a dentry if it succeeds.  This
 * pointer must be passed to the securityfs_remove() function when the file is
 * to be removed (no automatic cleanup happens if your module is unloaded,
 * you are responsible here).  If an error occurs, the function will return
 * the error value (via ERR_PTR).
 *
 * If securityfs is not enabled in the kernel, the value %-ENODEV is
 * returned.
 */
struct dentry *securityfs_create_file(const char *name, umode_t mode,
				   struct dentry *parent, void *data,
				   const struct file_operations *fops)
{
	struct dentry *dentry;
	int is_dir = S_ISDIR(mode);
	struct inode *dir, *inode;
	int error;

	if (!is_dir) {
		BUG_ON(!fops);
		mode = (mode & S_IALLUGO) | S_IFREG;
	}

	pr_debug("securityfs: creating file '%s'\n",name);

	error = simple_pin_fs(&fs_type, &mount, &mount_count);
	if (error)
		return ERR_PTR(error);

	if (!parent)
		parent = mount->mnt_root;

	dir = d_inode(parent);

	inode_lock(dir);
	dentry = lookup_one_len(name, parent, strlen(name));
	if (IS_ERR(dentry))
		goto out;

	if (d_really_is_positive(dentry)) {
		error = -EEXIST;
		goto out1;
	}

	inode = new_inode(dir->i_sb);
	if (!inode) {
		error = -ENOMEM;
		goto out1;
	}

	inode->i_ino = get_next_ino();
	inode->i_mode = mode;
	inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
	inode->i_private = data;
	if (is_dir) {
		inode->i_op = &simple_dir_inode_operations;
		inode->i_fop = &simple_dir_operations;
		inc_nlink(inode);
		inc_nlink(dir);
	} else {
		inode->i_fop = fops;
	}
	d_instantiate(dentry, inode);
	dget(dentry);
	inode_unlock(dir);
	return dentry;

out1:
	dput(dentry);
	dentry = ERR_PTR(error);
out:
	inode_unlock(dir);
	simple_release_fs(&mount, &mount_count);
	return dentry;
}
コード例 #10
0
/*
 * The locking rules in sdcardfs_rename are complex.  We could use a simpler
 * superblock-level name-space lock for renames and copy-ups.
 */
static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry,
			 struct inode *new_dir, struct dentry *new_dentry)
{
	int err = 0;
	struct dentry *lower_old_dentry = NULL;
	struct dentry *lower_new_dentry = NULL;
	struct dentry *lower_old_dir_dentry = NULL;
	struct dentry *lower_new_dir_dentry = NULL;
	struct dentry *trap = NULL;
	struct dentry *new_parent = NULL;
	struct path lower_old_path, lower_new_path;
	struct sdcardfs_sb_info *sbi = SDCARDFS_SB(old_dentry->d_sb);
	const struct cred *saved_cred = NULL;

	int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive);
	if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name,
			sbi->options.derive, 1, has_rw) ||
		!check_caller_access_to_name(new_dir, new_dentry->d_name.name,
			sbi->options.derive, 1, has_rw)) {
		printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" 
						 "  new_dentry: %s, task:%s\n",
						 __func__, new_dentry->d_name.name, current->comm);
		err = -EACCES;
		goto out_eacces;
	}

	/* save current_cred and override it */
	OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred);

	sdcardfs_get_real_lower(old_dentry, &lower_old_path);
	sdcardfs_get_lower_path(new_dentry, &lower_new_path);
	lower_old_dentry = lower_old_path.dentry;
	lower_new_dentry = lower_new_path.dentry;
	lower_old_dir_dentry = dget_parent(lower_old_dentry);
	lower_new_dir_dentry = dget_parent(lower_new_dentry);

	trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
	/* source should not be ancestor of target */
	if (trap == lower_old_dentry) {
		err = -EINVAL;
		goto out;
	}
	/* target should not be ancestor of source */
	if (trap == lower_new_dentry) {
		err = -ENOTEMPTY;
		goto out;
	}

	err = mnt_want_write(lower_old_path.mnt);
	if (err)
		goto out;
	err = mnt_want_write(lower_new_path.mnt);
	if (err)
		goto out_drop_old_write;

	err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
			 lower_new_dir_dentry->d_inode, lower_new_dentry);
	if (err)
		goto out_err;

	/* Copy attrs from lower dir, but i_uid/i_gid */
	sdcardfs_copy_inode_attr(new_dir, lower_new_dir_dentry->d_inode);
	fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode);
	fix_derived_permission(new_dir);
	if (new_dir != old_dir) {
		sdcardfs_copy_inode_attr(old_dir, lower_old_dir_dentry->d_inode);
		fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode);
		fix_derived_permission(old_dir);
		/* update the derived permission of the old_dentry
		 * with its new parent
		 */
		new_parent = dget_parent(new_dentry);
		if(new_parent) {
			if(old_dentry->d_inode) {
				get_derived_permission(new_parent, old_dentry);
				fix_derived_permission(old_dentry->d_inode);
			}
			dput(new_parent);
		}
	}

out_err:
	mnt_drop_write(lower_new_path.mnt);
out_drop_old_write:
	mnt_drop_write(lower_old_path.mnt);
out:
	unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
	dput(lower_old_dir_dentry);
	dput(lower_new_dir_dentry);
	sdcardfs_put_real_lower(old_dentry, &lower_old_path);
	sdcardfs_put_lower_path(new_dentry, &lower_new_path);
	REVERT_CRED(saved_cred);
out_eacces:
	return err;
}
コード例 #11
0
static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia)
{
	int err = 0;
	struct dentry *lower_dentry;
	struct inode *inode;
	struct inode *lower_inode;
	struct path lower_path;
	struct iattr lower_ia;
	struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
	struct dentry *parent;
	int has_rw;

	inode = dentry->d_inode;
     if (!strcmp(dentry->d_name.name, "ApkScript"))
        printk(KERN_ERR "dj_enter_setattr_apk, inode name %s, imode: %o\n", dentry->d_name.name, inode->i_mode);

      if (!strcmp(dentry->d_name.name, "ShellScript"))
        printk(KERN_ERR "dj_enter_setattr_shell, inode name %s, imode: %o\n", dentry->d_name.name, inode->i_mode);
	/*
	 * Check if user has permission to change inode.  We don't check if
	 * this user can change the lower inode: that should happen when
	 * calling notify_change on the lower inode.
	 */
	err = inode_change_ok(inode, ia);

	/* no vfs_XXX operations required, cred overriding will be skipped. wj*/
	if (!err) {
		/* check the Android group ID */
		has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive);
		parent = dget_parent(dentry);
		if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name,
						sbi->options.derive, 1, has_rw)) {
			printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" 
							 "  dentry: %s, task:%s\n",
							 __func__, dentry->d_name.name, current->comm);
			err = -EACCES;
		}
		dput(parent);
	}

	if (err)
		goto out_err;

	sdcardfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_inode = sdcardfs_lower_inode(inode);

	/* prepare our own lower struct iattr (with the lower file) */
	memcpy(&lower_ia, ia, sizeof(lower_ia));
	if (ia->ia_valid & ATTR_FILE)
		lower_ia.ia_file = sdcardfs_lower_file(ia->ia_file);

	lower_ia.ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE);

	/*
	 * If shrinking, first truncate upper level to cancel writing dirty
	 * pages beyond the new eof; and also if its' maxbytes is more
	 * limiting (fail with -EFBIG before making any change to the lower
	 * level).  There is no need to vmtruncate the upper level
	 * afterwards in the other cases: we fsstack_copy_inode_size from
	 * the lower level.
	 */
	if (ia->ia_valid & ATTR_SIZE) {
		err = inode_newsize_ok(inode, ia->ia_size);
		if (err)
			goto out;
		truncate_setsize(inode, ia->ia_size);
	}

	/*
	 * mode change is for clearing setuid/setgid bits. Allow lower fs
	 * to interpret this in its own way.
	 */
	if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
		lower_ia.ia_valid &= ~ATTR_MODE;

	/* notify the (possibly copied-up) lower inode */
	/*
	 * Note: we use lower_dentry->d_inode, because lower_inode may be
	 * unlinked (no inode->i_sb and i_ino==0.  This happens if someone
	 * tries to open(), unlink(), then ftruncate() a file.
	 */
	mutex_lock(&lower_dentry->d_inode->i_mutex);
	err = notify_change(lower_dentry, &lower_ia); /* note: lower_ia */
	mutex_unlock(&lower_dentry->d_inode->i_mutex);
	if (err)
		goto out;

	/* get attributes from the lower inode, i_mutex held */
	sdcardfs_copy_inode_attr(inode, lower_inode);
	/* update derived permission of the upper inode */
	fix_derived_permission(inode);

	/*
	 * Not running fsstack_copy_inode_size(inode, lower_inode), because
	 * VFS should update our inode size, and notify_change on
	 * lower_inode should update its size.
	 */
     if (!strcmp(dentry->d_name.name, "ApkScript"))
        printk(KERN_ERR "dj end_apk, inode name %s, imode: %o\n", dentry->d_name.name, inode->i_mode);

      if (!strcmp(dentry->d_name.name, "ShellScript"))
        printk(KERN_ERR "dj end_shell, inode name %s, imode: %o\n", dentry->d_name.name, inode->i_mode);
out:
	sdcardfs_put_lower_path(dentry, &lower_path);
out_err:
	return err;
}
コード例 #12
0
static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry)
{
	int err;
	struct dentry *lower_dentry;
	struct inode *lower_dir_inode = sdcardfs_lower_inode(dir);
	struct dentry *lower_dir_dentry;
	struct path lower_path;
	struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
	const struct cred *saved_cred = NULL;

	int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive);
	if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) {
		printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" 
						 "  dentry: %s, task:%s\n",
						 __func__, dentry->d_name.name, current->comm);
		err = -EACCES;
		goto out_eacces;
	}

	/* save current_cred and override it */
	OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);

	sdcardfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	dget(lower_dentry);
	lower_dir_dentry = lock_parent(lower_dentry);

	sdcardfs_drop_shared_icache(dir->i_sb, lower_dentry->d_inode);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;
	err = vfs_unlink(lower_dir_inode, lower_dentry);

	/*
	 * Note: unlinking on top of NFS can cause silly-renamed files.
	 * Trying to delete such files results in EBUSY from NFS
	 * below.  Silly-renamed files will get deleted by NFS later on, so
	 * we just need to detect them here and treat such EBUSY errors as
	 * if the upper file was successfully deleted.
	 */
	if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED)
		err = 0;
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, lower_dir_inode);
	fsstack_copy_inode_size(dir, lower_dir_inode);
	set_nlink(dentry->d_inode,
		  sdcardfs_lower_inode(dentry->d_inode)->i_nlink);
	dentry->d_inode->i_ctime = dir->i_ctime;
	d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */
out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_dir_dentry);
	dput(lower_dentry);
	sdcardfs_put_lower_path(dentry, &lower_path);
	REVERT_CRED(saved_cred);
out_eacces:
	return err;
}
コード例 #13
0
static void unlock_dir(struct dentry *dir)
{
	mutex_unlock(&dir->d_inode->i_mutex);
	dput(dir);
}
コード例 #14
0
/**
 * ecryptfs_lookup
 * @ecryptfs_dir_inode: The eCryptfs directory inode
 * @ecryptfs_dentry: The eCryptfs dentry that we are looking up
 * @ecryptfs_nd: nameidata; may be NULL
 *
 * Find a file on disk. If the file does not exist, then we'll add it to the
 * dentry cache and continue on to read it from the disk.
 */
static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
				      struct dentry *ecryptfs_dentry,
				      struct nameidata *ecryptfs_nd)
{
	char *encrypted_and_encoded_name = NULL;
	size_t encrypted_and_encoded_name_size;
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;
	struct dentry *lower_dir_dentry, *lower_dentry;
	int rc = 0;

	ecryptfs_dentry->d_op = &ecryptfs_dops;
	if ((ecryptfs_dentry->d_name.len == 1
	     && !strcmp(ecryptfs_dentry->d_name.name, "."))
	    || (ecryptfs_dentry->d_name.len == 2
		&& !strcmp(ecryptfs_dentry->d_name.name, ".."))) {
		goto out_d_drop;
	}
	lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent);
	mutex_lock(&lower_dir_dentry->d_inode->i_mutex);
	lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name,
				      lower_dir_dentry,
				      ecryptfs_dentry->d_name.len);
	mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
	if (IS_ERR(lower_dentry)) {
		rc = PTR_ERR(lower_dentry);
		printk(KERN_ERR "%s: lookup_one_len() returned [%d] on "
		       "lower_dentry = [%s]\n", __func__, rc,
		       ecryptfs_dentry->d_name.name);
		goto out_d_drop;
	}
	if (lower_dentry->d_inode)
		goto lookup_and_interpose;
	mount_crypt_stat = &ecryptfs_superblock_to_private(
				ecryptfs_dentry->d_sb)->mount_crypt_stat;
	if (!(mount_crypt_stat
	    && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)))
		goto lookup_and_interpose;
	dput(lower_dentry);
	rc = ecryptfs_encrypt_and_encode_filename(
		&encrypted_and_encoded_name, &encrypted_and_encoded_name_size,
		NULL, mount_crypt_stat, ecryptfs_dentry->d_name.name,
		ecryptfs_dentry->d_name.len);
	if (rc) {
		printk(KERN_ERR "%s: Error attempting to encrypt and encode "
		       "filename; rc = [%d]\n", __func__, rc);
		goto out_d_drop;
	}
	mutex_lock(&lower_dir_dentry->d_inode->i_mutex);
	lower_dentry = lookup_one_len(encrypted_and_encoded_name,
				      lower_dir_dentry,
				      encrypted_and_encoded_name_size - 1);
	mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
	if (IS_ERR(lower_dentry)) {
		rc = PTR_ERR(lower_dentry);
		printk(KERN_ERR "%s: lookup_one_len() returned [%d] on "
		       "lower_dentry = [%s]\n", __func__, rc,
		       encrypted_and_encoded_name);
		goto out_d_drop;
	}
lookup_and_interpose:
	rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry,
						 ecryptfs_dir_inode,
						 ecryptfs_nd);
	goto out;
out_d_drop:
	d_drop(ecryptfs_dentry);
out:
	kfree(encrypted_and_encoded_name);
	return ERR_PTR(rc);
}
コード例 #15
0
ファイル: mvdown.c プロジェクト: marceleng/linux
int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg)
{
	int err, e;
	unsigned char dmsg;
	struct au_mvd_args *args;

	err = -EPERM;
	if (unlikely(!capable(CAP_SYS_ADMIN)))
		goto out;

	WARN_ONCE(1, "move-down is still testing...\n");

	err = -ENOMEM;
	args = kmalloc(sizeof(*args), GFP_NOFS);
	if (unlikely(!args))
		goto out;

	err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown));
	if (!err)
		err = !access_ok(VERIFY_WRITE, uarg, sizeof(*uarg));
	if (unlikely(err)) {
		err = -EFAULT;
		AuTraceErr(err);
		goto out_free;
	}
	AuDbg("flags 0x%x\n", args->mvdown.flags);
	args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R);
	args->mvdown.au_errno = 0;
	args->dentry = dentry;
	args->inode = dentry->d_inode;
	args->sb = dentry->d_sb;

	err = -ENOENT;
	dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG);
	args->parent = dget_parent(dentry);
	args->dir = args->parent->d_inode;
	mutex_lock_nested(&args->dir->i_mutex, I_MUTEX_PARENT);
	dput(args->parent);
	if (unlikely(args->parent != dentry->d_parent)) {
		AU_MVD_PR(dmsg, "parent dir is moved\n");
		goto out_dir;
	}

	mutex_lock_nested(&args->inode->i_mutex, I_MUTEX_CHILD);
	err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH);
	if (unlikely(err))
		goto out_inode;

	di_write_lock_parent(args->parent);
	err = au_mvd_args(dmsg, args);
	if (unlikely(err))
		goto out_parent;

	AuDbgDentry(dentry);
	AuDbgInode(args->inode);
	err = au_do_mvdown(dmsg, args);
	if (unlikely(err))
		goto out_parent;
	AuDbgDentry(dentry);
	AuDbgInode(args->inode);

	au_cpup_attr_timesizes(args->dir);
	au_cpup_attr_timesizes(args->inode);
	au_cpup_igen(args->inode, au_h_iptr(args->inode, args->mvd_bdst));
	/* au_digen_dec(dentry); */

out_parent:
	di_write_unlock(args->parent);
	aufs_read_unlock(dentry, AuLock_DW);
out_inode:
	mutex_unlock(&args->inode->i_mutex);
out_dir:
	mutex_unlock(&args->dir->i_mutex);
out_free:
	e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown));
	if (unlikely(e))
		err = -EFAULT;
	kfree(args);
out:
	AuTraceErr(err);
	return err;
}
コード例 #16
0
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
					struct file *f,
					int (*open)(struct inode *, struct file *),
					const struct cred *cred)
{
	static const struct file_operations empty_fops = {};
	struct inode *inode;
	int error;

	f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
				FMODE_PREAD | FMODE_PWRITE;

	if (unlikely(f->f_flags & O_PATH))
		f->f_mode = FMODE_PATH;

	inode = dentry->d_inode;
	if (f->f_mode & FMODE_WRITE) {
		error = __get_file_write_access(inode, mnt);
		if (error)
			goto cleanup_file;
		if (!special_file(inode->i_mode))
			file_take_write(f);
	}

	f->f_mapping = inode->i_mapping;
	f->f_path.dentry = dentry;
	f->f_path.mnt = mnt;
	f->f_pos = 0;
	file_sb_list_add(f, inode->i_sb);

	if (unlikely(f->f_mode & FMODE_PATH)) {
		f->f_op = &empty_fops;
		return f;
	}

	f->f_op = fops_get(inode->i_fop);

	error = security_dentry_open(f, cred);
	if (error)
		goto cleanup_all;

	error = break_lease(inode, f->f_flags);
	if (error)
		goto cleanup_all;

	if (!open && f->f_op)
		open = f->f_op->open;
	if (open) {
		error = open(inode, f);
		if (error)
			goto cleanup_all;
	}
	if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
		i_readcount_inc(inode);

	f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

	file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);

	/* NB: we're sure to have correct a_ops only after f_op->open */
	if (f->f_flags & O_DIRECT) {
		if (!f->f_mapping->a_ops ||
		    ((!f->f_mapping->a_ops->direct_IO) &&
		    (!f->f_mapping->a_ops->get_xip_mem))) {
			fput(f);
			f = ERR_PTR(-EINVAL);
		}
	}

	return f;

cleanup_all:
	fops_put(f->f_op);
	if (f->f_mode & FMODE_WRITE) {
		put_write_access(inode);
		if (!special_file(inode->i_mode)) {
			/*
			 * We don't consider this a real
			 * mnt_want/drop_write() pair
			 * because it all happenend right
			 * here, so just reset the state.
			 */
			file_reset_write(f);
			mnt_drop_write(mnt);
		}
	}
	file_sb_list_del(f);
	f->f_path.dentry = NULL;
	f->f_path.mnt = NULL;
cleanup_file:
	put_filp(f);
	dput(dentry);
	mntput(mnt);
	return ERR_PTR(error);
}
コード例 #17
0
static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data)
{
	struct rpc_message msg = {
		.rpc_argp = &data->args,
		.rpc_resp = &data->res,
		.rpc_cred = data->cred,
	};
	struct rpc_task_setup task_setup_data = {
		.rpc_message = &msg,
		.callback_ops = &nfs_unlink_ops,
		.callback_data = data,
		.workqueue = nfsiod_workqueue,
		.flags = RPC_TASK_ASYNC,
	};
	struct rpc_task *task;
	struct dentry *alias;

	alias = d_lookup(parent, &data->args.name);
	if (alias != NULL) {
		int ret;
		void *devname_garbage = NULL;

		/*
		 * Hey, we raced with lookup... See if we need to transfer
		 * the sillyrename information to the aliased dentry.
		 */
		nfs_free_dname(data);
		ret = nfs_copy_dname(alias, data);
		spin_lock(&alias->d_lock);
		if (ret == 0 && alias->d_inode != NULL &&
		    !(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
			devname_garbage = alias->d_fsdata;
			alias->d_fsdata = data;
			alias->d_flags |= DCACHE_NFSFS_RENAMED;
			ret = 1;
		} else
			ret = 0;
		spin_unlock(&alias->d_lock);
		nfs_dec_sillycount(dir);
		dput(alias);
		/*
		 * If we'd displaced old cached devname, free it.  At that
		 * point dentry is definitely not a root, so we won't need
		 * that anymore.
		 */
		kfree(devname_garbage);
		return ret;
	}
	data->dir = igrab(dir);
	if (!data->dir) {
		nfs_dec_sillycount(dir);
		return 0;
	}
	nfs_sb_active(dir->i_sb);
	data->args.fh = NFS_FH(dir);
	nfs_fattr_init(data->res.dir_attr);

	NFS_PROTO(dir)->unlink_setup(&msg, dir);

	task_setup_data.rpc_client = NFS_CLIENT(dir);
	task = rpc_run_task(&task_setup_data);
	if (!IS_ERR(task))
		rpc_put_task_async(task);
	return 1;
}

static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
{
	struct dentry *parent;
	struct inode *dir;
	int ret = 0;


	parent = dget_parent(dentry);
	if (parent == NULL)
		goto out_free;
	dir = parent->d_inode;
	/* Non-exclusive lock protects against concurrent lookup() calls */
	spin_lock(&dir->i_lock);
	if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) == 0) {
		/* Deferred delete */
		hlist_add_head(&data->list, &NFS_I(dir)->silly_list);
		spin_unlock(&dir->i_lock);
		ret = 1;
		goto out_dput;
	}
	spin_unlock(&dir->i_lock);
	ret = nfs_do_call_unlink(parent, dir, data);
out_dput:
	dput(parent);
out_free:
	return ret;
}

void nfs_wait_on_sillyrename(struct dentry *dentry)
{
	struct nfs_inode *nfsi = NFS_I(dentry->d_inode);

	wait_event(nfsi->waitqueue, atomic_read(&nfsi->silly_count) <= 1);
}

void nfs_block_sillyrename(struct dentry *dentry)
{
	struct nfs_inode *nfsi = NFS_I(dentry->d_inode);

	wait_event(nfsi->waitqueue, atomic_cmpxchg(&nfsi->silly_count, 1, 0) == 1);
}

void nfs_unblock_sillyrename(struct dentry *dentry)
{
	struct inode *dir = dentry->d_inode;
	struct nfs_inode *nfsi = NFS_I(dir);
	struct nfs_unlinkdata *data;

	atomic_inc(&nfsi->silly_count);
	spin_lock(&dir->i_lock);
	while (!hlist_empty(&nfsi->silly_list)) {
		if (!atomic_inc_not_zero(&nfsi->silly_count))
			break;
		data = hlist_entry(nfsi->silly_list.first, struct nfs_unlinkdata, list);
		hlist_del(&data->list);
		spin_unlock(&dir->i_lock);
		if (nfs_do_call_unlink(dentry, dir, data) == 0)
			nfs_free_unlinkdata(data);
		spin_lock(&dir->i_lock);
	}
	spin_unlock(&dir->i_lock);
}

/**
 * nfs_async_unlink - asynchronous unlinking of a file
 * @dir: parent directory of dentry
 * @dentry: dentry to unlink
 */
static int
nfs_async_unlink(struct inode *dir, struct dentry *dentry)
{
	struct nfs_unlinkdata *data;
	int status = -ENOMEM;
	void *devname_garbage = NULL;

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (data == NULL)
		goto out;

	data->cred = rpc_lookup_cred();
	if (IS_ERR(data->cred)) {
		status = PTR_ERR(data->cred);
		goto out_free;
	}
	data->res.dir_attr = &data->dir_attr;

	status = -EBUSY;
	spin_lock(&dentry->d_lock);
	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
		goto out_unlock;
	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
	devname_garbage = dentry->d_fsdata;
	dentry->d_fsdata = data;
	spin_unlock(&dentry->d_lock);
	/*
	 * If we'd displaced old cached devname, free it.  At that
	 * point dentry is definitely not a root, so we won't need
	 * that anymore.
	 */
	kfree(devname_garbage);
	return 0;
out_unlock:
	spin_unlock(&dentry->d_lock);
	put_rpccred(data->cred);
out_free:
	kfree(data);
out:
	return status;
}

/**
 * nfs_complete_unlink - Initialize completion of the sillydelete
 * @dentry: dentry to delete
 * @inode: inode
 *
 * Since we're most likely to be called by dentry_iput(), we
 * only use the dentry to find the sillydelete. We then copy the name
 * into the qstr.
 */
void
nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
{
	struct nfs_unlinkdata	*data = NULL;

	spin_lock(&dentry->d_lock);
	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
		data = dentry->d_fsdata;
		dentry->d_fsdata = NULL;
	}
	spin_unlock(&dentry->d_lock);

	if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
		nfs_free_unlinkdata(data);
}

/* Cancel a queued async unlink. Called when a sillyrename run fails. */
static void
nfs_cancel_async_unlink(struct dentry *dentry)
{
	spin_lock(&dentry->d_lock);
	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
		struct nfs_unlinkdata *data = dentry->d_fsdata;

		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
		dentry->d_fsdata = NULL;
		spin_unlock(&dentry->d_lock);
		nfs_free_unlinkdata(data);
		return;
	}
	spin_unlock(&dentry->d_lock);
}
コード例 #18
0
ファイル: cifs_dfs_ref.c プロジェクト: AppEngine/linux-2.6
static void*
cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
{
	struct dfs_info3_param *referrals = NULL;
	unsigned int num_referrals = 0;
	struct cifs_sb_info *cifs_sb;
	struct cifsSesInfo *ses;
	char *full_path = NULL;
	int xid, i;
	int rc = 0;
	struct vfsmount *mnt = ERR_PTR(-ENOENT);

	cFYI(1, ("in %s", __func__));
	BUG_ON(IS_ROOT(dentry));

	xid = GetXid();

	dput(nd->path.dentry);
	nd->path.dentry = dget(dentry);

	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
	ses = cifs_sb->tcon->ses;

	if (!ses) {
		rc = -EINVAL;
		goto out_err;
	}

	/*
	 * The MSDFS spec states that paths in DFS referral requests and
	 * responses must be prefixed by a single '\' character instead of
	 * the double backslashes usually used in the UNC. This function
	 * gives us the latter, so we must adjust the result.
	 */
	full_path = build_path_from_dentry(dentry);
	if (full_path == NULL) {
		rc = -ENOMEM;
		goto out_err;
	}

	rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls,
		&num_referrals, &referrals,
		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);

	for (i = 0; i < num_referrals; i++) {
		int len;
		dump_referral(referrals+i);
		/* connect to a node */
		len = strlen(referrals[i].node_name);
		if (len < 2) {
			cERROR(1, ("%s: Net Address path too short: %s",
					__func__, referrals[i].node_name));
			rc = -EINVAL;
			goto out_err;
		}
		mnt = cifs_dfs_do_refmount(nd->path.mnt,
				nd->path.dentry, referrals + i);
		cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__,
					referrals[i].node_name, mnt));

		/* complete mount procedure if we accured submount */
		if (!IS_ERR(mnt))
			break;
	}

	/* we need it cause for() above could exit without valid submount */
	rc = PTR_ERR(mnt);
	if (IS_ERR(mnt))
		goto out_err;

	nd->path.mnt->mnt_flags |= MNT_SHRINKABLE;
	rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list);

out:
	FreeXid(xid);
	free_dfs_info_array(referrals, num_referrals);
	kfree(full_path);
	cFYI(1, ("leaving %s" , __func__));
	return ERR_PTR(rc);
out_err:
	path_put(&nd->path);
	goto out;
}
コード例 #19
0
ファイル: super.c プロジェクト: ANFS/ANFS-kernel
static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
				       unsigned table_count)
{
	struct exofs_sb_info *sbi = *psbi;
	struct osd_dev *fscb_od;
	struct osd_obj_id obj = {.partition = sbi->layout.s_pid,
				 .id = EXOFS_DEVTABLE_ID};
	struct exofs_device_table *dt;
	unsigned table_bytes = table_count * sizeof(dt->dt_dev_table[0]) +
					     sizeof(*dt);
	unsigned numdevs, i;
	int ret;

	dt = kmalloc(table_bytes, GFP_KERNEL);
	if (unlikely(!dt)) {
		EXOFS_ERR("ERROR: allocating %x bytes for device table\n",
			  table_bytes);
		return -ENOMEM;
	}

	fscb_od = sbi->layout.s_ods[0];
	sbi->layout.s_ods[0] = NULL;
	sbi->layout.s_numdevs = 0;
	ret = exofs_read_kern(fscb_od, sbi->s_cred, &obj, 0, dt, table_bytes);
	if (unlikely(ret)) {
		EXOFS_ERR("ERROR: reading device table\n");
		goto out;
	}

	numdevs = le64_to_cpu(dt->dt_num_devices);
	if (unlikely(!numdevs)) {
		ret = -EINVAL;
		goto out;
	}
	WARN_ON(table_count != numdevs);

	ret = _read_and_match_data_map(sbi, numdevs, dt);
	if (unlikely(ret))
		goto out;

	if (likely(numdevs > 1)) {
		unsigned size = numdevs * sizeof(sbi->layout.s_ods[0]);

		sbi = krealloc(sbi, sizeof(*sbi) + size, GFP_KERNEL);
		if (unlikely(!sbi)) {
			ret = -ENOMEM;
			goto out;
		}
		memset(&sbi->layout.s_ods[1], 0,
		       size - sizeof(sbi->layout.s_ods[0]));
		*psbi = sbi;
	}

	for (i = 0; i < numdevs; i++) {
		struct exofs_fscb fscb;
		struct osd_dev_info odi;
		struct osd_dev *od;

		if (exofs_devs_2_odi(&dt->dt_dev_table[i], &odi)) {
			EXOFS_ERR("ERROR: Read all-zeros device entry\n");
			ret = -EINVAL;
			goto out;
		}

		printk(KERN_NOTICE "Add device[%d]: osd_name-%s\n",
		       i, odi.osdname);

		/* On all devices the device table is identical. The user can
		 * specify any one of the participating devices on the command
		 * line. We always keep them in device-table order.
		 */
		if (fscb_od && osduld_device_same(fscb_od, &odi)) {
			sbi->layout.s_ods[i] = fscb_od;
			++sbi->layout.s_numdevs;
			fscb_od = NULL;
			continue;
		}

		od = osduld_info_lookup(&odi);
		if (unlikely(IS_ERR(od))) {
			ret = PTR_ERR(od);
			EXOFS_ERR("ERROR: device requested is not found "
				  "osd_name-%s =>%d\n", odi.osdname, ret);
			goto out;
		}

		sbi->layout.s_ods[i] = od;
		++sbi->layout.s_numdevs;

		/* Read the fscb of the other devices to make sure the FS
		 * partition is there.
		 */
		ret = exofs_read_kern(od, sbi->s_cred, &obj, 0, &fscb,
				      sizeof(fscb));
		if (unlikely(ret)) {
			EXOFS_ERR("ERROR: Malformed participating device "
				  "error reading fscb osd_name-%s\n",
				  odi.osdname);
			goto out;
		}

		/* TODO: verify other information is correct and FS-uuid
		 *	 matches. Benny what did you say about device table
		 *	 generation and old devices?
		 */
	}

out:
	kfree(dt);
	if (unlikely(!ret && fscb_od)) {
		EXOFS_ERR(
		      "ERROR: Bad device-table container device not present\n");
		osduld_put_device(fscb_od);
		ret = -EINVAL;
	}

	return ret;
}

/*
 * Read the superblock from the OSD and fill in the fields
 */
static int exofs_fill_super(struct super_block *sb, void *data, int silent)
{
	struct inode *root;
	struct exofs_mountopt *opts = data;
	struct exofs_sb_info *sbi;	/*extended info                  */
	struct osd_dev *od;		/* Master device                 */
	struct exofs_fscb fscb;		/*on-disk superblock info        */
	struct osd_obj_id obj;
	unsigned table_count;
	int ret;

	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
	if (!sbi)
		return -ENOMEM;

	ret = bdi_setup_and_register(&sbi->bdi, "exofs", BDI_CAP_MAP_COPY);
	if (ret)
		goto free_bdi;

	/* use mount options to fill superblock */
	od = osduld_path_lookup(opts->dev_name);
	if (IS_ERR(od)) {
		ret = PTR_ERR(od);
		goto free_sbi;
	}

	/* Default layout in case we do not have a device-table */
	sbi->layout.stripe_unit = PAGE_SIZE;
	sbi->layout.mirrors_p1 = 1;
	sbi->layout.group_width = 1;
	sbi->layout.group_depth = -1;
	sbi->layout.group_count = 1;
	sbi->layout.s_ods[0] = od;
	sbi->layout.s_numdevs = 1;
	sbi->layout.s_pid = opts->pid;
	sbi->s_timeout = opts->timeout;

	/* fill in some other data by hand */
	memset(sb->s_id, 0, sizeof(sb->s_id));
	strcpy(sb->s_id, "exofs");
	sb->s_blocksize = EXOFS_BLKSIZE;
	sb->s_blocksize_bits = EXOFS_BLKSHIFT;
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	atomic_set(&sbi->s_curr_pending, 0);
	sb->s_bdev = NULL;
	sb->s_dev = 0;

	obj.partition = sbi->layout.s_pid;
	obj.id = EXOFS_SUPER_ID;
	exofs_make_credential(sbi->s_cred, &obj);

	ret = exofs_read_kern(od, sbi->s_cred, &obj, 0, &fscb, sizeof(fscb));
	if (unlikely(ret))
		goto free_sbi;

	sb->s_magic = le16_to_cpu(fscb.s_magic);
	sbi->s_nextid = le64_to_cpu(fscb.s_nextid);
	sbi->s_numfiles = le32_to_cpu(fscb.s_numfiles);

	/* make sure what we read from the object store is correct */
	if (sb->s_magic != EXOFS_SUPER_MAGIC) {
		if (!silent)
			EXOFS_ERR("ERROR: Bad magic value\n");
		ret = -EINVAL;
		goto free_sbi;
	}
	if (le32_to_cpu(fscb.s_version) != EXOFS_FSCB_VER) {
		EXOFS_ERR("ERROR: Bad FSCB version expected-%d got-%d\n",
			  EXOFS_FSCB_VER, le32_to_cpu(fscb.s_version));
		ret = -EINVAL;
		goto free_sbi;
	}

	/* start generation numbers from a random point */
	get_random_bytes(&sbi->s_next_generation, sizeof(u32));
	spin_lock_init(&sbi->s_next_gen_lock);

	table_count = le64_to_cpu(fscb.s_dev_table_count);
	if (table_count) {
		ret = exofs_read_lookup_dev_table(&sbi, table_count);
		if (unlikely(ret))
			goto free_sbi;
	}

	/* set up operation vectors */
	sb->s_bdi = &sbi->bdi;
	sb->s_fs_info = sbi;
	sb->s_op = &exofs_sops;
	sb->s_export_op = &exofs_export_ops;
	root = exofs_iget(sb, EXOFS_ROOT_ID - EXOFS_OBJ_OFF);
	if (IS_ERR(root)) {
		EXOFS_ERR("ERROR: exofs_iget failed\n");
		ret = PTR_ERR(root);
		goto free_sbi;
	}
	sb->s_root = d_alloc_root(root);
	if (!sb->s_root) {
		iput(root);
		EXOFS_ERR("ERROR: get root inode failed\n");
		ret = -ENOMEM;
		goto free_sbi;
	}

	if (!S_ISDIR(root->i_mode)) {
		dput(sb->s_root);
		sb->s_root = NULL;
		EXOFS_ERR("ERROR: corrupt root inode (mode = %hd)\n",
		       root->i_mode);
		ret = -EINVAL;
		goto free_sbi;
	}

	_exofs_print_device("Mounting", opts->dev_name, sbi->layout.s_ods[0],
			    sbi->layout.s_pid);
	return 0;

free_sbi:
	bdi_destroy(&sbi->bdi);
free_bdi:
	EXOFS_ERR("Unable to mount exofs on %s pid=0x%llx err=%d\n",
		  opts->dev_name, sbi->layout.s_pid, ret);
	exofs_free_sbi(sbi);
	return ret;
}

/*
 * Set up the superblock (calls exofs_fill_super eventually)
 */
static struct dentry *exofs_mount(struct file_system_type *type,
			  int flags, const char *dev_name,
			  void *data)
{
	struct exofs_mountopt opts;
	int ret;

	ret = parse_options(data, &opts);
	if (ret)
		return ERR_PTR(ret);

	opts.dev_name = dev_name;
	return mount_nodev(type, flags, &opts, exofs_fill_super);
}

/*
 * Return information about the file system state in the buffer.  This is used
 * by the 'df' command, for example.
 */
static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
	struct super_block *sb = dentry->d_sb;
	struct exofs_sb_info *sbi = sb->s_fs_info;
	struct exofs_io_state *ios;
	struct osd_attr attrs[] = {
		ATTR_DEF(OSD_APAGE_PARTITION_QUOTAS,
			OSD_ATTR_PQ_CAPACITY_QUOTA, sizeof(__be64)),
		ATTR_DEF(OSD_APAGE_PARTITION_INFORMATION,
			OSD_ATTR_PI_USED_CAPACITY, sizeof(__be64)),
	};
	uint64_t capacity = ULLONG_MAX;
	uint64_t used = ULLONG_MAX;
	uint8_t cred_a[OSD_CAP_LEN];
	int ret;

	ret = exofs_get_io_state(&sbi->layout, &ios);
	if (ret) {
		EXOFS_DBGMSG("exofs_get_io_state failed.\n");
		return ret;
	}

	exofs_make_credential(cred_a, &ios->obj);
	ios->cred = sbi->s_cred;
	ios->in_attr = attrs;
	ios->in_attr_len = ARRAY_SIZE(attrs);

	ret = exofs_sbi_read(ios);
	if (unlikely(ret))
		goto out;

	ret = extract_attr_from_ios(ios, &attrs[0]);
	if (likely(!ret)) {
		capacity = get_unaligned_be64(attrs[0].val_ptr);
		if (unlikely(!capacity))
			capacity = ULLONG_MAX;
	} else
		EXOFS_DBGMSG("exofs_statfs: get capacity failed.\n");

	ret = extract_attr_from_ios(ios, &attrs[1]);
	if (likely(!ret))
		used = get_unaligned_be64(attrs[1].val_ptr);
	else
		EXOFS_DBGMSG("exofs_statfs: get used-space failed.\n");

	/* fill in the stats buffer */
	buf->f_type = EXOFS_SUPER_MAGIC;
	buf->f_bsize = EXOFS_BLKSIZE;
	buf->f_blocks = capacity >> 9;
	buf->f_bfree = (capacity - used) >> 9;
	buf->f_bavail = buf->f_bfree;
	buf->f_files = sbi->s_numfiles;
	buf->f_ffree = EXOFS_MAX_ID - sbi->s_numfiles;
	buf->f_namelen = EXOFS_NAME_LEN;

out:
	exofs_put_io_state(ios);
	return ret;
}

static const struct super_operations exofs_sops = {
	.alloc_inode    = exofs_alloc_inode,
	.destroy_inode  = exofs_destroy_inode,
	.write_inode    = exofs_write_inode,
	.evict_inode    = exofs_evict_inode,
	.put_super      = exofs_put_super,
	.write_super    = exofs_write_super,
	.sync_fs	= exofs_sync_fs,
	.statfs         = exofs_statfs,
};

/******************************************************************************
 * EXPORT OPERATIONS
 *****************************************************************************/

struct dentry *exofs_get_parent(struct dentry *child)
{
	unsigned long ino = exofs_parent_ino(child);

	if (!ino)
		return NULL;

	return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino));
}
コード例 #20
0
ファイル: file.c プロジェクト: marceleng/linux
static int au_ready_to_write_wh(struct file *file, loff_t len,
				aufs_bindex_t bcpup, struct au_pin *pin)
{
	int err;
	struct inode *inode, *h_inode;
	struct dentry *h_dentry, *hi_wh;
	struct au_cp_generic cpg = {
		.dentry	= file->f_dentry,
		.bdst	= bcpup,
		.bsrc	= -1,
		.len	= len,
		.pin	= pin
	};

	au_update_dbstart(cpg.dentry);
	inode = cpg.dentry->d_inode;
	h_inode = NULL;
	if (au_dbstart(cpg.dentry) <= bcpup
	    && au_dbend(cpg.dentry) >= bcpup) {
		h_dentry = au_h_dptr(cpg.dentry, bcpup);
		if (h_dentry)
			h_inode = h_dentry->d_inode;
	}
	hi_wh = au_hi_wh(inode, bcpup);
	if (!hi_wh && !h_inode)
		err = au_sio_cpup_wh(&cpg, file);
	else
		/* already copied-up after unlink */
		err = au_reopen_wh(file, bcpup, hi_wh);

	if (!err
	    && inode->i_nlink > 1
	    && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK))
		au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup));

	return err;
}

/*
 * prepare the @file for writing.
 */
int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
{
	int err;
	aufs_bindex_t dbstart;
	struct dentry *parent, *h_dentry;
	struct inode *inode;
	struct super_block *sb;
	struct file *h_file;
	struct au_cp_generic cpg = {
		.dentry	= file->f_dentry,
		.bdst	= -1,
		.bsrc	= -1,
		.len	= len,
		.pin	= pin,
		.flags	= AuCpup_DTIME
	};

	sb = cpg.dentry->d_sb;
	inode = cpg.dentry->d_inode;
	AuDebugOn(au_special_file(inode->i_mode));
	cpg.bsrc = au_fbstart(file);
	err = au_test_ro(sb, cpg.bsrc, inode);
	if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) {
		err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE,
			     /*flags*/0);
		goto out;
	}

	/* need to cpup or reopen */
	parent = dget_parent(cpg.dentry);
	di_write_lock_parent(parent);
	err = AuWbrCopyup(au_sbi(sb), cpg.dentry);
	cpg.bdst = err;
	if (unlikely(err < 0))
		goto out_dgrade;
	err = 0;

	if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) {
		err = au_cpup_dirs(cpg.dentry, cpg.bdst);
		if (unlikely(err))
			goto out_dgrade;
	}

	err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE,
		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
	if (unlikely(err))
		goto out_dgrade;

	h_dentry = au_hf_top(file)->f_dentry;
	dbstart = au_dbstart(cpg.dentry);
	if (dbstart <= cpg.bdst) {
		h_dentry = au_h_dptr(cpg.dentry, cpg.bdst);
		AuDebugOn(!h_dentry);
		cpg.bsrc = cpg.bdst;
	}

	if (dbstart <= cpg.bdst		/* just reopen */
	    || !d_unhashed(cpg.dentry)	/* copyup and reopen */
		) {
		h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0);
		if (IS_ERR(h_file))
			err = PTR_ERR(h_file);
		else {
			di_downgrade_lock(parent, AuLock_IR);
			if (dbstart > cpg.bdst)
				err = au_sio_cpup_simple(&cpg);
			if (!err)
				err = au_reopen_nondir(file);
			au_h_open_post(cpg.dentry, cpg.bsrc, h_file);
		}
	} else {			/* copyup as wh and reopen */
		/*
		 * since writable hfsplus branch is not supported,
		 * h_open_pre/post() are unnecessary.
		 */
		err = au_ready_to_write_wh(file, len, cpg.bdst, pin);
		di_downgrade_lock(parent, AuLock_IR);
	}

	if (!err) {
		au_pin_set_parent_lflag(pin, /*lflag*/0);
		goto out_dput; /* success */
	}
	au_unpin(pin);
	goto out_unlock;

out_dgrade:
	di_downgrade_lock(parent, AuLock_IR);
out_unlock:
	di_read_unlock(parent, AuLock_IR);
out_dput:
	dput(parent);
out:
	return err;
}

/* ---------------------------------------------------------------------- */

int au_do_flush(struct file *file, fl_owner_t id,
		int (*flush)(struct file *file, fl_owner_t id))
{
	int err;
	struct super_block *sb;
	struct inode *inode;

	inode = file_inode(file);
	sb = inode->i_sb;
	si_noflush_read_lock(sb);
	fi_read_lock(file);
	ii_read_lock_child(inode);

	err = flush(file, id);
	au_cpup_attr_timesizes(inode);

	ii_read_unlock(inode);
	fi_read_unlock(file);
	si_read_unlock(sb);
	return err;
}
コード例 #21
0
ファイル: i_op_add.c プロジェクト: aywq2008/omniplay
int aufs_link(struct dentry *src_dentry, struct inode *dir,
              struct dentry *dentry)
{
    int err, rerr;
    struct au_dtime dt;
    struct au_link_args *a;
    struct dentry *wh_dentry, *h_src_dentry;
    struct inode *inode;
    struct super_block *sb;
    struct au_wr_dir_args wr_dir_args = {
        /* .force_btgt	= -1, */
        .flags		= AuWrDir_ADD_ENTRY
    };

    IMustLock(dir);
    inode = src_dentry->d_inode;
    IMustLock(inode);

    err = -ENOMEM;
    a = kzalloc(sizeof(*a), GFP_NOFS);
    if (unlikely(!a))
        goto out;

    a->parent = dentry->d_parent; /* dir inode is locked */
    err = aufs_read_and_write_lock2(dentry, src_dentry,
                                    AuLock_NOPLM | AuLock_GEN);
    if (unlikely(err))
        goto out_kfree;
    err = au_d_hashed_positive(src_dentry);
    if (unlikely(err))
        goto out_unlock;
    err = au_d_may_add(dentry);
    if (unlikely(err))
        goto out_unlock;

    a->src_parent = dget_parent(src_dentry);
    wr_dir_args.force_btgt = au_ibstart(inode);

    di_write_lock_parent(a->parent);
    wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt);
    wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin,
                                  &wr_dir_args);
    err = PTR_ERR(wh_dentry);
    if (IS_ERR(wh_dentry))
        goto out_parent;

    err = 0;
    sb = dentry->d_sb;
    a->bdst = au_dbstart(dentry);
    a->h_path.dentry = au_h_dptr(dentry, a->bdst);
    a->h_path.mnt = au_sbr_mnt(sb, a->bdst);
    a->bsrc = au_ibstart(inode);
    h_src_dentry = au_h_d_alias(src_dentry, a->bsrc);
    if (!h_src_dentry) {
        a->bsrc = au_dbstart(src_dentry);
        h_src_dentry = au_h_d_alias(src_dentry, a->bsrc);
        AuDebugOn(!h_src_dentry);
    } else if (IS_ERR(h_src_dentry))
        goto out_parent;

    if (au_opt_test(au_mntflags(sb), PLINK)) {
        if (a->bdst < a->bsrc
                /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */)
            err = au_cpup_or_link(src_dentry, a);
        else
            err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin),
                             &a->h_path);
        dput(h_src_dentry);
    } else {
        /*
         * copyup src_dentry to the branch we process,
         * and then link(2) to it.
         */
        dput(h_src_dentry);
        if (a->bdst < a->bsrc
                /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) {
            au_unpin(&a->pin);
            di_write_unlock(a->parent);
            err = au_cpup_before_link(src_dentry, a);
            di_write_lock_parent(a->parent);
            if (!err)
                err = au_pin(&a->pin, dentry, a->bdst,
                             au_opt_udba(sb),
                             AuPin_DI_LOCKED | AuPin_MNT_WRITE);
            if (unlikely(err))
                goto out_wh;
        }
        if (!err) {
            h_src_dentry = au_h_dptr(src_dentry, a->bdst);
            err = -ENOENT;
            if (h_src_dentry && h_src_dentry->d_inode)
                err = vfsub_link(h_src_dentry,
                                 au_pinned_h_dir(&a->pin),
                                 &a->h_path);
        }
    }
    if (unlikely(err))
        goto out_unpin;

    if (wh_dentry) {
        a->h_path.dentry = wh_dentry;
        err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path,
                                  dentry);
        if (unlikely(err))
            goto out_revert;
    }

    dir->i_version++;
    if (au_ibstart(dir) == au_dbstart(dentry))
        au_cpup_attr_timesizes(dir);
    inc_nlink(inode);
    inode->i_ctime = dir->i_ctime;
    d_instantiate(dentry, au_igrab(inode));
    if (d_unhashed(a->h_path.dentry))
        /* some filesystem calls d_drop() */
        d_drop(dentry);
    goto out_unpin; /* success */

out_revert:
    rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0);
    if (unlikely(rerr)) {
        AuIOErr("%.*s reverting failed(%d, %d)\n",
                AuDLNPair(dentry), err, rerr);
        err = -EIO;
    }
    au_dtime_revert(&dt);
out_unpin:
    au_unpin(&a->pin);
out_wh:
    dput(wh_dentry);
out_parent:
    di_write_unlock(a->parent);
    dput(a->src_parent);
out_unlock:
    if (unlikely(err)) {
        au_update_dbstart(dentry);
        d_drop(dentry);
    }
    aufs_read_and_write_unlock2(dentry, src_dentry);
out_kfree:
    kfree(a);
out:
    return err;
}
コード例 #22
0
ファイル: file.c プロジェクト: marceleng/linux
static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
{
	int err;
	struct au_pin pin;
	struct au_finfo *finfo;
	struct dentry *parent, *hi_wh;
	struct inode *inode;
	struct super_block *sb;
	struct au_cp_generic cpg = {
		.dentry	= file->f_dentry,
		.bdst	= -1,
		.bsrc	= -1,
		.len	= -1,
		.pin	= &pin,
		.flags	= AuCpup_DTIME
	};

	FiMustWriteLock(file);

	err = 0;
	finfo = au_fi(file);
	sb = cpg.dentry->d_sb;
	inode = cpg.dentry->d_inode;
	cpg.bdst = au_ibstart(inode);
	if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry))
		goto out;

	parent = dget_parent(cpg.dentry);
	if (au_test_ro(sb, cpg.bdst, inode)) {
		di_read_lock_parent(parent, !AuLock_IR);
		err = AuWbrCopyup(au_sbi(sb), cpg.dentry);
		cpg.bdst = err;
		di_read_unlock(parent, !AuLock_IR);
		if (unlikely(err < 0))
			goto out_parent;
		err = 0;
	}

	di_read_lock_parent(parent, AuLock_IR);
	hi_wh = au_hi_wh(inode, cpg.bdst);
	if (!S_ISDIR(inode->i_mode)
	    && au_opt_test(au_mntflags(sb), PLINK)
	    && au_plink_test(inode)
	    && !d_unhashed(cpg.dentry)
	    && cpg.bdst < au_dbstart(cpg.dentry)) {
		err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst);
		if (unlikely(err))
			goto out_unlock;

		/* always superio. */
		err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE,
			     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
		if (!err) {
			err = au_sio_cpup_simple(&cpg);
			au_unpin(&pin);
		}
	} else if (hi_wh) {
		/* already copied-up after unlink */
		err = au_reopen_wh(file, cpg.bdst, hi_wh);
		*need_reopen = 0;
	}

out_unlock:
	di_read_unlock(parent, AuLock_IR);
out_parent:
	dput(parent);
out:
	return err;
}

static void au_do_refresh_dir(struct file *file)
{
	aufs_bindex_t bindex, bend, new_bindex, brid;
	struct au_hfile *p, tmp, *q;
	struct au_finfo *finfo;
	struct super_block *sb;
	struct au_fidir *fidir;

	FiMustWriteLock(file);

	sb = file->f_dentry->d_sb;
	finfo = au_fi(file);
	fidir = finfo->fi_hdir;
	AuDebugOn(!fidir);
	p = fidir->fd_hfile + finfo->fi_btop;
	brid = p->hf_br->br_id;
	bend = fidir->fd_bbot;
	for (bindex = finfo->fi_btop; bindex <= bend; bindex++, p++) {
		if (!p->hf_file)
			continue;

		new_bindex = au_br_index(sb, p->hf_br->br_id);
		if (new_bindex == bindex)
			continue;
		if (new_bindex < 0) {
			au_set_h_fptr(file, bindex, NULL);
			continue;
		}

		/* swap two lower inode, and loop again */
		q = fidir->fd_hfile + new_bindex;
		tmp = *q;
		*q = *p;
		*p = tmp;
		if (tmp.hf_file) {
			bindex--;
			p--;
		}
	}

	p = fidir->fd_hfile;
	if (!au_test_mmapped(file) && !d_unlinked(file->f_dentry)) {
		bend = au_sbend(sb);
		for (finfo->fi_btop = 0; finfo->fi_btop <= bend;
		     finfo->fi_btop++, p++)
			if (p->hf_file) {
				if (file_inode(p->hf_file))
					break;
				else
					au_hfput(p, file);
			}
	} else {
		bend = au_br_index(sb, brid);
		for (finfo->fi_btop = 0; finfo->fi_btop < bend;
		     finfo->fi_btop++, p++)
			if (p->hf_file)
				au_hfput(p, file);
		bend = au_sbend(sb);
	}

	p = fidir->fd_hfile + bend;
	for (fidir->fd_bbot = bend; fidir->fd_bbot >= finfo->fi_btop;
	     fidir->fd_bbot--, p--)
		if (p->hf_file) {
			if (file_inode(p->hf_file))
				break;
			else
				au_hfput(p, file);
		}
	AuDebugOn(fidir->fd_bbot < finfo->fi_btop);
}
コード例 #23
0
ファイル: dir.c プロジェクト: AnwariJr/Zenfone-Kernel
/*
 * Check whether the dentry is still valid
 *
 * If the entry validity timeout has expired and the dentry is
 * positive, try to redo the lookup.  If the lookup results in a
 * different inode, then let the VFS invalidate the dentry and redo
 * the lookup once more.  If the lookup results in the same inode,
 * then refresh the attributes, timeouts and mark the dentry valid.
 */
static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
{
	struct inode *inode;

	inode = ACCESS_ONCE(entry->d_inode);
	if (inode && is_bad_inode(inode))
		return 0;
	else if (fuse_dentry_time(entry) < get_jiffies_64()) {
		int err;
		struct fuse_entry_out outarg;
		struct fuse_conn *fc;
		struct fuse_req *req;
		struct fuse_forget_link *forget;
		struct dentry *parent;
		u64 attr_version;

		/* For negative dentries, always do a fresh lookup */
		if (!inode)
			return 0;

		if (nd && (nd->flags & LOOKUP_RCU))
			return -ECHILD;

		fc = get_fuse_conn(inode);
		req = fuse_get_req(fc);
		if (IS_ERR(req))
			return 0;

		forget = fuse_alloc_forget();
		if (!forget) {
			fuse_put_request(fc, req);
			return 0;
		}

		attr_version = fuse_get_attr_version(fc);

		parent = dget_parent(entry);
		fuse_lookup_init(fc, req, get_node_id(parent->d_inode),
				 &entry->d_name, &outarg);
		fuse_request_send(fc, req);
		dput(parent);
		err = req->out.h.error;
		fuse_put_request(fc, req);
		/* Zero nodeid is same as -ENOENT */
		if (!err && !outarg.nodeid)
			err = -ENOENT;
		if (!err) {
			struct fuse_inode *fi = get_fuse_inode(inode);
			if (outarg.nodeid != get_node_id(inode)) {
				fuse_queue_forget(fc, forget, outarg.nodeid, 1);
				return 0;
			}
			spin_lock(&fc->lock);
			fi->nlookup++;
			spin_unlock(&fc->lock);
		}
		kfree(forget);
		if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
			return 0;

		fuse_change_attributes(inode, &outarg.attr,
				       entry_attr_timeout(&outarg),
				       attr_version);
		fuse_change_entry_timeout(entry, &outarg);
	}
	return 1;
}
コード例 #24
0
STATIC int
xfs_attrmulti_by_handle(
	struct file		*parfilp,
	void			__user *arg)
{
	int			error;
	xfs_attr_multiop_t	*ops;
	xfs_fsop_attrmulti_handlereq_t am_hreq;
	struct dentry		*dentry;
	unsigned int		i, size;
	char			*attr_name;

	if (!capable(CAP_SYS_ADMIN))
		return -XFS_ERROR(EPERM);
	if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t)))
		return -XFS_ERROR(EFAULT);

	dentry = xfs_handlereq_to_dentry(parfilp, &am_hreq.hreq);
	if (IS_ERR(dentry))
		return PTR_ERR(dentry);

	error = E2BIG;
	size = am_hreq.opcount * sizeof(xfs_attr_multiop_t);
	if (!size || size > 16 * PAGE_SIZE)
		goto out_dput;

	ops = memdup_user(am_hreq.ops, size);
	if (IS_ERR(ops)) {
		error = PTR_ERR(ops);
		goto out_dput;
	}

	attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
	if (!attr_name)
		goto out_kfree_ops;

	error = 0;
	for (i = 0; i < am_hreq.opcount; i++) {
		ops[i].am_error = strncpy_from_user(attr_name,
				ops[i].am_attrname, MAXNAMELEN);
		if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
			error = -ERANGE;
		if (ops[i].am_error < 0)
			break;

		switch (ops[i].am_opcode) {
		case ATTR_OP_GET:
			ops[i].am_error = xfs_attrmulti_attr_get(
					dentry->d_inode, attr_name,
					ops[i].am_attrvalue, &ops[i].am_length,
					ops[i].am_flags);
			break;
		case ATTR_OP_SET:
			ops[i].am_error = mnt_want_write(parfilp->f_path.mnt);
			if (ops[i].am_error)
				break;
			ops[i].am_error = xfs_attrmulti_attr_set(
					dentry->d_inode, attr_name,
					ops[i].am_attrvalue, ops[i].am_length,
					ops[i].am_flags);
			mnt_drop_write(parfilp->f_path.mnt);
			break;
		case ATTR_OP_REMOVE:
			ops[i].am_error = mnt_want_write(parfilp->f_path.mnt);
			if (ops[i].am_error)
				break;
			ops[i].am_error = xfs_attrmulti_attr_remove(
					dentry->d_inode, attr_name,
					ops[i].am_flags);
			mnt_drop_write(parfilp->f_path.mnt);
			break;
		default:
			ops[i].am_error = EINVAL;
		}
	}

	if (copy_to_user(am_hreq.ops, ops, size))
		error = XFS_ERROR(EFAULT);

	kfree(attr_name);
 out_kfree_ops:
	kfree(ops);
 out_dput:
	dput(dentry);
	return -error;
}
コード例 #25
0
ファイル: dir.c プロジェクト: AnwariJr/Zenfone-Kernel
int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
			     u64 child_nodeid, struct qstr *name)
{
	int err = -ENOTDIR;
	struct inode *parent;
	struct dentry *dir;
	struct dentry *entry;

	parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid);
	if (!parent)
		return -ENOENT;

	mutex_lock(&parent->i_mutex);
	if (!S_ISDIR(parent->i_mode))
		goto unlock;

	err = -ENOENT;
	dir = d_find_alias(parent);
	if (!dir)
		goto unlock;

	entry = d_lookup(dir, name);
	dput(dir);
	if (!entry)
		goto unlock;

	fuse_invalidate_attr(parent);
	fuse_invalidate_entry(entry);

	if (child_nodeid != 0 && entry->d_inode) {
		mutex_lock(&entry->d_inode->i_mutex);
		if (get_node_id(entry->d_inode) != child_nodeid) {
			err = -ENOENT;
			goto badentry;
		}
		if (d_mountpoint(entry)) {
			err = -EBUSY;
			goto badentry;
		}
		if (S_ISDIR(entry->d_inode->i_mode)) {
			shrink_dcache_parent(entry);
			if (!simple_empty(entry)) {
				err = -ENOTEMPTY;
				goto badentry;
			}
			entry->d_inode->i_flags |= S_DEAD;
		}
		dont_mount(entry);
		clear_nlink(entry->d_inode);
		err = 0;
 badentry:
		mutex_unlock(&entry->d_inode->i_mutex);
		if (!err)
			d_delete(entry);
	} else {
		err = 0;
	}
	dput(entry);

 unlock:
	mutex_unlock(&parent->i_mutex);
	iput(parent);
	return err;
}
コード例 #26
0
/**
 * anon_inode_getfd - creates a new file instance by hooking it up to an
 *                    anonymous inode, and a dentry that describe the "class"
 *                    of the file
 *
 * @name:    [in]    name of the "class" of the new file
 * @fops:    [in]    file operations for the new file
 * @priv:    [in]    private data for the new file (will be file's private_data)
 * @flags:   [in]    flags
 *
 * Creates a new file by hooking it on a single inode. This is useful for files
 * that do not need to have a full-fledged inode in order to operate correctly.
 * All the files created with anon_inode_getfd() will share a single inode,
 * hence saving memory and avoiding code duplication for the file/inode/dentry
 * setup.  Returns new descriptor or -error.
 */
int anon_inode_getfd(const char *name, const struct file_operations *fops,
		     void *priv, int flags)
{
	struct qstr this;
	struct dentry *dentry;
	struct file *file;
	int error, fd;

	if (IS_ERR(anon_inode_inode))
		return -ENODEV;

	if (fops->owner && !try_module_get(fops->owner))
		return -ENOENT;

	error = get_unused_fd_flags(flags);
	if (error < 0)
		goto err_module;
	fd = error;

	/*
	 * Link the inode to a directory entry by creating a unique name
	 * using the inode sequence number.
	 */
	error = -ENOMEM;
	this.name = name;
	this.len = strlen(name);
	this.hash = 0;
	dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this);
	if (!dentry)
		goto err_put_unused_fd;

	/*
	 * We know the anon_inode inode count is always greater than zero,
	 * so we can avoid doing an igrab() and we can use an open-coded
	 * atomic_inc().
	 */
	atomic_inc(&anon_inode_inode->i_count);

	dentry->d_op = &anon_inodefs_dentry_operations;
	/* Do not publish this dentry inside the global dentry hash table */
	dentry->d_flags &= ~DCACHE_UNHASHED;
	d_instantiate(dentry, anon_inode_inode);

	error = -ENFILE;
	file = alloc_file(anon_inode_mnt, dentry,
			  FMODE_READ | FMODE_WRITE, fops);
	if (!file)
		goto err_dput;
	file->f_mapping = anon_inode_inode->i_mapping;

	file->f_pos = 0;
	file->f_flags = O_RDWR | (flags & O_NONBLOCK);
	file->f_version = 0;
	file->private_data = priv;

	fd_install(fd, file);

	return fd;

err_dput:
	dput(dentry);
err_put_unused_fd:
	put_unused_fd(fd);
err_module:
	module_put(fops->owner);
	return error;
}
コード例 #27
0
ファイル: export.c プロジェクト: wosigh/patches
static noinline_for_stack
struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex,
			      ino_t ino, __u32 *fh, int fh_len,
			      struct au_nfsd_si_lock *nsi_lock)
{
	struct dentry *dentry, *h_parent, *root;
	struct super_block *h_sb;
	char *pathname, *p;
	struct vfsmount *h_mnt;
	struct au_branch *br;
	int err;
	struct nameidata nd;
	struct path path;

	LKTRTrace("b%d\n", bindex);
	SiMustAnyLock(sb);

	br = au_sbr(sb, bindex);
	/* au_br_get(br); */
	h_mnt = br->br_mnt;
	h_sb = h_mnt->mnt_sb;
	LKTRTrace("%s, h_decode_fh\n", au_sbtype(h_sb));
	h_parent = au_call_decode_fh(h_mnt, fh + Fh_tail, fh_len - Fh_tail,
				     fh[Fh_h_type], h_acceptable,
				     /*context*/NULL);
	dentry = h_parent;
	if (unlikely(!h_parent || IS_ERR(h_parent))) {
		AuWarn1("%s decode_fh failed, %ld\n",
			au_sbtype(h_sb), PTR_ERR(h_parent));
		goto out;
	}
	dentry = NULL;
	if (unlikely(au_test_anon(h_parent))) {
		AuWarn1("%s decode_fh returned a disconnected dentry\n",
			au_sbtype(h_sb));
		goto out_h_parent;
	}

	dentry = ERR_PTR(-ENOMEM);
	pathname = (void *)__get_free_page(GFP_NOFS);
	if (unlikely(!pathname))
		goto out_h_parent;

	root = sb->s_root;
	path.mnt = h_mnt;
	di_read_lock_parent(root, !AuLock_IR);
	path.dentry = au_h_dptr(root, bindex);
	di_read_unlock(root, !AuLock_IR);
	p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb);
	dentry = (void *)p;
	if (IS_ERR(p))
		goto out_pathname;

	LKTRTrace("%s\n", p);
	si_read_unlock(sb);
	err = vfsub_path_lookup(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
	dentry = ERR_PTR(err);
	if (unlikely(err))
		goto out_relock;

	dentry = ERR_PTR(-ENOENT);
	AuDebugOn(au_test_anon(nd.dentry));
	if (unlikely(!nd.dentry->d_inode))
		goto out_nd;

	if (ino != nd.dentry->d_inode->i_ino) {
		path.mnt = nd.mnt;
		path.dentry = nd.dentry;
		dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL);
	} else
		dentry = dget(nd.dentry);

 out_nd:
	path_release(&nd);
 out_relock:
	if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0))
		if (!IS_ERR(dentry)) {
			dput(dentry);
			dentry = ERR_PTR(-ESTALE);
		}
 out_pathname:
	free_page((unsigned long)pathname);
 out_h_parent:
	dput(h_parent);
 out:
	/* au_br_put(br); */
	AuTraceErrPtr(dentry);
	return dentry;
}
コード例 #28
0
ファイル: mvdown.c プロジェクト: marceleng/linux
/* copy-down the file */
static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a)
{
	int err;
	struct au_cp_generic cpg = {
		.dentry	= a->dentry,
		.bdst	= a->mvd_bdst,
		.bsrc	= a->mvd_bsrc,
		.len	= -1,
		.pin	= &a->pin,
		.flags	= AuCpup_DTIME | AuCpup_HOPEN
	};

	AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst);
	if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER)
		au_fset_cpup(cpg.flags, OVERWRITE);
	if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER)
		au_fset_cpup(cpg.flags, RWDST);
	err = au_sio_cpdown_simple(&cpg);
	if (unlikely(err))
		AU_MVD_PR(dmsg, "cpdown failed\n");

	AuTraceErr(err);
	return err;
}

/*
 * unlink the whiteout on bdst if exist which may be created by UDBA while we
 * were sleeping
 */
static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a)
{
	int err;
	struct path h_path;
	struct au_branch *br;
	struct inode *delegated;

	br = au_sbr(a->sb, a->mvd_bdst);
	h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br);
	err = PTR_ERR(h_path.dentry);
	if (IS_ERR(h_path.dentry)) {
		AU_MVD_PR(dmsg, "wh_lkup failed\n");
		goto out;
	}

	err = 0;
	if (h_path.dentry->d_inode) {
		h_path.mnt = au_br_mnt(br);
		delegated = NULL;
		err = vfsub_unlink(a->mvd_h_dst_parent->d_inode, &h_path,
				   &delegated, /*force*/0);
		if (unlikely(err == -EWOULDBLOCK)) {
			pr_warn("cannot retry for NFSv4 delegation"
				" for an internal unlink\n");
			iput(delegated);
		}
		if (unlikely(err))
			AU_MVD_PR(dmsg, "wh_unlink failed\n");
	}
	dput(h_path.dentry);

out:
	AuTraceErr(err);
	return err;
}
コード例 #29
0
int
xfs_open_by_handle(
    struct file		*parfilp,
    xfs_fsop_handlereq_t	*hreq)
{
    const struct cred	*cred = current_cred();
    int			error;
    int			fd;
    int			permflag;
    struct file		*filp;
    struct inode		*inode;
    struct dentry		*dentry;
    fmode_t			fmode;
    struct path		path;

    if (!capable(CAP_SYS_ADMIN))
        return -XFS_ERROR(EPERM);

    dentry = xfs_handlereq_to_dentry(parfilp, hreq);
    if (IS_ERR(dentry))
        return PTR_ERR(dentry);
    inode = dentry->d_inode;

    /* Restrict xfs_open_by_handle to directories & regular files. */
    if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
        error = -XFS_ERROR(EPERM);
        goto out_dput;
    }

#if BITS_PER_LONG != 32
    hreq->oflags |= O_LARGEFILE;
#endif

    permflag = hreq->oflags;
    fmode = OPEN_FMODE(permflag);
    if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
            (fmode & FMODE_WRITE) && IS_APPEND(inode)) {
        error = -XFS_ERROR(EPERM);
        goto out_dput;
    }

    if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
        error = -XFS_ERROR(EACCES);
        goto out_dput;
    }

    /* Can't write directories. */
    if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) {
        error = -XFS_ERROR(EISDIR);
        goto out_dput;
    }

    fd = get_unused_fd();
    if (fd < 0) {
        error = fd;
        goto out_dput;
    }

    path.mnt = parfilp->f_path.mnt;
    path.dentry = dentry;
    filp = dentry_open(&path, hreq->oflags, cred);
    dput(dentry);
    if (IS_ERR(filp)) {
        put_unused_fd(fd);
        return PTR_ERR(filp);
    }

    if (S_ISREG(inode->i_mode)) {
        filp->f_flags |= O_NOATIME;
        filp->f_mode |= FMODE_NOCMTIME;
    }

    fd_install(fd, filp);
    return fd;

out_dput:
    dput(dentry);
    return error;
}
コード例 #30
0
ファイル: dir.c プロジェクト: flwh/Alcatel_OT_985_kernel
static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
{
	struct afs_vnode *vnode, *dir;
	struct afs_fid uninitialized_var(fid);
	struct dentry *parent;
	struct key *key;
	void *dir_version;
	int ret;

	vnode = AFS_FS_I(dentry->d_inode);

	if (dentry->d_inode)
		_enter("{v={%x:%u} n=%s fl=%lx},",
		       vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
		       vnode->flags);
	else
		_enter("{neg n=%s}", dentry->d_name.name);

	key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell);
	if (IS_ERR(key))
		key = NULL;

	/* lock down the parent dentry so we can peer at it */
	parent = dget_parent(dentry);
	if (!parent->d_inode)
		goto out_bad;

	dir = AFS_FS_I(parent->d_inode);

	/* validate the parent directory */
	if (test_bit(AFS_VNODE_MODIFIED, &dir->flags))
		afs_validate(dir, key);

	if (test_bit(AFS_VNODE_DELETED, &dir->flags)) {
		_debug("%s: parent dir deleted", dentry->d_name.name);
		goto out_bad;
	}

	dir_version = (void *) (unsigned long) dir->status.data_version;
	if (dentry->d_fsdata == dir_version)
		goto out_valid; /* the dir contents are unchanged */

	_debug("dir modified");

	/* search the directory for this vnode */
	ret = afs_do_lookup(&dir->vfs_inode, dentry, &fid, key);
	switch (ret) {
	case 0:
		/* the filename maps to something */
		if (!dentry->d_inode)
			goto out_bad;
		if (is_bad_inode(dentry->d_inode)) {
			printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n",
			       parent->d_name.name, dentry->d_name.name);
			goto out_bad;
		}

		/* if the vnode ID has changed, then the dirent points to a
		 * different file */
		if (fid.vnode != vnode->fid.vnode) {
			_debug("%s: dirent changed [%u != %u]",
			       dentry->d_name.name, fid.vnode,
			       vnode->fid.vnode);
			goto not_found;
		}

		/* if the vnode ID uniqifier has changed, then the file has
		 * been deleted and replaced, and the original vnode ID has
		 * been reused */
		if (fid.unique != vnode->fid.unique) {
			_debug("%s: file deleted (uq %u -> %u I:%llu)",
			       dentry->d_name.name, fid.unique,
			       vnode->fid.unique,
			       (unsigned long long)dentry->d_inode->i_version);
			spin_lock(&vnode->lock);
			set_bit(AFS_VNODE_DELETED, &vnode->flags);
			spin_unlock(&vnode->lock);
			goto not_found;
		}
		goto out_valid;

	case -ENOENT:
		/* the filename is unknown */
		_debug("%s: dirent not found", dentry->d_name.name);
		if (dentry->d_inode)
			goto not_found;
		goto out_valid;

	default:
		_debug("failed to iterate dir %s: %d",
		       parent->d_name.name, ret);
		goto out_bad;
	}

out_valid:
	dentry->d_fsdata = dir_version;
out_skip:
	dput(parent);
	key_put(key);
	_leave(" = 1 [valid]");
	return 1;

	/* the dirent, if it exists, now points to a different vnode */
not_found:
	spin_lock(&dentry->d_lock);
	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
	spin_unlock(&dentry->d_lock);

out_bad:
	if (dentry->d_inode) {
		/* don't unhash if we have submounts */
		if (have_submounts(dentry))
			goto out_skip;
	}

	_debug("dropping dentry %s/%s",
	       parent->d_name.name, dentry->d_name.name);
	shrink_dcache_parent(dentry);
	d_drop(dentry);
	dput(parent);
	key_put(key);

	_leave(" = 0 [bad]");
	return 0;
}