]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - libxfs/util.c
xfsprogs: make static things static
[thirdparty/xfsprogs-dev.git] / libxfs / util.c
index ecfe547573141e028dd5964e6fa6e0655e2417c6..993218615d008b745a1efb616b0e1876dab6e6ae 100644 (file)
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
  * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include "libxfs_priv.h"
@@ -36,6 +24,9 @@
 #include "xfs_ialloc.h"
 #include "xfs_alloc.h"
 #include "xfs_bit.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
+#include "xfs_dir2_priv.h"
 
 /*
  * Calculate the worst case log unit reservation for a given superblock
@@ -167,11 +158,69 @@ libxfs_trans_ichgtime(
        if (flags & XFS_ICHGTIME_CHG)
                VFS_I(ip)->i_ctime = tv;
        if (flags & XFS_ICHGTIME_CREATE) {
-               ip->i_d.di_crtime.t_sec = (__int32_t)tv.tv_sec;
-               ip->i_d.di_crtime.t_nsec = (__int32_t)tv.tv_nsec;
+               ip->i_d.di_crtime.t_sec = (int32_t)tv.tv_sec;
+               ip->i_d.di_crtime.t_nsec = (int32_t)tv.tv_nsec;
        }
 }
 
+STATIC uint16_t
+xfs_flags2diflags(
+       struct xfs_inode        *ip,
+       unsigned int            xflags)
+{
+       /* can't set PREALLOC this way, just preserve it */
+       uint16_t                di_flags =
+               (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
+
+       if (xflags & FS_XFLAG_IMMUTABLE)
+               di_flags |= XFS_DIFLAG_IMMUTABLE;
+       if (xflags & FS_XFLAG_APPEND)
+               di_flags |= XFS_DIFLAG_APPEND;
+       if (xflags & FS_XFLAG_SYNC)
+               di_flags |= XFS_DIFLAG_SYNC;
+       if (xflags & FS_XFLAG_NOATIME)
+               di_flags |= XFS_DIFLAG_NOATIME;
+       if (xflags & FS_XFLAG_NODUMP)
+               di_flags |= XFS_DIFLAG_NODUMP;
+       if (xflags & FS_XFLAG_NODEFRAG)
+               di_flags |= XFS_DIFLAG_NODEFRAG;
+       if (xflags & FS_XFLAG_FILESTREAM)
+               di_flags |= XFS_DIFLAG_FILESTREAM;
+       if (S_ISDIR(VFS_I(ip)->i_mode)) {
+               if (xflags & FS_XFLAG_RTINHERIT)
+                       di_flags |= XFS_DIFLAG_RTINHERIT;
+               if (xflags & FS_XFLAG_NOSYMLINKS)
+                       di_flags |= XFS_DIFLAG_NOSYMLINKS;
+               if (xflags & FS_XFLAG_EXTSZINHERIT)
+                       di_flags |= XFS_DIFLAG_EXTSZINHERIT;
+               if (xflags & FS_XFLAG_PROJINHERIT)
+                       di_flags |= XFS_DIFLAG_PROJINHERIT;
+       } else if (S_ISREG(VFS_I(ip)->i_mode)) {
+               if (xflags & FS_XFLAG_REALTIME)
+                       di_flags |= XFS_DIFLAG_REALTIME;
+               if (xflags & FS_XFLAG_EXTSIZE)
+                       di_flags |= XFS_DIFLAG_EXTSIZE;
+       }
+
+       return di_flags;
+}
+
+STATIC uint64_t
+xfs_flags2diflags2(
+       struct xfs_inode        *ip,
+       unsigned int            xflags)
+{
+       uint64_t                di_flags2 =
+               (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK);
+
+       if (xflags & FS_XFLAG_DAX)
+               di_flags2 |= XFS_DIFLAG2_DAX;
+       if (xflags & FS_XFLAG_COWEXTSIZE)
+               di_flags2 |= XFS_DIFLAG2_COWEXTSIZE;
+
+       return di_flags2;
+}
+
 /*
  * Allocate an inode on disk and return a copy of its in-core version.
  * Set mode, nlink, and rdev appropriately within the inode.
@@ -181,7 +230,7 @@ libxfs_trans_ichgtime(
  * This was once shared with the kernel, but has diverged to the point
  * where it's no longer worth the hassle of maintaining common code.
  */
-int
+static int
 libxfs_ialloc(
        xfs_trans_t     *tp,
        xfs_inode_t     *pip,
@@ -190,7 +239,6 @@ libxfs_ialloc(
        xfs_dev_t       rdev,
        struct cred     *cr,
        struct fsxattr  *fsx,
-       int             okalloc,
        xfs_buf_t       **ialloc_context,
        xfs_inode_t     **ipp)
 {
@@ -203,7 +251,7 @@ libxfs_ialloc(
         * Call the space management code to pick
         * the on-disk inode to be allocated.
         */
-       error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc,
+       error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode,
                            ialloc_context, &ino);
        if (error != 0)
                return error;
@@ -251,15 +299,17 @@ libxfs_ialloc(
        ip->i_d.di_extsize = pip ? 0 : fsx->fsx_extsize;
        ip->i_d.di_dmevmask = 0;
        ip->i_d.di_dmstate = 0;
-       ip->i_d.di_flags = pip ? 0 : fsx->fsx_xflags;
+       ip->i_d.di_flags = pip ? 0 : xfs_flags2diflags(ip, fsx->fsx_xflags);
 
        if (ip->i_d.di_version == 3) {
                ASSERT(ip->i_d.di_ino == ino);
                ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid));
                VFS_I(ip)->i_version = 1;
-               ip->i_d.di_flags2 = 0;
-               ip->i_d.di_crtime.t_sec = (__int32_t)VFS_I(ip)->i_mtime.tv_sec;
-               ip->i_d.di_crtime.t_nsec = (__int32_t)VFS_I(ip)->i_mtime.tv_nsec;
+               ip->i_d.di_flags2 = pip ? 0 : xfs_flags2diflags2(ip,
+                               fsx->fsx_xflags);
+               ip->i_d.di_crtime.t_sec = (int32_t)VFS_I(ip)->i_mtime.tv_sec;
+               ip->i_d.di_crtime.t_nsec = (int32_t)VFS_I(ip)->i_mtime.tv_nsec;
+               ip->i_d.di_cowextsize = pip ? 0 : fsx->fsx_cowextsize;
        }
 
        flags = XFS_ILOG_CORE;
@@ -272,8 +322,8 @@ libxfs_ialloc(
        case S_IFCHR:
        case S_IFBLK:
                ip->i_d.di_format = XFS_DINODE_FMT_DEV;
-               ip->i_df.if_u2.if_rdev = rdev;
                flags |= XFS_ILOG_DEV;
+               VFS_I(ip)->i_rdev = rdev;
                break;
        case S_IFREG:
        case S_IFDIR:
@@ -304,8 +354,8 @@ libxfs_ialloc(
        case S_IFLNK:
                ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
                ip->i_df.if_flags = XFS_IFEXTENTS;
-               ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0;
-               ip->i_df.if_u1.if_extents = NULL;
+               ip->i_df.if_bytes = 0;
+               ip->i_df.if_u1.if_root = NULL;
                break;
        default:
                ASSERT(0);
@@ -330,14 +380,15 @@ libxfs_ialloc(
        return 0;
 }
 
-void
+static void
 libxfs_iprint(
        xfs_inode_t             *ip)
 {
        struct xfs_icdinode     *dip;
-       xfs_bmbt_rec_host_t     *ep;
-       xfs_extnum_t            i;
-       xfs_extnum_t            nextents;
+       xfs_extnum_t            i = 0;
+       struct xfs_ifork        *ifp;           /* inode fork pointer */
+       struct xfs_iext_cursor  icur;
+       xfs_bmbt_irec_t         rec;
 
        printf("Inode %lx\n", (unsigned long)ip);
        printf("    i_ino %llx\n", (unsigned long long)ip->i_ino);
@@ -346,21 +397,18 @@ libxfs_iprint(
                printf("EXTENTS ");
        printf("\n");
        printf("    i_df.if_bytes %d\n", ip->i_df.if_bytes);
-       printf("    i_df.if_u1.if_extents/if_data %lx\n",
-               (unsigned long)ip->i_df.if_u1.if_extents);
+       printf("    i_df.if_u1.if_root/if_data %lx\n",
+               (unsigned long)ip->i_df.if_u1.if_root);
        if (ip->i_df.if_flags & XFS_IFEXTENTS) {
-               nextents = ip->i_df.if_bytes / (uint)sizeof(*ep);
-               for (ep = ip->i_df.if_u1.if_extents, i = 0; i < nextents;
-                                                               i++, ep++) {
-                       xfs_bmbt_irec_t rec;
-
-                       xfs_bmbt_get_all(ep, &rec);
+               ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+               for_each_xfs_iext(ifp, &icur, &rec) {
                        printf("\t%d: startoff %llu, startblock 0x%llx,"
                                " blockcount %llu, state %d\n",
                                i, (unsigned long long)rec.br_startoff,
                                (unsigned long long)rec.br_startblock,
                                (unsigned long long)rec.br_blockcount,
                                (int)rec.br_state);
+                       i++;
                }
        }
        printf("    i_df.if_broot %lx\n", (unsigned long)ip->i_df.if_broot);
@@ -406,7 +454,7 @@ libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp)
        xfs_dinode_t            *dip;
        xfs_mount_t             *mp;
 
-       ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
+       ASSERT(bp-b_log_item != NULL);
        ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
                ip->i_d.di_nextents > ip->i_df.if_ext_max);
        ASSERT(ip->i_d.di_version > 1);
@@ -433,6 +481,10 @@ libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp)
        if (ip->i_d.di_version == 3)
                VFS_I(ip)->i_version++;
 
+       /* Check the inline fork data before we write out. */
+       if (!libxfs_inode_verify_forks(ip, &xfs_default_ifork_ops))
+               return -EFSCORRUPTED;
+
        /*
         * Copy the dirty parts of the inode into the on-disk
         * inode.  We always copy out the core of the inode,
@@ -491,8 +543,6 @@ libxfs_alloc_file_space(
        xfs_filblks_t   datablocks;
        xfs_filblks_t   allocated_fsb;
        xfs_filblks_t   allocatesize_fsb;
-       xfs_fsblock_t   firstfsb;
-       xfs_bmap_free_t free_list;
        xfs_bmbt_irec_t *imapp;
        xfs_bmbt_irec_t imaps[1];
        int             reccount;
@@ -530,19 +580,15 @@ libxfs_alloc_file_space(
                }
                xfs_trans_ijoin(tp, ip, 0);
 
-               xfs_bmap_init(&free_list, &firstfsb);
                error = xfs_bmapi_write(tp, ip, startoffset_fsb, allocatesize_fsb,
-                               xfs_bmapi_flags, &firstfsb, 0, imapp,
-                               &reccount, &free_list);
+                               xfs_bmapi_flags, 0, imapp, &reccount);
 
                if (error)
                        goto error0;
 
-               /* complete the transaction */
-               error = xfs_bmap_finish(&tp, &free_list, ip);
-               if (error)
-                       goto error0;
-
+               /*
+                * Complete the transaction
+                */
                error = xfs_trans_commit(tp);
                if (error)
                        break;
@@ -557,23 +603,10 @@ libxfs_alloc_file_space(
        return error;
 
 error0:        /* Cancel bmap, cancel trans */
-       xfs_bmap_cancel(&free_list);
        xfs_trans_cancel(tp);
        return error;
 }
 
-unsigned int
-libxfs_log2_roundup(unsigned int i)
-{
-       unsigned int    rval;
-
-       for (rval = 0; rval < NBBY * sizeof(i); rval++) {
-               if ((1 << rval) >= i)
-                       break;
-       }
-       return rval;
-}
-
 /*
  * Wrapper around call to libxfs_ialloc. Takes care of committing and
  * allocating a new transaction as needed.
@@ -598,7 +631,7 @@ libxfs_inode_alloc(
 
        ialloc_context = (xfs_buf_t *)0;
        error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, fsx,
-                          1, &ialloc_context, &ip);
+                          &ialloc_context, &ip);
        if (error) {
                *ipp = NULL;
                return error;
@@ -612,7 +645,7 @@ libxfs_inode_alloc(
 
                xfs_trans_bhold(*tp, ialloc_context);
 
-               error = xfs_trans_roll(tp, NULL);
+               error = xfs_trans_roll(tp);
                if (error) {
                        fprintf(stderr, _("%s: cannot duplicate transaction: %s\n"),
                                progname, strerror(error));
@@ -620,7 +653,7 @@ libxfs_inode_alloc(
                }
                xfs_trans_bjoin(*tp, ialloc_context);
                error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr,
-                                  fsx, 1, &ialloc_context, &ip);
+                                  fsx, &ialloc_context, &ip);
                if (!ip)
                        error = -ENOSPC;
                if (error)
@@ -643,8 +676,9 @@ libxfs_fs_repair_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)
        vfprintf(stderr, fmt, ap);
        fprintf(stderr, "  This is a bug.\n");
        fprintf(stderr, "%s version %s\n", progname, VERSION);
-       fprintf(stderr, "Please capture the filesystem metadata with "
-                       "xfs_metadump and\nreport it to xfs@oss.sgi.com.\n");
+       fprintf(stderr,
+               "Please capture the filesystem metadata with xfs_metadump and\n"
+               "report it to linux-xfs@vger.kernel.org\n");
        va_end(ap);
 }
 
@@ -676,13 +710,37 @@ cmn_err(int level, char *fmt, ...)
  */
 void
 xfs_verifier_error(
-       struct xfs_buf          *bp)
+       struct xfs_buf          *bp,
+       int                     error,
+       xfs_failaddr_t          failaddr)
 {
-       xfs_alert(NULL, "Metadata %s detected at %s block 0x%llx/0x%x",
+       xfs_buf_ioerror(bp, error);
+
+       xfs_alert(NULL, "Metadata %s detected at %p, %s block 0x%llx/0x%x",
                  bp->b_error == -EFSBADCRC ? "CRC error" : "corruption",
+                 failaddr ? failaddr : __return_address,
                  bp->b_ops->name, bp->b_bn, BBTOB(bp->b_length));
 }
 
+/*
+ * Warnings for inode corruption problems.  Don't bother with the stack
+ * trace unless the error level is turned up high.
+ */
+void
+xfs_inode_verifier_error(
+       struct xfs_inode        *ip,
+       int                     error,
+       const char              *name,
+       void                    *buf,
+       size_t                  bufsz,
+       xfs_failaddr_t          failaddr)
+{
+       xfs_alert(NULL, "Metadata %s detected at %p, inode 0x%llx %s",
+                 error == -EFSBADCRC ? "CRC error" : "corruption",
+                 failaddr ? failaddr : __return_address,
+                 ip->i_ino, name);
+}
+
 /*
  * This is called from I/O verifiers on v5 superblock filesystems. In the
  * kernel, it validates the metadata LSN parameter against the current LSN of
@@ -695,7 +753,7 @@ xfs_verifier_error(
  * repair can validate it against the state of the log.
  */
 xfs_lsn_t      libxfs_max_lsn = 0;
-pthread_mutex_t        libxfs_max_lsn_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t libxfs_max_lsn_lock = PTHREAD_MUTEX_INITIALIZER;
 
 bool
 xfs_log_check_lsn(
@@ -755,3 +813,28 @@ libxfs_zero_extent(
        return libxfs_device_zero(xfs_find_bdev_for_inode(ip), sector, size);
 }
 
+unsigned int
+hweight8(unsigned int w)
+{
+       unsigned int res = w - ((w >> 1) & 0x55);
+       res = (res & 0x33) + ((res >> 2) & 0x33);
+       return (res + (res >> 4)) & 0x0F;
+}
+
+unsigned int
+hweight32(unsigned int w)
+{
+       unsigned int res = w - ((w >> 1) & 0x55555555);
+       res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+       res = (res + (res >> 4)) & 0x0F0F0F0F;
+       res = res + (res >> 8);
+       return (res + (res >> 16)) & 0x000000FF;
+}
+
+unsigned int
+hweight64(__u64 w)
+{
+       return hweight32((unsigned int)w) +
+              hweight32((unsigned int)(w >> 32));
+}
+