xfs_symlink_remote.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * Copyright (c) 2000-2006 Silicon Graphics, Inc.
  3. * Copyright (c) 2012-2013 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it would be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write the Free Software Foundation,
  17. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. #include "xfs.h"
  20. #include "xfs_fs.h"
  21. #include "xfs_format.h"
  22. #include "xfs_log.h"
  23. #include "xfs_trans.h"
  24. #include "xfs_sb.h"
  25. #include "xfs_mount.h"
  26. #include "xfs_bmap_btree.h"
  27. #include "xfs_inode.h"
  28. #include "xfs_error.h"
  29. #include "xfs_trace.h"
  30. #include "xfs_symlink.h"
  31. #include "xfs_cksum.h"
  32. #include "xfs_buf_item.h"
  33. /*
  34. * Each contiguous block has a header, so it is not just a simple pathlen
  35. * to FSB conversion.
  36. */
  37. int
  38. xfs_symlink_blocks(
  39. struct xfs_mount *mp,
  40. int pathlen)
  41. {
  42. int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
  43. return (pathlen + buflen - 1) / buflen;
  44. }
  45. int
  46. xfs_symlink_hdr_set(
  47. struct xfs_mount *mp,
  48. xfs_ino_t ino,
  49. uint32_t offset,
  50. uint32_t size,
  51. struct xfs_buf *bp)
  52. {
  53. struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  54. if (!xfs_sb_version_hascrc(&mp->m_sb))
  55. return 0;
  56. dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
  57. dsl->sl_offset = cpu_to_be32(offset);
  58. dsl->sl_bytes = cpu_to_be32(size);
  59. uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
  60. dsl->sl_owner = cpu_to_be64(ino);
  61. dsl->sl_blkno = cpu_to_be64(bp->b_bn);
  62. bp->b_ops = &xfs_symlink_buf_ops;
  63. return sizeof(struct xfs_dsymlink_hdr);
  64. }
  65. /*
  66. * Checking of the symlink header is split into two parts. the verifier does
  67. * CRC, location and bounds checking, the unpacking function checks the path
  68. * parameters and owner.
  69. */
  70. bool
  71. xfs_symlink_hdr_ok(
  72. struct xfs_mount *mp,
  73. xfs_ino_t ino,
  74. uint32_t offset,
  75. uint32_t size,
  76. struct xfs_buf *bp)
  77. {
  78. struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  79. if (offset != be32_to_cpu(dsl->sl_offset))
  80. return false;
  81. if (size != be32_to_cpu(dsl->sl_bytes))
  82. return false;
  83. if (ino != be64_to_cpu(dsl->sl_owner))
  84. return false;
  85. /* ok */
  86. return true;
  87. }
  88. static bool
  89. xfs_symlink_verify(
  90. struct xfs_buf *bp)
  91. {
  92. struct xfs_mount *mp = bp->b_target->bt_mount;
  93. struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  94. if (!xfs_sb_version_hascrc(&mp->m_sb))
  95. return false;
  96. if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
  97. return false;
  98. if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
  99. return false;
  100. if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
  101. return false;
  102. if (be32_to_cpu(dsl->sl_offset) +
  103. be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN)
  104. return false;
  105. if (dsl->sl_owner == 0)
  106. return false;
  107. return true;
  108. }
  109. static void
  110. xfs_symlink_read_verify(
  111. struct xfs_buf *bp)
  112. {
  113. struct xfs_mount *mp = bp->b_target->bt_mount;
  114. /* no verification of non-crc buffers */
  115. if (!xfs_sb_version_hascrc(&mp->m_sb))
  116. return;
  117. if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
  118. offsetof(struct xfs_dsymlink_hdr, sl_crc)) ||
  119. !xfs_symlink_verify(bp)) {
  120. XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
  121. xfs_buf_ioerror(bp, EFSCORRUPTED);
  122. }
  123. }
  124. static void
  125. xfs_symlink_write_verify(
  126. struct xfs_buf *bp)
  127. {
  128. struct xfs_mount *mp = bp->b_target->bt_mount;
  129. struct xfs_buf_log_item *bip = bp->b_fspriv;
  130. /* no verification of non-crc buffers */
  131. if (!xfs_sb_version_hascrc(&mp->m_sb))
  132. return;
  133. if (!xfs_symlink_verify(bp)) {
  134. XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
  135. xfs_buf_ioerror(bp, EFSCORRUPTED);
  136. return;
  137. }
  138. if (bip) {
  139. struct xfs_dsymlink_hdr *dsl = bp->b_addr;
  140. dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
  141. }
  142. xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
  143. offsetof(struct xfs_dsymlink_hdr, sl_crc));
  144. }
  145. const struct xfs_buf_ops xfs_symlink_buf_ops = {
  146. .verify_read = xfs_symlink_read_verify,
  147. .verify_write = xfs_symlink_write_verify,
  148. };
  149. void
  150. xfs_symlink_local_to_remote(
  151. struct xfs_trans *tp,
  152. struct xfs_buf *bp,
  153. struct xfs_inode *ip,
  154. struct xfs_ifork *ifp)
  155. {
  156. struct xfs_mount *mp = ip->i_mount;
  157. char *buf;
  158. if (!xfs_sb_version_hascrc(&mp->m_sb)) {
  159. bp->b_ops = NULL;
  160. memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
  161. return;
  162. }
  163. /*
  164. * As this symlink fits in an inode literal area, it must also fit in
  165. * the smallest buffer the filesystem supports.
  166. */
  167. ASSERT(BBTOB(bp->b_length) >=
  168. ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
  169. bp->b_ops = &xfs_symlink_buf_ops;
  170. buf = bp->b_addr;
  171. buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
  172. memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
  173. }