diff options
author | Dave Chinner <david@fromorbit.com> | 2016-05-19 20:32:10 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2016-05-19 20:32:10 -0400 |
commit | 5b9113547fedca92bb39b828f7f8cd11a153247b (patch) | |
tree | f6b489073b1584d8179bf553e6f90e91f9e79e83 /fs/xfs | |
parent | d6bd9615abdf89b147eb200ea4f63156af8a279e (diff) | |
parent | 30ee052e12b97c190b27fe6f20e3ac3047df7b5c (diff) |
Merge branch 'xfs-4.7-optimise-inline-symlinks' into for-next
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/libxfs/xfs_dir2_sf.c | 9 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_inode_fork.c | 62 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_inode_fork.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.h | 5 | ||||
-rw-r--r-- | fs/xfs/xfs_inode_item.c | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 18 | ||||
-rw-r--r-- | fs/xfs/xfs_iops.c | 88 | ||||
-rw-r--r-- | fs/xfs/xfs_symlink.c | 21 |
9 files changed, 125 insertions, 84 deletions
diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c index 974d62e677f4..e5bb9cc3b243 100644 --- a/fs/xfs/libxfs/xfs_dir2_sf.c +++ b/fs/xfs/libxfs/xfs_dir2_sf.c | |||
@@ -257,15 +257,12 @@ xfs_dir2_block_to_sf( | |||
257 | * | 257 | * |
258 | * Convert the inode to local format and copy the data in. | 258 | * Convert the inode to local format and copy the data in. |
259 | */ | 259 | */ |
260 | dp->i_df.if_flags &= ~XFS_IFEXTENTS; | ||
261 | dp->i_df.if_flags |= XFS_IFINLINE; | ||
262 | dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; | ||
263 | ASSERT(dp->i_df.if_bytes == 0); | 260 | ASSERT(dp->i_df.if_bytes == 0); |
264 | xfs_idata_realloc(dp, size, XFS_DATA_FORK); | 261 | xfs_init_local_fork(dp, XFS_DATA_FORK, dst, size); |
262 | dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; | ||
263 | dp->i_d.di_size = size; | ||
265 | 264 | ||
266 | logflags |= XFS_ILOG_DDATA; | 265 | logflags |= XFS_ILOG_DDATA; |
267 | memcpy(dp->i_df.if_u1.if_data, dst, size); | ||
268 | dp->i_d.di_size = size; | ||
269 | xfs_dir2_sf_check(args); | 266 | xfs_dir2_sf_check(args); |
270 | out: | 267 | out: |
271 | xfs_trans_log_inode(args->trans, dp, logflags); | 268 | xfs_trans_log_inode(args->trans, dp, logflags); |
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index 11faf7df14c8..4fbe2263c1fc 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c | |||
@@ -231,6 +231,48 @@ xfs_iformat_fork( | |||
231 | return error; | 231 | return error; |
232 | } | 232 | } |
233 | 233 | ||
234 | void | ||
235 | xfs_init_local_fork( | ||
236 | struct xfs_inode *ip, | ||
237 | int whichfork, | ||
238 | const void *data, | ||
239 | int size) | ||
240 | { | ||
241 | struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); | ||
242 | int mem_size = size, real_size = 0; | ||
243 | bool zero_terminate; | ||
244 | |||
245 | /* | ||
246 | * If we are using the local fork to store a symlink body we need to | ||
247 | * zero-terminate it so that we can pass it back to the VFS directly. | ||
248 | * Overallocate the in-memory fork by one for that and add a zero | ||
249 | * to terminate it below. | ||
250 | */ | ||
251 | zero_terminate = S_ISLNK(VFS_I(ip)->i_mode); | ||
252 | if (zero_terminate) | ||
253 | mem_size++; | ||
254 | |||
255 | if (size == 0) | ||
256 | ifp->if_u1.if_data = NULL; | ||
257 | else if (mem_size <= sizeof(ifp->if_u2.if_inline_data)) | ||
258 | ifp->if_u1.if_data = ifp->if_u2.if_inline_data; | ||
259 | else { | ||
260 | real_size = roundup(mem_size, 4); | ||
261 | ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS); | ||
262 | } | ||
263 | |||
264 | if (size) { | ||
265 | memcpy(ifp->if_u1.if_data, data, size); | ||
266 | if (zero_terminate) | ||
267 | ifp->if_u1.if_data[size] = '\0'; | ||
268 | } | ||
269 | |||
270 | ifp->if_bytes = size; | ||
271 | ifp->if_real_bytes = real_size; | ||
272 | ifp->if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT); | ||
273 | ifp->if_flags |= XFS_IFINLINE; | ||
274 | } | ||
275 | |||
234 | /* | 276 | /* |
235 | * The file is in-lined in the on-disk inode. | 277 | * The file is in-lined in the on-disk inode. |
236 | * If it fits into if_inline_data, then copy | 278 | * If it fits into if_inline_data, then copy |
@@ -248,8 +290,6 @@ xfs_iformat_local( | |||
248 | int whichfork, | 290 | int whichfork, |
249 | int size) | 291 | int size) |
250 | { | 292 | { |
251 | xfs_ifork_t *ifp; | ||
252 | int real_size; | ||
253 | 293 | ||
254 | /* | 294 | /* |
255 | * If the size is unreasonable, then something | 295 | * If the size is unreasonable, then something |
@@ -265,22 +305,8 @@ xfs_iformat_local( | |||
265 | ip->i_mount, dip); | 305 | ip->i_mount, dip); |
266 | return -EFSCORRUPTED; | 306 | return -EFSCORRUPTED; |
267 | } | 307 | } |
268 | ifp = XFS_IFORK_PTR(ip, whichfork); | 308 | |
269 | real_size = 0; | 309 | xfs_init_local_fork(ip, whichfork, XFS_DFORK_PTR(dip, whichfork), size); |
270 | if (size == 0) | ||
271 | ifp->if_u1.if_data = NULL; | ||
272 | else if (size <= sizeof(ifp->if_u2.if_inline_data)) | ||
273 | ifp->if_u1.if_data = ifp->if_u2.if_inline_data; | ||
274 | else { | ||
275 | real_size = roundup(size, 4); | ||
276 | ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS); | ||
277 | } | ||
278 | ifp->if_bytes = size; | ||
279 | ifp->if_real_bytes = real_size; | ||
280 | if (size) | ||
281 | memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size); | ||
282 | ifp->if_flags &= ~XFS_IFEXTENTS; | ||
283 | ifp->if_flags |= XFS_IFINLINE; | ||
284 | return 0; | 310 | return 0; |
285 | } | 311 | } |
286 | 312 | ||
diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h index 7d3b1ed6dcbe..f95e072ae646 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.h +++ b/fs/xfs/libxfs/xfs_inode_fork.h | |||
@@ -134,6 +134,7 @@ void xfs_iroot_realloc(struct xfs_inode *, int, int); | |||
134 | int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int); | 134 | int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int); |
135 | int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *, | 135 | int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *, |
136 | int); | 136 | int); |
137 | void xfs_init_local_fork(struct xfs_inode *, int, const void *, int); | ||
137 | 138 | ||
138 | struct xfs_bmbt_rec_host * | 139 | struct xfs_bmbt_rec_host * |
139 | xfs_iext_get_ext(struct xfs_ifork *, xfs_extnum_t); | 140 | xfs_iext_get_ext(struct xfs_ifork *, xfs_extnum_t); |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index b82c729634f6..ca270d9bbb90 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -2840,6 +2840,7 @@ xfs_rename_alloc_whiteout( | |||
2840 | * and flag it as linkable. | 2840 | * and flag it as linkable. |
2841 | */ | 2841 | */ |
2842 | drop_nlink(VFS_I(tmpfile)); | 2842 | drop_nlink(VFS_I(tmpfile)); |
2843 | xfs_setup_iops(tmpfile); | ||
2843 | xfs_finish_inode_setup(tmpfile); | 2844 | xfs_finish_inode_setup(tmpfile); |
2844 | VFS_I(tmpfile)->i_state |= I_LINKABLE; | 2845 | VFS_I(tmpfile)->i_state |= I_LINKABLE; |
2845 | 2846 | ||
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 43e1d51b15eb..e52d7c7aeb5b 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -440,6 +440,9 @@ loff_t __xfs_seek_hole_data(struct inode *inode, loff_t start, | |||
440 | 440 | ||
441 | 441 | ||
442 | /* from xfs_iops.c */ | 442 | /* from xfs_iops.c */ |
443 | extern void xfs_setup_inode(struct xfs_inode *ip); | ||
444 | extern void xfs_setup_iops(struct xfs_inode *ip); | ||
445 | |||
443 | /* | 446 | /* |
444 | * When setting up a newly allocated inode, we need to call | 447 | * When setting up a newly allocated inode, we need to call |
445 | * xfs_finish_inode_setup() once the inode is fully instantiated at | 448 | * xfs_finish_inode_setup() once the inode is fully instantiated at |
@@ -447,7 +450,6 @@ loff_t __xfs_seek_hole_data(struct inode *inode, loff_t start, | |||
447 | * before we've completed instantiation. Otherwise we can do it | 450 | * before we've completed instantiation. Otherwise we can do it |
448 | * the moment the inode lookup is complete. | 451 | * the moment the inode lookup is complete. |
449 | */ | 452 | */ |
450 | extern void xfs_setup_inode(struct xfs_inode *ip); | ||
451 | static inline void xfs_finish_inode_setup(struct xfs_inode *ip) | 453 | static inline void xfs_finish_inode_setup(struct xfs_inode *ip) |
452 | { | 454 | { |
453 | xfs_iflags_clear(ip, XFS_INEW); | 455 | xfs_iflags_clear(ip, XFS_INEW); |
@@ -458,6 +460,7 @@ static inline void xfs_finish_inode_setup(struct xfs_inode *ip) | |||
458 | static inline void xfs_setup_existing_inode(struct xfs_inode *ip) | 460 | static inline void xfs_setup_existing_inode(struct xfs_inode *ip) |
459 | { | 461 | { |
460 | xfs_setup_inode(ip); | 462 | xfs_setup_inode(ip); |
463 | xfs_setup_iops(ip); | ||
461 | xfs_finish_inode_setup(ip); | 464 | xfs_finish_inode_setup(ip); |
462 | } | 465 | } |
463 | 466 | ||
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index c48b5b18d771..37e23c7a5684 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c | |||
@@ -210,7 +210,7 @@ xfs_inode_item_format_data_fork( | |||
210 | */ | 210 | */ |
211 | data_bytes = roundup(ip->i_df.if_bytes, 4); | 211 | data_bytes = roundup(ip->i_df.if_bytes, 4); |
212 | ASSERT(ip->i_df.if_real_bytes == 0 || | 212 | ASSERT(ip->i_df.if_real_bytes == 0 || |
213 | ip->i_df.if_real_bytes == data_bytes); | 213 | ip->i_df.if_real_bytes >= data_bytes); |
214 | ASSERT(ip->i_df.if_u1.if_data != NULL); | 214 | ASSERT(ip->i_df.if_u1.if_data != NULL); |
215 | ASSERT(ip->i_d.di_size > 0); | 215 | ASSERT(ip->i_d.di_size > 0); |
216 | xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL, | 216 | xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL, |
@@ -305,7 +305,7 @@ xfs_inode_item_format_attr_fork( | |||
305 | */ | 305 | */ |
306 | data_bytes = roundup(ip->i_afp->if_bytes, 4); | 306 | data_bytes = roundup(ip->i_afp->if_bytes, 4); |
307 | ASSERT(ip->i_afp->if_real_bytes == 0 || | 307 | ASSERT(ip->i_afp->if_real_bytes == 0 || |
308 | ip->i_afp->if_real_bytes == data_bytes); | 308 | ip->i_afp->if_real_bytes >= data_bytes); |
309 | ASSERT(ip->i_afp->if_u1.if_data != NULL); | 309 | ASSERT(ip->i_afp->if_u1.if_data != NULL); |
310 | xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_LOCAL, | 310 | xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_LOCAL, |
311 | ip->i_afp->if_u1.if_data, | 311 | ip->i_afp->if_u1.if_data, |
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 6f82187ee297..dbca7375deef 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c | |||
@@ -277,7 +277,6 @@ xfs_readlink_by_handle( | |||
277 | { | 277 | { |
278 | struct dentry *dentry; | 278 | struct dentry *dentry; |
279 | __u32 olen; | 279 | __u32 olen; |
280 | void *link; | ||
281 | int error; | 280 | int error; |
282 | 281 | ||
283 | if (!capable(CAP_SYS_ADMIN)) | 282 | if (!capable(CAP_SYS_ADMIN)) |
@@ -288,7 +287,7 @@ xfs_readlink_by_handle( | |||
288 | return PTR_ERR(dentry); | 287 | return PTR_ERR(dentry); |
289 | 288 | ||
290 | /* Restrict this handle operation to symlinks only. */ | 289 | /* Restrict this handle operation to symlinks only. */ |
291 | if (!d_is_symlink(dentry)) { | 290 | if (!d_inode(dentry)->i_op->readlink) { |
292 | error = -EINVAL; | 291 | error = -EINVAL; |
293 | goto out_dput; | 292 | goto out_dput; |
294 | } | 293 | } |
@@ -298,21 +297,8 @@ xfs_readlink_by_handle( | |||
298 | goto out_dput; | 297 | goto out_dput; |
299 | } | 298 | } |
300 | 299 | ||
301 | link = kmalloc(MAXPATHLEN+1, GFP_KERNEL); | 300 | error = d_inode(dentry)->i_op->readlink(dentry, hreq->ohandle, olen); |
302 | if (!link) { | ||
303 | error = -ENOMEM; | ||
304 | goto out_dput; | ||
305 | } | ||
306 | |||
307 | error = xfs_readlink(XFS_I(d_inode(dentry)), link); | ||
308 | if (error) | ||
309 | goto out_kfree; | ||
310 | error = readlink_copy(hreq->ohandle, olen, link); | ||
311 | if (error) | ||
312 | goto out_kfree; | ||
313 | 301 | ||
314 | out_kfree: | ||
315 | kfree(link); | ||
316 | out_dput: | 302 | out_dput: |
317 | dput(dentry); | 303 | dput(dentry); |
318 | return error; | 304 | return error; |
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index fc7766164dc9..c5d4eba6972e 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
@@ -181,6 +181,8 @@ xfs_generic_create( | |||
181 | } | 181 | } |
182 | #endif | 182 | #endif |
183 | 183 | ||
184 | xfs_setup_iops(ip); | ||
185 | |||
184 | if (tmpfile) | 186 | if (tmpfile) |
185 | d_tmpfile(dentry, inode); | 187 | d_tmpfile(dentry, inode); |
186 | else | 188 | else |
@@ -368,6 +370,8 @@ xfs_vn_symlink( | |||
368 | if (unlikely(error)) | 370 | if (unlikely(error)) |
369 | goto out_cleanup_inode; | 371 | goto out_cleanup_inode; |
370 | 372 | ||
373 | xfs_setup_iops(cip); | ||
374 | |||
371 | d_instantiate(dentry, inode); | 375 | d_instantiate(dentry, inode); |
372 | xfs_finish_inode_setup(cip); | 376 | xfs_finish_inode_setup(cip); |
373 | return 0; | 377 | return 0; |
@@ -442,6 +446,16 @@ xfs_vn_get_link( | |||
442 | return ERR_PTR(error); | 446 | return ERR_PTR(error); |
443 | } | 447 | } |
444 | 448 | ||
449 | STATIC const char * | ||
450 | xfs_vn_get_link_inline( | ||
451 | struct dentry *dentry, | ||
452 | struct inode *inode, | ||
453 | struct delayed_call *done) | ||
454 | { | ||
455 | ASSERT(XFS_I(inode)->i_df.if_flags & XFS_IFINLINE); | ||
456 | return XFS_I(inode)->i_df.if_u1.if_data; | ||
457 | } | ||
458 | |||
445 | STATIC int | 459 | STATIC int |
446 | xfs_vn_getattr( | 460 | xfs_vn_getattr( |
447 | struct vfsmount *mnt, | 461 | struct vfsmount *mnt, |
@@ -1160,6 +1174,18 @@ static const struct inode_operations xfs_symlink_inode_operations = { | |||
1160 | .update_time = xfs_vn_update_time, | 1174 | .update_time = xfs_vn_update_time, |
1161 | }; | 1175 | }; |
1162 | 1176 | ||
1177 | static const struct inode_operations xfs_inline_symlink_inode_operations = { | ||
1178 | .readlink = generic_readlink, | ||
1179 | .get_link = xfs_vn_get_link_inline, | ||
1180 | .getattr = xfs_vn_getattr, | ||
1181 | .setattr = xfs_vn_setattr, | ||
1182 | .setxattr = generic_setxattr, | ||
1183 | .getxattr = generic_getxattr, | ||
1184 | .removexattr = generic_removexattr, | ||
1185 | .listxattr = xfs_vn_listxattr, | ||
1186 | .update_time = xfs_vn_update_time, | ||
1187 | }; | ||
1188 | |||
1163 | STATIC void | 1189 | STATIC void |
1164 | xfs_diflags_to_iflags( | 1190 | xfs_diflags_to_iflags( |
1165 | struct inode *inode, | 1191 | struct inode *inode, |
@@ -1186,7 +1212,7 @@ xfs_diflags_to_iflags( | |||
1186 | } | 1212 | } |
1187 | 1213 | ||
1188 | /* | 1214 | /* |
1189 | * Initialize the Linux inode and set up the operation vectors. | 1215 | * Initialize the Linux inode. |
1190 | * | 1216 | * |
1191 | * When reading existing inodes from disk this is called directly from xfs_iget, | 1217 | * When reading existing inodes from disk this is called directly from xfs_iget, |
1192 | * when creating a new inode it is called from xfs_ialloc after setting up the | 1218 | * when creating a new inode it is called from xfs_ialloc after setting up the |
@@ -1225,32 +1251,12 @@ xfs_setup_inode( | |||
1225 | i_size_write(inode, ip->i_d.di_size); | 1251 | i_size_write(inode, ip->i_d.di_size); |
1226 | xfs_diflags_to_iflags(inode, ip); | 1252 | xfs_diflags_to_iflags(inode, ip); |
1227 | 1253 | ||
1228 | ip->d_ops = ip->i_mount->m_nondir_inode_ops; | 1254 | if (S_ISDIR(inode->i_mode)) { |
1229 | lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class); | ||
1230 | switch (inode->i_mode & S_IFMT) { | ||
1231 | case S_IFREG: | ||
1232 | inode->i_op = &xfs_inode_operations; | ||
1233 | inode->i_fop = &xfs_file_operations; | ||
1234 | inode->i_mapping->a_ops = &xfs_address_space_operations; | ||
1235 | break; | ||
1236 | case S_IFDIR: | ||
1237 | lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class); | 1255 | lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class); |
1238 | if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) | ||
1239 | inode->i_op = &xfs_dir_ci_inode_operations; | ||
1240 | else | ||
1241 | inode->i_op = &xfs_dir_inode_operations; | ||
1242 | inode->i_fop = &xfs_dir_file_operations; | ||
1243 | ip->d_ops = ip->i_mount->m_dir_inode_ops; | 1256 | ip->d_ops = ip->i_mount->m_dir_inode_ops; |
1244 | break; | 1257 | } else { |
1245 | case S_IFLNK: | 1258 | ip->d_ops = ip->i_mount->m_nondir_inode_ops; |
1246 | inode->i_op = &xfs_symlink_inode_operations; | 1259 | lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class); |
1247 | if (!(ip->i_df.if_flags & XFS_IFINLINE)) | ||
1248 | inode->i_mapping->a_ops = &xfs_address_space_operations; | ||
1249 | break; | ||
1250 | default: | ||
1251 | inode->i_op = &xfs_inode_operations; | ||
1252 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | ||
1253 | break; | ||
1254 | } | 1260 | } |
1255 | 1261 | ||
1256 | /* | 1262 | /* |
@@ -1270,3 +1276,35 @@ xfs_setup_inode( | |||
1270 | cache_no_acl(inode); | 1276 | cache_no_acl(inode); |
1271 | } | 1277 | } |
1272 | } | 1278 | } |
1279 | |||
1280 | void | ||
1281 | xfs_setup_iops( | ||
1282 | struct xfs_inode *ip) | ||
1283 | { | ||
1284 | struct inode *inode = &ip->i_vnode; | ||
1285 | |||
1286 | switch (inode->i_mode & S_IFMT) { | ||
1287 | case S_IFREG: | ||
1288 | inode->i_op = &xfs_inode_operations; | ||
1289 | inode->i_fop = &xfs_file_operations; | ||
1290 | inode->i_mapping->a_ops = &xfs_address_space_operations; | ||
1291 | break; | ||
1292 | case S_IFDIR: | ||
1293 | if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) | ||
1294 | inode->i_op = &xfs_dir_ci_inode_operations; | ||
1295 | else | ||
1296 | inode->i_op = &xfs_dir_inode_operations; | ||
1297 | inode->i_fop = &xfs_dir_file_operations; | ||
1298 | break; | ||
1299 | case S_IFLNK: | ||
1300 | if (ip->i_df.if_flags & XFS_IFINLINE) | ||
1301 | inode->i_op = &xfs_inline_symlink_inode_operations; | ||
1302 | else | ||
1303 | inode->i_op = &xfs_symlink_inode_operations; | ||
1304 | break; | ||
1305 | default: | ||
1306 | inode->i_op = &xfs_inode_operations; | ||
1307 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | ||
1308 | break; | ||
1309 | } | ||
1310 | } | ||
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index c3aeaa884478..08a46c6181fd 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c | |||
@@ -131,6 +131,8 @@ xfs_readlink( | |||
131 | 131 | ||
132 | trace_xfs_readlink(ip); | 132 | trace_xfs_readlink(ip); |
133 | 133 | ||
134 | ASSERT(!(ip->i_df.if_flags & XFS_IFINLINE)); | ||
135 | |||
134 | if (XFS_FORCED_SHUTDOWN(mp)) | 136 | if (XFS_FORCED_SHUTDOWN(mp)) |
135 | return -EIO; | 137 | return -EIO; |
136 | 138 | ||
@@ -150,12 +152,7 @@ xfs_readlink( | |||
150 | } | 152 | } |
151 | 153 | ||
152 | 154 | ||
153 | if (ip->i_df.if_flags & XFS_IFINLINE) { | 155 | error = xfs_readlink_bmap(ip, link); |
154 | memcpy(link, ip->i_df.if_u1.if_data, pathlen); | ||
155 | link[pathlen] = '\0'; | ||
156 | } else { | ||
157 | error = xfs_readlink_bmap(ip, link); | ||
158 | } | ||
159 | 156 | ||
160 | out: | 157 | out: |
161 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 158 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
@@ -303,19 +300,11 @@ xfs_symlink( | |||
303 | * If the symlink will fit into the inode, write it inline. | 300 | * If the symlink will fit into the inode, write it inline. |
304 | */ | 301 | */ |
305 | if (pathlen <= XFS_IFORK_DSIZE(ip)) { | 302 | if (pathlen <= XFS_IFORK_DSIZE(ip)) { |
306 | xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK); | 303 | xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen); |
307 | memcpy(ip->i_df.if_u1.if_data, target_path, pathlen); | ||
308 | ip->i_d.di_size = pathlen; | ||
309 | |||
310 | /* | ||
311 | * The inode was initially created in extent format. | ||
312 | */ | ||
313 | ip->i_df.if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT); | ||
314 | ip->i_df.if_flags |= XFS_IFINLINE; | ||
315 | 304 | ||
305 | ip->i_d.di_size = pathlen; | ||
316 | ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; | 306 | ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; |
317 | xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE); | 307 | xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE); |
318 | |||
319 | } else { | 308 | } else { |
320 | int offset; | 309 | int offset; |
321 | 310 | ||