From: Eric Sandeen <sandeen@redhat.com>
To: Boris Ranto <branto@redhat.com>
Cc: xfs-oss <xfs@oss.sgi.com>
Subject: [PATCH] mkfs.xfs: fix protofile name create block reservation
Date: Wed, 07 Aug 2013 01:00:43 -0500 [thread overview]
Message-ID: <5201E28B.1050800@redhat.com> (raw)
A large protofile which creates a large directory and requires
a a dir tree split, can fail:
mkfs.xfs: directory createname error [28 - No space left on device]
This is because when we've split a block once, we decrement args->total:
(see kernel commit a7444053fb3ebd3d905e3c7a7bd5ea80a54b083a for the
rationale)
/* account for newly allocated blocks in reserved blocks total */
args->total -= dp->i_d.di_nblocks - nblks;
but every call into this path from proto file parsing started
reserved / args->total as only "1" as passed tro newdirent() -
so if we allocate a block, args->total hits 0, and then in
xfs_dir2_node_addname():
/*
* Add the new leaf entry.
*/
rval = xfs_dir2_leafn_add(blk->bp, args, blk->index);
if (rval == 0) {
...
} else {
/*
* It didn't work, we need to split the leaf block.
*/
if (args->total == 0) {
ASSERT(rval == ENOSPC);
goto done;
}
/*
* Split the leaf block and insert the new entry.
*/
we hit the args->total == 0 special case, and don't do the next
split, and ENOSPC gets returned all the way up, and we fail.
So rather than calling newdirent with a total of "1" in every case,
which doesn't account for possible tree splits, we should call it
with a more appropriate value: XFS_DIRENTER_SPACE_RES(mp, name->len),
which will handle the maximum nr of block allocations that might be
needed during a directory entry insert.
Since the reservation required doesn't depend on entry type,
just push this down a level, into newdirent() itself.
Reported-by: Boris Ranto <branto@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
diff --git a/mkfs/proto.c b/mkfs/proto.c
index f201096..7d96b46 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -306,12 +306,14 @@ newdirent(
struct xfs_name *name,
xfs_ino_t inum,
xfs_fsblock_t *first,
- xfs_bmap_free_t *flist,
- xfs_extlen_t total)
+ xfs_bmap_free_t *flist)
{
int error;
+ int rsv;
+
+ rsv = XFS_DIRENTER_SPACE_RES(mp, name->len);
- error = libxfs_dir_createname(tp, pip, name, inum, first, flist, total);
+ error = libxfs_dir_createname(tp, pip, name, inum, first, flist, rsv);
if (error)
fail(_("directory createname error"), error);
}
@@ -449,7 +451,7 @@ parseproto(
if (buf)
free(buf);
libxfs_trans_ijoin(tp, pip, 0);
- newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist, 1);
+ newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
libxfs_trans_ihold(tp, pip);
break;
@@ -465,7 +467,7 @@ parseproto(
libxfs_trans_ijoin(tp, pip, 0);
- newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist, 1);
+ newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
libxfs_trans_ihold(tp, pip);
libxfs_trans_log_inode(tp, ip, flags);
@@ -486,7 +488,7 @@ parseproto(
fail(_("Inode allocation failed"), error);
}
libxfs_trans_ijoin(tp, pip, 0);
- newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist, 1);
+ newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
libxfs_trans_ihold(tp, pip);
flags |= XFS_ILOG_DEV;
break;
@@ -500,7 +502,7 @@ parseproto(
if (error)
fail(_("Inode allocation failed"), error);
libxfs_trans_ijoin(tp, pip, 0);
- newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist, 1);
+ newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
libxfs_trans_ihold(tp, pip);
flags |= XFS_ILOG_DEV;
break;
@@ -512,7 +514,7 @@ parseproto(
if (error)
fail(_("Inode allocation failed"), error);
libxfs_trans_ijoin(tp, pip, 0);
- newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist, 1);
+ newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
libxfs_trans_ihold(tp, pip);
break;
case IF_SYMLINK:
@@ -525,7 +527,7 @@ parseproto(
fail(_("Inode allocation failed"), error);
flags |= newfile(tp, ip, &flist, &first, 1, 1, buf, len);
libxfs_trans_ijoin(tp, pip, 0);
- newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist, 1);
+ newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &flist);
libxfs_trans_ihold(tp, pip);
break;
case IF_DIRECTORY:
@@ -544,7 +546,7 @@ parseproto(
} else {
libxfs_trans_ijoin(tp, pip, 0);
newdirent(mp, tp, pip, &xname, ip->i_ino,
- &first, &flist, 1);
+ &first, &flist);
pip->i_d.di_nlink++;
libxfs_trans_ihold(tp, pip);
libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE);
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
next reply other threads:[~2013-08-07 6:00 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-07 6:00 Eric Sandeen [this message]
2013-08-07 20:19 ` [PATCH] mkfs.xfs: fix protofile name create block reservation Mark Tinguely
2013-08-07 20:42 ` Eric Sandeen
2013-08-09 13:34 ` Mark Tinguely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5201E28B.1050800@redhat.com \
--to=sandeen@redhat.com \
--cc=branto@redhat.com \
--cc=xfs@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox