Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea022dfb authored by Al Viro's avatar Al Viro
Browse files

ocfs: simplify symlink handling



seeing that "fast" symlinks still get allocation + copy, we might as
well simply switch them to pagecache-based variant of ->follow_link();
just need an appropriate ->readpage() for them...

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 408bd629
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -273,11 +273,13 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
	inode->i_gid = le32_to_cpu(fe->i_gid);

	/* Fast symlinks will have i_size but no allocated clusters. */
	if (S_ISLNK(inode->i_mode) && !fe->i_clusters)
	if (S_ISLNK(inode->i_mode) && !fe->i_clusters) {
		inode->i_blocks = 0;
	else
		inode->i_mapping->a_ops = &ocfs2_fast_symlink_aops;
	} else {
		inode->i_blocks = ocfs2_inode_sector_count(inode);
		inode->i_mapping->a_ops = &ocfs2_aops;
	}
	inode->i_atime.tv_sec = le64_to_cpu(fe->i_atime);
	inode->i_atime.tv_nsec = le32_to_cpu(fe->i_atime_nsec);
	inode->i_mtime.tv_sec = le64_to_cpu(fe->i_mtime);
@@ -331,9 +333,6 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
		    OCFS2_I(inode)->ip_dir_lock_gen = 1;
		    break;
	    case S_IFLNK:
		    if (ocfs2_inode_is_fast_symlink(inode))
			inode->i_op = &ocfs2_fast_symlink_inode_operations;
		    else
		    inode->i_op = &ocfs2_symlink_inode_operations;
		    i_size_write(inode, le64_to_cpu(fe->i_size));
		    break;
+3 −2
Original line number Diff line number Diff line
@@ -1724,15 +1724,16 @@ static int ocfs2_symlink(struct inode *dir,
	fe = (struct ocfs2_dinode *) new_fe_bh->b_data;
	inode->i_rdev = 0;
	newsize = l - 1;
	inode->i_op = &ocfs2_symlink_inode_operations;
	if (l > ocfs2_fast_symlink_chars(sb)) {
		u32 offset = 0;

		inode->i_op = &ocfs2_symlink_inode_operations;
		status = dquot_alloc_space_nodirty(inode,
		    ocfs2_clusters_to_bytes(osb->sb, 1));
		if (status)
			goto bail;
		did_quota = 1;
		inode->i_mapping->a_ops = &ocfs2_aops;
		status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0,
					      new_fe_bh,
					      handle, data_ac, NULL,
@@ -1750,7 +1751,7 @@ static int ocfs2_symlink(struct inode *dir,
		i_size_write(inode, newsize);
		inode->i_blocks = ocfs2_inode_sector_count(inode);
	} else {
		inode->i_op = &ocfs2_fast_symlink_inode_operations;
		inode->i_mapping->a_ops = &ocfs2_fast_symlink_aops;
		memcpy((char *) fe->id2.i_symlink, symname, l);
		i_size_write(inode, newsize);
		inode->i_blocks = 0;
+21 −94
Original line number Diff line number Diff line
@@ -54,101 +54,40 @@
#include "buffer_head_io.h"


static char *ocfs2_fast_symlink_getlink(struct inode *inode,
					struct buffer_head **bh)
static int ocfs2_fast_symlink_readpage(struct file *unused, struct page *page)
{
	int status;
	char *link = NULL;
	struct inode *inode = page->mapping->host;
	struct buffer_head *bh;
	int status = ocfs2_read_inode_block(inode, &bh);
	struct ocfs2_dinode *fe;
	const char *link;
	void *kaddr;
	size_t len;

	status = ocfs2_read_inode_block(inode, bh);
	if (status < 0) {
		mlog_errno(status);
		link = ERR_PTR(status);
		goto bail;
		return status;
	}

	fe = (struct ocfs2_dinode *) (*bh)->b_data;
	fe = (struct ocfs2_dinode *) bh->b_data;
	link = (char *) fe->id2.i_symlink;
bail:

	return link;
}

static int ocfs2_readlink(struct dentry *dentry,
			  char __user *buffer,
			  int buflen)
{
	int ret;
	char *link;
	struct buffer_head *bh = NULL;
	struct inode *inode = dentry->d_inode;

	link = ocfs2_fast_symlink_getlink(inode, &bh);
	if (IS_ERR(link)) {
		ret = PTR_ERR(link);
		goto out;
	}

	/*
	 * Without vfsmount we can't update atime now,
	 * but we will update atime here ultimately.
	 */
	ret = vfs_readlink(dentry, buffer, buflen, link);

	brelse(bh);
out:
	if (ret < 0)
		mlog_errno(ret);
	return ret;
}

static void *ocfs2_fast_follow_link(struct dentry *dentry,
				    struct nameidata *nd)
{
	int status = 0;
	int len;
	char *target, *link = ERR_PTR(-ENOMEM);
	struct inode *inode = dentry->d_inode;
	struct buffer_head *bh = NULL;

	BUG_ON(!ocfs2_inode_is_fast_symlink(inode));
	target = ocfs2_fast_symlink_getlink(inode, &bh);
	if (IS_ERR(target)) {
		status = PTR_ERR(target);
		mlog_errno(status);
		goto bail;
	}

	/* Fast symlinks can't be large */
	len = strnlen(target, ocfs2_fast_symlink_chars(inode->i_sb));
	link = kzalloc(len + 1, GFP_NOFS);
	if (!link) {
		status = -ENOMEM;
		mlog_errno(status);
		goto bail;
	}

	memcpy(link, target, len);

bail:
	nd_set_link(nd, status ? ERR_PTR(status) : link);
	/* will be less than a page size */
	len = strnlen(link, ocfs2_fast_symlink_chars(inode->i_sb));
	kaddr = kmap_atomic(page);
	memcpy(kaddr, link, len + 1);
	kunmap_atomic(kaddr);
	SetPageUptodate(page);
	unlock_page(page);
	brelse(bh);

	if (status)
		mlog_errno(status);
	return NULL;
	return 0;
}

static void ocfs2_fast_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
{
	char *link = nd_get_link(nd);
	if (!IS_ERR(link))
		kfree(link);
}
const struct address_space_operations ocfs2_fast_symlink_aops = {
	.readpage		= ocfs2_fast_symlink_readpage,
};

const struct inode_operations ocfs2_symlink_inode_operations = {
	.readlink	= page_readlink,
	.readlink	= generic_readlink,
	.follow_link	= page_follow_link_light,
	.put_link	= page_put_link,
	.getattr	= ocfs2_getattr,
@@ -159,15 +98,3 @@ const struct inode_operations ocfs2_symlink_inode_operations = {
	.removexattr	= generic_removexattr,
	.fiemap		= ocfs2_fiemap,
};
const struct inode_operations ocfs2_fast_symlink_inode_operations = {
	.readlink	= ocfs2_readlink,
	.follow_link	= ocfs2_fast_follow_link,
	.put_link	= ocfs2_fast_put_link,
	.getattr	= ocfs2_getattr,
	.setattr	= ocfs2_setattr,
	.setxattr	= generic_setxattr,
	.getxattr	= generic_getxattr,
	.listxattr	= ocfs2_listxattr,
	.removexattr	= generic_removexattr,
	.fiemap		= ocfs2_fiemap,
};
+1 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@
#define OCFS2_SYMLINK_H

extern const struct inode_operations ocfs2_symlink_inode_operations;
extern const struct inode_operations ocfs2_fast_symlink_inode_operations;
extern const struct address_space_operations ocfs2_fast_symlink_aops;

/*
 * Test whether an inode is a fast symlink.