0001
0002
0003
0004
0005
0006
0007 #include "xfs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_fs.h"
0010 #include "xfs_format.h"
0011 #include "xfs_log_format.h"
0012 #include "xfs_trans_resv.h"
0013 #include "xfs_bit.h"
0014 #include "xfs_mount.h"
0015 #include "xfs_dir2.h"
0016 #include "xfs_inode.h"
0017 #include "xfs_bmap.h"
0018 #include "xfs_bmap_btree.h"
0019 #include "xfs_quota.h"
0020 #include "xfs_symlink.h"
0021 #include "xfs_trans_space.h"
0022 #include "xfs_trace.h"
0023 #include "xfs_trans.h"
0024 #include "xfs_ialloc.h"
0025 #include "xfs_error.h"
0026
0027
0028 int
0029 xfs_readlink_bmap_ilocked(
0030 struct xfs_inode *ip,
0031 char *link)
0032 {
0033 struct xfs_mount *mp = ip->i_mount;
0034 struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
0035 struct xfs_buf *bp;
0036 xfs_daddr_t d;
0037 char *cur_chunk;
0038 int pathlen = ip->i_disk_size;
0039 int nmaps = XFS_SYMLINK_MAPS;
0040 int byte_cnt;
0041 int n;
0042 int error = 0;
0043 int fsblocks = 0;
0044 int offset;
0045
0046 ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
0047
0048 fsblocks = xfs_symlink_blocks(mp, pathlen);
0049 error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0);
0050 if (error)
0051 goto out;
0052
0053 offset = 0;
0054 for (n = 0; n < nmaps; n++) {
0055 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
0056 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
0057
0058 error = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0,
0059 &bp, &xfs_symlink_buf_ops);
0060 if (error)
0061 return error;
0062 byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
0063 if (pathlen < byte_cnt)
0064 byte_cnt = pathlen;
0065
0066 cur_chunk = bp->b_addr;
0067 if (xfs_has_crc(mp)) {
0068 if (!xfs_symlink_hdr_ok(ip->i_ino, offset,
0069 byte_cnt, bp)) {
0070 error = -EFSCORRUPTED;
0071 xfs_alert(mp,
0072 "symlink header does not match required off/len/owner (0x%x/Ox%x,0x%llx)",
0073 offset, byte_cnt, ip->i_ino);
0074 xfs_buf_relse(bp);
0075 goto out;
0076
0077 }
0078
0079 cur_chunk += sizeof(struct xfs_dsymlink_hdr);
0080 }
0081
0082 memcpy(link + offset, cur_chunk, byte_cnt);
0083
0084 pathlen -= byte_cnt;
0085 offset += byte_cnt;
0086
0087 xfs_buf_relse(bp);
0088 }
0089 ASSERT(pathlen == 0);
0090
0091 link[ip->i_disk_size] = '\0';
0092 error = 0;
0093
0094 out:
0095 return error;
0096 }
0097
0098 int
0099 xfs_readlink(
0100 struct xfs_inode *ip,
0101 char *link)
0102 {
0103 struct xfs_mount *mp = ip->i_mount;
0104 xfs_fsize_t pathlen;
0105 int error = -EFSCORRUPTED;
0106
0107 trace_xfs_readlink(ip);
0108
0109 if (xfs_is_shutdown(mp))
0110 return -EIO;
0111
0112 xfs_ilock(ip, XFS_ILOCK_SHARED);
0113
0114 pathlen = ip->i_disk_size;
0115 if (!pathlen)
0116 goto out;
0117
0118 if (pathlen < 0 || pathlen > XFS_SYMLINK_MAXLEN) {
0119 xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)",
0120 __func__, (unsigned long long) ip->i_ino,
0121 (long long) pathlen);
0122 ASSERT(0);
0123 goto out;
0124 }
0125
0126 if (ip->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
0127
0128
0129
0130
0131 if (XFS_IS_CORRUPT(ip->i_mount, !ip->i_df.if_u1.if_data))
0132 goto out;
0133
0134 memcpy(link, ip->i_df.if_u1.if_data, pathlen + 1);
0135 error = 0;
0136 } else {
0137 error = xfs_readlink_bmap_ilocked(ip, link);
0138 }
0139
0140 out:
0141 xfs_iunlock(ip, XFS_ILOCK_SHARED);
0142 return error;
0143 }
0144
0145 int
0146 xfs_symlink(
0147 struct user_namespace *mnt_userns,
0148 struct xfs_inode *dp,
0149 struct xfs_name *link_name,
0150 const char *target_path,
0151 umode_t mode,
0152 struct xfs_inode **ipp)
0153 {
0154 struct xfs_mount *mp = dp->i_mount;
0155 struct xfs_trans *tp = NULL;
0156 struct xfs_inode *ip = NULL;
0157 int error = 0;
0158 int pathlen;
0159 bool unlock_dp_on_error = false;
0160 xfs_fileoff_t first_fsb;
0161 xfs_filblks_t fs_blocks;
0162 int nmaps;
0163 struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS];
0164 xfs_daddr_t d;
0165 const char *cur_chunk;
0166 int byte_cnt;
0167 int n;
0168 struct xfs_buf *bp;
0169 prid_t prid;
0170 struct xfs_dquot *udqp = NULL;
0171 struct xfs_dquot *gdqp = NULL;
0172 struct xfs_dquot *pdqp = NULL;
0173 uint resblks;
0174 xfs_ino_t ino;
0175
0176 *ipp = NULL;
0177
0178 trace_xfs_symlink(dp, link_name);
0179
0180 if (xfs_is_shutdown(mp))
0181 return -EIO;
0182
0183
0184
0185
0186 pathlen = strlen(target_path);
0187 if (pathlen >= XFS_SYMLINK_MAXLEN)
0188 return -ENAMETOOLONG;
0189 ASSERT(pathlen > 0);
0190
0191 prid = xfs_get_initial_prid(dp);
0192
0193
0194
0195
0196 error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns, &init_user_ns),
0197 mapped_fsgid(mnt_userns, &init_user_ns), prid,
0198 XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
0199 &udqp, &gdqp, &pdqp);
0200 if (error)
0201 return error;
0202
0203
0204
0205
0206
0207 if (pathlen <= XFS_LITINO(mp))
0208 fs_blocks = 0;
0209 else
0210 fs_blocks = xfs_symlink_blocks(mp, pathlen);
0211 resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
0212
0213 error = xfs_trans_alloc_icreate(mp, &M_RES(mp)->tr_symlink, udqp, gdqp,
0214 pdqp, resblks, &tp);
0215 if (error)
0216 goto out_release_dquots;
0217
0218 xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
0219 unlock_dp_on_error = true;
0220
0221
0222
0223
0224 if (dp->i_diflags & XFS_DIFLAG_NOSYMLINKS) {
0225 error = -EPERM;
0226 goto out_trans_cancel;
0227 }
0228
0229
0230
0231
0232 error = xfs_dialloc(&tp, dp->i_ino, S_IFLNK, &ino);
0233 if (!error)
0234 error = xfs_init_new_inode(mnt_userns, tp, dp, ino,
0235 S_IFLNK | (mode & ~S_IFMT), 1, 0, prid,
0236 false, &ip);
0237 if (error)
0238 goto out_trans_cancel;
0239
0240
0241
0242
0243
0244
0245
0246
0247 xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
0248 unlock_dp_on_error = false;
0249
0250
0251
0252
0253 xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
0254
0255 resblks -= XFS_IALLOC_SPACE_RES(mp);
0256
0257
0258
0259 if (pathlen <= xfs_inode_data_fork_size(ip)) {
0260 xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
0261
0262 ip->i_disk_size = pathlen;
0263 ip->i_df.if_format = XFS_DINODE_FMT_LOCAL;
0264 xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
0265 } else {
0266 int offset;
0267
0268 first_fsb = 0;
0269 nmaps = XFS_SYMLINK_MAPS;
0270
0271 error = xfs_bmapi_write(tp, ip, first_fsb, fs_blocks,
0272 XFS_BMAPI_METADATA, resblks, mval, &nmaps);
0273 if (error)
0274 goto out_trans_cancel;
0275
0276 resblks -= fs_blocks;
0277 ip->i_disk_size = pathlen;
0278 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
0279
0280 cur_chunk = target_path;
0281 offset = 0;
0282 for (n = 0; n < nmaps; n++) {
0283 char *buf;
0284
0285 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
0286 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
0287 error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
0288 BTOBB(byte_cnt), 0, &bp);
0289 if (error)
0290 goto out_trans_cancel;
0291 bp->b_ops = &xfs_symlink_buf_ops;
0292
0293 byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
0294 byte_cnt = min(byte_cnt, pathlen);
0295
0296 buf = bp->b_addr;
0297 buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset,
0298 byte_cnt, bp);
0299
0300 memcpy(buf, cur_chunk, byte_cnt);
0301
0302 cur_chunk += byte_cnt;
0303 pathlen -= byte_cnt;
0304 offset += byte_cnt;
0305
0306 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
0307 xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
0308 (char *)bp->b_addr);
0309 }
0310 ASSERT(pathlen == 0);
0311 }
0312 i_size_write(VFS_I(ip), ip->i_disk_size);
0313
0314
0315
0316
0317 error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, resblks);
0318 if (error)
0319 goto out_trans_cancel;
0320 xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
0321 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
0322
0323
0324
0325
0326
0327
0328 if (xfs_has_wsync(mp) || xfs_has_dirsync(mp))
0329 xfs_trans_set_sync(tp);
0330
0331 error = xfs_trans_commit(tp);
0332 if (error)
0333 goto out_release_inode;
0334
0335 xfs_qm_dqrele(udqp);
0336 xfs_qm_dqrele(gdqp);
0337 xfs_qm_dqrele(pdqp);
0338
0339 *ipp = ip;
0340 return 0;
0341
0342 out_trans_cancel:
0343 xfs_trans_cancel(tp);
0344 out_release_inode:
0345
0346
0347
0348
0349
0350 if (ip) {
0351 xfs_finish_inode_setup(ip);
0352 xfs_irele(ip);
0353 }
0354 out_release_dquots:
0355 xfs_qm_dqrele(udqp);
0356 xfs_qm_dqrele(gdqp);
0357 xfs_qm_dqrele(pdqp);
0358
0359 if (unlock_dp_on_error)
0360 xfs_iunlock(dp, XFS_ILOCK_EXCL);
0361 return error;
0362 }
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373 STATIC int
0374 xfs_inactive_symlink_rmt(
0375 struct xfs_inode *ip)
0376 {
0377 struct xfs_buf *bp;
0378 int done;
0379 int error;
0380 int i;
0381 xfs_mount_t *mp;
0382 xfs_bmbt_irec_t mval[XFS_SYMLINK_MAPS];
0383 int nmaps;
0384 int size;
0385 xfs_trans_t *tp;
0386
0387 mp = ip->i_mount;
0388 ASSERT(!xfs_need_iread_extents(&ip->i_df));
0389
0390
0391
0392
0393
0394
0395
0396 ASSERT(ip->i_df.if_nextents > 0 && ip->i_df.if_nextents <= 2);
0397
0398 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
0399 if (error)
0400 return error;
0401
0402 xfs_ilock(ip, XFS_ILOCK_EXCL);
0403 xfs_trans_ijoin(tp, ip, 0);
0404
0405
0406
0407
0408
0409
0410
0411 size = (int)ip->i_disk_size;
0412 ip->i_disk_size = 0;
0413 VFS_I(ip)->i_mode = (VFS_I(ip)->i_mode & ~S_IFMT) | S_IFREG;
0414 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
0415
0416
0417
0418 done = 0;
0419 nmaps = ARRAY_SIZE(mval);
0420 error = xfs_bmapi_read(ip, 0, xfs_symlink_blocks(mp, size),
0421 mval, &nmaps, 0);
0422 if (error)
0423 goto error_trans_cancel;
0424
0425
0426
0427 for (i = 0; i < nmaps; i++) {
0428 error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
0429 XFS_FSB_TO_DADDR(mp, mval[i].br_startblock),
0430 XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0,
0431 &bp);
0432 if (error)
0433 goto error_trans_cancel;
0434 xfs_trans_binval(tp, bp);
0435 }
0436
0437
0438
0439 error = xfs_bunmapi(tp, ip, 0, size, 0, nmaps, &done);
0440 if (error)
0441 goto error_trans_cancel;
0442 ASSERT(done);
0443
0444
0445
0446
0447
0448 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
0449 error = xfs_trans_commit(tp);
0450 if (error) {
0451 ASSERT(xfs_is_shutdown(mp));
0452 goto error_unlock;
0453 }
0454
0455
0456
0457
0458 if (ip->i_df.if_bytes)
0459 xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK);
0460 ASSERT(ip->i_df.if_bytes == 0);
0461
0462 xfs_iunlock(ip, XFS_ILOCK_EXCL);
0463 return 0;
0464
0465 error_trans_cancel:
0466 xfs_trans_cancel(tp);
0467 error_unlock:
0468 xfs_iunlock(ip, XFS_ILOCK_EXCL);
0469 return error;
0470 }
0471
0472
0473
0474
0475 int
0476 xfs_inactive_symlink(
0477 struct xfs_inode *ip)
0478 {
0479 struct xfs_mount *mp = ip->i_mount;
0480 int pathlen;
0481
0482 trace_xfs_inactive_symlink(ip);
0483
0484 if (xfs_is_shutdown(mp))
0485 return -EIO;
0486
0487 xfs_ilock(ip, XFS_ILOCK_EXCL);
0488 pathlen = (int)ip->i_disk_size;
0489 ASSERT(pathlen);
0490
0491 if (pathlen <= 0 || pathlen > XFS_SYMLINK_MAXLEN) {
0492 xfs_alert(mp, "%s: inode (0x%llx) bad symlink length (%d)",
0493 __func__, (unsigned long long)ip->i_ino, pathlen);
0494 xfs_iunlock(ip, XFS_ILOCK_EXCL);
0495 ASSERT(0);
0496 return -EFSCORRUPTED;
0497 }
0498
0499
0500
0501
0502
0503 if (ip->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
0504 xfs_iunlock(ip, XFS_ILOCK_EXCL);
0505 return 0;
0506 }
0507
0508 xfs_iunlock(ip, XFS_ILOCK_EXCL);
0509
0510
0511 return xfs_inactive_symlink_rmt(ip);
0512 }