aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-04-03 01:11:18 -0400
committerBen Myers <bpm@sgi.com>2013-04-21 16:38:04 -0400
commit19de7351a8eb82dc99745e60e8f43474831d99c7 (patch)
tree2c0c1afc963c41e6766a08dfc631ccdfe913e574 /fs/xfs/xfs_vnodeops.c
parent93848a999cf9b9e4f4f77dba843a48c393f33c59 (diff)
xfs: split out symlink code into it's own file.
The symlink code is about to get more complicated when CRCs are added for remote symlink blocks. The symlink management code is mostly self contained, so move it to it's own files so that all the new code and the existing symlink code will not be intermingled with other unrelated code. 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_vnodeops.c')
-rw-r--r--fs/xfs/xfs_vnodeops.c478
1 files changed, 2 insertions, 476 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index aa0c06692e18..1501f4fa51a6 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 2 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
3 * Copyright (c) 2012 Red Hat, Inc.
3 * All Rights Reserved. 4 * All Rights Reserved.
4 * 5 *
5 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
@@ -48,103 +49,8 @@
48#include "xfs_vnodeops.h" 49#include "xfs_vnodeops.h"
49#include "xfs_trace.h" 50#include "xfs_trace.h"
50#include "xfs_icache.h" 51#include "xfs_icache.h"
52#include "xfs_symlink.h"
51 53
52/*
53 * The maximum pathlen is 1024 bytes. Since the minimum file system
54 * blocksize is 512 bytes, we can get a max of 2 extents back from
55 * bmapi.
56 */
57#define SYMLINK_MAPS 2
58
59STATIC int
60xfs_readlink_bmap(
61 xfs_inode_t *ip,
62 char *link)
63{
64 xfs_mount_t *mp = ip->i_mount;
65 int pathlen = ip->i_d.di_size;
66 int nmaps = SYMLINK_MAPS;
67 xfs_bmbt_irec_t mval[SYMLINK_MAPS];
68 xfs_daddr_t d;
69 int byte_cnt;
70 int n;
71 xfs_buf_t *bp;
72 int error = 0;
73
74 error = xfs_bmapi_read(ip, 0, XFS_B_TO_FSB(mp, pathlen), mval, &nmaps,
75 0);
76 if (error)
77 goto out;
78
79 for (n = 0; n < nmaps; n++) {
80 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
81 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
82
83 bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0, NULL);
84 if (!bp)
85 return XFS_ERROR(ENOMEM);
86 error = bp->b_error;
87 if (error) {
88 xfs_buf_ioerror_alert(bp, __func__);
89 xfs_buf_relse(bp);
90 goto out;
91 }
92 if (pathlen < byte_cnt)
93 byte_cnt = pathlen;
94 pathlen -= byte_cnt;
95
96 memcpy(link, bp->b_addr, byte_cnt);
97 xfs_buf_relse(bp);
98 }
99
100 link[ip->i_d.di_size] = '\0';
101 error = 0;
102
103 out:
104 return error;
105}
106
107int
108xfs_readlink(
109 xfs_inode_t *ip,
110 char *link)
111{
112 xfs_mount_t *mp = ip->i_mount;
113 xfs_fsize_t pathlen;
114 int error = 0;
115
116 trace_xfs_readlink(ip);
117
118 if (XFS_FORCED_SHUTDOWN(mp))
119 return XFS_ERROR(EIO);
120
121 xfs_ilock(ip, XFS_ILOCK_SHARED);
122
123 pathlen = ip->i_d.di_size;
124 if (!pathlen)
125 goto out;
126
127 if (pathlen < 0 || pathlen > MAXPATHLEN) {
128 xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)",
129 __func__, (unsigned long long) ip->i_ino,
130 (long long) pathlen);
131 ASSERT(0);
132 error = XFS_ERROR(EFSCORRUPTED);
133 goto out;
134 }
135
136
137 if (ip->i_df.if_flags & XFS_IFINLINE) {
138 memcpy(link, ip->i_df.if_u1.if_data, pathlen);
139 link[pathlen] = '\0';
140 } else {
141 error = xfs_readlink_bmap(ip, link);
142 }
143
144 out:
145 xfs_iunlock(ip, XFS_ILOCK_SHARED);
146 return error;
147}
148 54
149/* 55/*
150 * This is called by xfs_inactive to free any blocks beyond eof 56 * This is called by xfs_inactive to free any blocks beyond eof
@@ -249,145 +155,6 @@ xfs_free_eofblocks(
249 return error; 155 return error;
250} 156}
251 157
252/*
253 * Free a symlink that has blocks associated with it.
254 */
255STATIC int
256xfs_inactive_symlink_rmt(
257 xfs_inode_t *ip,
258 xfs_trans_t **tpp)
259{
260 xfs_buf_t *bp;
261 int committed;
262 int done;
263 int error;
264 xfs_fsblock_t first_block;
265 xfs_bmap_free_t free_list;
266 int i;
267 xfs_mount_t *mp;
268 xfs_bmbt_irec_t mval[SYMLINK_MAPS];
269 int nmaps;
270 xfs_trans_t *ntp;
271 int size;
272 xfs_trans_t *tp;
273
274 tp = *tpp;
275 mp = ip->i_mount;
276 ASSERT(ip->i_d.di_size > XFS_IFORK_DSIZE(ip));
277 /*
278 * We're freeing a symlink that has some
279 * blocks allocated to it. Free the
280 * blocks here. We know that we've got
281 * either 1 or 2 extents and that we can
282 * free them all in one bunmapi call.
283 */
284 ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2);
285
286 /*
287 * Lock the inode, fix the size, and join it to the transaction.
288 * Hold it so in the normal path, we still have it locked for
289 * the second transaction. In the error paths we need it
290 * held so the cancel won't rele it, see below.
291 */
292 size = (int)ip->i_d.di_size;
293 ip->i_d.di_size = 0;
294 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
295 /*
296 * Find the block(s) so we can inval and unmap them.
297 */
298 done = 0;
299 xfs_bmap_init(&free_list, &first_block);
300 nmaps = ARRAY_SIZE(mval);
301 error = xfs_bmapi_read(ip, 0, XFS_B_TO_FSB(mp, size),
302 mval, &nmaps, 0);
303 if (error)
304 goto error0;
305 /*
306 * Invalidate the block(s).
307 */
308 for (i = 0; i < nmaps; i++) {
309 bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,
310 XFS_FSB_TO_DADDR(mp, mval[i].br_startblock),
311 XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0);
312 if (!bp) {
313 error = ENOMEM;
314 goto error1;
315 }
316 xfs_trans_binval(tp, bp);
317 }
318 /*
319 * Unmap the dead block(s) to the free_list.
320 */
321 if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps,
322 &first_block, &free_list, &done)))
323 goto error1;
324 ASSERT(done);
325 /*
326 * Commit the first transaction. This logs the EFI and the inode.
327 */
328 if ((error = xfs_bmap_finish(&tp, &free_list, &committed)))
329 goto error1;
330 /*
331 * The transaction must have been committed, since there were
332 * actually extents freed by xfs_bunmapi. See xfs_bmap_finish.
333 * The new tp has the extent freeing and EFDs.
334 */
335 ASSERT(committed);
336 /*
337 * The first xact was committed, so add the inode to the new one.
338 * Mark it dirty so it will be logged and moved forward in the log as
339 * part of every commit.
340 */
341 xfs_trans_ijoin(tp, ip, 0);
342 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
343 /*
344 * Get a new, empty transaction to return to our caller.
345 */
346 ntp = xfs_trans_dup(tp);
347 /*
348 * Commit the transaction containing extent freeing and EFDs.
349 * If we get an error on the commit here or on the reserve below,
350 * we need to unlock the inode since the new transaction doesn't
351 * have the inode attached.
352 */
353 error = xfs_trans_commit(tp, 0);
354 tp = ntp;
355 if (error) {
356 ASSERT(XFS_FORCED_SHUTDOWN(mp));
357 goto error0;
358 }
359 /*
360 * transaction commit worked ok so we can drop the extra ticket
361 * reference that we gained in xfs_trans_dup()
362 */
363 xfs_log_ticket_put(tp->t_ticket);
364
365 /*
366 * Remove the memory for extent descriptions (just bookkeeping).
367 */
368 if (ip->i_df.if_bytes)
369 xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK);
370 ASSERT(ip->i_df.if_bytes == 0);
371 /*
372 * Put an itruncate log reservation in the new transaction
373 * for our caller.
374 */
375 if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
376 XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) {
377 ASSERT(XFS_FORCED_SHUTDOWN(mp));
378 goto error0;
379 }
380
381 xfs_trans_ijoin(tp, ip, 0);
382 *tpp = tp;
383 return 0;
384
385 error1:
386 xfs_bmap_cancel(&free_list);
387 error0:
388 return error;
389}
390
391int 158int
392xfs_release( 159xfs_release(
393 xfs_inode_t *ip) 160 xfs_inode_t *ip)
@@ -1353,247 +1120,6 @@ xfs_link(
1353} 1120}
1354 1121
1355int 1122int
1356xfs_symlink(
1357 xfs_inode_t *dp,
1358 struct xfs_name *link_name,
1359 const char *target_path,
1360 umode_t mode,
1361 xfs_inode_t **ipp)
1362{
1363 xfs_mount_t *mp = dp->i_mount;
1364 xfs_trans_t *tp;
1365 xfs_inode_t *ip;
1366 int error;
1367 int pathlen;
1368 xfs_bmap_free_t free_list;
1369 xfs_fsblock_t first_block;
1370 bool unlock_dp_on_error = false;
1371 uint cancel_flags;
1372 int committed;
1373 xfs_fileoff_t first_fsb;
1374 xfs_filblks_t fs_blocks;
1375 int nmaps;
1376 xfs_bmbt_irec_t mval[SYMLINK_MAPS];
1377 xfs_daddr_t d;
1378 const char *cur_chunk;
1379 int byte_cnt;
1380 int n;
1381 xfs_buf_t *bp;
1382 prid_t prid;
1383 struct xfs_dquot *udqp, *gdqp;
1384 uint resblks;
1385
1386 *ipp = NULL;
1387 error = 0;
1388 ip = NULL;
1389 tp = NULL;
1390
1391 trace_xfs_symlink(dp, link_name);
1392
1393 if (XFS_FORCED_SHUTDOWN(mp))
1394 return XFS_ERROR(EIO);
1395
1396 /*
1397 * Check component lengths of the target path name.
1398 */
1399 pathlen = strlen(target_path);
1400 if (pathlen >= MAXPATHLEN) /* total string too long */
1401 return XFS_ERROR(ENAMETOOLONG);
1402
1403 udqp = gdqp = NULL;
1404 if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
1405 prid = xfs_get_projid(dp);
1406 else
1407 prid = XFS_PROJID_DEFAULT;
1408
1409 /*
1410 * Make sure that we have allocated dquot(s) on disk.
1411 */
1412 error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
1413 XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
1414 if (error)
1415 goto std_return;
1416
1417 tp = xfs_trans_alloc(mp, XFS_TRANS_SYMLINK);
1418 cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
1419 /*
1420 * The symlink will fit into the inode data fork?
1421 * There can't be any attributes so we get the whole variable part.
1422 */
1423 if (pathlen <= XFS_LITINO(mp, dp->i_d.di_version))
1424 fs_blocks = 0;
1425 else
1426 fs_blocks = XFS_B_TO_FSB(mp, pathlen);
1427 resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
1428 error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0,
1429 XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
1430 if (error == ENOSPC && fs_blocks == 0) {
1431 resblks = 0;
1432 error = xfs_trans_reserve(tp, 0, XFS_SYMLINK_LOG_RES(mp), 0,
1433 XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
1434 }
1435 if (error) {
1436 cancel_flags = 0;
1437 goto error_return;
1438 }
1439
1440 xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
1441 unlock_dp_on_error = true;
1442
1443 /*
1444 * Check whether the directory allows new symlinks or not.
1445 */
1446 if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) {
1447 error = XFS_ERROR(EPERM);
1448 goto error_return;
1449 }
1450
1451 /*
1452 * Reserve disk quota : blocks and inode.
1453 */
1454 error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
1455 if (error)
1456 goto error_return;
1457
1458 /*
1459 * Check for ability to enter directory entry, if no space reserved.
1460 */
1461 error = xfs_dir_canenter(tp, dp, link_name, resblks);
1462 if (error)
1463 goto error_return;
1464 /*
1465 * Initialize the bmap freelist prior to calling either
1466 * bmapi or the directory create code.
1467 */
1468 xfs_bmap_init(&free_list, &first_block);
1469
1470 /*
1471 * Allocate an inode for the symlink.
1472 */
1473 error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0,
1474 prid, resblks > 0, &ip, NULL);
1475 if (error) {
1476 if (error == ENOSPC)
1477 goto error_return;
1478 goto error1;
1479 }
1480
1481 /*
1482 * An error after we've joined dp to the transaction will result in the
1483 * transaction cancel unlocking dp so don't do it explicitly in the
1484 * error path.
1485 */
1486 xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
1487 unlock_dp_on_error = false;
1488
1489 /*
1490 * Also attach the dquot(s) to it, if applicable.
1491 */
1492 xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
1493
1494 if (resblks)
1495 resblks -= XFS_IALLOC_SPACE_RES(mp);
1496 /*
1497 * If the symlink will fit into the inode, write it inline.
1498 */
1499 if (pathlen <= XFS_IFORK_DSIZE(ip)) {
1500 xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK);
1501 memcpy(ip->i_df.if_u1.if_data, target_path, pathlen);
1502 ip->i_d.di_size = pathlen;
1503
1504 /*
1505 * The inode was initially created in extent format.
1506 */
1507 ip->i_df.if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT);
1508 ip->i_df.if_flags |= XFS_IFINLINE;
1509
1510 ip->i_d.di_format = XFS_DINODE_FMT_LOCAL;
1511 xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
1512
1513 } else {
1514 first_fsb = 0;
1515 nmaps = SYMLINK_MAPS;
1516
1517 error = xfs_bmapi_write(tp, ip, first_fsb, fs_blocks,
1518 XFS_BMAPI_METADATA, &first_block, resblks,
1519 mval, &nmaps, &free_list);
1520 if (error)
1521 goto error2;
1522
1523 if (resblks)
1524 resblks -= fs_blocks;
1525 ip->i_d.di_size = pathlen;
1526 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
1527
1528 cur_chunk = target_path;
1529 for (n = 0; n < nmaps; n++) {
1530 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
1531 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
1532 bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
1533 BTOBB(byte_cnt), 0);
1534 if (!bp) {
1535 error = ENOMEM;
1536 goto error2;
1537 }
1538 if (pathlen < byte_cnt) {
1539 byte_cnt = pathlen;
1540 }
1541 pathlen -= byte_cnt;
1542
1543 memcpy(bp->b_addr, cur_chunk, byte_cnt);
1544 cur_chunk += byte_cnt;
1545
1546 xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1);
1547 }
1548 }
1549
1550 /*
1551 * Create the directory entry for the symlink.
1552 */
1553 error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
1554 &first_block, &free_list, resblks);
1555 if (error)
1556 goto error2;
1557 xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
1558 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
1559
1560 /*
1561 * If this is a synchronous mount, make sure that the
1562 * symlink transaction goes to disk before returning to
1563 * the user.
1564 */
1565 if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
1566 xfs_trans_set_sync(tp);
1567 }
1568
1569 error = xfs_bmap_finish(&tp, &free_list, &committed);
1570 if (error) {
1571 goto error2;
1572 }
1573 error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
1574 xfs_qm_dqrele(udqp);
1575 xfs_qm_dqrele(gdqp);
1576
1577 *ipp = ip;
1578 return 0;
1579
1580 error2:
1581 IRELE(ip);
1582 error1:
1583 xfs_bmap_cancel(&free_list);
1584 cancel_flags |= XFS_TRANS_ABORT;
1585 error_return:
1586 xfs_trans_cancel(tp, cancel_flags);
1587 xfs_qm_dqrele(udqp);
1588 xfs_qm_dqrele(gdqp);
1589
1590 if (unlock_dp_on_error)
1591 xfs_iunlock(dp, XFS_ILOCK_EXCL);
1592 std_return:
1593 return error;
1594}
1595
1596int
1597xfs_set_dmattrs( 1123xfs_set_dmattrs(
1598 xfs_inode_t *ip, 1124 xfs_inode_t *ip,
1599 u_int evmask, 1125 u_int evmask,