#include "libxfs.h"
#include "threads.h"
+#include "threads.h"
#include "prefetch.h"
#include "avl.h"
#include "globals.h"
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
* and whether their leaf entry has been seen. Also used for name
* duplicate checking and rebuilding step if required.
*/
-typedef struct dir_hash_ent {
- struct dir_hash_ent *nextbyaddr; /* next in addr bucket */
+struct dir_hash_ent {
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 */
- xfs_ino_t inum; /* inode num of entry */
+ xfs_ino_t inum; /* inode num of entry */
short junkit; /* name starts with / */
short seen; /* have seen leaf entry */
struct xfs_name name;
-} dir_hash_ent_t;
+ unsigned char namebuf[];
+};
-typedef struct dir_hash_tab {
+struct dir_hash_tab {
int size; /* size of hash tables */
- int names_duped; /* 1 = ent names malloced */
- dir_hash_ent_t *first; /* ptr to first added entry */
- dir_hash_ent_t *last; /* ptr to last added entry */
- dir_hash_ent_t **byhash; /* ptr to name hash buckets */
- dir_hash_ent_t **byaddr; /* ptr to addr hash buckets */
-} dir_hash_tab_t;
+ struct dir_hash_ent *first; /* ptr to first added entry */
+ struct dir_hash_ent *last; /* ptr to last added entry */
+ struct dir_hash_ent **byhash; /* ptr to name hash buckets */
+#define HT_UNSEEN 1
+ struct radix_tree_root byaddr;
+};
#define DIR_HASH_TAB_SIZE(n) \
- (sizeof(dir_hash_tab_t) + (sizeof(dir_hash_ent_t *) * (n) * 2))
+ (sizeof(struct dir_hash_tab) + (sizeof(struct dir_hash_ent *) * (n)))
#define DIR_HASH_FUNC(t,a) ((a) % (t)->size)
/*
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);
+ error = -libxfs_da_read_buf(NULL, ip, bno, 0, 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);
+ error2 = -libxfs_da_read_buf(NULL, ip, bno, 0, bpp, XFS_DATA_FORK,
+ NULL);
if (error2)
return error2;
*/
static int
dir_hash_add(
- xfs_mount_t *mp,
- dir_hash_tab_t *hashtab,
+ struct xfs_mount *mp,
+ struct dir_hash_tab *hashtab,
uint32_t addr,
xfs_ino_t inum,
int namelen,
uint8_t ftype)
{
xfs_dahash_t hash = 0;
- int byaddr;
int byhash = 0;
- dir_hash_ent_t *p;
+ struct dir_hash_ent *p;
int dup;
short junk;
struct xfs_name xname;
-
- ASSERT(!hashtab->names_duped);
+ int error;
xname.name = name;
xname.len = namelen;
xname.type = ftype;
junk = name[0] == '/';
- byaddr = DIR_HASH_FUNC(hashtab, addr);
dup = 0;
if (!junk) {
- hash = mp->m_dirnameops->hashname(&xname);
+ hash = libxfs_dir2_hashname(mp, &xname);
byhash = DIR_HASH_FUNC(hashtab, hash);
/*
}
}
- if ((p = malloc(sizeof(*p))) == NULL)
+ /*
+ * Allocate enough space for the hash entry and the name in a single
+ * allocation so we can store our own copy of the name for later use.
+ */
+ p = calloc(1, sizeof(*p) + namelen + 1);
+ if (!p)
do_error(_("malloc failed in dir_hash_add (%zu bytes)\n"),
sizeof(*p));
- p->nextbyaddr = hashtab->byaddr[byaddr];
- hashtab->byaddr[byaddr] = p;
+ error = radix_tree_insert(&hashtab->byaddr, addr, p);
+ if (error == EEXIST) {
+ do_warn(_("duplicate addrs %u in directory!\n"), addr);
+ free(p);
+ return 0;
+ }
+ radix_tree_tag_set(&hashtab->byaddr, addr, HT_UNSEEN);
+
if (hashtab->last)
hashtab->last->nextbyorder = p;
else
p->address = addr;
p->inum = inum;
p->seen = 0;
- p->name = xname;
+ /* Set up the name in the region trailing the hash entry. */
+ memcpy(p->namebuf, name, namelen);
+ p->name.name = p->namebuf;
+ p->name.len = namelen;
+ p->name.type = ftype;
return !dup;
}
-/*
- * checks to see if any data entries are not in the leaf blocks
- */
-static int
-dir_hash_unseen(
- dir_hash_tab_t *hashtab)
+/* Mark an existing directory hashtable entry as junk. */
+static void
+dir_hash_junkit(
+ struct dir_hash_tab *hashtab,
+ xfs_dir2_dataptr_t addr)
{
- int i;
- dir_hash_ent_t *p;
+ struct dir_hash_ent *p;
- for (i = 0; i < hashtab->size; i++) {
- for (p = hashtab->byaddr[i]; p; p = p->nextbyaddr) {
- if (p->seen == 0)
- return 1;
- }
- }
- return 0;
+ p = radix_tree_lookup(&hashtab->byaddr, addr);
+ assert(p != NULL);
+
+ p->junkit = 1;
+ p->namebuf[0] = '/';
}
static int
dir_hash_check(
- dir_hash_tab_t *hashtab,
- xfs_inode_t *ip,
- int seeval)
+ struct dir_hash_tab *hashtab,
+ struct xfs_inode *ip,
+ int seeval)
{
- static char *seevalstr[DIR_HASH_CK_TOTAL];
- static int done;
+ static char *seevalstr[DIR_HASH_CK_TOTAL];
+ static int done;
if (!done) {
seevalstr[DIR_HASH_CK_OK] = _("ok");
done = 1;
}
- if (seeval == DIR_HASH_CK_OK && dir_hash_unseen(hashtab))
+ if (seeval == DIR_HASH_CK_OK &&
+ radix_tree_tagged(&hashtab->byaddr, HT_UNSEEN))
seeval = DIR_HASH_CK_NOLEAF;
if (seeval == DIR_HASH_CK_OK)
return 0;
static void
dir_hash_done(
- dir_hash_tab_t *hashtab)
+ struct dir_hash_tab *hashtab)
{
- int i;
- dir_hash_ent_t *n;
- dir_hash_ent_t *p;
+ int i;
+ struct dir_hash_ent *n;
+ struct dir_hash_ent *p;
for (i = 0; i < hashtab->size; i++) {
- for (p = hashtab->byaddr[i]; p; p = n) {
- n = p->nextbyaddr;
- if (hashtab->names_duped)
- free((void *)p->name.name);
+ for (p = hashtab->byhash[i]; p; p = n) {
+ n = p->nextbyhash;
+ radix_tree_delete(&hashtab->byaddr, p->address);
free(p);
}
}
free(hashtab);
}
-static dir_hash_tab_t *
+/*
+ * Create a directory hash index structure based on the size of the directory we
+ * are about to try to repair. The size passed in is the size of the data
+ * segment of the directory in bytes, so we don't really know exactly how many
+ * entries are in it. Hence assume an entry size of around 64 bytes - that's a
+ * name length of 40+ bytes so should cover a most situations with really large
+ * directories.
+ */
+static struct dir_hash_tab *
dir_hash_init(
- xfs_fsize_t size)
+ xfs_fsize_t size)
{
- dir_hash_tab_t *hashtab;
- int hsize;
+ struct dir_hash_tab *hashtab = NULL;
+ int hsize;
- hsize = size / (16 * 4);
- if (hsize > 65536)
- hsize = 63336;
- else if (hsize < 16)
+ hsize = size / 64;
+ if (hsize < 16)
hsize = 16;
- if ((hashtab = calloc(DIR_HASH_TAB_SIZE(hsize), 1)) == NULL)
+
+ /*
+ * Try to allocate as large a hash table as possible. Failure to
+ * allocate isn't fatal, it will just result in slower performance as we
+ * reduce the size of the table.
+ */
+ while (hsize >= 16) {
+ hashtab = calloc(DIR_HASH_TAB_SIZE(hsize), 1);
+ if (hashtab)
+ break;
+ hsize /= 2;
+ }
+ if (!hashtab)
do_error(_("calloc failed in dir_hash_init\n"));
hashtab->size = hsize;
- hashtab->byhash = (dir_hash_ent_t**)((char *)hashtab +
- sizeof(dir_hash_tab_t));
- hashtab->byaddr = (dir_hash_ent_t**)((char *)hashtab +
- sizeof(dir_hash_tab_t) + sizeof(dir_hash_ent_t*) * hsize);
+ hashtab->byhash = (struct dir_hash_ent **)((char *)hashtab +
+ sizeof(struct dir_hash_tab));
+ INIT_RADIX_TREE(&hashtab->byaddr, 0);
return hashtab;
}
static int
dir_hash_see(
- dir_hash_tab_t *hashtab,
+ struct dir_hash_tab *hashtab,
xfs_dahash_t hash,
xfs_dir2_dataptr_t addr)
{
- 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;
- if (p->seen)
- return DIR_HASH_CK_DUPLEAF;
- if (p->junkit == 0 && p->hashval != hash)
- return DIR_HASH_CK_BADHASH;
- p->seen = 1;
- return DIR_HASH_CK_OK;
- }
- return DIR_HASH_CK_NODATA;
+ struct dir_hash_ent *p;
+
+ p = radix_tree_lookup(&hashtab->byaddr, addr);
+ if (!p)
+ return DIR_HASH_CK_NODATA;
+ if (!radix_tree_tag_get(&hashtab->byaddr, addr, HT_UNSEEN))
+ return DIR_HASH_CK_DUPLEAF;
+ if (p->junkit == 0 && p->hashval != hash)
+ return DIR_HASH_CK_BADHASH;
+ radix_tree_tag_clear(&hashtab->byaddr, addr, HT_UNSEEN);
+ return DIR_HASH_CK_OK;
}
static void
dir_hash_update_ftype(
- dir_hash_tab_t *hashtab,
+ struct dir_hash_tab *hashtab,
xfs_dir2_dataptr_t addr,
uint8_t ftype)
{
- int i;
- dir_hash_ent_t *p;
+ struct dir_hash_ent *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;
- }
+ p = radix_tree_lookup(&hashtab->byaddr, addr);
+ if (!p)
+ return;
+ p->name.type = ftype;
}
/*
*/
static int
dir_hash_see_all(
- dir_hash_tab_t *hashtab,
+ struct dir_hash_tab *hashtab,
xfs_dir2_leaf_entry_t *ents,
int count,
int stale)
}
/*
- * Convert name pointers into locally allocated memory.
- * This must only be done after all the entries have been added.
- */
-static void
-dir_hash_dup_names(dir_hash_tab_t *hashtab)
-{
- unsigned char *name;
- dir_hash_ent_t *p;
-
- if (hashtab->names_duped)
- return;
-
- for (p = hashtab->first; p; p = p->nextbyorder) {
- name = malloc(p->name.len);
- memcpy(name, p->name.name, p->name.len);
- p->name.name = name;
- }
- hashtab->names_duped = 1;
-}
-
-/*
- * Given a block number in a fork, return the next valid block number
- * (not a hole).
- * If this is the last block number then NULLFILEOFF is returned.
- *
- * This was originally in the kernel, but only used in xfs_repair.
+ * Given a block number in a fork, return the next valid block number (not a
+ * hole). If this is the last block number then NULLFILEOFF is returned.
*/
static int
bmap_next_offset(
- xfs_trans_t *tp, /* transaction pointer */
- xfs_inode_t *ip, /* incore inode */
- xfs_fileoff_t *bnop, /* current block */
- int whichfork) /* data or attr fork */
+ struct xfs_inode *ip,
+ xfs_fileoff_t *bnop)
{
- xfs_fileoff_t bno; /* current block */
- int error; /* error return value */
- xfs_bmbt_irec_t got; /* current extent value */
- struct xfs_ifork *ifp; /* inode fork pointer */
+ xfs_fileoff_t bno;
+ int error;
+ struct xfs_bmbt_irec got;
struct xfs_iext_cursor icur;
- if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
- XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
- XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
- return EIO;
- if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
+ switch (ip->i_df.if_format) {
+ case XFS_DINODE_FMT_LOCAL:
*bnop = NULLFILEOFF;
return 0;
+ case XFS_DINODE_FMT_BTREE:
+ case XFS_DINODE_FMT_EXTENTS:
+ break;
+ default:
+ return EIO;
}
- ifp = XFS_IFORK_PTR(ip, whichfork);
- if (!(ifp->if_flags & XFS_IFEXTENTS) &&
- (error = -libxfs_iread_extents(tp, ip, whichfork)))
+
+ /* Read extent map. */
+ error = -libxfs_iread_extents(NULL, ip, XFS_DATA_FORK);
+ if (error)
return error;
+
bno = *bnop + 1;
- if (!libxfs_iext_lookup_extent(ip, ifp, bno, &icur, &got))
+ if (!libxfs_iext_lookup_extent(ip, &ip->i_df, bno, &icur, &got))
*bnop = NULLFILEOFF;
else
*bnop = got.br_startoff < bno ? bno : got.br_startoff;
return 0;
}
-
static void
res_failed(
int err)
do_error(_("xfs_trans_reserve returned %d\n"), err);
}
+static inline void
+reset_inode_fields(struct xfs_inode *ip)
+{
+ ip->i_projid = 0;
+ ip->i_disk_size = 0;
+ ip->i_nblocks = 0;
+ ip->i_extsize = 0;
+ ip->i_cowextsize = 0;
+ ip->i_flushiter = 0;
+ ip->i_forkoff = 0;
+ ip->i_diflags = 0;
+ ip->i_diflags2 = 0;
+ ip->i_crtime.tv_sec = 0;
+ ip->i_crtime.tv_nsec = 0;
+}
+
static void
mk_rbmino(xfs_mount_t *mp)
{
int error;
xfs_fileoff_t bno;
xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP];
- int vers;
int times;
uint blocks;
if (i)
res_failed(i);
- error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, 0, &ip);
+ error = -libxfs_iget(mp, tp, mp->m_sb.sb_rbmino, 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 : 2;
- memset(&ip->i_d, 0, sizeof(ip->i_d));
+ reset_inode_fields(ip);
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_df.if_format = XFS_DINODE_FMT_EXTENTS;
+ if (ip->i_afp)
+ ip->i_afp->if_format = XFS_DINODE_FMT_EXTENTS;
set_nlink(VFS_I(ip), 1); /* account for sb ptr */
times = XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD;
- if (ip->i_d.di_version == 3) {
+ if (xfs_has_v3inodes(mp)) {
VFS_I(ip)->i_version = 1;
- ip->i_d.di_flags2 = 0;
+ ip->i_diflags2 = 0;
times |= XFS_ICHGTIME_CREATE;
}
libxfs_trans_ichgtime(tp, ip, times);
/*
* now the ifork
*/
- ip->i_df.if_flags = XFS_IFEXTENTS;
ip->i_df.if_bytes = 0;
ip->i_df.if_u1.if_root = NULL;
- ip->i_d.di_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize;
+ ip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize;
/*
* commit changes
*/
+ libxfs_trans_ijoin(tp, ip, 0);
libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = -libxfs_trans_commit(tp);
if (error)
static int
fill_rbmino(xfs_mount_t *mp)
{
- xfs_buf_t *bp;
+ struct xfs_buf *bp;
xfs_trans_t *tp;
xfs_inode_t *ip;
xfs_rtword_t *bmp;
if (error)
res_failed(error);
- error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, 0, &ip);
+ error = -libxfs_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip);
if (error) {
do_error(
_("couldn't iget realtime bitmap inode -- error - %d\n"),
bno++;
}
+ libxfs_trans_ijoin(tp, ip, 0);
error = -libxfs_trans_commit(tp);
if (error)
do_error(_("%s: commit failed, error %d\n"), __func__, error);
static int
fill_rsumino(xfs_mount_t *mp)
{
- xfs_buf_t *bp;
+ struct xfs_buf *bp;
xfs_trans_t *tp;
xfs_inode_t *ip;
xfs_suminfo_t *smp;
if (error)
res_failed(error);
- error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, 0, &ip);
+ error = -libxfs_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip);
if (error) {
do_error(
_("couldn't iget realtime summary inode -- error - %d\n"),
bno++;
}
+ libxfs_trans_ijoin(tp, ip, 0);
error = -libxfs_trans_commit(tp);
if (error)
do_error(_("%s: commit failed, error %d\n"), __func__, error);
int nsumblocks;
xfs_fileoff_t bno;
xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP];
- int vers;
int times;
uint blocks;
if (i)
res_failed(i);
- error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, 0, &ip);
+ error = -libxfs_iget(mp, tp, mp->m_sb.sb_rsumino, 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 : 2;
- memset(&ip->i_d, 0, sizeof(ip->i_d));
+ reset_inode_fields(ip);
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_df.if_format = XFS_DINODE_FMT_EXTENTS;
+ if (ip->i_afp)
+ ip->i_afp->if_format = XFS_DINODE_FMT_EXTENTS;
set_nlink(VFS_I(ip), 1); /* account for sb ptr */
times = XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD;
- if (ip->i_d.di_version == 3) {
+ if (xfs_has_v3inodes(mp)) {
VFS_I(ip)->i_version = 1;
- ip->i_d.di_flags2 = 0;
+ ip->i_diflags2 = 0;
times |= XFS_ICHGTIME_CREATE;
}
libxfs_trans_ichgtime(tp, ip, times);
/*
* now the ifork
*/
- ip->i_df.if_flags = XFS_IFEXTENTS;
ip->i_df.if_bytes = 0;
ip->i_df.if_u1.if_root = NULL;
- ip->i_d.di_size = mp->m_rsumsize;
+ ip->i_disk_size = mp->m_rsumsize;
/*
* commit changes
*/
+ libxfs_trans_ijoin(tp, ip, 0);
libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = -libxfs_trans_commit(tp);
if (error)
int error;
const mode_t mode = 0755;
ino_tree_node_t *irec;
- int vers;
int times;
ip = NULL;
if (i)
res_failed(i);
- error = -libxfs_trans_iget(mp, tp, mp->m_sb.sb_rootino, 0, 0, &ip);
+ error = -libxfs_iget(mp, tp, mp->m_sb.sb_rootino, 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 : 2;
- memset(&ip->i_d, 0, sizeof(ip->i_d));
+ reset_inode_fields(ip);
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_df.if_format = XFS_DINODE_FMT_EXTENTS;
+ if (ip->i_afp)
+ ip->i_afp->if_format = XFS_DINODE_FMT_EXTENTS;
- set_nlink(VFS_I(ip), 1); /* account for . */
+ set_nlink(VFS_I(ip), 2); /* account for . and .. */
times = XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD;
- if (ip->i_d.di_version == 3) {
+ if (xfs_has_v3inodes(mp)) {
VFS_I(ip)->i_version = 1;
- ip->i_d.di_flags2 = 0;
+ ip->i_diflags2 = 0;
times |= XFS_ICHGTIME_CREATE;
}
libxfs_trans_ichgtime(tp, ip, times);
-
+ libxfs_trans_ijoin(tp, ip, 0);
libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
/*
* now the ifork
*/
- ip->i_df.if_flags = XFS_IFEXTENTS;
ip->i_df.if_bytes = 0;
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);
error = -libxfs_trans_commit(tp);
* would have been cleared in phase3 and phase4.
*/
- i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip,
- &xfs_default_ifork_ops);
+ i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip);
if (i)
do_error(_("%d - couldn't iget root inode to obtain %s\n"),
i, ORPHANAGE);
* use iget/ijoin instead of trans_iget because the ialloc
* wrapper can commit the transaction and start a new one
*/
-/* i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip,
- &xfs_default_ifork_ops);
+/* i = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip);
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_dir_ialloc(&tp, pip, mode|S_IFDIR,
1, 0, &zerocr, &zerofsx, &ip);
if (error) {
do_error(_("%s inode allocation failed %d\n"),
*/
set_inode_used(irec, ino_offset);
add_inode_ref(irec, ino_offset);
+ add_inode_reached(irec, ino_offset);
/*
* now that we know the transaction will stay around,
/*
* bump up the link count in the root directory to account
- * for .. in the new directory
+ * for .. in the new directory, and update the irec copy of the
+ * on-disk nlink so we don't fail the link count check later.
*/
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);
-
-
+ 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));
+ add_inode_ref(irec, 0);
+ set_inode_disk_nlinks(irec, 0, get_inode_disk_nlinks(irec, 0) + 1);
libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE);
libxfs_dir_init(tp, ip, pip);
}
libxfs_irele(ip);
libxfs_irele(pip);
- add_inode_reached(irec,ino_offset);
return(ino);
}
xname.len = snprintf((char *)fname, sizeof(fname), "%llu",
(unsigned long long)ino);
- err = -libxfs_iget(mp, NULL, orphanage_ino, 0, &orphanage_ip,
- &xfs_default_ifork_ops);
+ err = -libxfs_iget(mp, NULL, orphanage_ino, 0, &orphanage_ip);
if (err)
do_error(_("%d - couldn't iget orphanage inode\n"), err);
/*
(unsigned long long)ino, ++incr);
/* Orphans may not have a proper parent, so use custom ops here */
- err = -libxfs_iget(mp, NULL, ino, 0, &ino_p, &phase6_ifork_ops);
+ err = -libxfs_iget(mp, NULL, ino, 0, &ino_p);
if (err)
do_error(_("%d - couldn't iget disconnected inode\n"), err);
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"),
- err);
+ res_failed(err);
libxfs_trans_ijoin(tp, orphanage_ip, 0);
libxfs_trans_ijoin(tp, ino_p, 0);
ino, nres);
if (err)
do_error(
- _("name create failed in %s (%d), filesystem may be out of space\n"),
- ORPHANAGE, err);
+ _("name create failed in %s (%d)\n"), ORPHANAGE, err);
if (irec)
add_inode_ref(irec, ino_offset);
orphanage_ino, nres);
if (err)
do_error(
- _("creation of .. entry failed (%d), filesystem may be out of space\n"),
- err);
+ _("creation of .. entry failed (%d)\n"), err);
inc_nlink(VFS_I(ino_p));
libxfs_trans_log_inode(tp, ino_p, XFS_ILOG_CORE);
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"),
- err);
+ res_failed(err);
libxfs_trans_ijoin(tp, orphanage_ip, 0);
libxfs_trans_ijoin(tp, ino_p, 0);
ino, nres);
if (err)
do_error(
- _("name create failed in %s (%d), filesystem may be out of space\n"),
- ORPHANAGE, err);
+ _("name create failed in %s (%d)\n"), ORPHANAGE, err);
if (irec)
add_inode_ref(irec, ino_offset);
nres);
if (err)
do_error(
- _("name replace op failed (%d), filesystem may be out of space\n"),
- err);
+ _("name replace op failed (%d)\n"), err);
}
err = -libxfs_trans_commit(tp);
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"),
- err);
+ res_failed(err);
libxfs_trans_ijoin(tp, orphanage_ip, 0);
libxfs_trans_ijoin(tp, ino_p, 0);
nres);
if (err)
do_error(
- _("name create failed in %s (%d), filesystem may be out of space\n"),
- ORPHANAGE, err);
+ _("name create failed in %s (%d)\n"), ORPHANAGE, err);
ASSERT(err == 0);
set_nlink(VFS_I(ino_p), 1);
struct xfs_ifork *ifp;
struct xfs_da_geometry *geo;
struct xfs_buf *bp;
- xfs_dablk_t dabno, end_dabno;
+ xfs_dablk_t dabno;
int error = 0;
- if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
- ip->i_d.di_format != XFS_DINODE_FMT_BTREE)
+ if (ip->i_df.if_format != XFS_DINODE_FMT_EXTENTS &&
+ ip->i_df.if_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) {
+ for (dabno = roundup(rec.br_startoff, geo->fsbcount);
+ dabno < rec.br_startoff + rec.br_blockcount;
+ dabno += geo->fsbcount) {
bp = NULL;
- error = -libxfs_da_get_buf(tp, ip, dabno, -2, &bp,
+ error = -libxfs_da_get_buf(tp, ip, dabno, &bp,
whichfork);
if (error)
return error;
static void
longform_dir2_rebuild(
- xfs_mount_t *mp,
+ struct xfs_mount *mp,
xfs_ino_t ino,
- xfs_inode_t *ip,
- ino_tree_node_t *irec,
+ struct xfs_inode *ip,
+ struct ino_tree_node *irec,
int ino_offset,
- dir_hash_tab_t *hashtab)
+ struct dir_hash_tab *hashtab)
{
int error;
int nres;
- xfs_trans_t *tp;
+ struct xfs_trans *tp;
xfs_fileoff_t lastblock;
- xfs_inode_t pip;
- dir_hash_ent_t *p;
- int done;
+ struct xfs_inode pip;
+ struct dir_hash_ent *p;
+ int done = 0;
/*
* trash directory completely and rebuild from scratch using the
error = dir_binval(tp, ip, XFS_DATA_FORK);
if (error)
- res_failed(error);
+ do_error(_("error %d invalidating directory %llu blocks\n"),
+ error, (unsigned long long)ip->i_ino);
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,
- &done);
- if (error) {
- do_warn(_("xfs_bunmapi failed -- error - %d\n"), error);
- goto out_bmap_cancel;
- }
-
- ASSERT(done);
+ while (!done) {
+ error = -libxfs_bunmapi(tp, ip, 0, lastblock, XFS_BMAPI_METADATA,
+ 0, &done);
+ if (error) {
+ do_warn(_("xfs_bunmapi failed -- error - %d\n"), error);
+ goto out_bmap_cancel;
+ }
+ error = -libxfs_defer_finish(&tp);
+ if (error) {
+ do_warn(("defer_finish failed -- error - %d\n"), error);
+ goto out_bmap_cancel;
+ }
+ /*
+ * Close out trans and start the next one in the chain.
+ */
+ error = -libxfs_trans_roll_inode(&tp, ip);
+ if (error)
+ goto out_bmap_cancel;
+ }
error = -libxfs_dir_init(tp, ip, &pip);
if (error) {
nres);
if (error) {
do_warn(
-_("name create failed in ino %" PRIu64 " (%d), filesystem may be out of space\n"),
- ino, error);
+_("name create failed in ino %" PRIu64 " (%d)\n"), ino, error);
goto out_bmap_cancel;
}
res_failed(error);
libxfs_trans_ijoin(tp, ip, 0);
libxfs_trans_bjoin(tp, bp);
+ libxfs_trans_bhold(tp, bp);
memset(&args, 0, sizeof(args));
args.dp = ip;
args.trans = tp;
_("directory shrink failed (%d)\n"), error);
}
+static inline void
+check_longform_ftype(
+ struct xfs_mount *mp,
+ struct xfs_inode *ip,
+ xfs_dir2_data_entry_t *dep,
+ ino_tree_node_t *irec,
+ int ino_offset,
+ struct dir_hash_tab *hashtab,
+ xfs_dir2_dataptr_t addr,
+ struct xfs_da_args *da,
+ struct xfs_buf *bp)
+{
+ xfs_ino_t inum = be64_to_cpu(dep->inumber);
+ uint8_t dir_ftype;
+ uint8_t ino_ftype;
+
+ if (!xfs_has_ftype(mp))
+ return;
+
+ dir_ftype = libxfs_dir2_data_get_ftype(mp, dep);
+ ino_ftype = get_inode_ftype(irec, ino_offset);
+
+ if (dir_ftype == ino_ftype)
+ return;
+
+ 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);
+ return;
+ }
+
+ do_warn(
+_("fixing ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
+ dir_ftype, ino_ftype,
+ ip->i_ino, inum);
+ libxfs_dir2_data_put_ftype(mp, dep, ino_ftype);
+ libxfs_dir2_data_log_entry(da, bp, dep);
+ dir_hash_update_ftype(hashtab, addr, ino_ftype);
+}
+
/*
* process a data block, also checks for .. entry
* and corrects it to match what we think .. should be
*/
static void
longform_dir2_entry_check_data(
- xfs_mount_t *mp,
- xfs_inode_t *ip,
+ struct xfs_mount *mp,
+ struct xfs_inode *ip,
int *num_illegal,
int *need_dot,
- ino_tree_node_t *current_irec,
+ struct ino_tree_node *current_irec,
int current_ino_offset,
- struct xfs_buf **bpp,
- dir_hash_tab_t *hashtab,
+ struct xfs_buf *bp,
+ struct dir_hash_tab *hashtab,
freetab_t **freetabp,
xfs_dablk_t da_bno,
int isblock)
{
xfs_dir2_dataptr_t addr;
xfs_dir2_leaf_entry_t *blp;
- struct xfs_buf *bp;
xfs_dir2_block_tail_t *btp;
struct xfs_dir2_data_hdr *d;
xfs_dir2_db_t db;
};
- bp = *bpp;
d = bp->b_addr;
- ptr = (char *)M_DIROPS(mp)->data_entry_p(d);
+ ptr = (char *)d + mp->m_dir_geo->data_entry_offset;
nbad = 0;
needscan = needlog = 0;
junkit = 0;
endptr = (char *)blp;
if (endptr > (char *)btp)
endptr = (char *)btp;
- if (xfs_sb_version_hascrc(&mp->m_sb))
+ if (xfs_has_crc(mp))
wantmagic = XFS_DIR3_BLOCK_MAGIC;
else
wantmagic = XFS_DIR2_BLOCK_MAGIC;
} else {
endptr = (char *)d + mp->m_dir_geo->blksize;
- if (xfs_sb_version_hascrc(&mp->m_sb))
+ if (xfs_has_crc(mp))
wantmagic = XFS_DIR3_DATA_MAGIC;
else
wantmagic = XFS_DIR2_DATA_MAGIC;
break;
/* check for block with no data entries */
- if ((ptr == (char *)M_DIROPS(mp)->data_entry_p(d)) &&
+ if ((ptr == (char *)d + mp->m_dir_geo->data_entry_offset) &&
(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 + M_DIROPS(mp)->data_entsize(dep->namelen) > endptr)
+ if (ptr + libxfs_dir2_data_entsize(mp, dep->namelen) > endptr)
break;
- if (be16_to_cpu(*M_DIROPS(mp)->data_entry_tag_p(dep)) !=
+ if (be16_to_cpu(*libxfs_dir2_data_entry_tag_p(mp, dep)) !=
(char *)dep - (char *)d)
break;
- ptr += M_DIROPS(mp)->data_entsize(dep->namelen);
+ ptr += libxfs_dir2_data_entsize(mp, dep->namelen);
}
/* did we find an empty or corrupt block? */
dir2_kill_block(mp, ip, da_bno, bp);
} else {
do_warn(_("would junk block\n"));
- libxfs_putbuf(bp);
}
freetab->ents[db].v = NULLDATAOFF;
- *bpp = NULL;
return;
}
do_warn(_("would fix magic # to %#x\n"), wantmagic);
}
lastfree = 0;
- ptr = (char *)M_DIROPS(mp)->data_entry_p(d);
+ ptr = (char *)d + mp->m_dir_geo->data_entry_offset;
/*
* look at each entry. reference inode pointed to by each
* entry in the incore inode tree.
addr = xfs_dir2_db_off_to_dataptr(mp->m_dir_geo, db,
ptr - (char *)d);
dep = (xfs_dir2_data_entry_t *)ptr;
- ptr += M_DIROPS(mp)->data_entsize(dep->namelen);
+ ptr += libxfs_dir2_data_entsize(mp, dep->namelen);
inum = be64_to_cpu(dep->inumber);
lastfree = 0;
/*
* check for duplicate names in directory.
*/
if (!dir_hash_add(mp, hashtab, addr, inum, dep->namelen,
- dep->name, M_DIROPS(mp)->data_get_ftype(dep))) {
+ dep->name, libxfs_dir2_data_get_ftype(mp, dep))) {
nbad++;
if (entry_junked(
_("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"),
if (entry_junked(
_("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is not in the the first block"), fname,
inum, ip->i_ino)) {
+ dir_hash_junkit(hashtab, addr);
dep->name[0] = '/';
libxfs_dir2_data_log_entry(&da, bp, dep);
}
}
+
+ if (!nbad)
+ check_longform_ftype(mp, ip, dep, irec,
+ ino_offset, hashtab, addr, &da,
+ bp);
continue;
}
- ASSERT(no_modify || !verify_inum(mp, inum));
+ ASSERT(no_modify || libxfs_verify_dir_ino(mp, inum));
/*
* special case the . entry. we know there's only one
* '.' and only '.' points to itself because bogus entries
(dep->name[0] == '.' && dep->namelen == 1));
add_inode_ref(current_irec, current_ino_offset);
if (da_bno != 0 ||
- dep != M_DIROPS(mp)->data_entry_p(d)) {
+ dep != (void *)d + mp->m_dir_geo->data_entry_offset) {
/* "." should be the first entry */
nbad++;
if (entry_junked(
_("entry \"%s\" in dir %" PRIu64 " is not the first entry"),
fname, inum, ip->i_ino)) {
+ dir_hash_junkit(hashtab, addr);
dep->name[0] = '/';
libxfs_dir2_data_log_entry(&da, bp, dep);
}
}
+
+ if (!nbad)
+ check_longform_ftype(mp, ip, dep, irec,
+ ino_offset, hashtab, addr, &da,
+ bp);
*need_dot = 0;
continue;
}
/*
* skip entries with bogus inumbers if we're in no modify mode
*/
- if (no_modify && verify_inum(mp, inum))
+ if (no_modify && !libxfs_verify_dir_ino(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_longform_ftype(mp, ip, dep, irec, ino_offset, hashtab,
+ addr, &da, bp);
/*
* check easy case first, regular inode, just bump
orphanage_ino = 0;
nbad++;
if (!no_modify) {
+ dir_hash_junkit(hashtab, addr);
dep->name[0] = '/';
libxfs_dir2_data_log_entry(&da, bp, dep);
if (verbose)
}
*num_illegal += nbad;
if (needscan)
- libxfs_dir2_data_freescan_int(mp->m_dir_geo, M_DIROPS(mp),
- d, &i);
+ libxfs_dir2_data_freescan(mp, d, &i);
if (needlog)
libxfs_dir2_data_log_header(&da, bp);
error = -libxfs_trans_commit(tp);
_("directory block fixing failed (%d)\n"), error);
/* record the largest free space in the freetab for later checking */
- bf = M_DIROPS(mp)->data_bestfree_p(d);
+ bf = libxfs_dir2_data_bestfree_p(mp, d);
freetab->ents[db].v = be16_to_cpu(bf[0].length);
freetab->ents[db].s = 0;
}
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);
+ ino, (unsigned long long)be64_to_cpu(owner), xfs_buf_daddr(bp));
return 1;
}
/* verify block number */
- if (be64_to_cpu(blkno) != bp->b_bn) {
+ if (be64_to_cpu(blkno) != xfs_buf_daddr(bp)) {
do_warn(
_("expected block %" PRIu64 ", got %llu, directory inode %" PRIu64 "\n"),
- bp->b_bn, (unsigned long long)be64_to_cpu(blkno), ino);
+ xfs_buf_daddr(bp), (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);
+ ino, xfs_buf_daddr(bp));
return 1;
}
*/
static int
longform_dir2_check_leaf(
- xfs_mount_t *mp,
- xfs_inode_t *ip,
- dir_hash_tab_t *hashtab,
- freetab_t *freetab)
+ struct xfs_mount *mp,
+ struct xfs_inode *ip,
+ struct dir_hash_tab *hashtab,
+ struct freetab *freetab)
{
int badtail;
__be16 *bestsp;
int fixit = 0;
da_bno = mp->m_dir_geo->leafblk;
- error = dir_read_buf(ip, da_bno, -1, &bp, &xfs_dir3_leaf1_buf_ops,
- &fixit);
+ error = dir_read_buf(ip, da_bno, &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"),
}
leaf = bp->b_addr;
- M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf);
- ents = M_DIROPS(mp)->leaf_ents_p(leaf);
+ libxfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
+ ents = leafhdr.ents;
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 >
- M_DIROPS(mp)->leaf_max_ents(mp->m_dir_geo) ||
+ leafhdr.count > mp->m_dir_geo->leaf_max_ents ||
(char *)&ents[leafhdr.count] > (char *)bestsp) {
do_warn(
_("leaf block %u for directory inode %" PRIu64 " bad header\n"),
da_bno, ip->i_ino);
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return 1;
}
if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) {
error = check_da3_header(mp, bp, ip->i_ino);
if (error) {
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return error;
}
}
seeval = dir_hash_see_all(hashtab, ents, leafhdr.count, leafhdr.stale);
if (dir_hash_check(hashtab, ip, seeval)) {
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return 1;
}
badtail = freetab->nents != be32_to_cpu(ltp->bestcount);
do_warn(
_("leaf block %u for directory inode %" PRIu64 " bad tail\n"),
da_bno, ip->i_ino);
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return 1;
}
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return fixit;
}
*/
static int
longform_dir2_check_node(
- xfs_mount_t *mp,
- xfs_inode_t *ip,
- dir_hash_tab_t *hashtab,
- freetab_t *freetab)
+ struct xfs_mount *mp,
+ struct xfs_inode *ip,
+ struct dir_hash_tab *hashtab,
+ struct freetab *freetab)
{
struct xfs_buf *bp;
xfs_dablk_t da_bno;
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_dir_geo->fsbcount - 1;
- if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
+ if (bmap_next_offset(ip, &next_da_bno))
break;
/*
* a node block, then we'll skip it below based on a magic
* number check.
*/
- error = dir_read_buf(ip, da_bno, -1, &bp,
- &xfs_da3_node_buf_ops, &fixit);
+ error = dir_read_buf(ip, da_bno, &bp, &xfs_da3_node_buf_ops,
+ &fixit);
if (error) {
do_warn(
_("can't read leaf block %u for directory inode %" PRIu64 ", error %d\n"),
return 1;
}
leaf = bp->b_addr;
- M_DIROPS(mp)->leaf_hdr_from_disk(&leafhdr, leaf);
- ents = M_DIROPS(mp)->leaf_ents_p(leaf);
+ libxfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
+ ents = leafhdr.ents;
if (!(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
leafhdr.magic == XFS_DIR3_LEAFN_MAGIC ||
leafhdr.magic == XFS_DA_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);
+ libxfs_buf_relse(bp);
return 1;
}
leafhdr.magic == XFS_DA3_NODE_MAGIC) {
error = check_da3_header(mp, bp, ip->i_ino);
if (error) {
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return error;
}
}
/* ignore nodes */
if (leafhdr.magic == XFS_DA_NODE_MAGIC ||
leafhdr.magic == XFS_DA3_NODE_MAGIC) {
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
continue;
}
* 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) ||
+ if (leafhdr.count > mp->m_dir_geo->leaf_max_ents ||
leafhdr.count < leafhdr.stale) {
do_warn(
_("leaf block %u for directory inode %" PRIu64 " bad header\n"),
da_bno, ip->i_ino);
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return 1;
}
seeval = dir_hash_see_all(hashtab, ents,
leafhdr.count, leafhdr.stale);
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
if (seeval != DIR_HASH_CK_OK)
return 1;
}
next_da_bno != NULLFILEOFF;
da_bno = (xfs_dablk_t)next_da_bno) {
next_da_bno = da_bno + mp->m_dir_geo->fsbcount - 1;
- if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
+ if (bmap_next_offset(ip, &next_da_bno))
break;
- error = dir_read_buf(ip, da_bno, -1, &bp,
- &xfs_dir3_free_buf_ops, &fixit);
+ error = dir_read_buf(ip, da_bno, &bp, &xfs_dir3_free_buf_ops,
+ &fixit);
if (error) {
do_warn(
_("can't read freespace block %u for directory inode %" PRIu64 ", error %d\n"),
return 1;
}
free = bp->b_addr;
- M_DIROPS(mp)->free_hdr_from_disk(&freehdr, free);
- bests = M_DIROPS(mp)->free_bests_p(free);
+ libxfs_dir2_free_hdr_from_disk(mp, &freehdr, free);
+ bests = freehdr.bests;
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_byte_to_db(mp->m_dir_geo, XFS_DIR2_FREE_OFFSET)) *
- M_DIROPS(mp)->free_max_bests(mp->m_dir_geo) ||
+ mp->m_dir_geo->free_max_bests ||
freehdr.nvalid < freehdr.nused) {
do_warn(
_("free block %u for directory inode %" PRIu64 " bad header\n"),
da_bno, ip->i_ino);
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return 1;
}
if (freehdr.magic == XFS_DIR3_FREE_MAGIC) {
error = check_dir3_header(mp, bp, ip->i_ino);
if (error) {
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return error;
}
}
do_warn(
_("free block %u entry %i for directory ino %" PRIu64 " bad\n"),
da_bno, i, ip->i_ino);
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return 1;
}
used += be16_to_cpu(bests[i]) != NULLDATAOFF;
do_warn(
_("free block %u for directory inode %" PRIu64 " bad nused\n"),
da_bno, ip->i_ino);
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
return 1;
}
- libxfs_putbuf(bp);
+ libxfs_buf_relse(bp);
}
for (i = 0; i < freetab->nents; i++) {
if ((freetab->ents[i].s == 0) &&
* (ie. get libxfs to do all the grunt work)
*/
static void
-longform_dir2_entry_check(xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_inode_t *ip,
- int *num_illegal,
- int *need_dot,
- ino_tree_node_t *irec,
- int ino_offset,
- dir_hash_tab_t *hashtab)
+longform_dir2_entry_check(
+ struct xfs_mount *mp,
+ xfs_ino_t ino,
+ struct xfs_inode *ip,
+ int *num_illegal,
+ int *need_dot,
+ struct ino_tree_node *irec,
+ int ino_offset,
+ struct dir_hash_tab *hashtab)
{
- struct xfs_buf **bplist;
+ struct xfs_buf *bp = NULL;
xfs_dablk_t da_bno;
freetab_t *freetab;
- int num_bps;
int i;
int isblock;
int isleaf;
xfs_fileoff_t next_da_bno;
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_dir_geo->blksize));
+ freetab = malloc(FREETAB_SIZE(ip->i_disk_size / mp->m_dir_geo->blksize));
if (!freetab) {
do_error(_("malloc failed in %s (%" PRId64 " bytes)\n"),
__func__,
- FREETAB_SIZE(ip->i_d.di_size / mp->m_dir_geo->blksize));
+ FREETAB_SIZE(ip->i_disk_size / mp->m_dir_geo->blksize));
exit(1);
}
- freetab->naents = ip->i_d.di_size / mp->m_dir_geo->blksize;
+ freetab->naents = ip->i_disk_size / mp->m_dir_geo->blksize;
freetab->nents = 0;
for (i = 0; i < freetab->naents; i++) {
freetab->ents[i].v = NULLDATAOFF;
freetab->ents[i].s = 0;
}
- 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? */
args.dp = ip;
struct xfs_dir2_data_hdr *d;
next_da_bno = da_bno + mp->m_dir_geo->fsbcount - 1;
- if (bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) {
+ if (bmap_next_offset(ip, &next_da_bno)) {
/*
* if this is the first block, there isn't anything we
* can recover so we just trash it.
break;
}
- db = xfs_dir2_da_to_db(mp->m_dir_geo, da_bno);
- if (db >= num_bps) {
- int last_size = 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 %s (%zu bytes)\n"),
- __func__,
- num_bps * sizeof(struct xfs_buf*));
- /* Initialize the new elements */
- for (i = last_size; i < num_bps; i++)
- bplist[i] = NULL;
- }
-
if (isblock)
ops = &xfs_dir3_block_buf_ops;
else
ops = &xfs_dir3_data_buf_ops;
- error = dir_read_buf(ip, da_bno, -1, &bplist[db], ops, &fixit);
+ error = dir_read_buf(ip, da_bno, &bp, ops, &fixit);
if (error) {
do_warn(
_("can't read data block %u for directory inode %" PRIu64 " error %d\n"),
}
/* check v5 metadata */
- d = bplist[db]->b_addr;
+ d = bp->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++;
+ if (isblock)
+ goto out_fix;
continue;
}
}
longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot,
- irec, ino_offset, &bplist[db], hashtab,
+ irec, ino_offset, bp, hashtab,
&freetab, da_bno, isblock);
+ if (isblock)
+ break;
+
+ libxfs_buf_relse(bp);
}
fixit |= (*num_illegal != 0) || dir2_is_badino(ino) || *need_dot;
xfs_dir2_block_tail_t *btp;
xfs_dir2_leaf_entry_t *blp;
- block = bplist[0]->b_addr;
+ block = bp->b_addr;
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,
}
}
out_fix:
+ if (isblock && bp)
+ libxfs_buf_relse(bp);
+
if (!no_modify && (fixit || dotdot_update)) {
- dir_hash_dup_names(hashtab);
- 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 < num_bps; i++)
- if (bplist[i])
- libxfs_putbuf(bplist[i]);
+ if (fixit || dotdot_update)
+ do_warn(
+ _("would rebuild directory inode %" PRIu64 "\n"), ino);
}
- free(bplist);
free(freetab);
}
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);
+ next_elen = libxfs_dir2_sf_entsize(mp, sfp, sfep->namelen);
+ next_sfep = libxfs_dir2_sf_nextentry(mp, sfp, sfep);
/*
* if we are just checking, simply return the pointer to the next entry
}
static void
-shortform_dir2_entry_check(xfs_mount_t *mp,
- xfs_ino_t ino,
- xfs_inode_t *ip,
- int *ino_dirty,
- ino_tree_node_t *current_irec,
- int current_ino_offset,
- dir_hash_tab_t *hashtab)
+shortform_dir2_entry_check(
+ struct xfs_mount *mp,
+ xfs_ino_t ino,
+ struct xfs_inode *ip,
+ int *ino_dirty,
+ struct ino_tree_node *current_irec,
+ int current_ino_offset,
+ struct dir_hash_tab *hashtab)
{
xfs_ino_t lino;
xfs_ino_t parent;
bytes_deleted = 0;
max_size = ifp->if_bytes;
- ASSERT(ip->i_d.di_size <= ifp->if_bytes);
+ ASSERT(ip->i_disk_size <= ifp->if_bytes);
/*
* if just rebuild a directory due to a "..", update and return
do_warn(
_("setting .. in sf dir inode %" PRIu64 " to %" PRIu64 "\n"),
ino, parent);
- M_DIROPS(mp)->sf_put_parent_ino(sfp, parent);
+ libxfs_dir2_sf_put_parent_ino(sfp, parent);
*ino_dirty = 1;
}
return;
/*
* Initialise i8 counter -- the parent inode number counts as well.
*/
- i8 = M_DIROPS(mp)->sf_get_parent_ino(sfp) > XFS_DIR2_MAX_SHORT_INUM;
+ i8 = libxfs_dir2_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, i++) {
bad_sfnamelen = 0;
- lino = M_DIROPS(mp)->sf_get_ino(sfp, sfep);
+ lino = libxfs_dir2_sf_get_ino(mp, sfp, sfep);
namelen = sfep->namelen;
bad_sfnamelen = 1;
if (i == sfp->count - 1) {
- namelen = ip->i_d.di_size -
+ namelen = ip->i_disk_size -
((intptr_t) &sfep->name[0] -
(intptr_t) sfp);
} else {
break;
}
} else if (no_modify && (intptr_t) sfep - (intptr_t) sfp +
- + M_DIROPS(mp)->sf_entsize(sfp, sfep->namelen)
- > ip->i_d.di_size) {
+ + libxfs_dir2_sf_entsize(mp, sfp, sfep->namelen)
+ > ip->i_disk_size) {
bad_sfnamelen = 1;
if (i == sfp->count - 1) {
- namelen = ip->i_d.di_size -
+ namelen = ip->i_disk_size -
((intptr_t) &sfep->name[0] -
(intptr_t) sfp);
} else {
fname[sfep->namelen] = '\0';
ASSERT(no_modify || (lino != NULLFSINO && lino != 0));
- ASSERT(no_modify || !verify_inum(mp, lino));
+ ASSERT(no_modify || libxfs_verify_dir_ino(mp, lino));
/*
* Also skip entries with bogus inode numbers if we're
* in no modify mode.
*/
- if (no_modify && verify_inum(mp, lino)) {
- next_sfep = M_DIROPS(mp)->sf_nextentry(sfp, sfep);
+ if (no_modify && !libxfs_verify_dir_ino(mp, lino)) {
+ next_sfep = libxfs_dir2_sf_nextentry(mp, sfp, sfep);
continue;
}
if (!dir_hash_add(mp, hashtab, (xfs_dir2_dataptr_t)
(sfep - xfs_dir2_sf_firstentry(sfp)),
lino, sfep->namelen, sfep->name,
- M_DIROPS(mp)->sf_get_ftype(sfep))) {
+ libxfs_dir2_sf_get_ftype(mp, sfep))) {
do_warn(
_("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"),
fname, lino, ino);
}
/* validate ftype field if supported */
- if (xfs_sb_version_hasftype(&mp->m_sb)) {
+ if (xfs_has_ftype(mp)) {
uint8_t dir_ftype;
uint8_t ino_ftype;
- dir_ftype = M_DIROPS(mp)->sf_get_ftype(sfep);
+ dir_ftype = libxfs_dir2_sf_get_ftype(mp, sfep);
ino_ftype = get_inode_ftype(irec, ino_offset);
if (dir_ftype != ino_ftype) {
_("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,
+ libxfs_dir2_sf_put_ftype(mp, sfep,
ino_ftype);
dir_hash_update_ftype(hashtab,
(xfs_dir2_dataptr_t)(sfep - xfs_dir2_sf_firstentry(sfp)),
ASSERT(no_modify || bad_sfnamelen == 0);
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)));
+ ? libxfs_dir2_sf_entsize(mp, sfp, namelen)
+ : libxfs_dir2_sf_entsize(mp, sfp, sfep->namelen)));
}
if (sfp->i8count != i8) {
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;
+ ip->i_disk_size -= bytes_deleted;
}
- if (ip->i_d.di_size != ip->i_df.if_bytes) {
+ if (ip->i_disk_size != ip->i_df.if_bytes) {
ASSERT(ip->i_df.if_bytes == (xfs_fsize_t)
((intptr_t) next_sfep - (intptr_t) sfp));
- ip->i_d.di_size = (xfs_fsize_t)
+ ip->i_disk_size = (xfs_fsize_t)
((intptr_t) next_sfep - (intptr_t) sfp);
do_warn(
_("setting size to %" PRId64 " bytes to reflect junked entries\n"),
- ip->i_d.di_size);
+ ip->i_disk_size);
*ino_dirty = 1;
}
}
*/
static void
process_dir_inode(
- xfs_mount_t *mp,
+ struct xfs_mount *mp,
xfs_agnumber_t agno,
- ino_tree_node_t *irec,
+ struct ino_tree_node *irec,
int ino_offset)
{
xfs_ino_t ino;
- xfs_inode_t *ip;
- xfs_trans_t *tp;
- dir_hash_tab_t *hashtab;
+ struct xfs_inode *ip;
+ struct xfs_trans *tp;
+ struct dir_hash_tab *hashtab;
int need_dot;
int dirty, num_illegal, error, nres;
ASSERT(!is_inode_refchecked(irec, ino_offset) || dotdot_update);
- error = -libxfs_iget(mp, NULL, ino, 0, &ip, &phase6_ifork_ops);
+ error = -libxfs_iget(mp, NULL, ino, 0, &ip);
if (error) {
if (!no_modify)
do_error(
add_inode_refchecked(irec, ino_offset);
- hashtab = dir_hash_init(ip->i_d.di_size);
+ hashtab = dir_hash_init(ip->i_disk_size);
/*
* look for bogus entries
*/
- switch (ip->i_d.di_format) {
+ switch (ip->i_df.if_format) {
case XFS_DINODE_FMT_EXTENTS:
case XFS_DINODE_FMT_BTREE:
/*
XFS_ILOG_CORE | XFS_ILOG_DDATA);
error = -libxfs_trans_commit(tp);
if (error)
- res_failed(error);
+ do_error(
+_("error %d fixing shortform directory %llu\n"),
+ error,
+ (unsigned long long)ip->i_ino);
} else {
libxfs_trans_cancel(tp);
}
* if it has to move them around.
*/
if (!no_modify && need_root_dotdot && ino == mp->m_sb.sb_rootino) {
- ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_LOCAL);
+ ASSERT(ip->i_df.if_format != XFS_DINODE_FMT_LOCAL);
do_warn(_("recreating root directory .. entry\n"));
do_warn(
_("would create missing \".\" entry in dir ino %" PRIu64 "\n"),
ino);
- } else if (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) {
+ } else if (ip->i_df.if_format != XFS_DINODE_FMT_LOCAL) {
/*
* need to create . entry in longform dir.
*/
}
static void
-traverse_function(
+do_dir_inode(
struct workqueue *wq,
- xfs_agnumber_t agno,
+ xfs_agnumber_t agno,
void *arg)
{
- ino_tree_node_t *irec;
+ struct ino_tree_node *irec = arg;
int i;
+
+ for (i = 0; i < XFS_INODES_PER_CHUNK; i++) {
+ if (inode_isadir(irec, i))
+ process_dir_inode(wq->wq_ctx, agno, irec, i);
+ }
+}
+
+static void
+traverse_function(
+ struct workqueue *wq,
+ xfs_agnumber_t agno,
+ void *arg)
+{
+ struct ino_tree_node *irec;
prefetch_args_t *pf_args = arg;
+ struct workqueue lwq;
+ struct xfs_mount *mp = wq->wq_ctx;
wait_for_inode_prefetch(pf_args);
if (verbose)
do_log(_(" - agno = %d\n"), agno);
+ /*
+ * The more AGs we have in flight at once, the fewer processing threads
+ * per AG. This means we don't overwhelm the machine with hundreds of
+ * threads when we start acting on lots of AGs at once. We just want
+ * enough that we can keep multiple CPUs busy across multiple AGs.
+ */
+ workqueue_create_bound(&lwq, mp, ag_stride, 1000);
+
for (irec = findfirst_inode_rec(agno); irec; irec = next_ino_rec(irec)) {
if (irec->ino_isa_dir == 0)
continue;
if (pf_args) {
sem_post(&pf_args->ra_count);
#ifdef XR_PF_TRACE
+ {
+ int i;
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->wq_ctx, agno, irec, i);
- }
+ queue_work(&lwq, do_dir_inode, agno, irec);
}
+ destroy_work_queue(&lwq);
cleanup_inode_prefetch(pf_args);
}
traverse_ags(
struct xfs_mount *mp)
{
- do_inode_prefetch(mp, 0, traverse_function, false, true);
+ do_inode_prefetch(mp, ag_stride, traverse_function, false, true);
}
void