Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Al Viro <viro@zeniv.linux.org.uk>

Al Viro ea022dfb 408bd629

+31 -104
+6 -7
fs/ocfs2/inode.c
··· 273 273 inode->i_gid = le32_to_cpu(fe->i_gid); 274 274 275 275 /* Fast symlinks will have i_size but no allocated clusters. */ 276 - if (S_ISLNK(inode->i_mode) && !fe->i_clusters) 276 + if (S_ISLNK(inode->i_mode) && !fe->i_clusters) { 277 277 inode->i_blocks = 0; 278 - else 278 + inode->i_mapping->a_ops = &ocfs2_fast_symlink_aops; 279 + } else { 279 280 inode->i_blocks = ocfs2_inode_sector_count(inode); 280 - inode->i_mapping->a_ops = &ocfs2_aops; 281 + inode->i_mapping->a_ops = &ocfs2_aops; 282 + } 281 283 inode->i_atime.tv_sec = le64_to_cpu(fe->i_atime); 282 284 inode->i_atime.tv_nsec = le32_to_cpu(fe->i_atime_nsec); 283 285 inode->i_mtime.tv_sec = le64_to_cpu(fe->i_mtime); ··· 333 331 OCFS2_I(inode)->ip_dir_lock_gen = 1; 334 332 break; 335 333 case S_IFLNK: 336 - if (ocfs2_inode_is_fast_symlink(inode)) 337 - inode->i_op = &ocfs2_fast_symlink_inode_operations; 338 - else 339 - inode->i_op = &ocfs2_symlink_inode_operations; 334 + inode->i_op = &ocfs2_symlink_inode_operations; 340 335 i_size_write(inode, le64_to_cpu(fe->i_size)); 341 336 break; 342 337 default:
+3 -2
fs/ocfs2/namei.c
··· 1724 1724 fe = (struct ocfs2_dinode *) new_fe_bh->b_data; 1725 1725 inode->i_rdev = 0; 1726 1726 newsize = l - 1; 1727 + inode->i_op = &ocfs2_symlink_inode_operations; 1727 1728 if (l > ocfs2_fast_symlink_chars(sb)) { 1728 1729 u32 offset = 0; 1729 1730 1730 - inode->i_op = &ocfs2_symlink_inode_operations; 1731 1731 status = dquot_alloc_space_nodirty(inode, 1732 1732 ocfs2_clusters_to_bytes(osb->sb, 1)); 1733 1733 if (status) 1734 1734 goto bail; 1735 1735 did_quota = 1; 1736 + inode->i_mapping->a_ops = &ocfs2_aops; 1736 1737 status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0, 1737 1738 new_fe_bh, 1738 1739 handle, data_ac, NULL, ··· 1751 1750 i_size_write(inode, newsize); 1752 1751 inode->i_blocks = ocfs2_inode_sector_count(inode); 1753 1752 } else { 1754 - inode->i_op = &ocfs2_fast_symlink_inode_operations; 1753 + inode->i_mapping->a_ops = &ocfs2_fast_symlink_aops; 1755 1754 memcpy((char *) fe->id2.i_symlink, symname, l); 1756 1755 i_size_write(inode, newsize); 1757 1756 inode->i_blocks = 0;
+21 -94
fs/ocfs2/symlink.c
··· 54 54 #include "buffer_head_io.h" 55 55 56 56 57 - static char *ocfs2_fast_symlink_getlink(struct inode *inode, 58 - struct buffer_head **bh) 57 + static int ocfs2_fast_symlink_readpage(struct file *unused, struct page *page) 59 58 { 60 - int status; 61 - char *link = NULL; 59 + struct inode *inode = page->mapping->host; 60 + struct buffer_head *bh; 61 + int status = ocfs2_read_inode_block(inode, &bh); 62 62 struct ocfs2_dinode *fe; 63 + const char *link; 64 + void *kaddr; 65 + size_t len; 63 66 64 - status = ocfs2_read_inode_block(inode, bh); 65 67 if (status < 0) { 66 68 mlog_errno(status); 67 - link = ERR_PTR(status); 68 - goto bail; 69 + return status; 69 70 } 70 71 71 - fe = (struct ocfs2_dinode *) (*bh)->b_data; 72 + fe = (struct ocfs2_dinode *) bh->b_data; 72 73 link = (char *) fe->id2.i_symlink; 73 - bail: 74 - 75 - return link; 76 - } 77 - 78 - static int ocfs2_readlink(struct dentry *dentry, 79 - char __user *buffer, 80 - int buflen) 81 - { 82 - int ret; 83 - char *link; 84 - struct buffer_head *bh = NULL; 85 - struct inode *inode = dentry->d_inode; 86 - 87 - link = ocfs2_fast_symlink_getlink(inode, &bh); 88 - if (IS_ERR(link)) { 89 - ret = PTR_ERR(link); 90 - goto out; 91 - } 92 - 93 - /* 94 - * Without vfsmount we can't update atime now, 95 - * but we will update atime here ultimately. 96 - */ 97 - ret = vfs_readlink(dentry, buffer, buflen, link); 98 - 74 + /* will be less than a page size */ 75 + len = strnlen(link, ocfs2_fast_symlink_chars(inode->i_sb)); 76 + kaddr = kmap_atomic(page); 77 + memcpy(kaddr, link, len + 1); 78 + kunmap_atomic(kaddr); 79 + SetPageUptodate(page); 80 + unlock_page(page); 99 81 brelse(bh); 100 - out: 101 - if (ret < 0) 102 - mlog_errno(ret); 103 - return ret; 82 + return 0; 104 83 } 105 84 106 - static void *ocfs2_fast_follow_link(struct dentry *dentry, 107 - struct nameidata *nd) 108 - { 109 - int status = 0; 110 - int len; 111 - char *target, *link = ERR_PTR(-ENOMEM); 112 - struct inode *inode = dentry->d_inode; 113 - struct buffer_head *bh = NULL; 114 - 115 - BUG_ON(!ocfs2_inode_is_fast_symlink(inode)); 116 - target = ocfs2_fast_symlink_getlink(inode, &bh); 117 - if (IS_ERR(target)) { 118 - status = PTR_ERR(target); 119 - mlog_errno(status); 120 - goto bail; 121 - } 122 - 123 - /* Fast symlinks can't be large */ 124 - len = strnlen(target, ocfs2_fast_symlink_chars(inode->i_sb)); 125 - link = kzalloc(len + 1, GFP_NOFS); 126 - if (!link) { 127 - status = -ENOMEM; 128 - mlog_errno(status); 129 - goto bail; 130 - } 131 - 132 - memcpy(link, target, len); 133 - 134 - bail: 135 - nd_set_link(nd, status ? ERR_PTR(status) : link); 136 - brelse(bh); 137 - 138 - if (status) 139 - mlog_errno(status); 140 - return NULL; 141 - } 142 - 143 - static void ocfs2_fast_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) 144 - { 145 - char *link = nd_get_link(nd); 146 - if (!IS_ERR(link)) 147 - kfree(link); 148 - } 85 + const struct address_space_operations ocfs2_fast_symlink_aops = { 86 + .readpage = ocfs2_fast_symlink_readpage, 87 + }; 149 88 150 89 const struct inode_operations ocfs2_symlink_inode_operations = { 151 - .readlink = page_readlink, 90 + .readlink = generic_readlink, 152 91 .follow_link = page_follow_link_light, 153 92 .put_link = page_put_link, 154 - .getattr = ocfs2_getattr, 155 - .setattr = ocfs2_setattr, 156 - .setxattr = generic_setxattr, 157 - .getxattr = generic_getxattr, 158 - .listxattr = ocfs2_listxattr, 159 - .removexattr = generic_removexattr, 160 - .fiemap = ocfs2_fiemap, 161 - }; 162 - const struct inode_operations ocfs2_fast_symlink_inode_operations = { 163 - .readlink = ocfs2_readlink, 164 - .follow_link = ocfs2_fast_follow_link, 165 - .put_link = ocfs2_fast_put_link, 166 93 .getattr = ocfs2_getattr, 167 94 .setattr = ocfs2_setattr, 168 95 .setxattr = generic_setxattr,
+1 -1
fs/ocfs2/symlink.h
··· 27 27 #define OCFS2_SYMLINK_H 28 28 29 29 extern const struct inode_operations ocfs2_symlink_inode_operations; 30 - extern const struct inode_operations ocfs2_fast_symlink_inode_operations; 30 + extern const struct address_space_operations ocfs2_fast_symlink_aops; 31 31 32 32 /* 33 33 * Test whether an inode is a fast symlink.