aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_symlink.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-04-03 01:11:19 -0400
committerBen Myers <bpm@sgi.com>2013-04-27 12:49:28 -0400
commitf948dd76dde021c050c7c35720dc066a8b9a5e35 (patch)
tree457f8097ba46f72ecb6417f96f890f9ee202f6cc /fs/xfs/xfs_symlink.c
parent19de7351a8eb82dc99745e60e8f43474831d99c7 (diff)
xfs: add CRC checks to remote symlinks
Add a header to the remote symlink block, containing location and owner information, as well as CRCs and LSN fields. This requires verifiers to be added to the remote symlink buffers for CRC enabled filesystems. This also fixes a bug reading multiple block symlinks, where the second block overwrites the first block when copying out the link name. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Ben Myers <bpm@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_symlink.c')
-rw-r--r--fs/xfs/xfs_symlink.c279
1 files changed, 240 insertions, 39 deletions
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 */
54int
55xfs_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
71static int
72xfs_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 */
100bool
101xfs_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
121static bool
122xfs_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
145static void
146xfs_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
163static void
164xfs_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
188const 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
47void 193void
48xfs_symlink_local_to_remote( 194xfs_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
61STATIC int 224STATIC int
62xfs_readlink_bmap( 225xfs_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
109int 298int
110xfs_readlink( 299xfs_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
151int 340int
152xfs_symlink( 341xfs_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 */
395STATIC int 596int
396xfs_inactive_symlink_rmt( 597xfs_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,