root/fs/xfs/xfs_symlink.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xfs_readlink_bmap_ilocked
  2. xfs_readlink
  3. xfs_symlink
  4. xfs_inactive_symlink_rmt
  5. xfs_inactive_symlink

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2000-2006 Silicon Graphics, Inc.
   4  * Copyright (c) 2012-2013 Red Hat, Inc.
   5  * All rights reserved.
   6  */
   7 #include "xfs.h"
   8 #include "xfs_shared.h"
   9 #include "xfs_fs.h"
  10 #include "xfs_format.h"
  11 #include "xfs_log_format.h"
  12 #include "xfs_trans_resv.h"
  13 #include "xfs_bit.h"
  14 #include "xfs_mount.h"
  15 #include "xfs_dir2.h"
  16 #include "xfs_inode.h"
  17 #include "xfs_bmap.h"
  18 #include "xfs_bmap_btree.h"
  19 #include "xfs_quota.h"
  20 #include "xfs_trans_space.h"
  21 #include "xfs_trace.h"
  22 #include "xfs_trans.h"
  23 
  24 /* ----- Kernel only functions below ----- */
  25 int
  26 xfs_readlink_bmap_ilocked(
  27         struct xfs_inode        *ip,
  28         char                    *link)
  29 {
  30         struct xfs_mount        *mp = ip->i_mount;
  31         struct xfs_bmbt_irec    mval[XFS_SYMLINK_MAPS];
  32         struct xfs_buf          *bp;
  33         xfs_daddr_t             d;
  34         char                    *cur_chunk;
  35         int                     pathlen = ip->i_d.di_size;
  36         int                     nmaps = XFS_SYMLINK_MAPS;
  37         int                     byte_cnt;
  38         int                     n;
  39         int                     error = 0;
  40         int                     fsblocks = 0;
  41         int                     offset;
  42 
  43         ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
  44 
  45         fsblocks = xfs_symlink_blocks(mp, pathlen);
  46         error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0);
  47         if (error)
  48                 goto out;
  49 
  50         offset = 0;
  51         for (n = 0; n < nmaps; n++) {
  52                 d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
  53                 byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
  54 
  55                 bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0,
  56                                   &xfs_symlink_buf_ops);
  57                 if (!bp)
  58                         return -ENOMEM;
  59                 error = bp->b_error;
  60                 if (error) {
  61                         xfs_buf_ioerror_alert(bp, __func__);
  62                         xfs_buf_relse(bp);
  63 
  64                         /* bad CRC means corrupted metadata */
  65                         if (error == -EFSBADCRC)
  66                                 error = -EFSCORRUPTED;
  67                         goto out;
  68                 }
  69                 byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
  70                 if (pathlen < byte_cnt)
  71                         byte_cnt = pathlen;
  72 
  73                 cur_chunk = bp->b_addr;
  74                 if (xfs_sb_version_hascrc(&mp->m_sb)) {
  75                         if (!xfs_symlink_hdr_ok(ip->i_ino, offset,
  76                                                         byte_cnt, bp)) {
  77                                 error = -EFSCORRUPTED;
  78                                 xfs_alert(mp,
  79 "symlink header does not match required off/len/owner (0x%x/Ox%x,0x%llx)",
  80                                         offset, byte_cnt, ip->i_ino);
  81                                 xfs_buf_relse(bp);
  82                                 goto out;
  83 
  84                         }
  85 
  86                         cur_chunk += sizeof(struct xfs_dsymlink_hdr);
  87                 }
  88 
  89                 memcpy(link + offset, cur_chunk, byte_cnt);
  90 
  91                 pathlen -= byte_cnt;
  92                 offset += byte_cnt;
  93 
  94                 xfs_buf_relse(bp);
  95         }
  96         ASSERT(pathlen == 0);
  97 
  98         link[ip->i_d.di_size] = '\0';
  99         error = 0;
 100 
 101  out:
 102         return error;
 103 }
 104 
 105 int
 106 xfs_readlink(
 107         struct xfs_inode *ip,
 108         char            *link)
 109 {
 110         struct xfs_mount *mp = ip->i_mount;
 111         xfs_fsize_t     pathlen;
 112         int             error = 0;
 113 
 114         trace_xfs_readlink(ip);
 115 
 116         ASSERT(!(ip->i_df.if_flags & XFS_IFINLINE));
 117 
 118         if (XFS_FORCED_SHUTDOWN(mp))
 119                 return -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 > XFS_SYMLINK_MAXLEN) {
 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 = -EFSCORRUPTED;
 133                 goto out;
 134         }
 135 
 136 
 137         error = xfs_readlink_bmap_ilocked(ip, link);
 138 
 139  out:
 140         xfs_iunlock(ip, XFS_ILOCK_SHARED);
 141         return error;
 142 }
 143 
 144 int
 145 xfs_symlink(
 146         struct xfs_inode        *dp,
 147         struct xfs_name         *link_name,
 148         const char              *target_path,
 149         umode_t                 mode,
 150         struct xfs_inode        **ipp)
 151 {
 152         struct xfs_mount        *mp = dp->i_mount;
 153         struct xfs_trans        *tp = NULL;
 154         struct xfs_inode        *ip = NULL;
 155         int                     error = 0;
 156         int                     pathlen;
 157         bool                    unlock_dp_on_error = false;
 158         xfs_fileoff_t           first_fsb;
 159         xfs_filblks_t           fs_blocks;
 160         int                     nmaps;
 161         struct xfs_bmbt_irec    mval[XFS_SYMLINK_MAPS];
 162         xfs_daddr_t             d;
 163         const char              *cur_chunk;
 164         int                     byte_cnt;
 165         int                     n;
 166         xfs_buf_t               *bp;
 167         prid_t                  prid;
 168         struct xfs_dquot        *udqp = NULL;
 169         struct xfs_dquot        *gdqp = NULL;
 170         struct xfs_dquot        *pdqp = NULL;
 171         uint                    resblks;
 172 
 173         *ipp = NULL;
 174 
 175         trace_xfs_symlink(dp, link_name);
 176 
 177         if (XFS_FORCED_SHUTDOWN(mp))
 178                 return -EIO;
 179 
 180         /*
 181          * Check component lengths of the target path name.
 182          */
 183         pathlen = strlen(target_path);
 184         if (pathlen >= XFS_SYMLINK_MAXLEN)      /* total string too long */
 185                 return -ENAMETOOLONG;
 186         ASSERT(pathlen > 0);
 187 
 188         udqp = gdqp = NULL;
 189         prid = xfs_get_initial_prid(dp);
 190 
 191         /*
 192          * Make sure that we have allocated dquot(s) on disk.
 193          */
 194         error = xfs_qm_vop_dqalloc(dp,
 195                         xfs_kuid_to_uid(current_fsuid()),
 196                         xfs_kgid_to_gid(current_fsgid()), prid,
 197                         XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
 198                         &udqp, &gdqp, &pdqp);
 199         if (error)
 200                 return error;
 201 
 202         /*
 203          * The symlink will fit into the inode data fork?
 204          * There can't be any attributes so we get the whole variable part.
 205          */
 206         if (pathlen <= XFS_LITINO(mp, dp->i_d.di_version))
 207                 fs_blocks = 0;
 208         else
 209                 fs_blocks = xfs_symlink_blocks(mp, pathlen);
 210         resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
 211 
 212         error = xfs_trans_alloc(mp, &M_RES(mp)->tr_symlink, resblks, 0, 0, &tp);
 213         if (error)
 214                 goto out_release_inode;
 215 
 216         xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 217         unlock_dp_on_error = true;
 218 
 219         /*
 220          * Check whether the directory allows new symlinks or not.
 221          */
 222         if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) {
 223                 error = -EPERM;
 224                 goto out_trans_cancel;
 225         }
 226 
 227         /*
 228          * Reserve disk quota : blocks and inode.
 229          */
 230         error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
 231                                                 pdqp, resblks, 1, 0);
 232         if (error)
 233                 goto out_trans_cancel;
 234 
 235         /*
 236          * Allocate an inode for the symlink.
 237          */
 238         error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0,
 239                                prid, &ip);
 240         if (error)
 241                 goto out_trans_cancel;
 242 
 243         /*
 244          * Now we join the directory inode to the transaction.  We do not do it
 245          * earlier because xfs_dir_ialloc might commit the previous transaction
 246          * (and release all the locks).  An error from here on will result in
 247          * the transaction cancel unlocking dp so don't do it explicitly in the
 248          * error path.
 249          */
 250         xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
 251         unlock_dp_on_error = false;
 252 
 253         /*
 254          * Also attach the dquot(s) to it, if applicable.
 255          */
 256         xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
 257 
 258         if (resblks)
 259                 resblks -= XFS_IALLOC_SPACE_RES(mp);
 260         /*
 261          * If the symlink will fit into the inode, write it inline.
 262          */
 263         if (pathlen <= XFS_IFORK_DSIZE(ip)) {
 264                 xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen);
 265 
 266                 ip->i_d.di_size = pathlen;
 267                 ip->i_d.di_format = XFS_DINODE_FMT_LOCAL;
 268                 xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);
 269         } else {
 270                 int     offset;
 271 
 272                 first_fsb = 0;
 273                 nmaps = XFS_SYMLINK_MAPS;
 274 
 275                 error = xfs_bmapi_write(tp, ip, first_fsb, fs_blocks,
 276                                   XFS_BMAPI_METADATA, resblks, mval, &nmaps);
 277                 if (error)
 278                         goto out_trans_cancel;
 279 
 280                 if (resblks)
 281                         resblks -= fs_blocks;
 282                 ip->i_d.di_size = pathlen;
 283                 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 284 
 285                 cur_chunk = target_path;
 286                 offset = 0;
 287                 for (n = 0; n < nmaps; n++) {
 288                         char    *buf;
 289 
 290                         d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
 291                         byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
 292                         bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
 293                                                BTOBB(byte_cnt), 0);
 294                         if (!bp) {
 295                                 error = -ENOMEM;
 296                                 goto out_trans_cancel;
 297                         }
 298                         bp->b_ops = &xfs_symlink_buf_ops;
 299 
 300                         byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt);
 301                         byte_cnt = min(byte_cnt, pathlen);
 302 
 303                         buf = bp->b_addr;
 304                         buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset,
 305                                                    byte_cnt, bp);
 306 
 307                         memcpy(buf, cur_chunk, byte_cnt);
 308 
 309                         cur_chunk += byte_cnt;
 310                         pathlen -= byte_cnt;
 311                         offset += byte_cnt;
 312 
 313                         xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
 314                         xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
 315                                                         (char *)bp->b_addr);
 316                 }
 317                 ASSERT(pathlen == 0);
 318         }
 319 
 320         /*
 321          * Create the directory entry for the symlink.
 322          */
 323         error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, resblks);
 324         if (error)
 325                 goto out_trans_cancel;
 326         xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 327         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 328 
 329         /*
 330          * If this is a synchronous mount, make sure that the
 331          * symlink transaction goes to disk before returning to
 332          * the user.
 333          */
 334         if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
 335                 xfs_trans_set_sync(tp);
 336         }
 337 
 338         error = xfs_trans_commit(tp);
 339         if (error)
 340                 goto out_release_inode;
 341 
 342         xfs_qm_dqrele(udqp);
 343         xfs_qm_dqrele(gdqp);
 344         xfs_qm_dqrele(pdqp);
 345 
 346         *ipp = ip;
 347         return 0;
 348 
 349 out_trans_cancel:
 350         xfs_trans_cancel(tp);
 351 out_release_inode:
 352         /*
 353          * Wait until after the current transaction is aborted to finish the
 354          * setup of the inode and release the inode.  This prevents recursive
 355          * transactions and deadlocks from xfs_inactive.
 356          */
 357         if (ip) {
 358                 xfs_finish_inode_setup(ip);
 359                 xfs_irele(ip);
 360         }
 361 
 362         xfs_qm_dqrele(udqp);
 363         xfs_qm_dqrele(gdqp);
 364         xfs_qm_dqrele(pdqp);
 365 
 366         if (unlock_dp_on_error)
 367                 xfs_iunlock(dp, XFS_ILOCK_EXCL);
 368         return error;
 369 }
 370 
 371 /*
 372  * Free a symlink that has blocks associated with it.
 373  *
 374  * Note: zero length symlinks are not allowed to exist. When we set the size to
 375  * zero, also change it to a regular file so that it does not get written to
 376  * disk as a zero length symlink. The inode is on the unlinked list already, so
 377  * userspace cannot find this inode anymore, so this change is not user visible
 378  * but allows us to catch corrupt zero-length symlinks in the verifiers.
 379  */
 380 STATIC int
 381 xfs_inactive_symlink_rmt(
 382         struct xfs_inode *ip)
 383 {
 384         xfs_buf_t       *bp;
 385         int             done;
 386         int             error;
 387         int             i;
 388         xfs_mount_t     *mp;
 389         xfs_bmbt_irec_t mval[XFS_SYMLINK_MAPS];
 390         int             nmaps;
 391         int             size;
 392         xfs_trans_t     *tp;
 393 
 394         mp = ip->i_mount;
 395         ASSERT(ip->i_df.if_flags & XFS_IFEXTENTS);
 396         /*
 397          * We're freeing a symlink that has some
 398          * blocks allocated to it.  Free the
 399          * blocks here.  We know that we've got
 400          * either 1 or 2 extents and that we can
 401          * free them all in one bunmapi call.
 402          */
 403         ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2);
 404 
 405         error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
 406         if (error)
 407                 return error;
 408 
 409         xfs_ilock(ip, XFS_ILOCK_EXCL);
 410         xfs_trans_ijoin(tp, ip, 0);
 411 
 412         /*
 413          * Lock the inode, fix the size, turn it into a regular file and join it
 414          * to the transaction.  Hold it so in the normal path, we still have it
 415          * locked for the second transaction.  In the error paths we need it
 416          * held so the cancel won't rele it, see below.
 417          */
 418         size = (int)ip->i_d.di_size;
 419         ip->i_d.di_size = 0;
 420         VFS_I(ip)->i_mode = (VFS_I(ip)->i_mode & ~S_IFMT) | S_IFREG;
 421         xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 422         /*
 423          * Find the block(s) so we can inval and unmap them.
 424          */
 425         done = 0;
 426         nmaps = ARRAY_SIZE(mval);
 427         error = xfs_bmapi_read(ip, 0, xfs_symlink_blocks(mp, size),
 428                                 mval, &nmaps, 0);
 429         if (error)
 430                 goto error_trans_cancel;
 431         /*
 432          * Invalidate the block(s). No validation is done.
 433          */
 434         for (i = 0; i < nmaps; i++) {
 435                 bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,
 436                         XFS_FSB_TO_DADDR(mp, mval[i].br_startblock),
 437                         XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0);
 438                 if (!bp) {
 439                         error = -ENOMEM;
 440                         goto error_trans_cancel;
 441                 }
 442                 xfs_trans_binval(tp, bp);
 443         }
 444         /*
 445          * Unmap the dead block(s) to the dfops.
 446          */
 447         error = xfs_bunmapi(tp, ip, 0, size, 0, nmaps, &done);
 448         if (error)
 449                 goto error_trans_cancel;
 450         ASSERT(done);
 451 
 452         /*
 453          * Commit the transaction. This first logs the EFI and the inode, then
 454          * rolls and commits the transaction that frees the extents.
 455          */
 456         xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 457         error = xfs_trans_commit(tp);
 458         if (error) {
 459                 ASSERT(XFS_FORCED_SHUTDOWN(mp));
 460                 goto error_unlock;
 461         }
 462 
 463         /*
 464          * Remove the memory for extent descriptions (just bookkeeping).
 465          */
 466         if (ip->i_df.if_bytes)
 467                 xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK);
 468         ASSERT(ip->i_df.if_bytes == 0);
 469 
 470         xfs_iunlock(ip, XFS_ILOCK_EXCL);
 471         return 0;
 472 
 473 error_trans_cancel:
 474         xfs_trans_cancel(tp);
 475 error_unlock:
 476         xfs_iunlock(ip, XFS_ILOCK_EXCL);
 477         return error;
 478 }
 479 
 480 /*
 481  * xfs_inactive_symlink - free a symlink
 482  */
 483 int
 484 xfs_inactive_symlink(
 485         struct xfs_inode        *ip)
 486 {
 487         struct xfs_mount        *mp = ip->i_mount;
 488         int                     pathlen;
 489 
 490         trace_xfs_inactive_symlink(ip);
 491 
 492         if (XFS_FORCED_SHUTDOWN(mp))
 493                 return -EIO;
 494 
 495         xfs_ilock(ip, XFS_ILOCK_EXCL);
 496         pathlen = (int)ip->i_d.di_size;
 497         ASSERT(pathlen);
 498 
 499         if (pathlen <= 0 || pathlen > XFS_SYMLINK_MAXLEN) {
 500                 xfs_alert(mp, "%s: inode (0x%llx) bad symlink length (%d)",
 501                          __func__, (unsigned long long)ip->i_ino, pathlen);
 502                 xfs_iunlock(ip, XFS_ILOCK_EXCL);
 503                 ASSERT(0);
 504                 return -EFSCORRUPTED;
 505         }
 506 
 507         /*
 508          * Inline fork state gets removed by xfs_difree() so we have nothing to
 509          * do here in that case.
 510          */
 511         if (ip->i_df.if_flags & XFS_IFINLINE) {
 512                 xfs_iunlock(ip, XFS_ILOCK_EXCL);
 513                 return 0;
 514         }
 515 
 516         xfs_iunlock(ip, XFS_ILOCK_EXCL);
 517 
 518         /* remove the remote symlink */
 519         return xfs_inactive_symlink_rmt(ip);
 520 }

/* [<][>][^][v][top][bottom][index][help] */