Beispiel #1
0
/*
 * A single inode exist for all anon_inode files. Contrary to pipes,
 * anon_inode inodes has no per-instance data associated, so we can avoid
 * the allocation of multiple of them.
 */
static struct inode *anon_inode_mkinode(void)
{
	struct inode *inode = new_inode(anon_inode_mnt->mnt_sb);
	struct _inode *_inode;
	
	if (!inode)
		return ERR_PTR(-ENOMEM);

	_inode = tx_cache_get_inode(inode);

	_inode->i_fop = &anon_inode_fops;

	/*
	 * Mark the inode dirty from the very beginning,
	 * that way it will never be moved to the dirty
	 * list because mark_inode_dirty() will think
	 * that it already _is_ on the dirty list.
	 */
	inode->i_state = I_DIRTY;
	_inode->i_mode = S_IRUSR | S_IWUSR;
	_inode->i_uid = current->fsuid;
	_inode->i_gid = current->fsgid;
	_inode->i_atime = _inode->i_mtime = _inode->i_ctime = CURRENT_TIME;
	return inode;
}
Beispiel #2
0
int abort_dentry(struct txobj_thread_list_node * xnode){
				
	struct dentry * orig = (struct dentry *)xnode->orig_obj;
	struct _dentry * shadow = (struct _dentry *)xnode->shadow_obj;

	if(xnode->rw == ACCESS_R){
		atomic_dec(&shadow->tx_readcount);
		atomic_dec(&shadow->tx_refcount);
	} else {
		if((shadow->d_flags & DCACHE_SPECULATIVE_CREATE)){
			struct _dentry *old_dentry = orig->d_contents;

			/* Free up the speculatively created inode reference to force deletion */
			tx_atomic_dec(&shadow->d_inode->i_count);
			tx_cache_get_inode(shadow->d_inode)->i_nlink--;
			free_tx_dentry(shadow);

			/* Use this as a signal to release_dentry */
			old_dentry->d_flags |= DCACHE_SPECULATIVE_CREATE;
			
			/* We also need the dentry to be negative */
			KSTM_BUG_ON(old_dentry->d_inode != NULL);

			/* And hack to avoid messing up the parent
			 * dentry's refcount when we put, as we will
			 * rollback the refcount increase elsewhere
			 */
			tx_atomic_inc(&old_dentry->d_parent->d_count);

		} else
			free_tx_dentry(shadow);
	}

	return 0;
}
Beispiel #3
0
static int oprofilefs_fill_super(struct super_block * sb, void * data, int silent)
{
	struct inode * root_inode;
	struct _inode * _root_inode;
	struct dentry * root_dentry;

	sb->s_blocksize = PAGE_CACHE_SIZE;
	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
	sb->s_magic = OPROFILEFS_MAGIC;
	sb->s_op = &s_ops;
	sb->s_time_gran = 1;

	root_inode = oprofilefs_get_inode(sb, S_IFDIR | 0755);
	if (!root_inode)
		return -ENOMEM;
	_root_inode = tx_cache_get_inode(root_inode);
	_root_inode->i_op = &simple_dir_inode_operations;
	_root_inode->i_fop = &simple_dir_operations;
	root_dentry = d_alloc_root(_root_inode);
	if (!root_dentry) {
		iput(root_inode);
		return -ENOMEM;
	}

	sb->s_root = root_dentry;

	oprofile_create_files(sb, tx_cache_get_dentry(root_dentry));

	// FIXME: verify kill_litter_super removes our dentries
	return 0;
}
Beispiel #4
0
void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page)
{
	swp_entry_t entry;

	down_read(&swap_unplug_sem);
	entry.val = page_private(page);
	if (PageSwapCache(page)) {
		struct block_device *bdev = swap_info[swp_type(entry)].bdev;
		struct backing_dev_info *bdi;

		/*
		 * If the page is removed from swapcache from under us (with a
		 * racy try_to_unuse/swapoff) we need an additional reference
		 * count to avoid reading garbage from page_private(page) above.
		 * If the WARN_ON triggers during a swapoff it maybe the race
		 * condition and it's harmless. However if it triggers without
		 * swapoff it signals a problem.
		 */
		WARN_ON(page_count(page) <= 1);

		bdi = tx_cache_get_inode(bdev->bd_inode)->i_mapping->backing_dev_info;
		blk_run_backing_dev(bdi, page);
	}
	up_read(&swap_unplug_sem);
}
Beispiel #5
0
static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode)
{
	struct inode * inode = new_inode(sb);

	if (inode) {
		struct _inode *_inode = tx_cache_get_inode(inode);
		_inode->i_mode = mode;
		_inode->i_uid = 0;
		_inode->i_gid = 0;
		inode->i_blocks = 0;
		_inode->i_atime = _inode->i_mtime = _inode->i_ctime = CURRENT_TIME;
	}
	return inode;
}
Beispiel #6
0
static struct _dentry * __oprofilefs_create_file(struct super_block * sb,
	struct _dentry * root, char const * name, const struct file_operations * fops,
	int perm)
{
	struct dentry * dentry;
	struct _dentry * _dentry;
	struct inode * inode;
	struct _inode * _inode;

	dentry = d_alloc_name(root, name);
	if (!dentry)
		return NULL;
	inode = oprofilefs_get_inode(sb, S_IFREG | perm);
	if (!inode) {
		dput(dentry);
		return NULL;
	}
	_inode = tx_cache_get_inode(inode);
	_inode->i_fop = fops;
	_dentry = tx_cache_get_dentry(dentry);
	d_add(_dentry, _inode);
	return _dentry;
}
Beispiel #7
0
struct _dentry * oprofilefs_mkdir(struct super_block * sb,
	struct _dentry * root, char const * name)
{
	struct dentry * dentry;
	struct _dentry * _dentry;
	struct inode * inode;
	struct _inode * _inode;

	dentry = d_alloc_name(root, name);
	if (!dentry)
		return NULL;
	inode = oprofilefs_get_inode(sb, S_IFDIR | 0755);
	if (!inode) {
		dput(dentry);
		return NULL;
	}

	_inode = tx_cache_get_inode(inode);
	_inode->i_op = &simple_dir_inode_operations;
	_inode->i_fop = &simple_dir_operations;
	_dentry = tx_cache_get_dentry(dentry);
	d_add(_dentry, _inode);
	return _dentry;
}
Beispiel #8
0
static struct file *__dentry_open(struct _dentry *dentry, struct vfsmount *mnt,
					int flags, struct file *f,
					int (*open)(struct _inode *, struct file *))
{
	struct _inode *inode;
	int error;
	struct super_block *sb;
	struct _file *_f = tx_cache_get_file(f);

	_f->f_flags = flags;
	_f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK |
		 		FMODE_PREAD | FMODE_PWRITE;
	inode = d_get_inode(dentry);
	sb = inode->i_sb;

	if (_f->f_mode & FMODE_WRITE) {
		error = get_write_access(parent(inode));
		if (error)
			goto cleanup_file;
	}

	f->f_mapping = inode->i_mapping;
	_f->f_path.dentry = parent(dentry);
	_f->f_path.mnt = mnt;
	_f->f_pos = 0;
	f->f_op = fops_get(inode->i_fop);
	file_move(f, &sb->s_files);

	if (!open && f->f_op)
		open = f->f_op->open;
	if (open) {
		error = open(inode, f);
		if (error)
			goto cleanup_all;
	}

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

	file_ra_state_init(&f->f_ra, 
			   tx_cache_get_inode(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_page))) {
			fput(f);
			f = ERR_PTR(-EINVAL);
		}
	}

	return f;

cleanup_all:
	fops_put(f->f_op);
	if (_f->f_mode & FMODE_WRITE)
		put_write_access(parent(inode));
	file_kill(f);
	_f->f_path.dentry = NULL;
	_f->f_path.mnt = NULL;
cleanup_file:
	/* Avoid issues if we recycle this object */
	if(live_transaction())
		early_release(&f->xobj, 1);
	put_filp(f);
	dput(parent(dentry));
	mntput(mnt);
	return ERR_PTR(error);
}
Beispiel #9
0
/*
 * 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,
			    int mode)
{
	struct fuse_entry_out outarg;
	struct inode *inode;
	struct _inode *_inode;
	int err;
	struct fuse_req *forget_req;

	forget_req = fuse_get_req(fc);
	if (IS_ERR(forget_req)) {
		fuse_put_request(fc, req);
		return PTR_ERR(forget_req);
	}

	req->in.h.nodeid = _get_node_id(dir);
	req->out.numargs = 1;
	req->out.args[0].size = sizeof(outarg);
	req->out.args[0].value = &outarg;
	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);
	if (!inode) {
		fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
		return -ENOMEM;
	}
	fuse_put_request(fc, forget_req);

	_inode = tx_cache_get_inode(inode);

	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_timeout(entry, &outarg);
	fuse_invalidate_attr(dir);
	return 0;

 out_put_forget_req:
	fuse_put_request(fc, forget_req);
	return err;
}
Beispiel #10
0
/*
 * Atomic create+open operation
 *
 * If the filesystem doesn't support this, then fall back to separate
 * 'mknod' + 'open' requests.
 */
static int fuse_create_open(struct _inode *dir, struct dentry *entry, int mode,
			    struct nameidata *nd)
{
	int err;
	struct inode *inode;
	struct _inode *_inode;
	struct fuse_conn *fc = get_fuse_conn(dir);
	struct fuse_req *req;
	struct fuse_req *forget_req;
	struct fuse_open_in inarg;
	struct fuse_open_out outopen;
	struct fuse_entry_out outentry;
	struct fuse_file *ff;
	struct file *file;
	int flags = nd->intent.open.flags - 1;

	if (fc->no_create)
		return -ENOSYS;

	forget_req = fuse_get_req(fc);
	if (IS_ERR(forget_req))
		return PTR_ERR(forget_req);

	req = fuse_get_req(fc);
	err = PTR_ERR(req);
	if (IS_ERR(req))
		goto out_put_forget_req;

	err = -ENOMEM;
	ff = fuse_file_alloc();
	if (!ff)
		goto out_put_request;

	flags &= ~O_NOCTTY;
	memset(&inarg, 0, sizeof(inarg));
	inarg.flags = flags;
	inarg.mode = mode;
	req->in.h.opcode = FUSE_CREATE;
	req->in.h.nodeid = _get_node_id(dir);
	req->in.numargs = 2;
	req->in.args[0].size = sizeof(inarg);
	req->in.args[0].value = &inarg;
	req->in.args[1].size = entry->d_name.len + 1;
	req->in.args[1].value = entry->d_name.name;
	req->out.numargs = 2;
	req->out.args[0].size = sizeof(outentry);
	req->out.args[0].value = &outentry;
	req->out.args[1].size = sizeof(outopen);
	req->out.args[1].value = &outopen;
	request_send(fc, req);
	err = req->out.h.error;
	if (err) {
		if (err == -ENOSYS)
			fc->no_create = 1;
		goto out_free_ff;
	}

	err = -EIO;
	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
		goto out_free_ff;

	fuse_put_request(fc, req);
	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
			  &outentry.attr);
	if (!inode) {
		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
		ff->fh = outopen.fh;
		fuse_sync_release(fc, ff, outentry.nodeid, flags);
		fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
		return -ENOMEM;
	}
	_inode = tx_cache_get_inode(inode);
	fuse_put_request(fc, forget_req);
	d_instantiate(entry, _inode);
	fuse_change_timeout(entry, &outentry);
	file = lookup_instantiate_filp(nd, entry, generic_file_open);
	if (IS_ERR(file)) {
		ff->fh = outopen.fh;
		fuse_sync_release(fc, ff, outentry.nodeid, flags);
		return PTR_ERR(file);
	}
	fuse_finish_open(_inode, file, ff, &outopen);
	return 0;

 out_free_ff:
	fuse_file_free(ff);
 out_put_request:
	fuse_put_request(fc, req);
 out_put_forget_req:
	fuse_put_request(fc, forget_req);
	return err;
}
Beispiel #11
0
static struct dentry *fuse_lookup(struct _inode *dir, struct dentry *entry,
				  struct nameidata *nd)
{
	int err;
	struct fuse_entry_out outarg;
	struct inode *inode = NULL;
	struct _inode *_inode = NULL;
	struct fuse_conn *fc = get_fuse_conn(dir);
	struct fuse_req *req;
	struct fuse_req *forget_req;

	if (entry->d_name.len > FUSE_NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);

	req = fuse_get_req(fc);
	if (IS_ERR(req))
		return ERR_PTR(PTR_ERR(req));

	forget_req = fuse_get_req(fc);
	if (IS_ERR(forget_req)) {
		fuse_put_request(fc, req);
		return ERR_PTR(PTR_ERR(forget_req));
	}

	fuse_lookup_init(req, dir, entry, &outarg);
	request_send(fc, req);
	err = req->out.h.error;
	fuse_put_request(fc, req);
	/* Zero nodeid is same as -ENOENT, but with valid timeout */
	if (!err && outarg.nodeid &&
	    (invalid_nodeid(outarg.nodeid) ||
	     !fuse_valid_type(outarg.attr.mode)))
		err = -EIO;
	if (!err && outarg.nodeid) {
		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
				  &outarg.attr);
		if (!inode) {
			fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
			return ERR_PTR(-ENOMEM);
		}
	}
	fuse_put_request(fc, forget_req);
	if (err && err != -ENOENT)
		return ERR_PTR(err);

	_inode = tx_cache_get_inode(inode);
	if (inode && S_ISDIR(_inode->i_mode)) {
		mutex_lock(&fc->inst_mutex);
		err = fuse_d_add_directory(entry, _inode);
		mutex_unlock(&fc->inst_mutex);
		if (err) {
			iput(inode);
			return ERR_PTR(err);
		}
	} else
		d_add(entry, _inode);

	entry->d_op = &fuse_dentry_operations;
	if (!err)
		fuse_change_timeout(entry, &outarg);
	else
		fuse_invalidate_entry_cache(entry);
	return NULL;
}
Beispiel #12
0
/**
 * anon_inode_getfd - creates a new file instance by hooking it up to and
 *                    anonymous inode, and a dentry that describe the "class"
 *                    of the file
 *
 * @pfd:     [out]   pointer to the file descriptor
 * @dpinode: [out]   pointer to the inode
 * @pfile:   [out]   pointer to the file struct
 * @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)
 *
 * 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, by
 * hence saving memory and avoiding code duplication for the file/inode/dentry
 * setup.
 */
int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
		     const char *name, const struct file_operations *fops,
		     void *priv)
{
	struct qstr this;
	struct dentry *dentry;
	struct _dentry *_dentry;
	struct inode *inode;
	struct _inode *_inode;
	struct file *file;
	struct _file *_file;
	int error, fd;

	if (IS_ERR(anon_inode_inode))
		return -ENODEV;
	file = get_empty_filp();
	if (!file)
		return -ENFILE;

	_file = tx_cache_get_file(file);

	inode = igrab(anon_inode_inode);
	if (IS_ERR(inode)) {
		error = PTR_ERR(inode);
		goto err_put_filp;
	}

	_inode = tx_cache_get_inode(inode);

	error = get_unused_fd();
	if (error < 0)
		goto err_iput;
	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(tx_cache_get_dentry(anon_inode_mnt->mnt_sb->s_root), &this);
	if (!dentry)
		goto err_put_unused_fd;
	_dentry = tx_cache_get_dentry(dentry);
	_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, _inode);

	_file->f_path.mnt = mntget(anon_inode_mnt);
	_file->f_path.dentry = dentry;
	file->f_mapping = _inode->i_mapping;

	_file->f_pos = 0;
	_file->f_flags = O_RDWR;
	file->f_op = fops;
	_file->f_mode = FMODE_READ | FMODE_WRITE;
	_file->f_version = 0;
	file->private_data = priv;

	fd_install(fd, file);

	*pfd = fd;
	*pinode = inode;
	*pfile = file;
	return 0;

err_put_unused_fd:
	put_unused_fd(fd);
err_iput:
	iput(inode);
err_put_filp:
	put_filp(file);
	return error;
}
Beispiel #13
0
/*
 * This is the worker routine which does all the work of mapping the disk
 * blocks and constructs largest possible bios, submits them for IO if the
 * blocks are not contiguous on the disk.
 *
 * We pass a buffer_head back and forth and use its buffer_mapped() flag to
 * represent the validity of its disk mapping and to decide when to do the next
 * get_block() call.
 */
static struct bio *
do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
		sector_t *last_block_in_bio, struct buffer_head *map_bh,
		unsigned long *first_logical_block, get_block_t get_block)
{
	struct _inode *inode = tx_cache_get_inode(page->mapping->host);
	const unsigned blkbits = inode->i_blkbits;
	const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits;
	const unsigned blocksize = 1 << blkbits;
	sector_t block_in_file;
	sector_t last_block;
	sector_t last_block_in_file;
	sector_t blocks[MAX_BUF_PER_PAGE];
	unsigned page_block;
	unsigned first_hole = blocks_per_page;
	struct block_device *bdev = NULL;
	int length;
	int fully_mapped = 1;
	unsigned nblocks;
	unsigned relative_block;

	if (page_has_buffers(page))
		goto confused;

	block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits);
	last_block = block_in_file + nr_pages * blocks_per_page;
	last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits;
	if (last_block > last_block_in_file)
		last_block = last_block_in_file;
	page_block = 0;

	/*
	 * Map blocks using the result from the previous get_blocks call first.
	 */
	nblocks = map_bh->b_size >> blkbits;
	if (buffer_mapped(map_bh) && block_in_file > *first_logical_block &&
			block_in_file < (*first_logical_block + nblocks)) {
		unsigned map_offset = block_in_file - *first_logical_block;
		unsigned last = nblocks - map_offset;

		for (relative_block = 0; ; relative_block++) {
			if (relative_block == last) {
				clear_buffer_mapped(map_bh);
				break;
			}
			if (page_block == blocks_per_page)
				break;
			blocks[page_block] = map_bh->b_blocknr + map_offset +
						relative_block;
			page_block++;
			block_in_file++;
		}
		bdev = map_bh->b_bdev;
	}

	/*
	 * Then do more get_blocks calls until we are done with this page.
	 */
	map_bh->b_page = page;
	while (page_block < blocks_per_page) {
		map_bh->b_state = 0;
		map_bh->b_size = 0;

		if (block_in_file < last_block) {
			map_bh->b_size = (last_block-block_in_file) << blkbits;
			if (get_block(inode, block_in_file, map_bh, 0))
				goto confused;
			*first_logical_block = block_in_file;
		}

		if (!buffer_mapped(map_bh)) {
			fully_mapped = 0;
			if (first_hole == blocks_per_page)
				first_hole = page_block;
			page_block++;
			block_in_file++;
			clear_buffer_mapped(map_bh);
			continue;
		}

		/* some filesystems will copy data into the page during
		 * the get_block call, in which case we don't want to
		 * read it again.  map_buffer_to_page copies the data
		 * we just collected from get_block into the page's buffers
		 * so readpage doesn't have to repeat the get_block call
		 */
		if (buffer_uptodate(map_bh)) {
			map_buffer_to_page(page, map_bh, page_block);
			goto confused;
		}
	
		if (first_hole != blocks_per_page)
			goto confused;		/* hole -> non-hole */

		/* Contiguous blocks? */
		if (page_block && blocks[page_block-1] != map_bh->b_blocknr-1)
			goto confused;
		nblocks = map_bh->b_size >> blkbits;
		for (relative_block = 0; ; relative_block++) {
			if (relative_block == nblocks) {
				clear_buffer_mapped(map_bh);
				break;
			} else if (page_block == blocks_per_page)
				break;
			blocks[page_block] = map_bh->b_blocknr+relative_block;
			page_block++;
			block_in_file++;
		}
		bdev = map_bh->b_bdev;
	}

	if (first_hole != blocks_per_page) {
		zero_user_page(page, first_hole << blkbits,
				PAGE_CACHE_SIZE - (first_hole << blkbits),
				KM_USER0);
		if (first_hole == 0) {
			SetPageUptodate(page);
			unlock_page(page);
			goto out;
		}
	} else if (fully_mapped) {
		SetPageMappedToDisk(page);
	}

	/*
	 * This page will go to BIO.  Do we need to send this BIO off first?
	 */
	if (bio && (*last_block_in_bio != blocks[0] - 1))
		bio = mpage_bio_submit(READ, bio);

alloc_new:
	if (bio == NULL) {
		bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),
			  	min_t(int, nr_pages, bio_get_nr_vecs(bdev)),
				GFP_KERNEL);
		if (bio == NULL)
			goto confused;
	}