+// 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.h>
+#include "libxfs.h"
+#include "threads.h"
+#include "prefetch.h"
#include "avl.h"
#include "globals.h"
#include "agheader.h"
#include "protos.h"
#include "err_protos.h"
#include "dinode.h"
-#include "prefetch.h"
#include "progress.h"
-#include "threads.h"
#include "versions.h"
static struct cred zerocr;
1,
XFS_DIR3_FT_DIR};
+/*
+ * When we're checking directory inodes, we're allowed to set a directory's
+ * dotdot entry to zero to signal that the parent needs to be reconnected
+ * during phase 6. If we're handling a shortform directory the ifork
+ * verifiers will fail, so temporarily patch out this canary so that we can
+ * verify the rest of the fork and move on to fixing the dir.
+ */
+static xfs_failaddr_t
+phase6_verify_dir(
+ struct xfs_inode *ip)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ const struct xfs_dir_ops *dops;
+ struct xfs_ifork *ifp;
+ struct xfs_dir2_sf_hdr *sfp;
+ xfs_failaddr_t fa;
+ xfs_ino_t old_parent;
+ bool parent_bypass = false;
+ int size;
+
+ dops = libxfs_dir_get_ops(mp, NULL);
+
+ ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+ sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data;
+ size = ifp->if_bytes;
+
+ /*
+ * If this is a shortform directory, phase4 may have set the parent
+ * inode to zero to indicate that it must be fixed. Temporarily
+ * set a valid parent so that the directory verifier will pass.
+ */
+ if (size > offsetof(struct xfs_dir2_sf_hdr, parent) &&
+ size >= xfs_dir2_sf_hdr_size(sfp->i8count)) {
+ old_parent = dops->sf_get_parent_ino(sfp);
+ if (old_parent == 0) {
+ dops->sf_put_parent_ino(sfp, mp->m_sb.sb_rootino);
+ parent_bypass = true;
+ }
+ }
+
+ fa = libxfs_default_ifork_ops.verify_dir(ip);
+
+ /* Put it back. */
+ if (parent_bypass)
+ dops->sf_put_parent_ino(sfp, old_parent);
+
+ return fa;
+}
+
+static struct xfs_ifork_ops phase6_ifork_ops = {
+ .verify_attr = xfs_attr_shortform_verify,
+ .verify_dir = phase6_verify_dir,
+ .verify_symlink = xfs_symlink_shortform_verify,
+};
+
/*
* Data structures used to keep track of directories where the ".."
* entries are updated. These must be rebuilt after the initial pass
*/
typedef struct dotdot_update {
- struct dotdot_update *next;
+ struct list_head list;
ino_tree_node_t *irec;
xfs_agnumber_t agno;
int ino_offset;
} dotdot_update_t;
-static dotdot_update_t *dotdot_update_list;
+static LIST_HEAD(dotdot_update_list);
static int dotdot_update;
static void
do_error(_("malloc failed add_dotdot_update (%zu bytes)\n"),
sizeof(dotdot_update_t));
- dir->next = dotdot_update_list;
+ INIT_LIST_HEAD(&dir->list);
dir->irec = irec;
dir->agno = agno;
dir->ino_offset = ino_offset;
- dotdot_update_list = dir;
+ list_add(&dir->list, &dotdot_update_list);
}
/*
struct dir_hash_ent *nextbyhash; /* next in name bucket */
struct dir_hash_ent *nextbyorder; /* next in order added */
xfs_dahash_t hashval; /* hash value of name */
- __uint32_t address; /* offset of data entry */
+ uint32_t address; /* offset of data entry */
xfs_ino_t inum; /* inode num of entry */
short junkit; /* name starts with / */
short seen; /* have seen leaf entry */
#define DIR_HASH_CK_BADSTALE 5
#define DIR_HASH_CK_TOTAL 6
+/*
+ * Need to handle CRC and validation errors specially here. If there is a
+ * validator error, re-read without the verifier so that we get a buffer we can
+ * check and repair. Re-attach the ops to the buffer after the read so that when
+ * it is rewritten the CRC is recalculated.
+ *
+ * If the buffer was not read, we return an error. If the buffer was read but
+ * had a CRC or corruption error, we reread it without the verifier and if it is
+ * read successfully we increment *crc_error and return 0. Otherwise we
+ * return the read error.
+ */
+static int
+dir_read_buf(
+ struct xfs_inode *ip,
+ xfs_dablk_t bno,
+ xfs_daddr_t mappedbno,
+ struct xfs_buf **bpp,
+ const struct xfs_buf_ops *ops,
+ int *crc_error)
+{
+ int error;
+ int error2;
+
+ error = -libxfs_da_read_buf(NULL, ip, bno, mappedbno, bpp,
+ XFS_DATA_FORK, ops);
+
+ if (error != EFSBADCRC && error != EFSCORRUPTED)
+ return error;
+
+ error2 = -libxfs_da_read_buf(NULL, ip, bno, mappedbno, bpp,
+ XFS_DATA_FORK, NULL);
+ if (error2)
+ return error2;
+
+ (*crc_error)++;
+ (*bpp)->b_ops = ops;
+ return 0;
+}
+
/*
* Returns 0 if the name already exists (ie. a duplicate)
*/
dir_hash_add(
xfs_mount_t *mp,
dir_hash_tab_t *hashtab,
- __uint32_t addr,
+ uint32_t addr,
xfs_ino_t inum,
int namelen,
- unsigned char *name)
+ unsigned char *name,
+ uint8_t ftype)
{
xfs_dahash_t hash = 0;
int byaddr;
xname.name = name;
xname.len = namelen;
+ xname.type = ftype;
junk = name[0] == '/';
byaddr = DIR_HASH_FUNC(hashtab, addr);
return DIR_HASH_CK_NODATA;
}
+static void
+dir_hash_update_ftype(
+ dir_hash_tab_t *hashtab,
+ xfs_dir2_dataptr_t addr,
+ uint8_t ftype)
+{
+ int i;
+ dir_hash_ent_t *p;
+
+ i = DIR_HASH_FUNC(hashtab, addr);
+ for (p = hashtab->byaddr[i]; p; p = p->nextbyaddr) {
+ if (p->address != addr)
+ continue;
+ p->name.type = ftype;
+ }
+}
+
/*
* checks to make sure leafs match a data entry, and that the stale
* count is valid.
int whichfork) /* data or attr fork */
{
xfs_fileoff_t bno; /* current block */
- int eof; /* hit end of file */
int error; /* error return value */
xfs_bmbt_irec_t got; /* current extent value */
xfs_ifork_t *ifp; /* inode fork pointer */
- xfs_extnum_t lastx; /* last extent used */
- xfs_bmbt_irec_t prev; /* previous extent value */
+ struct xfs_iext_cursor icur;
if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
}
ifp = XFS_IFORK_PTR(ip, whichfork);
if (!(ifp->if_flags & XFS_IFEXTENTS) &&
- (error = xfs_iread_extents(tp, ip, whichfork)))
+ (error = -libxfs_iread_extents(tp, ip, whichfork)))
return error;
bno = *bnop + 1;
- xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev);
- if (eof)
+ if (!libxfs_iext_lookup_extent(ip, ifp, bno, &icur, &got))
*bnop = NULLFILEOFF;
else
*bnop = got.br_startoff < bno ? bno : got.br_startoff;
xfs_fsblock_t first;
int i;
int nmap;
- int committed;
int error;
- xfs_bmap_free_t flist;
- xfs_dfiloff_t bno;
+ struct xfs_defer_ops dfops;
+ xfs_fileoff_t bno;
xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP];
int vers;
int times;
- struct xfs_trans_res tres = {0};
+ uint blocks;
/*
* first set up inode
*/
- tp = libxfs_trans_alloc(mp, 0);
-
- i = libxfs_trans_reserve(tp, &tres, 10, 0);
+ i = -libxfs_trans_alloc_rollable(mp, 10, &tp);
if (i)
res_failed(i);
- error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, 0, &ip);
+ error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, 0, &ip);
if (error) {
do_error(
_("couldn't iget realtime bitmap inode -- error - %d\n"),
error);
}
- vers = xfs_sb_version_hascrc(&mp->m_sb) ? 3 : 1;
- memset(&ip->i_d, 0, xfs_icdinode_size(vers));
+ vers = xfs_sb_version_hascrc(&mp->m_sb) ? 3 : 2;
+ memset(&ip->i_d, 0, sizeof(ip->i_d));
- ip->i_d.di_magic = XFS_DINODE_MAGIC;
- ip->i_d.di_mode = S_IFREG;
+ VFS_I(ip)->i_mode = S_IFREG;
ip->i_d.di_version = vers;
ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
- ip->i_d.di_nlink = 1; /* account for sb ptr */
+ set_nlink(VFS_I(ip), 1); /* account for sb ptr */
times = XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD;
if (ip->i_d.di_version == 3) {
- ip->i_d.di_crc = 0;
- ip->i_d.di_changecount = 1;
- ip->i_d.di_lsn = 0;
+ VFS_I(ip)->i_version = 1;
ip->i_d.di_flags2 = 0;
- ip->i_d.di_ino = mp->m_sb.sb_rbmino;
- memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
- platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
times |= XFS_ICHGTIME_CREATE;
}
libxfs_trans_ichgtime(tp, ip, times);
*/
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_u1.if_root = NULL;
ip->i_d.di_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize;
* commit changes
*/
libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- libxfs_trans_ihold(tp, ip);
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
/*
* then allocate blocks for file and fill with zeroes (stolen
* from mkfs)
*/
- tp = libxfs_trans_alloc(mp, 0);
- error = libxfs_trans_reserve(tp, &tres, mp->m_sb.sb_rbmblocks +
- (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1), 0);
+ blocks = mp->m_sb.sb_rbmblocks +
+ XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
+ error = -libxfs_trans_alloc_rollable(mp, blocks, &tp);
if (error)
res_failed(error);
libxfs_trans_ijoin(tp, ip, 0);
bno = 0;
- xfs_bmap_init(&flist, &first);
+ libxfs_defer_init(&dfops, &first);
+ tp->t_dfops = &dfops;
while (bno < mp->m_sb.sb_rbmblocks) {
nmap = XFS_BMAP_MAX_NMAP;
- error = libxfs_bmapi_write(tp, ip, bno,
+ error = -libxfs_bmapi_write(tp, ip, bno,
(xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno),
- 0, &first, mp->m_sb.sb_rbmblocks,
- map, &nmap, &flist);
+ 0, &first, mp->m_sb.sb_rbmblocks, map, &nmap);
if (error) {
do_error(
_("couldn't allocate realtime bitmap, error = %d\n"),
bno += ep->br_blockcount;
}
}
- error = libxfs_bmap_finish(&tp, &flist, &committed);
+ libxfs_defer_ijoin(&dfops, ip);
+ error = -libxfs_defer_finish(&tp, &dfops);
if (error) {
do_error(
_("allocation of the realtime bitmap failed, error = %d\n"),
error);
}
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
+ IRELE(ip);
}
static int
xfs_fsblock_t first;
int nmap;
int error;
- xfs_dfiloff_t bno;
+ xfs_fileoff_t bno;
xfs_bmbt_irec_t map;
- struct xfs_trans_res tres = {0};
bmp = btmcompute;
bno = 0;
- tp = libxfs_trans_alloc(mp, 0);
-
- error = libxfs_trans_reserve(tp, &tres, 10, 0);
+ error = -libxfs_trans_alloc_rollable(mp, 10, &tp);
if (error)
res_failed(error);
- error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, 0, &ip);
+ error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, 0, &ip);
if (error) {
do_error(
_("couldn't iget realtime bitmap inode -- error - %d\n"),
* fill the file one block at a time
*/
nmap = 1;
- error = libxfs_bmapi_write(tp, ip, bno, 1, 0,
- &first, 1, &map, &nmap, NULL);
+ error = -libxfs_bmapi_write(tp, ip, bno, 1, 0,
+ &first, 1, &map, &nmap);
if (error || nmap != 1) {
do_error(
_("couldn't map realtime bitmap block %" PRIu64 ", error = %d\n"),
ASSERT(map.br_startblock != HOLESTARTBLOCK);
- error = libxfs_trans_read_buf(
+ error = -libxfs_trans_read_buf(
mp, tp, mp->m_dev,
XFS_FSB_TO_DADDR(mp, map.br_startblock),
XFS_FSB_TO_BB(mp, 1), 1, &bp, NULL);
return(1);
}
- memmove(XFS_BUF_PTR(bp), bmp, mp->m_sb.sb_blocksize);
+ memmove(bp->b_addr, bmp, mp->m_sb.sb_blocksize);
libxfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
- bmp = (xfs_rtword_t *)((__psint_t) bmp + mp->m_sb.sb_blocksize);
+ bmp = (xfs_rtword_t *)((intptr_t) bmp + mp->m_sb.sb_blocksize);
bno++;
}
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
+ IRELE(ip);
return(0);
}
xfs_fsblock_t first;
int nmap;
int error;
- xfs_dfiloff_t bno;
- xfs_dfiloff_t end_bno;
+ xfs_fileoff_t bno;
+ xfs_fileoff_t end_bno;
xfs_bmbt_irec_t map;
- struct xfs_trans_res tres = {0};
smp = sumcompute;
bno = 0;
end_bno = mp->m_rsumsize >> mp->m_sb.sb_blocklog;
- tp = libxfs_trans_alloc(mp, 0);
-
- error = libxfs_trans_reserve(tp, &tres, 10, 0);
+ error = -libxfs_trans_alloc_rollable(mp, 10, &tp);
if (error)
res_failed(error);
- error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, 0, &ip);
+ error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, 0, &ip);
if (error) {
do_error(
_("couldn't iget realtime summary inode -- error - %d\n"),
* fill the file one block at a time
*/
nmap = 1;
- error = libxfs_bmapi_write(tp, ip, bno, 1, 0,
- &first, 1, &map, &nmap, NULL);
+ error = -libxfs_bmapi_write(tp, ip, bno, 1, 0,
+ &first, 1, &map, &nmap);
if (error || nmap != 1) {
do_error(
_("couldn't map realtime summary inode block %" PRIu64 ", error = %d\n"),
ASSERT(map.br_startblock != HOLESTARTBLOCK);
- error = libxfs_trans_read_buf(
+ error = -libxfs_trans_read_buf(
mp, tp, mp->m_dev,
XFS_FSB_TO_DADDR(mp, map.br_startblock),
XFS_FSB_TO_BB(mp, 1), 1, &bp, NULL);
do_warn(
_("can't access block %" PRIu64 " (fsbno %" PRIu64 ") of realtime summary inode %" PRIu64 "\n"),
bno, map.br_startblock, mp->m_sb.sb_rsumino);
+ IRELE(ip);
return(1);
}
- memmove(XFS_BUF_PTR(bp), smp, mp->m_sb.sb_blocksize);
+ memmove(bp->b_addr, smp, mp->m_sb.sb_blocksize);
libxfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
- smp = (xfs_suminfo_t *)((__psint_t)smp + mp->m_sb.sb_blocksize);
+ smp = (xfs_suminfo_t *)((intptr_t)smp + mp->m_sb.sb_blocksize);
bno++;
}
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
+ IRELE(ip);
return(0);
}
xfs_fsblock_t first;
int i;
int nmap;
- int committed;
int error;
int nsumblocks;
- xfs_bmap_free_t flist;
- xfs_dfiloff_t bno;
+ struct xfs_defer_ops dfops;
+ xfs_fileoff_t bno;
xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP];
int vers;
int times;
- struct xfs_trans_res tres = {0};
+ uint blocks;
/*
* first set up inode
*/
- tp = libxfs_trans_alloc(mp, 0);
-
- i = libxfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 10, 0);
+ i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 10, 0, 0, &tp);
if (i)
res_failed(i);
- error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, 0, &ip);
+ error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, 0, &ip);
if (error) {
do_error(
_("couldn't iget realtime summary inode -- error - %d\n"),
error);
}
- vers = xfs_sb_version_hascrc(&mp->m_sb) ? 3 : 1;
- memset(&ip->i_d, 0, xfs_icdinode_size(vers));
+ vers = xfs_sb_version_hascrc(&mp->m_sb) ? 3 : 2;
+ memset(&ip->i_d, 0, sizeof(ip->i_d));
- ip->i_d.di_magic = XFS_DINODE_MAGIC;
- ip->i_d.di_mode = S_IFREG;
+ VFS_I(ip)->i_mode = S_IFREG;
ip->i_d.di_version = vers;
ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
- ip->i_d.di_nlink = 1; /* account for sb ptr */
+ set_nlink(VFS_I(ip), 1); /* account for sb ptr */
times = XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD;
if (ip->i_d.di_version == 3) {
- ip->i_d.di_crc = 0;
- ip->i_d.di_changecount = 1;
- ip->i_d.di_lsn = 0;
+ VFS_I(ip)->i_version = 1;
ip->i_d.di_flags2 = 0;
- ip->i_d.di_ino = mp->m_sb.sb_rsumino;
- memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
- platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
times |= XFS_ICHGTIME_CREATE;
}
libxfs_trans_ichgtime(tp, ip, times);
*/
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_u1.if_root = NULL;
ip->i_d.di_size = mp->m_rsumsize;
* commit changes
*/
libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- libxfs_trans_ihold(tp, ip);
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
/*
* then allocate blocks for file and fill with zeroes (stolen
* from mkfs)
*/
- tp = libxfs_trans_alloc(mp, 0);
- xfs_bmap_init(&flist, &first);
-
nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog;
- tres.tr_logres = BBTOB(128);
- tres.tr_logcount = XFS_DEFAULT_PERM_LOG_COUNT;
- tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
- error = libxfs_trans_reserve(tp, &tres, mp->m_sb.sb_rbmblocks +
- (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1), 0);
+ blocks = nsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
+ error = -libxfs_trans_alloc_rollable(mp, blocks, &tp);
if (error)
res_failed(error);
libxfs_trans_ijoin(tp, ip, 0);
bno = 0;
- xfs_bmap_init(&flist, &first);
+ libxfs_defer_init(&dfops, &first);
+ tp->t_dfops = &dfops;
while (bno < nsumblocks) {
nmap = XFS_BMAP_MAX_NMAP;
- error = libxfs_bmapi_write(tp, ip, bno,
+ error = -libxfs_bmapi_write(tp, ip, bno,
(xfs_extlen_t)(nsumblocks - bno),
- 0, &first, nsumblocks, map, &nmap, &flist);
+ 0, &first, nsumblocks, map, &nmap);
if (error) {
do_error(
_("couldn't allocate realtime summary inode, error = %d\n"),
bno += ep->br_blockcount;
}
}
- error = libxfs_bmap_finish(&tp, &flist, &committed);
+ libxfs_defer_ijoin(&dfops, ip);
+ error = -libxfs_defer_finish(&tp, &dfops);
if (error) {
do_error(
_("allocation of the realtime summary ino failed, error = %d\n"),
error);
}
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
+ IRELE(ip);
}
/*
int vers;
int times;
- ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb));
-
- tp = libxfs_trans_alloc(mp, 0);
ip = NULL;
-
- i = libxfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 10, 0);
+ i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 10, 0, 0, &tp);
if (i)
res_failed(i);
- error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rootino, 0, 0, &ip);
+ error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rootino, 0, 0, &ip);
if (error) {
do_error(_("could not iget root inode -- error - %d\n"), error);
}
/*
* take care of the core -- initialization from xfs_ialloc()
*/
- vers = xfs_sb_version_hascrc(&mp->m_sb) ? 3 : 1;
- memset(&ip->i_d, 0, xfs_icdinode_size(vers));
+ vers = xfs_sb_version_hascrc(&mp->m_sb) ? 3 : 2;
+ memset(&ip->i_d, 0, sizeof(ip->i_d));
- ip->i_d.di_magic = XFS_DINODE_MAGIC;
- ip->i_d.di_mode = (__uint16_t) mode|S_IFDIR;
+ VFS_I(ip)->i_mode = mode|S_IFDIR;
ip->i_d.di_version = vers;
ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
- ip->i_d.di_nlink = 1; /* account for . */
+ set_nlink(VFS_I(ip), 1); /* account for . */
times = XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD;
if (ip->i_d.di_version == 3) {
- ip->i_d.di_crc = 0;
- ip->i_d.di_changecount = 1;
- ip->i_d.di_lsn = 0;
+ VFS_I(ip)->i_version = 1;
ip->i_d.di_flags2 = 0;
- ip->i_d.di_ino = mp->m_sb.sb_rootino;
- memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2));
- platform_uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
times |= XFS_ICHGTIME_CREATE;
}
libxfs_trans_ichgtime(tp, ip, times);
*/
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_u1.if_root = NULL;
+
+
/*
* initialize the directory
*/
+ ip->d_ops = mp->m_dir_inode_ops;
libxfs_dir_init(tp, ip, ip);
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
+ IRELE(ip);
irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino),
XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino));
ino_tree_node_t *irec;
int ino_offset = 0;
int i;
- int committed;
int error;
- xfs_bmap_free_t flist;
+ struct xfs_defer_ops dfops;
const int mode = 0755;
int nres;
struct xfs_name xname;
- ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb));
-
/*
* check for an existing lost+found first, if it exists, return
* its inode. Otherwise, we can create it. Bad lost+found inodes
* would have been cleared in phase3 and phase4.
*/
- if ((i = libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, 0)))
+ i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip,
+ &xfs_default_ifork_ops);
+ if (i)
do_error(_("%d - couldn't iget root inode to obtain %s\n"),
i, ORPHANAGE);
/*
* could not be found, create it
*/
-
- tp = libxfs_trans_alloc(mp, 0);
- xfs_bmap_init(&flist, &first);
-
+ libxfs_defer_init(&dfops, &first);
nres = XFS_MKDIR_SPACE_RES(mp, xname.len);
- i = libxfs_trans_reserve(tp, &M_RES(mp)->tr_mkdir, nres, 0);
+ i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir, nres, 0, 0, &tp);
if (i)
res_failed(i);
* use iget/ijoin instead of trans_iget because the ialloc
* wrapper can commit the transaction and start a new one
*/
-/* if ((i = libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, 0)))
+/* i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip,
+ &xfs_default_ifork_ops);
+ if (i)
do_error(_("%d - couldn't iget root inode to make %s\n"),
i, ORPHANAGE);*/
- error = libxfs_inode_alloc(&tp, pip, mode|S_IFDIR,
+ error = -libxfs_inode_alloc(&tp, pip, mode|S_IFDIR,
1, 0, &zerocr, &zerofsx, &ip);
if (error) {
do_error(_("%s inode allocation failed %d\n"),
ORPHANAGE, error);
}
- ip->i_d.di_nlink++; /* account for . */
+ inc_nlink(VFS_I(ip)); /* account for . */
ino = ip->i_ino;
irec = find_inode_rec(mp,
/*
* create the actual entry
*/
- error = libxfs_dir_createname(tp, pip, &xname, ip->i_ino, &first,
- &flist, nres);
- if (error)
+ error = -libxfs_dir_createname(tp, pip, &xname, ip->i_ino, &first,
+ nres);
+ if (error)
do_error(
_("can't make %s, createname error %d\n"),
ORPHANAGE, error);
* bump up the link count in the root directory to account
* for .. in the new directory
*/
- pip->i_d.di_nlink++;
+ inc_nlink(VFS_I(pip));
add_inode_ref(find_inode_rec(mp,
XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino),
XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)), 0);
libxfs_dir_init(tp, ip, pip);
libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- error = libxfs_bmap_finish(&tp, &flist, &committed);
+ libxfs_defer_ijoin(&dfops, ip);
+ error = -libxfs_defer_finish(&tp, &dfops);
if (error) {
do_error(_("%s directory creation failed -- bmapf error %d\n"),
ORPHANAGE, error);
}
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
+ IRELE(ip);
+ IRELE(pip);
add_inode_reached(irec,ino_offset);
return(ino);
xfs_inode_t *ino_p;
xfs_trans_t *tp;
xfs_fsblock_t first;
- xfs_bmap_free_t flist;
+ struct xfs_defer_ops dfops;
int err;
- int committed;
unsigned char fname[MAXPATHLEN + 1];
int nres;
int incr;
int ino_offset = 0;
struct xfs_name xname;
- ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb));
-
xname.name = fname;
xname.len = snprintf((char *)fname, sizeof(fname), "%llu",
(unsigned long long)ino);
- /* XXX use xfs_mode_to_ftype[] when userspace gains it */
- xname.type = XFS_DIR3_FT_UNKNOWN;
- err = libxfs_iget(mp, NULL, orphanage_ino, 0, &orphanage_ip, 0);
+ err = -libxfs_iget(mp, NULL, orphanage_ino, 0, &orphanage_ip,
+ &xfs_default_ifork_ops);
if (err)
do_error(_("%d - couldn't iget orphanage inode\n"), err);
/*
xname.len = snprintf((char *)fname, sizeof(fname), "%llu.%d",
(unsigned long long)ino, ++incr);
- tp = libxfs_trans_alloc(mp, 0);
-
- if ((err = libxfs_iget(mp, NULL, ino, 0, &ino_p, 0)))
+ /* Orphans may not have a proper parent, so use custom ops here */
+ err = -libxfs_iget(mp, NULL, ino, 0, &ino_p, &phase6_ifork_ops);
+ if (err)
do_error(_("%d - couldn't iget disconnected inode\n"), err);
+ xname.type = libxfs_mode_to_ftype(VFS_I(ino_p)->i_mode);
+
if (isa_dir) {
irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, orphanage_ino),
XFS_INO_TO_AGINO(mp, orphanage_ino));
irec->ino_startnum;
nres = XFS_DIRENTER_SPACE_RES(mp, fnamelen) +
XFS_DIRENTER_SPACE_RES(mp, 2);
- err = libxfs_dir_lookup(tp, ino_p, &xfs_name_dotdot,
+ err = -libxfs_dir_lookup(NULL, ino_p, &xfs_name_dotdot,
&entry_ino_num, NULL);
if (err) {
ASSERT(err == ENOENT);
- err = libxfs_trans_reserve(tp, &M_RES(mp)->tr_rename,
- nres, 0);
+ err = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_rename,
+ nres, 0, 0, &tp);
if (err)
do_error(
_("space reservation failed (%d), filesystem may be out of space\n"),
libxfs_trans_ijoin(tp, orphanage_ip, 0);
libxfs_trans_ijoin(tp, ino_p, 0);
- xfs_bmap_init(&flist, &first);
- err = libxfs_dir_createname(tp, orphanage_ip, &xname,
- ino, &first, &flist, nres);
+ libxfs_defer_init(&dfops, &first);
+ err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
+ ino, &first, nres);
if (err)
do_error(
_("name create failed in %s (%d), filesystem may be out of space\n"),
if (irec)
add_inode_ref(irec, ino_offset);
else
- orphanage_ip->i_d.di_nlink++;
+ inc_nlink(VFS_I(orphanage_ip));
libxfs_trans_log_inode(tp, orphanage_ip, XFS_ILOG_CORE);
- err = libxfs_dir_createname(tp, ino_p, &xfs_name_dotdot,
- orphanage_ino, &first, &flist, nres);
+ err = -libxfs_dir_createname(tp, ino_p, &xfs_name_dotdot,
+ orphanage_ino, &first, nres);
if (err)
do_error(
_("creation of .. entry failed (%d), filesystem may be out of space\n"),
err);
- ino_p->i_d.di_nlink++;
+ inc_nlink(VFS_I(ino_p));
libxfs_trans_log_inode(tp, ino_p, XFS_ILOG_CORE);
- err = libxfs_bmap_finish(&tp, &flist, &committed);
+ libxfs_defer_ijoin(&dfops, ino_p);
+ err = -libxfs_defer_finish(&tp, &dfops);
if (err)
do_error(
_("bmap finish failed (err - %d), filesystem may be out of space\n"),
err);
- libxfs_trans_commit(tp,
- XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
} else {
- err = libxfs_trans_reserve(tp, &M_RES(mp)->tr_rename,
- nres, 0);
+ err = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_rename,
+ nres, 0, 0, &tp);
if (err)
do_error(
_("space reservation failed (%d), filesystem may be out of space\n"),
libxfs_trans_ijoin(tp, orphanage_ip, 0);
libxfs_trans_ijoin(tp, ino_p, 0);
- xfs_bmap_init(&flist, &first);
+ libxfs_defer_init(&dfops, &first);
- err = libxfs_dir_createname(tp, orphanage_ip, &xname,
- ino, &first, &flist, nres);
+ err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
+ ino, &first, nres);
if (err)
do_error(
_("name create failed in %s (%d), filesystem may be out of space\n"),
if (irec)
add_inode_ref(irec, ino_offset);
else
- orphanage_ip->i_d.di_nlink++;
+ inc_nlink(VFS_I(orphanage_ip));
libxfs_trans_log_inode(tp, orphanage_ip, XFS_ILOG_CORE);
/*
* to us. that'll pop a libxfs/kernel ASSERT.
*/
if (entry_ino_num != orphanage_ino) {
- err = libxfs_dir_replace(tp, ino_p,
+ err = -libxfs_dir_replace(tp, ino_p,
&xfs_name_dotdot, orphanage_ino,
- &first, &flist, nres);
+ &first, nres);
if (err)
do_error(
_("name replace op failed (%d), filesystem may be out of space\n"),
err);
}
- err = libxfs_bmap_finish(&tp, &flist, &committed);
+ libxfs_defer_ijoin(&dfops, ino_p);
+ err = -libxfs_defer_finish(&tp, &dfops);
if (err)
do_error(
_("bmap finish failed (%d), filesystem may be out of space\n"),
err);
- libxfs_trans_commit(tp,
- XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
}
} else {
* also accounted for in the create
*/
nres = XFS_DIRENTER_SPACE_RES(mp, xname.len);
- err = libxfs_trans_reserve(tp, &M_RES(mp)->tr_remove,
- nres, 0);
+ err = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove,
+ nres, 0, 0, &tp);
if (err)
do_error(
_("space reservation failed (%d), filesystem may be out of space\n"),
libxfs_trans_ijoin(tp, orphanage_ip, 0);
libxfs_trans_ijoin(tp, ino_p, 0);
- xfs_bmap_init(&flist, &first);
- err = libxfs_dir_createname(tp, orphanage_ip, &xname, ino,
- &first, &flist, nres);
+ libxfs_defer_init(&dfops, &first);
+ err = -libxfs_dir_createname(tp, orphanage_ip, &xname, ino,
+ &first, nres);
if (err)
do_error(
_("name create failed in %s (%d), filesystem may be out of space\n"),
ORPHANAGE, err);
ASSERT(err == 0);
- ino_p->i_d.di_nlink = 1;
+ set_nlink(VFS_I(ino_p), 1);
libxfs_trans_log_inode(tp, ino_p, XFS_ILOG_CORE);
- err = libxfs_bmap_finish(&tp, &flist, &committed);
+ libxfs_defer_ijoin(&dfops, ino_p);
+ err = -libxfs_defer_finish(&tp, &dfops);
if (err)
do_error(
_("bmap finish failed (%d), filesystem may be out of space\n"),
err);
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
}
+ IRELE(ino_p);
+ IRELE(orphanage_ip);
}
static int
return !no_modify;
}
+/* Find and invalidate all the directory's buffers. */
+static int
+dir_binval(
+ struct xfs_trans *tp,
+ struct xfs_inode *ip,
+ int whichfork)
+{
+ struct xfs_iext_cursor icur;
+ struct xfs_bmbt_irec rec;
+ struct xfs_ifork *ifp;
+ struct xfs_da_geometry *geo;
+ struct xfs_buf *bp;
+ xfs_dablk_t dabno, end_dabno;
+ int error = 0;
+
+ if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
+ ip->i_d.di_format != XFS_DINODE_FMT_BTREE)
+ return 0;
+
+ geo = tp->t_mountp->m_dir_geo;
+ ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+ for_each_xfs_iext(ifp, &icur, &rec) {
+ dabno = xfs_dir2_db_to_da(geo, rec.br_startoff +
+ geo->fsbcount - 1);
+ end_dabno = xfs_dir2_db_to_da(geo, rec.br_startoff +
+ rec.br_blockcount);
+ for (; dabno <= end_dabno; dabno += geo->fsbcount) {
+ bp = NULL;
+ error = -libxfs_da_get_buf(tp, ip, dabno, -2, &bp,
+ whichfork);
+ if (error)
+ return error;
+ if (!bp)
+ continue;
+ libxfs_trans_binval(tp, bp);
+ libxfs_trans_brelse(tp, bp);
+ }
+ }
+
+ return error;
+}
+
/*
* Unexpected failure during the rebuild will leave the entries in
* lost+found on the next run
xfs_trans_t *tp;
xfs_fileoff_t lastblock;
xfs_fsblock_t firstblock;
- xfs_bmap_free_t flist;
+ struct xfs_defer_ops dfops;
xfs_inode_t pip;
dir_hash_ent_t *p;
- int committed;
int done;
/*
* for the libxfs_dir_init() call).
*/
pip.i_ino = get_inode_parent(irec, ino_offset);
- if (pip.i_ino == NULLFSINO)
+ if (pip.i_ino == NULLFSINO ||
+ libxfs_dir_ino_validate(mp, pip.i_ino))
pip.i_ino = mp->m_sb.sb_rootino;
- xfs_bmap_init(&flist, &firstblock);
+ libxfs_defer_init(&dfops, &firstblock);
- tp = libxfs_trans_alloc(mp, 0);
nres = XFS_REMOVE_SPACE_RES(mp);
- error = libxfs_trans_reserve(tp, &M_RES(mp)->tr_remove, nres, 0);
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp);
if (error)
res_failed(error);
libxfs_trans_ijoin(tp, ip, 0);
- libxfs_trans_ihold(tp, ip);
- if ((error = libxfs_bmap_last_offset(tp, ip, &lastblock,
- XFS_DATA_FORK)))
+ error = dir_binval(tp, ip, XFS_DATA_FORK);
+ if (error)
+ res_failed(error);
+
+ if ((error = -libxfs_bmap_last_offset(ip, &lastblock, XFS_DATA_FORK)))
do_error(_("xfs_bmap_last_offset failed -- error - %d\n"),
error);
/* free all data, leaf, node and freespace blocks */
- error = libxfs_bunmapi(tp, ip, 0, lastblock, XFS_BMAPI_METADATA, 0,
- &firstblock, &flist, &done);
+ error = -libxfs_bunmapi(tp, ip, 0, lastblock, XFS_BMAPI_METADATA, 0,
+ &firstblock, &dfops, &done);
if (error) {
do_warn(_("xfs_bunmapi failed -- error - %d\n"), error);
goto out_bmap_cancel;
ASSERT(done);
- libxfs_dir_init(tp, ip, &pip);
+ error = -libxfs_dir_init(tp, ip, &pip);
+ if (error) {
+ do_warn(_("xfs_dir_init failed -- error - %d\n"), error);
+ goto out_bmap_cancel;
+ }
+
+ libxfs_defer_ijoin(&dfops, ip);
+ error = -libxfs_defer_finish(&tp, &dfops);
- error = libxfs_bmap_finish(&tp, &flist, &committed);
+ libxfs_trans_commit(tp);
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ if (ino == mp->m_sb.sb_rootino)
+ need_root_dotdot = 0;
/* go through the hash list and re-add the inodes */
p->name.name[1] == '.'))))
continue;
- tp = libxfs_trans_alloc(mp, 0);
nres = XFS_CREATE_SPACE_RES(mp, p->name.len);
- error = libxfs_trans_reserve(tp, &M_RES(mp)->tr_create,
- nres, 0);
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_create,
+ nres, 0, 0, &tp);
if (error)
res_failed(error);
libxfs_trans_ijoin(tp, ip, 0);
- libxfs_trans_ihold(tp, ip);
- xfs_bmap_init(&flist, &firstblock);
- error = libxfs_dir_createname(tp, ip, &p->name, p->inum,
- &firstblock, &flist, nres);
+ libxfs_defer_init(&dfops, &firstblock);
+ error = -libxfs_dir_createname(tp, ip, &p->name, p->inum,
+ &firstblock, nres);
if (error) {
do_warn(
_("name create failed in ino %" PRIu64 " (%d), filesystem may be out of space\n"),
goto out_bmap_cancel;
}
- error = libxfs_bmap_finish(&tp, &flist, &committed);
+ libxfs_defer_ijoin(&dfops, ip);
+ error = -libxfs_defer_finish(&tp, &dfops);
if (error) {
do_warn(
_("bmap finish failed (%d), filesystem may be out of space\n"),
goto out_bmap_cancel;
}
- libxfs_trans_commit(tp,
- XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
}
return;
out_bmap_cancel:
- libxfs_bmap_cancel(&flist);
- libxfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
+ libxfs_defer_cancel(&dfops);
+ libxfs_trans_cancel(tp);
return;
}
struct xfs_buf *bp)
{
xfs_da_args_t args;
- int committed;
int error;
xfs_fsblock_t firstblock;
- xfs_bmap_free_t flist;
+ struct xfs_defer_ops dfops;
int nres;
xfs_trans_t *tp;
- tp = libxfs_trans_alloc(mp, 0);
nres = XFS_REMOVE_SPACE_RES(mp);
- error = libxfs_trans_reserve(tp, &M_RES(mp)->tr_remove, nres, 0);
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp);
if (error)
res_failed(error);
libxfs_trans_ijoin(tp, ip, 0);
- libxfs_trans_ihold(tp, ip);
libxfs_trans_bjoin(tp, bp);
memset(&args, 0, sizeof(args));
- xfs_bmap_init(&flist, &firstblock);
+ libxfs_defer_init(&dfops, &firstblock);
args.dp = ip;
args.trans = tp;
args.firstblock = &firstblock;
- args.flist = &flist;
args.whichfork = XFS_DATA_FORK;
- if (da_bno >= mp->m_dirleafblk && da_bno < mp->m_dirfreeblk)
- error = libxfs_da_shrink_inode(&args, da_bno, bp);
+ args.geo = mp->m_dir_geo;
+ if (da_bno >= mp->m_dir_geo->leafblk && da_bno < mp->m_dir_geo->freeblk)
+ error = -libxfs_da_shrink_inode(&args, da_bno, bp);
else
- error = libxfs_dir2_shrink_inode(&args,
- xfs_dir2_da_to_db(mp, da_bno), bp);
+ error = -libxfs_dir2_shrink_inode(&args,
+ xfs_dir2_da_to_db(mp->m_dir_geo, da_bno), bp);
if (error)
do_error(_("shrink_inode failed inode %" PRIu64 " block %u\n"),
ip->i_ino, da_bno);
- libxfs_bmap_finish(&tp, &flist, &committed);
- libxfs_trans_commit(tp, 0);
+ libxfs_defer_ijoin(&dfops, ip);
+ libxfs_defer_finish(&tp, &dfops);
+ libxfs_trans_commit(tp);
}
/*
xfs_dir2_leaf_entry_t *blp;
struct xfs_buf *bp;
xfs_dir2_block_tail_t *btp;
- int committed;
struct xfs_dir2_data_hdr *d;
xfs_dir2_db_t db;
xfs_dir2_data_entry_t *dep;
char *endptr;
int error;
xfs_fsblock_t firstblock;
- xfs_bmap_free_t flist;
+ struct xfs_defer_ops dfops;
char fname[MAXNAMELEN + 1];
freetab_t *freetab;
int i;
char *ptr;
xfs_trans_t *tp;
int wantmagic;
+ struct xfs_da_args da = {
+ .dp = ip,
+ .geo = mp->m_dir_geo,
+ };
+
bp = *bpp;
d = bp->b_addr;
- ptr = (char *)xfs_dir3_data_entry_p(d);
+ ptr = (char *)M_DIROPS(mp)->data_entry_p(d);
nbad = 0;
needscan = needlog = 0;
junkit = 0;
freetab = *freetabp;
if (isblock) {
- btp = xfs_dir2_block_tail_p(mp, (struct xfs_dir2_data_hdr *)d);
+ btp = xfs_dir2_block_tail_p(mp->m_dir_geo, d);
blp = xfs_dir2_block_leaf_p(btp);
endptr = (char *)blp;
if (endptr > (char *)btp)
else
wantmagic = XFS_DIR2_BLOCK_MAGIC;
} else {
- endptr = (char *)d + mp->m_dirblksize;
+ endptr = (char *)d + mp->m_dir_geo->blksize;
if (xfs_sb_version_hascrc(&mp->m_sb))
wantmagic = XFS_DIR3_DATA_MAGIC;
else
wantmagic = XFS_DIR2_DATA_MAGIC;
}
- db = xfs_dir2_da_to_db(mp, da_bno);
+ db = xfs_dir2_da_to_db(mp->m_dir_geo, da_bno);
/* check for data block beyond expected end */
if (freetab->naents <= db) {
*freetabp = freetab = realloc(freetab, FREETAB_SIZE(db + 1));
if (!freetab) {
- do_error(
- _("realloc failed in longform_dir2_entry_check_data (%zu bytes)\n"),
- FREETAB_SIZE(db + 1));
+ do_error(_("realloc failed in %s (%zu bytes)\n"),
+ __func__, FREETAB_SIZE(db + 1));
}
e.v = NULLDATAOFF;
e.s = 0;
break;
/* check for block with no data entries */
- if ((ptr == (char *)xfs_dir3_data_entry_p(d)) &&
+ if ((ptr == (char *)M_DIROPS(mp)->data_entry_p(d)) &&
(ptr + be16_to_cpu(dup->length) >= endptr)) {
junkit = 1;
*num_illegal += 1;
/* validate data entry size */
dep = (xfs_dir2_data_entry_t *)ptr;
- if (ptr + xfs_dir3_data_entsize(mp, dep->namelen) > endptr)
+ if (ptr + M_DIROPS(mp)->data_entsize(dep->namelen) > endptr)
break;
- if (be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)) !=
+ if (be16_to_cpu(*M_DIROPS(mp)->data_entry_tag_p(dep)) !=
(char *)dep - (char *)d)
break;
- ptr += xfs_dir3_data_entsize(mp, dep->namelen);
+ ptr += M_DIROPS(mp)->data_entsize(dep->namelen);
}
/* did we find an empty or corrupt block? */
if (freetab->nents < db + 1)
freetab->nents = db + 1;
- tp = libxfs_trans_alloc(mp, 0);
- error = libxfs_trans_reserve(tp, &M_RES(mp)->tr_remove, 0, 0);
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, 0, 0, 0, &tp);
if (error)
res_failed(error);
+ da.trans = tp;
libxfs_trans_ijoin(tp, ip, 0);
- libxfs_trans_ihold(tp, ip);
libxfs_trans_bjoin(tp, bp);
libxfs_trans_bhold(tp, bp);
- xfs_bmap_init(&flist, &firstblock);
+ libxfs_defer_init(&dfops, &firstblock);
if (be32_to_cpu(d->magic) != wantmagic) {
do_warn(
_("bad directory block magic # %#x for directory inode %" PRIu64 " block %d: "),
do_warn(_("would fix magic # to %#x\n"), wantmagic);
}
lastfree = 0;
- ptr = (char *)xfs_dir3_data_entry_p(d);
+ ptr = (char *)M_DIROPS(mp)->data_entry_p(d);
/*
* look at each entry. reference inode pointed to by each
* entry in the incore inode tree.
_("directory inode %" PRIu64 " block %u has consecutive free entries: "),
ip->i_ino, da_bno);
if (!no_modify) {
+
do_warn(_("joining together\n"));
len = be16_to_cpu(dup->length);
- libxfs_dir2_data_use_free(tp, bp, dup,
+ libxfs_dir2_data_use_free(&da, bp, dup,
ptr - (char *)d, len, &needlog,
&needscan);
- libxfs_dir2_data_make_free(tp, bp,
+ libxfs_dir2_data_make_free(&da, bp,
ptr - (char *)d, len, &needlog,
&needscan);
} else
lastfree = 1;
continue;
}
- addr = xfs_dir2_db_off_to_dataptr(mp, db, ptr - (char *)d);
+ addr = xfs_dir2_db_off_to_dataptr(mp->m_dir_geo, db,
+ ptr - (char *)d);
dep = (xfs_dir2_data_entry_t *)ptr;
- ptr += xfs_dir3_data_entsize(mp, dep->namelen);
+ ptr += M_DIROPS(mp)->data_entsize(dep->namelen);
inum = be64_to_cpu(dep->inumber);
lastfree = 0;
/*
if (dep->name[0] == '/') {
nbad++;
if (!no_modify)
- libxfs_dir2_data_log_entry(tp, bp, dep);
+ libxfs_dir2_data_log_entry(&da, bp, dep);
continue;
}
_("entry \"%s\" in directory inode %" PRIu64 " points to non-existent inode %" PRIu64 ""),
fname, ip->i_ino, inum)) {
dep->name[0] = '/';
- libxfs_dir2_data_log_entry(tp, bp, dep);
+ libxfs_dir2_data_log_entry(&da, bp, dep);
}
continue;
}
_("entry \"%s\" in directory inode %" PRIu64 " points to free inode %" PRIu64),
fname, ip->i_ino, inum)) {
dep->name[0] = '/';
- libxfs_dir2_data_log_entry(tp, bp, dep);
+ libxfs_dir2_data_log_entry(&da, bp, dep);
}
continue;
}
_("%s (ino %" PRIu64 ") in root (%" PRIu64 ") is not a directory"),
ORPHANAGE, inum, ip->i_ino)) {
dep->name[0] = '/';
- libxfs_dir2_data_log_entry(tp, bp, dep);
+ libxfs_dir2_data_log_entry(&da, bp, dep);
}
continue;
}
if (!orphanage_ino)
orphanage_ino = inum;
}
+
/*
* check for duplicate names in directory.
*/
if (!dir_hash_add(mp, hashtab, addr, inum, dep->namelen,
- dep->name)) {
+ dep->name, M_DIROPS(mp)->data_get_ftype(dep))) {
nbad++;
if (entry_junked(
_("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"),
fname, inum, ip->i_ino)) {
dep->name[0] = '/';
- libxfs_dir2_data_log_entry(tp, bp, dep);
+ libxfs_dir2_data_log_entry(&da, bp, dep);
}
if (inum == orphanage_ino)
orphanage_ino = 0;
_("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is not in the the first block"), fname,
inum, ip->i_ino)) {
dep->name[0] = '/';
- libxfs_dir2_data_log_entry(tp, bp, dep);
+ libxfs_dir2_data_log_entry(&da, bp, dep);
}
}
continue;
* of when directory is moved to orphanage.
*/
if (ip->i_ino == inum) {
- ASSERT(dep->name[0] == '.' && dep->namelen == 1);
+ ASSERT(no_modify ||
+ (dep->name[0] == '.' && dep->namelen == 1));
add_inode_ref(current_irec, current_ino_offset);
if (da_bno != 0 ||
- dep != xfs_dir3_data_entry_p(d)) {
+ dep != M_DIROPS(mp)->data_entry_p(d)) {
/* "." should be the first entry */
nbad++;
if (entry_junked(
_("entry \"%s\" in dir %" PRIu64 " is not the first entry"),
fname, inum, ip->i_ino)) {
dep->name[0] = '/';
- libxfs_dir2_data_log_entry(tp, bp, dep);
+ libxfs_dir2_data_log_entry(&da, bp, dep);
}
}
*need_dot = 0;
*/
if (no_modify && verify_inum(mp, inum))
continue;
+
+ /* validate ftype field if supported */
+ if (xfs_sb_version_hasftype(&mp->m_sb)) {
+ uint8_t dir_ftype;
+ uint8_t ino_ftype;
+
+ dir_ftype = M_DIROPS(mp)->data_get_ftype(dep);
+ ino_ftype = get_inode_ftype(irec, ino_offset);
+
+ if (dir_ftype != ino_ftype) {
+ if (no_modify) {
+ do_warn(
+ _("would fix ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
+ dir_ftype, ino_ftype,
+ ip->i_ino, inum);
+ } else {
+ do_warn(
+ _("fixing ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
+ dir_ftype, ino_ftype,
+ ip->i_ino, inum);
+ M_DIROPS(mp)->data_put_ftype(dep,
+ ino_ftype);
+ libxfs_dir2_data_log_entry(&da, bp, dep);
+ dir_hash_update_ftype(hashtab, addr,
+ ino_ftype);
+ }
+ }
+ }
+
/*
* check easy case first, regular inode, just bump
* the link count and continue
if (junkit) {
if (inum == orphanage_ino)
orphanage_ino = 0;
- junkit = 0;
nbad++;
if (!no_modify) {
dep->name[0] = '/';
- libxfs_dir2_data_log_entry(tp, bp, dep);
+ libxfs_dir2_data_log_entry(&da, bp, dep);
if (verbose)
do_warn(
_("\twill clear entry \"%s\"\n"),
}
*num_illegal += nbad;
if (needscan)
- libxfs_dir2_data_freescan(mp, d, &needlog);
+ libxfs_dir2_data_freescan_int(mp->m_dir_geo, M_DIROPS(mp),
+ d, &i);
if (needlog)
- libxfs_dir2_data_log_header(tp, bp);
- libxfs_bmap_finish(&tp, &flist, &committed);
- libxfs_trans_commit(tp, 0);
+ libxfs_dir2_data_log_header(&da, bp);
+ libxfs_defer_ijoin(&dfops, ip);
+ libxfs_defer_finish(&tp, &dfops);
+ libxfs_trans_commit(tp);
/* record the largest free space in the freetab for later checking */
- bf = xfs_dir3_data_bestfree_p(d);
+ bf = M_DIROPS(mp)->data_bestfree_p(d);
freetab->ents[db].v = be16_to_cpu(bf[0].length);
freetab->ents[db].s = 0;
}
+/* check v5 metadata */
+static int
+__check_dir3_header(
+ struct xfs_mount *mp,
+ struct xfs_buf *bp,
+ xfs_ino_t ino,
+ __be64 owner,
+ __be64 blkno,
+ uuid_t *uuid)
+{
+
+ /* verify owner */
+ if (be64_to_cpu(owner) != ino) {
+ do_warn(
+_("expected owner inode %" PRIu64 ", got %llu, directory block %" PRIu64 "\n"),
+ ino, (unsigned long long)be64_to_cpu(owner), bp->b_bn);
+ return 1;
+ }
+ /* verify block number */
+ if (be64_to_cpu(blkno) != bp->b_bn) {
+ do_warn(
+_("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 "\n"),
+ bp->b_bn, (unsigned long long)be64_to_cpu(blkno), ino);
+ return 1;
+ }
+ /* verify uuid */
+ if (platform_uuid_compare(uuid, &mp->m_sb.sb_meta_uuid) != 0) {
+ do_warn(
+_("wrong FS UUID, directory inode %" PRIu64 " block %" PRIu64 "\n"),
+ ino, bp->b_bn);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+check_da3_header(
+ struct xfs_mount *mp,
+ struct xfs_buf *bp,
+ xfs_ino_t ino)
+{
+ struct xfs_da3_blkinfo *info = bp->b_addr;
+
+ return __check_dir3_header(mp, bp, ino, info->owner, info->blkno,
+ &info->uuid);
+}
+
+static int
+check_dir3_header(
+ struct xfs_mount *mp,
+ struct xfs_buf *bp,
+ xfs_ino_t ino)
+{
+ struct xfs_dir3_blk_hdr *info = bp->b_addr;
+
+ return __check_dir3_header(mp, bp, ino, info->owner, info->blkno,
+ &info->uuid);
+}
+
/*
* Check contents of leaf-form block.
*/
int seeval;
struct xfs_dir2_leaf_entry *ents;
struct xfs_dir3_icleaf_hdr leafhdr;
+ int error;
+ int fixit = 0;
- da_bno = mp->m_dirleafblk;
- if (libxfs_da_read_buf(NULL, ip, da_bno, -1, &bp, XFS_DATA_FORK,
- &xfs_dir3_leaf1_buf_ops)) {
- do_error(
- _("can't read block %u for directory inode %" PRIu64 "\n"),
+ da_bno = mp->m_dir_geo->leafblk;
+ error = dir_read_buf(ip, da_bno, -1, &bp, &xfs_dir3_leaf1_buf_ops,
+ &fixit);
+ if (error == EFSBADCRC || error == EFSCORRUPTED || fixit) {
+ do_warn(
+ _("leaf block %u for directory inode %" PRIu64 " bad CRC\n"),
da_bno, ip->i_ino);
+ return 1;
+ } else if (error) {
+ do_error(
+ _("can't read block %u for directory inode %" PRIu64 ", error %d\n"),
+ da_bno, ip->i_ino, error);
/* NOTREACHED */
}
+
leaf = bp->b_addr;
- xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
- ents = xfs_dir3_leaf_ents_p(leaf);
- ltp = xfs_dir2_leaf_tail_p(mp, leaf);
+ M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf);
+ ents = M_DIROPS(mp)->leaf_ents_p(leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf);
bestsp = xfs_dir2_leaf_bests_p(ltp);
if (!(leafhdr.magic == XFS_DIR2_LEAF1_MAGIC ||
leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) ||
leafhdr.forw || leafhdr.back ||
leafhdr.count < leafhdr.stale ||
leafhdr.count >
- xfs_dir3_max_leaf_ents(mp, leaf) ||
+ M_DIROPS(mp)->leaf_max_ents(mp->m_dir_geo) ||
(char *)&ents[leafhdr.count] > (char *)bestsp) {
do_warn(
_("leaf block %u for directory inode %" PRIu64 " bad header\n"),
libxfs_putbuf(bp);
return 1;
}
+
+ if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) {
+ error = check_da3_header(mp, bp, ip->i_ino);
+ if (error) {
+ libxfs_putbuf(bp);
+ return error;
+ }
+ }
+
seeval = dir_hash_see_all(hashtab, ents, leafhdr.count, leafhdr.stale);
if (dir_hash_check(hashtab, ip, seeval)) {
libxfs_putbuf(bp);
return 1;
}
libxfs_putbuf(bp);
- return 0;
+ return fixit;
}
/*
struct xfs_dir3_icleaf_hdr leafhdr;
struct xfs_dir3_icfree_hdr freehdr;
__be16 *bests;
+ int error;
+ int fixit = 0;
- for (da_bno = mp->m_dirleafblk, next_da_bno = 0;
- next_da_bno != NULLFILEOFF && da_bno < mp->m_dirfreeblk;
+ for (da_bno = mp->m_dir_geo->leafblk, next_da_bno = 0;
+ next_da_bno != NULLFILEOFF && da_bno < mp->m_dir_geo->freeblk;
da_bno = (xfs_dablk_t)next_da_bno) {
- next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
+ next_da_bno = da_bno + mp->m_dir_geo->fsbcount - 1;
if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
break;
* a node block, then we'll skip it below based on a magic
* number check.
*/
- if (libxfs_da_read_buf(NULL, ip, da_bno, -1, &bp,
- XFS_DATA_FORK, &xfs_da3_node_buf_ops)) {
+ error = dir_read_buf(ip, da_bno, -1, &bp,
+ &xfs_da3_node_buf_ops, &fixit);
+ if (error) {
do_warn(
- _("can't read leaf block %u for directory inode %" PRIu64 "\n"),
- da_bno, ip->i_ino);
+ _("can't read leaf block %u for directory inode %" PRIu64 ", error %d\n"),
+ da_bno, ip->i_ino, error);
return 1;
}
leaf = bp->b_addr;
- xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
- ents = xfs_dir3_leaf_ents_p(leaf);
+ M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf);
+ ents = M_DIROPS(mp)->leaf_ents_p(leaf);
if (!(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
- leafhdr.magic == XFS_DIR3_LEAFN_MAGIC)) {
- if (leafhdr.magic == XFS_DA_NODE_MAGIC ||
- leafhdr.magic == XFS_DA3_NODE_MAGIC) {
- libxfs_putbuf(bp);
- continue;
- }
+ leafhdr.magic == XFS_DIR3_LEAFN_MAGIC ||
+ leafhdr.magic == XFS_DA_NODE_MAGIC ||
+ leafhdr.magic == XFS_DA3_NODE_MAGIC)) {
do_warn(
_("unknown magic number %#x for block %u in directory inode %" PRIu64 "\n"),
leafhdr.magic, da_bno, ip->i_ino);
libxfs_putbuf(bp);
return 1;
}
- if (leafhdr.count > xfs_dir3_max_leaf_ents(mp, leaf) ||
+
+ /* check v5 metadata */
+ if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC ||
+ leafhdr.magic == XFS_DA3_NODE_MAGIC) {
+ error = check_da3_header(mp, bp, ip->i_ino);
+ if (error) {
+ libxfs_putbuf(bp);
+ return error;
+ }
+ }
+
+ /* ignore nodes */
+ if (leafhdr.magic == XFS_DA_NODE_MAGIC ||
+ leafhdr.magic == XFS_DA3_NODE_MAGIC) {
+ libxfs_putbuf(bp);
+ continue;
+ }
+
+ /*
+ * If there's a validator error, we need to ensure that we got
+ * the right ops on the buffer for when we write it back out.
+ */
+ bp->b_ops = &xfs_dir3_leafn_buf_ops;
+ if (leafhdr.count > M_DIROPS(mp)->leaf_max_ents(mp->m_dir_geo) ||
leafhdr.count < leafhdr.stale) {
do_warn(
_("leaf block %u for directory inode %" PRIu64 " bad header\n"),
if (dir_hash_check(hashtab, ip, seeval))
return 1;
- for (da_bno = mp->m_dirfreeblk, next_da_bno = 0;
+ for (da_bno = mp->m_dir_geo->freeblk, next_da_bno = 0;
next_da_bno != NULLFILEOFF;
da_bno = (xfs_dablk_t)next_da_bno) {
- next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
+ next_da_bno = da_bno + mp->m_dir_geo->fsbcount - 1;
if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
break;
- if (libxfs_da_read_buf(NULL, ip, da_bno, -1, &bp,
- XFS_DATA_FORK, &xfs_dir3_free_buf_ops)) {
+
+ error = dir_read_buf(ip, da_bno, -1, &bp,
+ &xfs_dir3_free_buf_ops, &fixit);
+ if (error) {
do_warn(
- _("can't read freespace block %u for directory inode %" PRIu64 "\n"),
- da_bno, ip->i_ino);
+ _("can't read freespace block %u for directory inode %" PRIu64 ", error %d\n"),
+ da_bno, ip->i_ino, error);
return 1;
}
free = bp->b_addr;
- xfs_dir3_free_hdr_from_disk(&freehdr, free);
- bests = xfs_dir3_free_bests_p(mp, free);
- fdb = xfs_dir2_da_to_db(mp, da_bno);
+ M_DIROPS(mp)->free_hdr_from_disk(&freehdr, free);
+ bests = M_DIROPS(mp)->free_bests_p(free);
+ fdb = xfs_dir2_da_to_db(mp->m_dir_geo, da_bno);
if (!(freehdr.magic == XFS_DIR2_FREE_MAGIC ||
freehdr.magic == XFS_DIR3_FREE_MAGIC) ||
- freehdr.firstdb !=
- (fdb - XFS_DIR2_FREE_FIRSTDB(mp)) *
- xfs_dir3_free_max_bests(mp) ||
- freehdr.nvalid < freehdr.nused) {
+ freehdr.firstdb !=
+ (fdb - xfs_dir2_byte_to_db(mp->m_dir_geo, XFS_DIR2_FREE_OFFSET)) *
+ M_DIROPS(mp)->free_max_bests(mp->m_dir_geo) ||
+ freehdr.nvalid < freehdr.nused) {
do_warn(
_("free block %u for directory inode %" PRIu64 " bad header\n"),
da_bno, ip->i_ino);
libxfs_putbuf(bp);
return 1;
}
+
+ if (freehdr.magic == XFS_DIR3_FREE_MAGIC) {
+ error = check_dir3_header(mp, bp, ip->i_ino);
+ if (error) {
+ libxfs_putbuf(bp);
+ return error;
+ }
+ }
for (i = used = 0; i < freehdr.nvalid; i++) {
if (i + freehdr.firstdb >= freetab->nents ||
freetab->ents[i + freehdr.firstdb].v !=
return 1;
}
}
- return 0;
+ return fixit;
}
/*
int seeval;
int fixit = 0;
xfs_dir2_db_t db;
+ struct xfs_da_args args;
*need_dot = 1;
- freetab = malloc(FREETAB_SIZE(ip->i_d.di_size / mp->m_dirblksize));
+ freetab = malloc(FREETAB_SIZE(ip->i_d.di_size / mp->m_dir_geo->blksize));
if (!freetab) {
- do_error(
- _("malloc failed in longform_dir2_entry_check (%" PRId64 " bytes)\n"),
- FREETAB_SIZE(ip->i_d.di_size / mp->m_dirblksize));
+ do_error(_("malloc failed in %s (%" PRId64 " bytes)\n"),
+ __func__,
+ FREETAB_SIZE(ip->i_d.di_size / mp->m_dir_geo->blksize));
exit(1);
}
- freetab->naents = ip->i_d.di_size / mp->m_dirblksize;
+ freetab->naents = ip->i_d.di_size / mp->m_dir_geo->blksize;
freetab->nents = 0;
for (i = 0; i < freetab->naents; i++) {
freetab->ents[i].v = NULLDATAOFF;
}
num_bps = freetab->naents;
bplist = calloc(num_bps, sizeof(struct xfs_buf*));
+ if (!bplist)
+ do_error(_("calloc failed in %s (%zu bytes)\n"),
+ __func__, num_bps * sizeof(struct xfs_buf*));
+
/* is this a block, leaf, or node directory? */
- libxfs_dir2_isblock(NULL, ip, &isblock);
- libxfs_dir2_isleaf(NULL, ip, &isleaf);
+ args.dp = ip;
+ args.geo = mp->m_dir_geo;
+ libxfs_dir2_isblock(&args, &isblock);
+ libxfs_dir2_isleaf(&args, &isleaf);
/* check directory "data" blocks (ie. name/inode pairs) */
for (da_bno = 0, next_da_bno = 0;
- next_da_bno != NULLFILEOFF && da_bno < mp->m_dirleafblk;
+ next_da_bno != NULLFILEOFF && da_bno < mp->m_dir_geo->leafblk;
da_bno = (xfs_dablk_t)next_da_bno) {
const struct xfs_buf_ops *ops;
+ int error;
+ struct xfs_dir2_data_hdr *d;
- next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
- if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
+ next_da_bno = da_bno + mp->m_dir_geo->fsbcount - 1;
+ if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) {
+ /*
+ * if this is the first block, there isn't anything we
+ * can recover so we just trash it.
+ */
+ if (da_bno == 0) {
+ fixit++;
+ goto out_fix;
+ }
break;
- db = xfs_dir2_da_to_db(mp, da_bno);
+ }
+
+ db = xfs_dir2_da_to_db(mp->m_dir_geo, da_bno);
if (db >= num_bps) {
/* more data blocks than expected */
num_bps = db + 1;
bplist = realloc(bplist, num_bps * sizeof(struct xfs_buf*));
if (!bplist)
- do_error(
- _("realloc failed in longform_dir2_entry_check (%zu bytes)\n"),
+ do_error(_("realloc failed in %s (%zu bytes)\n"),
+ __func__,
num_bps * sizeof(struct xfs_buf*));
}
ops = &xfs_dir3_block_buf_ops;
else
ops = &xfs_dir3_data_buf_ops;
- if (libxfs_da_read_buf(NULL, ip, da_bno, -1, &bplist[db],
- XFS_DATA_FORK, ops)) {
+
+ error = dir_read_buf(ip, da_bno, -1, &bplist[db], ops, &fixit);
+ if (error) {
do_warn(
- _("can't read data block %u for directory inode %" PRIu64 "\n"),
- da_bno, ino);
+ _("can't read data block %u for directory inode %" PRIu64 " error %d\n"),
+ da_bno, ino, error);
*num_illegal += 1;
/*
}
continue;
}
+
+ /* check v5 metadata */
+ d = bplist[db]->b_addr;
+ if (be32_to_cpu(d->magic) == XFS_DIR3_BLOCK_MAGIC ||
+ be32_to_cpu(d->magic) == XFS_DIR3_DATA_MAGIC) {
+ struct xfs_buf *bp = bplist[db];
+
+ error = check_dir3_header(mp, bp, ino);
+ if (error) {
+ fixit++;
+ continue;
+ }
+ }
+
longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot,
irec, ino_offset, &bplist[db], hashtab,
&freetab, da_bno, isblock);
}
- fixit = (*num_illegal != 0) || dir2_is_badino(ino) || *need_dot;
+ fixit |= (*num_illegal != 0) || dir2_is_badino(ino) || *need_dot;
if (!dotdot_update) {
/* check btree and freespace */
xfs_dir2_leaf_entry_t *blp;
block = bplist[0]->b_addr;
- btp = xfs_dir2_block_tail_p(mp, block);
+ btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block);
blp = xfs_dir2_block_leaf_p(btp);
seeval = dir_hash_see_all(hashtab, blp,
be32_to_cpu(btp->count),
out_fix:
if (!no_modify && (fixit || dotdot_update)) {
dir_hash_dup_names(hashtab);
- for (i = 0; i < freetab->naents; i++)
+ for (i = 0; i < num_bps; i++)
if (bplist[i])
libxfs_putbuf(bplist[i]);
longform_dir2_rebuild(mp, ino, ip, irec, ino_offset, hashtab);
*num_illegal = 0;
*need_dot = 0;
} else {
- for (i = 0; i < freetab->naents; i++)
+ for (i = 0; i < num_bps; i++)
if (bplist[i])
libxfs_putbuf(bplist[i]);
}
* shortform directory v2 processing routines -- entry verification and
* bad entry deletion (pruning).
*/
+static struct xfs_dir2_sf_entry *
+shortform_dir2_junk(
+ struct xfs_mount *mp,
+ struct xfs_dir2_sf_hdr *sfp,
+ struct xfs_dir2_sf_entry *sfep,
+ xfs_ino_t lino,
+ int *max_size,
+ int *index,
+ int *bytes_deleted,
+ int *ino_dirty)
+{
+ struct xfs_dir2_sf_entry *next_sfep;
+ int next_len;
+ int next_elen;
+
+ if (lino == orphanage_ino)
+ orphanage_ino = 0;
+
+ next_elen = M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen);
+ next_sfep = M_DIROPS(mp)->sf_nextentry(sfp, sfep);
+
+ /*
+ * if we are just checking, simply return the pointer to the next entry
+ * here so that the checking loop can continue.
+ */
+ if (no_modify) {
+ do_warn(_("would junk entry\n"));
+ return next_sfep;
+ }
+
+ /*
+ * now move all the remaining entries down over the junked entry and
+ * clear the newly unused bytes at the tail of the directory region.
+ */
+ next_len = *max_size - ((intptr_t)next_sfep - (intptr_t)sfp);
+ *max_size -= next_elen;
+ *bytes_deleted += next_elen;
+
+ memmove(sfep, next_sfep, next_len);
+ memset((void *)((intptr_t)sfep + next_len), 0, next_elen);
+ sfp->count -= 1;
+ *ino_dirty = 1;
+
+ /*
+ * WARNING: drop the index i by one so it matches the decremented count
+ * for accurate comparisons in the loop test
+ */
+ (*index)--;
+
+ if (verbose)
+ do_warn(_("junking entry\n"));
+ else
+ do_warn("\n");
+ return sfep;
+}
+
static void
shortform_dir2_entry_check(xfs_mount_t *mp,
xfs_ino_t ino,
xfs_ino_t lino;
xfs_ino_t parent;
struct xfs_dir2_sf_hdr *sfp;
- xfs_dir2_sf_entry_t *sfep, *next_sfep, *tmp_sfep;
- xfs_ifork_t *ifp;
- ino_tree_node_t *irec;
+ struct xfs_dir2_sf_entry *sfep;
+ struct xfs_dir2_sf_entry *next_sfep;
+ struct xfs_ifork *ifp;
+ struct ino_tree_node *irec;
int max_size;
int ino_offset;
int i;
- int junkit;
- int tmp_len;
- int tmp_elen;
int bad_sfnamelen;
int namelen;
int bytes_deleted;
do_warn(
_("setting .. in sf dir inode %" PRIu64 " to %" PRIu64 "\n"),
ino, parent);
- xfs_dir2_sf_put_parent_ino(sfp, parent);
+ M_DIROPS(mp)->sf_put_parent_ino(sfp, parent);
*ino_dirty = 1;
}
return;
/*
* Initialise i8 counter -- the parent inode number counts as well.
*/
- i8 = xfs_dir2_sf_get_parent_ino(sfp) > XFS_DIR2_MAX_SHORT_INUM;
+ i8 = M_DIROPS(mp)->sf_get_parent_ino(sfp) > XFS_DIR2_MAX_SHORT_INUM;
/*
* now run through entries, stop at first bad entry, don't need
sfep = next_sfep = xfs_dir2_sf_firstentry(sfp);
for (i = 0; i < sfp->count && max_size >
- (__psint_t)next_sfep - (__psint_t)sfp;
+ (intptr_t)next_sfep - (intptr_t)sfp;
sfep = next_sfep, i++) {
- junkit = 0;
bad_sfnamelen = 0;
- tmp_sfep = NULL;
- lino = xfs_dir3_sfe_get_ino(mp, sfp, sfep);
+ lino = M_DIROPS(mp)->sf_get_ino(sfp, sfep);
namelen = sfep->namelen;
if (i == sfp->count - 1) {
namelen = ip->i_d.di_size -
- ((__psint_t) &sfep->name[0] -
- (__psint_t) sfp);
+ ((intptr_t) &sfep->name[0] -
+ (intptr_t) sfp);
} else {
/*
* don't process the rest of the directory,
*/
break;
}
- } else if (no_modify && (__psint_t) sfep - (__psint_t) sfp +
- + xfs_dir3_sf_entsize(mp, sfp, sfep->namelen)
+ } else if (no_modify && (intptr_t) sfep - (intptr_t) sfp +
+ + M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen)
> ip->i_d.di_size) {
bad_sfnamelen = 1;
if (i == sfp->count - 1) {
namelen = ip->i_d.di_size -
- ((__psint_t) &sfep->name[0] -
- (__psint_t) sfp);
+ ((intptr_t) &sfep->name[0] -
+ (intptr_t) sfp);
} else {
/*
* don't process the rest of the directory,
*/
if (no_modify && verify_inum(mp, lino)) {
- next_sfep = (xfs_dir2_sf_entry_t *)((__psint_t)sfep +
- xfs_dir3_sf_entsize(mp, sfp, sfep->namelen));
+ next_sfep = M_DIROPS(mp)->sf_nextentry(sfp, sfep);
continue;
}
do_warn(
_("entry \"%s\" in shortform directory %" PRIu64 " references non-existent inode %" PRIu64 "\n"),
fname, ino, lino);
- goto do_junkit;
+ next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino,
+ &max_size, &i, &bytes_deleted,
+ ino_dirty);
+ continue;
}
ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum;
do_warn(
_("entry \"%s\" in shortform directory inode %" PRIu64 " points to free inode %" PRIu64 "\n"),
fname, ino, lino);
- goto do_junkit;
+ next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino,
+ &max_size, &i, &bytes_deleted,
+ ino_dirty);
+ continue;
}
/*
* check if this inode is lost+found dir in the root
do_warn(
_("%s (ino %" PRIu64 ") in root (%" PRIu64 ") is not a directory"),
ORPHANAGE, lino, ino);
- goto do_junkit;
+ next_sfep = shortform_dir2_junk(mp, sfp, sfep,
+ lino, &max_size, &i,
+ &bytes_deleted, ino_dirty);
+ continue;
}
/*
* if this is a dup, it will be picked up below,
*/
if (!dir_hash_add(mp, hashtab, (xfs_dir2_dataptr_t)
(sfep - xfs_dir2_sf_firstentry(sfp)),
- lino, sfep->namelen, sfep->name)) {
+ lino, sfep->namelen, sfep->name,
+ M_DIROPS(mp)->sf_get_ftype(sfep))) {
do_warn(
_("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"),
fname, lino, ino);
- goto do_junkit;
+ next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino,
+ &max_size, &i, &bytes_deleted,
+ ino_dirty);
+ continue;
}
if (!inode_isadir(irec, ino_offset)) {
* the .. in the child, blow out the entry
*/
if (is_inode_reached(irec, ino_offset)) {
- junkit = 1;
do_warn(
_("entry \"%s\" in directory inode %" PRIu64
" references already connected inode %" PRIu64 ".\n"),
fname, ino, lino);
+ next_sfep = shortform_dir2_junk(mp, sfp, sfep,
+ lino, &max_size, &i,
+ &bytes_deleted, ino_dirty);
+ continue;
} else if (parent == ino) {
add_inode_reached(irec, ino_offset);
add_inode_ref(current_irec, current_ino_offset);
add_dotdot_update(XFS_INO_TO_AGNO(mp, lino),
irec, ino_offset);
} else {
- junkit = 1;
do_warn(
_("entry \"%s\" in directory inode %" PRIu64
" not consistent with .. value (%" PRIu64
") in inode %" PRIu64 ",\n"),
fname, ino, parent, lino);
+ next_sfep = shortform_dir2_junk(mp, sfp, sfep,
+ lino, &max_size, &i,
+ &bytes_deleted, ino_dirty);
+ continue;
}
}
- if (junkit) {
-do_junkit:
- if (lino == orphanage_ino)
- orphanage_ino = 0;
- if (!no_modify) {
- tmp_elen = xfs_dir3_sf_entsize(mp, sfp,
- sfep->namelen);
- tmp_sfep = (xfs_dir2_sf_entry_t *)
- ((__psint_t) sfep + tmp_elen);
- tmp_len = max_size - ((__psint_t) tmp_sfep
- - (__psint_t) sfp);
- max_size -= tmp_elen;
- bytes_deleted += tmp_elen;
-
- memmove(sfep, tmp_sfep, tmp_len);
-
- sfp->count -= 1;
- memset((void *)((__psint_t)sfep + tmp_len), 0,
- tmp_elen);
-
- /*
- * set the tmp value to the current
- * pointer so we'll process the entry
- * we just moved up
- */
- tmp_sfep = sfep;
-
- /*
- * WARNING: drop the index i by one
- * so it matches the decremented count for
- * accurate comparisons in the loop test
- */
- i--;
+ /* validate ftype field if supported */
+ if (xfs_sb_version_hasftype(&mp->m_sb)) {
+ uint8_t dir_ftype;
+ uint8_t ino_ftype;
- *ino_dirty = 1;
+ dir_ftype = M_DIROPS(mp)->sf_get_ftype(sfep);
+ ino_ftype = get_inode_ftype(irec, ino_offset);
- if (verbose)
- do_warn(_("junking entry\n"));
- else
- do_warn("\n");
- } else {
- do_warn(_("would junk entry\n"));
+ if (dir_ftype != ino_ftype) {
+ if (no_modify) {
+ do_warn(
+ _("would fix ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
+ dir_ftype, ino_ftype,
+ ino, lino);
+ } else {
+ do_warn(
+ _("fixing ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
+ dir_ftype, ino_ftype,
+ ino, lino);
+ M_DIROPS(mp)->sf_put_ftype(sfep,
+ ino_ftype);
+ dir_hash_update_ftype(hashtab,
+ (xfs_dir2_dataptr_t)(sfep - xfs_dir2_sf_firstentry(sfp)),
+ ino_ftype);
+ *ino_dirty = 1;
+ }
}
- } else if (lino > XFS_DIR2_MAX_SHORT_INUM)
+ }
+
+ if (lino > XFS_DIR2_MAX_SHORT_INUM)
i8++;
/*
- * go onto next entry unless we've just junked an
- * entry in which the current entry pointer points
- * to an unprocessed entry. have to take into entries
- * with bad namelen into account in no modify mode since we
- * calculate size based on next_sfep.
+ * go onto next entry - we have to take entries with bad namelen
+ * into account in no modify mode since we calculate size based
+ * on next_sfep.
*/
ASSERT(no_modify || bad_sfnamelen == 0);
-
- next_sfep = (tmp_sfep == NULL)
- ? (xfs_dir2_sf_entry_t *) ((__psint_t) sfep
- + ((!bad_sfnamelen)
- ? xfs_dir3_sf_entsize(mp, sfp, sfep->namelen)
- : xfs_dir3_sf_entsize(mp, sfp, namelen)))
- : tmp_sfep;
+ next_sfep = (struct xfs_dir2_sf_entry *)((intptr_t)sfep +
+ (bad_sfnamelen
+ ? M_DIROPS(mp)->sf_entsize(sfp, namelen)
+ : M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen)));
}
if (sfp->i8count != i8) {
ino);
} else {
if (i8 == 0) {
+ struct xfs_dir2_sf_entry *tmp_sfep;
+
tmp_sfep = next_sfep;
process_sf_dir2_fixi8(mp, sfp, &tmp_sfep);
bytes_deleted +=
- (__psint_t)next_sfep -
- (__psint_t)tmp_sfep;
+ (intptr_t)next_sfep -
+ (intptr_t)tmp_sfep;
next_sfep = tmp_sfep;
} else
sfp->i8count = i8;
/*
* sync up sizes if required
*/
- if (*ino_dirty) {
- ASSERT(bytes_deleted > 0);
+ if (*ino_dirty && bytes_deleted > 0) {
ASSERT(!no_modify);
libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK);
ip->i_d.di_size -= bytes_deleted;
if (ip->i_d.di_size != ip->i_df.if_bytes) {
ASSERT(ip->i_df.if_bytes == (xfs_fsize_t)
- ((__psint_t) next_sfep - (__psint_t) sfp));
+ ((intptr_t) next_sfep - (intptr_t) sfp));
ip->i_d.di_size = (xfs_fsize_t)
- ((__psint_t) next_sfep - (__psint_t) sfp);
+ ((intptr_t) next_sfep - (intptr_t) sfp);
do_warn(
_("setting size to %" PRId64 " bytes to reflect junked entries\n"),
ip->i_d.di_size);
int ino_offset)
{
xfs_ino_t ino;
- xfs_bmap_free_t flist;
+ struct xfs_defer_ops dfops;
xfs_fsblock_t first;
xfs_inode_t *ip;
xfs_trans_t *tp;
dir_hash_tab_t *hashtab;
- int need_dot, committed;
+ int need_dot;
int dirty, num_illegal, error, nres;
ino = XFS_AGINO_TO_INO(mp, agno, irec->ino_startnum + ino_offset);
ASSERT(!is_inode_refchecked(irec, ino_offset) || dotdot_update);
- error = libxfs_iget(mp, NULL, ino, 0, &ip, 0);
+ error = -libxfs_iget(mp, NULL, ino, 0, &ip, &phase6_ifork_ops);
if (error) {
if (!no_modify)
do_error(
break;
case XFS_DINODE_FMT_LOCAL:
- tp = libxfs_trans_alloc(mp, 0);
/*
* using the remove reservation is overkill
* since at most we'll only need to log the
* new define in ourselves.
*/
nres = no_modify ? 0 : XFS_REMOVE_SPACE_RES(mp);
- error = libxfs_trans_reserve(tp, &M_RES(mp)->tr_remove,
- nres, 0);
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove,
+ nres, 0, 0, &tp);
if (error)
res_failed(error);
libxfs_trans_ijoin(tp, ip, 0);
- libxfs_trans_ihold(tp, ip);
shortform_dir2_entry_check(mp, ino, ip, &dirty,
irec, ino_offset,
if (dirty) {
libxfs_trans_log_inode(tp, ip,
XFS_ILOG_CORE | XFS_ILOG_DDATA);
- libxfs_trans_commit(tp,
- XFS_TRANS_RELEASE_LOG_RES |
- XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
} else {
- libxfs_trans_cancel(tp,
- XFS_TRANS_RELEASE_LOG_RES);
+ libxfs_trans_cancel(tp);
}
break;
do_warn(_("recreating root directory .. entry\n"));
- tp = libxfs_trans_alloc(mp, 0);
- ASSERT(tp != NULL);
-
nres = XFS_MKDIR_SPACE_RES(mp, 2);
- error = libxfs_trans_reserve(tp, &M_RES(mp)->tr_mkdir, nres, 0);
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir,
+ nres, 0, 0, &tp);
if (error)
res_failed(error);
libxfs_trans_ijoin(tp, ip, 0);
- libxfs_trans_ihold(tp, ip);
- xfs_bmap_init(&flist, &first);
+ libxfs_defer_init(&dfops, &first);
- error = libxfs_dir_createname(tp, ip, &xfs_name_dotdot,
- ip->i_ino, &first, &flist, nres);
+ error = -libxfs_dir_createname(tp, ip, &xfs_name_dotdot,
+ ip->i_ino, &first, nres);
if (error)
do_error(
_("can't make \"..\" entry in root inode %" PRIu64 ", createname error %d\n"), ino, error);
libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- error = libxfs_bmap_finish(&tp, &flist, &committed);
+ libxfs_defer_ijoin(&dfops, ip);
+ error = -libxfs_defer_finish(&tp, &dfops);
ASSERT(error == 0);
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES |
- XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
need_root_dotdot = 0;
} else if (need_root_dotdot && ino == mp->m_sb.sb_rootino) {
do_warn(
_("creating missing \".\" entry in dir ino %" PRIu64 "\n"), ino);
- tp = libxfs_trans_alloc(mp, 0);
- ASSERT(tp != NULL);
-
nres = XFS_MKDIR_SPACE_RES(mp, 1);
- error = libxfs_trans_reserve(tp, &M_RES(mp)->tr_mkdir,
- nres, 0);
+ error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir,
+ nres, 0, 0, &tp);
if (error)
res_failed(error);
libxfs_trans_ijoin(tp, ip, 0);
- libxfs_trans_ihold(tp, ip);
- xfs_bmap_init(&flist, &first);
+ libxfs_defer_init(&dfops, &first);
- error = libxfs_dir_createname(tp, ip, &xfs_name_dot,
- ip->i_ino, &first, &flist, nres);
+ error = -libxfs_dir_createname(tp, ip, &xfs_name_dot,
+ ip->i_ino, &first, nres);
if (error)
do_error(
_("can't make \".\" entry in dir ino %" PRIu64 ", createname error %d\n"),
libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- error = libxfs_bmap_finish(&tp, &flist, &committed);
+ libxfs_defer_ijoin(&dfops, ip);
+ error = -libxfs_defer_finish(&tp, &dfops);
ASSERT(error == 0);
- libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES
- |XFS_TRANS_SYNC);
+ libxfs_trans_commit(tp);
}
}
- libxfs_iput(ip, 0);
+ IRELE(ip);
}
/*
irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rbmino),
XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rbmino));
- ASSERT(irec != NULL);
-
offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rbmino) -
irec->ino_startnum;
offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rsumino) -
irec->ino_startnum;
- ASSERT(irec != NULL);
-
add_inode_reached(irec, offset);
if (fs_quotas) {
static void
traverse_function(
- work_queue_t *wq,
+ struct workqueue *wq,
xfs_agnumber_t agno,
void *arg)
{
if (irec->ino_isa_dir == 0)
continue;
- if (pf_args)
+ if (pf_args) {
sem_post(&pf_args->ra_count);
+#ifdef XR_PF_TRACE
+ sem_getvalue(&pf_args->ra_count, &i);
+ pftrace(
+ "processing inode chunk %p in AG %d (sem count = %d)",
+ irec, agno, i);
+#endif
+ }
for (i = 0; i < XFS_INODES_PER_CHUNK; i++) {
if (inode_isadir(irec, i))
- process_dir_inode(wq->mp, agno, irec, i);
+ process_dir_inode(wq->wq_ctx, agno, irec, i);
}
}
cleanup_inode_prefetch(pf_args);
* set dotdot_update flag so processing routines do not count links
*/
dotdot_update = 1;
- while (dotdot_update_list) {
- dir = dotdot_update_list;
- dotdot_update_list = dir->next;
+ while (!list_empty(&dotdot_update_list)) {
+ dir = list_entry(dotdot_update_list.prev, struct dotdot_update,
+ list);
+ list_del(&dir->list);
process_dir_inode(mp, dir->agno, dir->irec, dir->ino_offset);
free(dir);
}
static void
traverse_ags(
- xfs_mount_t *mp)
+ struct xfs_mount *mp)
{
- int i;
- work_queue_t queue;
- prefetch_args_t *pf_args[2];
-
- /*
- * we always do prefetch for phase 6 as it will fill in the gaps
- * not read during phase 3 prefetch.
- */
- queue.mp = mp;
- pf_args[0] = start_inode_prefetch(0, 1, NULL);
- for (i = 0; i < glob_agcount; i++) {
- pf_args[(~i) & 1] = start_inode_prefetch(i + 1, 1,
- pf_args[i & 1]);
- traverse_function(&queue, i, pf_args[i & 1]);
- }
+ do_inode_prefetch(mp, 0, traverse_function, false, true);
}
void