diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_buf_item.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_symlink.c | 279 | ||||
-rw-r--r-- | fs/xfs/xfs_symlink.h | 34 |
4 files changed, 283 insertions, 43 deletions
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index abae8c8c4ec4..09cab4ed1065 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h | |||
@@ -49,6 +49,7 @@ extern kmem_zone_t *xfs_buf_item_zone; | |||
49 | #define XFS_BLF_AGFL_BUF (1<<7) | 49 | #define XFS_BLF_AGFL_BUF (1<<7) |
50 | #define XFS_BLF_AGI_BUF (1<<8) | 50 | #define XFS_BLF_AGI_BUF (1<<8) |
51 | #define XFS_BLF_DINO_BUF (1<<9) | 51 | #define XFS_BLF_DINO_BUF (1<<9) |
52 | #define XFS_BLF_SYMLINK_BUF (1<<10) | ||
52 | 53 | ||
53 | #define XFS_BLF_TYPE_MASK \ | 54 | #define XFS_BLF_TYPE_MASK \ |
54 | (XFS_BLF_UDQUOT_BUF | \ | 55 | (XFS_BLF_UDQUOT_BUF | \ |
@@ -58,7 +59,8 @@ extern kmem_zone_t *xfs_buf_item_zone; | |||
58 | XFS_BLF_AGF_BUF | \ | 59 | XFS_BLF_AGF_BUF | \ |
59 | XFS_BLF_AGFL_BUF | \ | 60 | XFS_BLF_AGFL_BUF | \ |
60 | XFS_BLF_AGI_BUF | \ | 61 | XFS_BLF_AGI_BUF | \ |
61 | XFS_BLF_DINO_BUF) | 62 | XFS_BLF_DINO_BUF | \ |
63 | XFS_BLF_SYMLINK_BUF) | ||
62 | 64 | ||
63 | #define XFS_BLF_CHUNK 128 | 65 | #define XFS_BLF_CHUNK 128 |
64 | #define XFS_BLF_SHIFT 7 | 66 | #define XFS_BLF_SHIFT 7 |
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 287878219af7..d1292fd1112a 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include "xfs_cksum.h" | 45 | #include "xfs_cksum.h" |
46 | #include "xfs_trace.h" | 46 | #include "xfs_trace.h" |
47 | #include "xfs_icache.h" | 47 | #include "xfs_icache.h" |
48 | #include "xfs_symlink.h" | ||
48 | 49 | ||
49 | STATIC int | 50 | STATIC int |
50 | xlog_find_zeroed( | 51 | xlog_find_zeroed( |
@@ -2002,6 +2003,14 @@ xlog_recover_do_reg_buffer( | |||
2002 | } | 2003 | } |
2003 | bp->b_ops = &xfs_inode_buf_ops; | 2004 | bp->b_ops = &xfs_inode_buf_ops; |
2004 | break; | 2005 | break; |
2006 | case XFS_BLF_SYMLINK_BUF: | ||
2007 | if (*(__be32 *)bp->b_addr != cpu_to_be32(XFS_SYMLINK_MAGIC)) { | ||
2008 | xfs_warn(mp, "Bad symlink block magic!"); | ||
2009 | ASSERT(0); | ||
2010 | break; | ||
2011 | } | ||
2012 | bp->b_ops = &xfs_symlink_buf_ops; | ||
2013 | break; | ||
2005 | default: | 2014 | default: |
2006 | break; | 2015 | break; |
2007 | } | 2016 | } |
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 7512c96c7f29..5f234389327c 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c | |||
@@ -43,6 +43,152 @@ | |||
43 | #include "xfs_log_priv.h" | 43 | #include "xfs_log_priv.h" |
44 | #include "xfs_trace.h" | 44 | #include "xfs_trace.h" |
45 | #include "xfs_symlink.h" | 45 | #include "xfs_symlink.h" |
46 | #include "xfs_cksum.h" | ||
47 | #include "xfs_buf_item.h" | ||
48 | |||
49 | |||
50 | /* | ||
51 | * Each contiguous block has a header, so it is not just a simple pathlen | ||
52 | * to FSB conversion. | ||
53 | */ | ||
54 | int | ||
55 | xfs_symlink_blocks( | ||
56 | struct xfs_mount *mp, | ||
57 | int pathlen) | ||
58 | { | ||
59 | int fsblocks = 0; | ||
60 | int len = pathlen; | ||
61 | |||
62 | do { | ||
63 | fsblocks++; | ||
64 | len -= XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize); | ||
65 | } while (len > 0); | ||
66 | |||
67 | ASSERT(fsblocks <= XFS_SYMLINK_MAPS); | ||
68 | return fsblocks; | ||
69 | } | ||
70 | |||
71 | static int | ||
72 | xfs_symlink_hdr_set( | ||
73 | struct xfs_mount *mp, | ||
74 | xfs_ino_t ino, | ||
75 | uint32_t offset, | ||
76 | uint32_t size, | ||
77 | struct xfs_buf *bp) | ||
78 | { | ||
79 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
80 | |||
81 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
82 | return 0; | ||
83 | |||
84 | dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC); | ||
85 | dsl->sl_offset = cpu_to_be32(offset); | ||
86 | dsl->sl_bytes = cpu_to_be32(size); | ||
87 | uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid); | ||
88 | dsl->sl_owner = cpu_to_be64(ino); | ||
89 | dsl->sl_blkno = cpu_to_be64(bp->b_bn); | ||
90 | bp->b_ops = &xfs_symlink_buf_ops; | ||
91 | |||
92 | return sizeof(struct xfs_dsymlink_hdr); | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * Checking of the symlink header is split into two parts. the verifier does | ||
97 | * CRC, location and bounds checking, the unpacking function checks the path | ||
98 | * parameters and owner. | ||
99 | */ | ||
100 | bool | ||
101 | xfs_symlink_hdr_ok( | ||
102 | struct xfs_mount *mp, | ||
103 | xfs_ino_t ino, | ||
104 | uint32_t offset, | ||
105 | uint32_t size, | ||
106 | struct xfs_buf *bp) | ||
107 | { | ||
108 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
109 | |||
110 | if (offset != be32_to_cpu(dsl->sl_offset)) | ||
111 | return false; | ||
112 | if (size != be32_to_cpu(dsl->sl_bytes)) | ||
113 | return false; | ||
114 | if (ino != be64_to_cpu(dsl->sl_owner)) | ||
115 | return false; | ||
116 | |||
117 | /* ok */ | ||
118 | return true; | ||
119 | } | ||
120 | |||
121 | static bool | ||
122 | xfs_symlink_verify( | ||
123 | struct xfs_buf *bp) | ||
124 | { | ||
125 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
126 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
127 | |||
128 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
129 | return false; | ||
130 | if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC)) | ||
131 | return false; | ||
132 | if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid)) | ||
133 | return false; | ||
134 | if (bp->b_bn != be64_to_cpu(dsl->sl_blkno)) | ||
135 | return false; | ||
136 | if (be32_to_cpu(dsl->sl_offset) + | ||
137 | be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN) | ||
138 | return false; | ||
139 | if (dsl->sl_owner == 0) | ||
140 | return false; | ||
141 | |||
142 | return true; | ||
143 | } | ||
144 | |||
145 | static void | ||
146 | xfs_symlink_read_verify( | ||
147 | struct xfs_buf *bp) | ||
148 | { | ||
149 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
150 | |||
151 | /* no verification of non-crc buffers */ | ||
152 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
153 | return; | ||
154 | |||
155 | if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
156 | offsetof(struct xfs_dsymlink_hdr, sl_crc)) || | ||
157 | !xfs_symlink_verify(bp)) { | ||
158 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
159 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | static void | ||
164 | xfs_symlink_write_verify( | ||
165 | struct xfs_buf *bp) | ||
166 | { | ||
167 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
168 | struct xfs_buf_log_item *bip = bp->b_fspriv; | ||
169 | |||
170 | /* no verification of non-crc buffers */ | ||
171 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
172 | return; | ||
173 | |||
174 | if (!xfs_symlink_verify(bp)) { | ||
175 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
176 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | if (bip) { | ||
181 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; | ||
182 | dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn); | ||
183 | } | ||
184 | xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
185 | offsetof(struct xfs_dsymlink_hdr, sl_crc)); | ||
186 | } | ||
187 | |||
188 | const struct xfs_buf_ops xfs_symlink_buf_ops = { | ||
189 | .verify_read = xfs_symlink_read_verify, | ||
190 | .verify_write = xfs_symlink_write_verify, | ||
191 | }; | ||
46 | 192 | ||
47 | void | 193 | void |
48 | xfs_symlink_local_to_remote( | 194 | xfs_symlink_local_to_remote( |
@@ -51,38 +197,60 @@ xfs_symlink_local_to_remote( | |||
51 | struct xfs_inode *ip, | 197 | struct xfs_inode *ip, |
52 | struct xfs_ifork *ifp) | 198 | struct xfs_ifork *ifp) |
53 | { | 199 | { |
54 | /* remote symlink blocks are not verifiable until CRCs come along */ | 200 | struct xfs_mount *mp = ip->i_mount; |
55 | bp->b_ops = NULL; | 201 | char *buf; |
56 | memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); | 202 | |
203 | if (!xfs_sb_version_hascrc(&mp->m_sb)) { | ||
204 | bp->b_ops = NULL; | ||
205 | memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * As this symlink fits in an inode literal area, it must also fit in | ||
211 | * the smallest buffer the filesystem supports. | ||
212 | */ | ||
213 | ASSERT(BBTOB(bp->b_length) >= | ||
214 | ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr)); | ||
215 | |||
216 | bp->b_ops = &xfs_symlink_buf_ops; | ||
217 | |||
218 | buf = bp->b_addr; | ||
219 | buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp); | ||
220 | memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes); | ||
57 | } | 221 | } |
58 | 222 | ||
59 | /* ----- Kernel only functions below ----- */ | 223 | /* ----- Kernel only functions below ----- */ |
60 | |||
61 | STATIC int | 224 | STATIC int |
62 | xfs_readlink_bmap( | 225 | xfs_readlink_bmap( |
63 | xfs_inode_t *ip, | 226 | struct xfs_inode *ip, |
64 | char *link) | 227 | char *link) |
65 | { | 228 | { |
66 | xfs_mount_t *mp = ip->i_mount; | 229 | struct xfs_mount *mp = ip->i_mount; |
67 | int pathlen = ip->i_d.di_size; | 230 | struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS]; |
68 | int nmaps = XFS_SYMLINK_MAPS; | 231 | struct xfs_buf *bp; |
69 | xfs_bmbt_irec_t mval[XFS_SYMLINK_MAPS]; | 232 | xfs_daddr_t d; |
70 | xfs_daddr_t d; | 233 | char *cur_chunk; |
71 | int byte_cnt; | 234 | int pathlen = ip->i_d.di_size; |
72 | int n; | 235 | int nmaps = XFS_SYMLINK_MAPS; |
73 | xfs_buf_t *bp; | 236 | int byte_cnt; |
74 | int error = 0; | 237 | int n; |
238 | int error = 0; | ||
239 | int fsblocks = 0; | ||
240 | int offset; | ||
75 | 241 | ||
76 | error = xfs_bmapi_read(ip, 0, XFS_B_TO_FSB(mp, pathlen), mval, &nmaps, | 242 | fsblocks = xfs_symlink_blocks(mp, pathlen); |
77 | 0); | 243 | error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0); |
78 | if (error) | 244 | if (error) |
79 | goto out; | 245 | goto out; |
80 | 246 | ||
247 | offset = 0; | ||
81 | for (n = 0; n < nmaps; n++) { | 248 | for (n = 0; n < nmaps; n++) { |
82 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); | 249 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); |
83 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); | 250 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); |
84 | 251 | ||
85 | bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0, NULL); | 252 | bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0, |
253 | &xfs_symlink_buf_ops); | ||
86 | if (!bp) | 254 | if (!bp) |
87 | return XFS_ERROR(ENOMEM); | 255 | return XFS_ERROR(ENOMEM); |
88 | error = bp->b_error; | 256 | error = bp->b_error; |
@@ -91,13 +259,34 @@ xfs_readlink_bmap( | |||
91 | xfs_buf_relse(bp); | 259 | xfs_buf_relse(bp); |
92 | goto out; | 260 | goto out; |
93 | } | 261 | } |
262 | byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); | ||
94 | if (pathlen < byte_cnt) | 263 | if (pathlen < byte_cnt) |
95 | byte_cnt = pathlen; | 264 | byte_cnt = pathlen; |
265 | |||
266 | cur_chunk = bp->b_addr; | ||
267 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||
268 | if (!xfs_symlink_hdr_ok(mp, ip->i_ino, offset, | ||
269 | byte_cnt, bp)) { | ||
270 | error = EFSCORRUPTED; | ||
271 | xfs_alert(mp, | ||
272 | "symlink header does not match required off/len/owner (0x%x/Ox%x,0x%llx)", | ||
273 | offset, byte_cnt, ip->i_ino); | ||
274 | xfs_buf_relse(bp); | ||
275 | goto out; | ||
276 | |||
277 | } | ||
278 | |||
279 | cur_chunk += sizeof(struct xfs_dsymlink_hdr); | ||
280 | } | ||
281 | |||
282 | memcpy(link + offset, bp->b_addr, byte_cnt); | ||
283 | |||
96 | pathlen -= byte_cnt; | 284 | pathlen -= byte_cnt; |
285 | offset += byte_cnt; | ||
97 | 286 | ||
98 | memcpy(link, bp->b_addr, byte_cnt); | ||
99 | xfs_buf_relse(bp); | 287 | xfs_buf_relse(bp); |
100 | } | 288 | } |
289 | ASSERT(pathlen == 0); | ||
101 | 290 | ||
102 | link[ip->i_d.di_size] = '\0'; | 291 | link[ip->i_d.di_size] = '\0'; |
103 | error = 0; | 292 | error = 0; |
@@ -108,10 +297,10 @@ xfs_readlink_bmap( | |||
108 | 297 | ||
109 | int | 298 | int |
110 | xfs_readlink( | 299 | xfs_readlink( |
111 | xfs_inode_t *ip, | 300 | struct xfs_inode *ip, |
112 | char *link) | 301 | char *link) |
113 | { | 302 | { |
114 | xfs_mount_t *mp = ip->i_mount; | 303 | struct xfs_mount *mp = ip->i_mount; |
115 | xfs_fsize_t pathlen; | 304 | xfs_fsize_t pathlen; |
116 | int error = 0; | 305 | int error = 0; |
117 | 306 | ||
@@ -150,26 +339,26 @@ xfs_readlink( | |||
150 | 339 | ||
151 | int | 340 | int |
152 | xfs_symlink( | 341 | xfs_symlink( |
153 | xfs_inode_t *dp, | 342 | struct xfs_inode *dp, |
154 | struct xfs_name *link_name, | 343 | struct xfs_name *link_name, |
155 | const char *target_path, | 344 | const char *target_path, |
156 | umode_t mode, | 345 | umode_t mode, |
157 | xfs_inode_t **ipp) | 346 | struct xfs_inode **ipp) |
158 | { | 347 | { |
159 | xfs_mount_t *mp = dp->i_mount; | 348 | struct xfs_mount *mp = dp->i_mount; |
160 | xfs_trans_t *tp; | 349 | struct xfs_trans *tp = NULL; |
161 | xfs_inode_t *ip; | 350 | struct xfs_inode *ip = NULL; |
162 | int error; | 351 | int error = 0; |
163 | int pathlen; | 352 | int pathlen; |
164 | xfs_bmap_free_t free_list; | 353 | struct xfs_bmap_free free_list; |
165 | xfs_fsblock_t first_block; | 354 | xfs_fsblock_t first_block; |
166 | bool unlock_dp_on_error = false; | 355 | bool unlock_dp_on_error = false; |
167 | uint cancel_flags; | 356 | uint cancel_flags; |
168 | int committed; | 357 | int committed; |
169 | xfs_fileoff_t first_fsb; | 358 | xfs_fileoff_t first_fsb; |
170 | xfs_filblks_t fs_blocks; | 359 | xfs_filblks_t fs_blocks; |
171 | int nmaps; | 360 | int nmaps; |
172 | xfs_bmbt_irec_t mval[XFS_SYMLINK_MAPS]; | 361 | struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS]; |
173 | xfs_daddr_t d; | 362 | xfs_daddr_t d; |
174 | const char *cur_chunk; | 363 | const char *cur_chunk; |
175 | int byte_cnt; | 364 | int byte_cnt; |
@@ -180,9 +369,6 @@ xfs_symlink( | |||
180 | uint resblks; | 369 | uint resblks; |
181 | 370 | ||
182 | *ipp = NULL; | 371 | *ipp = NULL; |
183 | error = 0; | ||
184 | ip = NULL; | ||
185 | tp = NULL; | ||
186 | 372 | ||
187 | trace_xfs_symlink(dp, link_name); | 373 | trace_xfs_symlink(dp, link_name); |
188 | 374 | ||
@@ -307,6 +493,8 @@ xfs_symlink( | |||
307 | xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE); | 493 | xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE); |
308 | 494 | ||
309 | } else { | 495 | } else { |
496 | int offset; | ||
497 | |||
310 | first_fsb = 0; | 498 | first_fsb = 0; |
311 | nmaps = XFS_SYMLINK_MAPS; | 499 | nmaps = XFS_SYMLINK_MAPS; |
312 | 500 | ||
@@ -322,7 +510,10 @@ xfs_symlink( | |||
322 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 510 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
323 | 511 | ||
324 | cur_chunk = target_path; | 512 | cur_chunk = target_path; |
513 | offset = 0; | ||
325 | for (n = 0; n < nmaps; n++) { | 514 | for (n = 0; n < nmaps; n++) { |
515 | char *buf; | ||
516 | |||
326 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); | 517 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); |
327 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); | 518 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); |
328 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, | 519 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, |
@@ -331,15 +522,25 @@ xfs_symlink( | |||
331 | error = ENOMEM; | 522 | error = ENOMEM; |
332 | goto error2; | 523 | goto error2; |
333 | } | 524 | } |
525 | bp->b_ops = &xfs_symlink_buf_ops; | ||
526 | |||
527 | byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); | ||
334 | if (pathlen < byte_cnt) { | 528 | if (pathlen < byte_cnt) { |
335 | byte_cnt = pathlen; | 529 | byte_cnt = pathlen; |
336 | } | 530 | } |
337 | pathlen -= byte_cnt; | ||
338 | 531 | ||
339 | memcpy(bp->b_addr, cur_chunk, byte_cnt); | 532 | buf = bp->b_addr; |
533 | buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset, | ||
534 | byte_cnt, bp); | ||
535 | |||
536 | memcpy(buf, cur_chunk, byte_cnt); | ||
537 | |||
340 | cur_chunk += byte_cnt; | 538 | cur_chunk += byte_cnt; |
539 | pathlen -= byte_cnt; | ||
540 | offset += byte_cnt; | ||
341 | 541 | ||
342 | xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1); | 542 | xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) - |
543 | (char *)bp->b_addr); | ||
343 | } | 544 | } |
344 | } | 545 | } |
345 | 546 | ||
@@ -392,7 +593,7 @@ xfs_symlink( | |||
392 | /* | 593 | /* |
393 | * Free a symlink that has blocks associated with it. | 594 | * Free a symlink that has blocks associated with it. |
394 | */ | 595 | */ |
395 | STATIC int | 596 | int |
396 | xfs_inactive_symlink_rmt( | 597 | xfs_inactive_symlink_rmt( |
397 | xfs_inode_t *ip, | 598 | xfs_inode_t *ip, |
398 | xfs_trans_t **tpp) | 599 | xfs_trans_t **tpp) |
@@ -438,12 +639,12 @@ xfs_inactive_symlink_rmt( | |||
438 | done = 0; | 639 | done = 0; |
439 | xfs_bmap_init(&free_list, &first_block); | 640 | xfs_bmap_init(&free_list, &first_block); |
440 | nmaps = ARRAY_SIZE(mval); | 641 | nmaps = ARRAY_SIZE(mval); |
441 | error = xfs_bmapi_read(ip, 0, XFS_B_TO_FSB(mp, size), | 642 | error = xfs_bmapi_read(ip, 0, xfs_symlink_blocks(mp, size), |
442 | mval, &nmaps, 0); | 643 | mval, &nmaps, 0); |
443 | if (error) | 644 | if (error) |
444 | goto error0; | 645 | goto error0; |
445 | /* | 646 | /* |
446 | * Invalidate the block(s). | 647 | * Invalidate the block(s). No validation is done. |
447 | */ | 648 | */ |
448 | for (i = 0; i < nmaps; i++) { | 649 | for (i = 0; i < nmaps; i++) { |
449 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, | 650 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, |
diff --git a/fs/xfs/xfs_symlink.h b/fs/xfs/xfs_symlink.h index 07bdabcc4158..b39398d2097c 100644 --- a/fs/xfs/xfs_symlink.h +++ b/fs/xfs/xfs_symlink.h | |||
@@ -17,16 +17,44 @@ | |||
17 | #ifndef __XFS_SYMLINK_H | 17 | #ifndef __XFS_SYMLINK_H |
18 | #define __XFS_SYMLINK_H 1 | 18 | #define __XFS_SYMLINK_H 1 |
19 | 19 | ||
20 | struct xfs_mount; | ||
21 | struct xfs_trans; | ||
22 | struct xfs_inode; | ||
23 | struct xfs_buf; | ||
24 | struct xfs_ifork; | ||
25 | struct xfs_name; | ||
26 | |||
27 | #define XFS_SYMLINK_MAGIC 0x58534c4d /* XSLM */ | ||
28 | |||
29 | struct xfs_dsymlink_hdr { | ||
30 | __be32 sl_magic; | ||
31 | __be32 sl_offset; | ||
32 | __be32 sl_bytes; | ||
33 | __be32 sl_crc; | ||
34 | uuid_t sl_uuid; | ||
35 | __be64 sl_owner; | ||
36 | __be64 sl_blkno; | ||
37 | __be64 sl_lsn; | ||
38 | }; | ||
39 | |||
20 | /* | 40 | /* |
21 | * The maximum pathlen is 1024 bytes. Since the minimum file system | 41 | * The maximum pathlen is 1024 bytes. Since the minimum file system |
22 | * blocksize is 512 bytes, we can get a max of 2 extents back from | 42 | * blocksize is 512 bytes, we can get a max of 3 extents back from |
23 | * bmapi. | 43 | * bmapi when crc headers are taken into account. |
24 | */ | 44 | */ |
25 | #define XFS_SYMLINK_MAPS 2 | 45 | #define XFS_SYMLINK_MAPS 3 |
46 | |||
47 | #define XFS_SYMLINK_BUF_SPACE(mp, bufsize) \ | ||
48 | ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \ | ||
49 | sizeof(struct xfs_dsymlink_hdr) : 0)) | ||
50 | |||
51 | int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen); | ||
26 | 52 | ||
27 | void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp, | 53 | void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp, |
28 | struct xfs_inode *ip, struct xfs_ifork *ifp); | 54 | struct xfs_inode *ip, struct xfs_ifork *ifp); |
29 | 55 | ||
56 | extern const struct xfs_buf_ops xfs_symlink_buf_ops; | ||
57 | |||
30 | #ifdef __KERNEL__ | 58 | #ifdef __KERNEL__ |
31 | 59 | ||
32 | int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, | 60 | int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, |