diff options
Diffstat (limited to 'fs/ocfs2/symlink.c')
-rw-r--r-- | fs/ocfs2/symlink.c | 115 |
1 files changed, 21 insertions, 94 deletions
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c index 5d22872e2bb3..f1fbb4b552ad 100644 --- a/fs/ocfs2/symlink.c +++ b/fs/ocfs2/symlink.c | |||
@@ -54,101 +54,40 @@ | |||
54 | #include "buffer_head_io.h" | 54 | #include "buffer_head_io.h" |
55 | 55 | ||
56 | 56 | ||
57 | static char *ocfs2_fast_symlink_getlink(struct inode *inode, | 57 | static int ocfs2_fast_symlink_readpage(struct file *unused, struct page *page) |
58 | struct buffer_head **bh) | ||
59 | { | 58 | { |
60 | int status; | 59 | struct inode *inode = page->mapping->host; |
61 | char *link = NULL; | 60 | struct buffer_head *bh; |
61 | int status = ocfs2_read_inode_block(inode, &bh); | ||
62 | struct ocfs2_dinode *fe; | 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 | if (status < 0) { | 67 | if (status < 0) { |
66 | mlog_errno(status); | 68 | mlog_errno(status); |
67 | link = ERR_PTR(status); | 69 | return status; |
68 | goto bail; | ||
69 | } | 70 | } |
70 | 71 | ||
71 | fe = (struct ocfs2_dinode *) (*bh)->b_data; | 72 | fe = (struct ocfs2_dinode *) bh->b_data; |
72 | link = (char *) fe->id2.i_symlink; | 73 | link = (char *) fe->id2.i_symlink; |
73 | bail: | 74 | /* will be less than a page size */ |
74 | 75 | len = strnlen(link, ocfs2_fast_symlink_chars(inode->i_sb)); | |
75 | return link; | 76 | kaddr = kmap_atomic(page); |
76 | } | 77 | memcpy(kaddr, link, len + 1); |
77 | 78 | kunmap_atomic(kaddr); | |
78 | static int ocfs2_readlink(struct dentry *dentry, | 79 | SetPageUptodate(page); |
79 | char __user *buffer, | 80 | unlock_page(page); |
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 | |||
99 | brelse(bh); | 81 | brelse(bh); |
100 | out: | 82 | return 0; |
101 | if (ret < 0) | ||
102 | mlog_errno(ret); | ||
103 | return ret; | ||
104 | } | 83 | } |
105 | 84 | ||
106 | static void *ocfs2_fast_follow_link(struct dentry *dentry, | 85 | const struct address_space_operations ocfs2_fast_symlink_aops = { |
107 | struct nameidata *nd) | 86 | .readpage = ocfs2_fast_symlink_readpage, |
108 | { | 87 | }; |
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 | } | ||
149 | 88 | ||
150 | const struct inode_operations ocfs2_symlink_inode_operations = { | 89 | const struct inode_operations ocfs2_symlink_inode_operations = { |
151 | .readlink = page_readlink, | 90 | .readlink = generic_readlink, |
152 | .follow_link = page_follow_link_light, | 91 | .follow_link = page_follow_link_light, |
153 | .put_link = page_put_link, | 92 | .put_link = page_put_link, |
154 | .getattr = ocfs2_getattr, | 93 | .getattr = ocfs2_getattr, |
@@ -159,15 +98,3 @@ const struct inode_operations ocfs2_symlink_inode_operations = { | |||
159 | .removexattr = generic_removexattr, | 98 | .removexattr = generic_removexattr, |
160 | .fiemap = ocfs2_fiemap, | 99 | .fiemap = ocfs2_fiemap, |
161 | }; | 100 | }; |
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 | .getattr = ocfs2_getattr, | ||
167 | .setattr = ocfs2_setattr, | ||
168 | .setxattr = generic_setxattr, | ||
169 | .getxattr = generic_getxattr, | ||
170 | .listxattr = ocfs2_listxattr, | ||
171 | .removexattr = generic_removexattr, | ||
172 | .fiemap = ocfs2_fiemap, | ||
173 | }; | ||