@@ -50,6 +50,7 @@ struct iomap;
* This mirrors the kernel include for xfs_buf.h - it's implicitly included in
* every files via a similar include in the kernel xfs_linux.h.
*/
+#include "xfs_buftarg.h"
#include "libxfs_io.h"
#include "xfs_bit.h"
@@ -67,7 +67,6 @@ typedef struct xfs_inode {
struct xfs_mount *i_mount; /* fs mount struct ptr */
xfs_ino_t i_ino; /* inode number (agno/agino) */
struct xfs_imap i_imap; /* location for xfs_imap() */
- struct xfs_buftarg i_dev; /* dev for this inode */
struct xfs_ifork *i_afp; /* attribute fork pointer */
struct xfs_ifork *i_cowfp; /* copy on write extents */
struct xfs_ifork i_df; /* data fork */
@@ -129,7 +129,19 @@ platform_check_iswritable(char *name, char *block, struct stat *s)
int
platform_set_blocksize(int fd, char *path, dev_t device, int blocksize, int fatal)
{
- int error = 0;
+ struct stat st;
+ int error = 0;
+
+ if (fstat(fd, &st) < 0) {
+ fprintf(stderr, _("%s: "
+ "cannot stat the device file \"%s\": %s\n"),
+ progname, path, strerror(errno));
+ exit(1);
+ }
+
+ /* Can't set block sizes on image files. */
+ if ((st.st_mode & S_IFMT) != S_IFBLK)
+ return 0;
if (major(device) != RAMDISK_MAJOR) {
if ((error = ioctl(fd, BLKBSZSET, &blocksize)) < 0) {
@@ -30,6 +30,7 @@ HFILES = \
xfs_bmap_btree.h \
xfs_btree.h \
xfs_btree_staging.h \
+ xfs_buftarg.h \
xfs_attr_remote.h \
xfs_cksum.h \
xfs_da_btree.h \
@@ -54,7 +55,8 @@ HFILES = \
libxfs_priv.h \
xfs_dir2_priv.h
-CFILES = cache.c \
+CFILES = buftarg.c \
+ cache.c \
defer_item.c \
init.c \
kmem.c \
new file mode 100644
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
+ * Copyright (c) 2019 Red Hat, Inc.
+ * All Rights Reserved.
+ */
+
+#include "libxfs_priv.h"
+#include "libfrog/platform.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_shared.h"
+#include "xfs_trans_resv.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_trace.h"
+#include "xfs_errortag.h"
+
+#include "libxfs.h" /* for libxfs_device_to_fd */
+
+int
+xfs_buftarg_setsize(
+ struct xfs_buftarg *btp,
+ unsigned int sectorsize)
+{
+ long long size;
+ int bsize;
+
+ /* Set up metadata sector size info */
+ btp->bt_meta_sectorsize = sectorsize;
+ btp->bt_meta_sectormask = sectorsize - 1;
+
+ if (platform_set_blocksize(btp->bt_fd, NULL, btp->bt_bdev,
+ sectorsize, true)) {
+ xfs_warn(btp->bt_mount,
+ "Cannot set_blocksize to %u on device %pg",
+ sectorsize, btp->bt_bdev);
+ return -EINVAL;
+ }
+
+ /* Set up device logical sector size mask */
+ platform_findsizes(NULL, btp->bt_fd, &size, &bsize);
+ btp->bt_logical_sectorsize = bsize;
+ btp->bt_logical_sectormask = bsize - 1;
+
+ return 0;
+}
+
+/*
+ * When allocating the initial buffer target we have not yet read in the
+ * superblock, so don't know what sized sectors are being used at this early
+ * stage. Play safe.
+ */
+STATIC int
+xfs_buftarg_setsize_early(
+ struct xfs_buftarg *btp)
+{
+ long long size;
+ int bsize;
+
+ platform_findsizes(NULL, btp->bt_fd, &size, &bsize);
+ return xfs_buftarg_setsize(btp, bsize);
+}
+
+struct xfs_buftarg *
+xfs_buftarg_alloc(
+ struct xfs_mount *mp,
+ dev_t bdev)
+{
+ struct xfs_buftarg *btp;
+
+ btp = kmem_zalloc(sizeof(*btp), KM_NOFS);
+
+ btp->bt_mount = mp;
+ btp->bt_fd = libxfs_device_to_fd(bdev);
+ btp->bt_bdev = bdev;
+
+ if (xfs_buftarg_setsize_early(btp))
+ goto error_free;
+
+ if (percpu_counter_init(&btp->bt_io_count, 0, GFP_KERNEL))
+ goto error_free;
+
+ return btp;
+
+error_free:
+ free(btp);
+ return NULL;
+}
+
+void
+xfs_buftarg_free(
+ struct xfs_buftarg *btp)
+{
+ ASSERT(percpu_counter_sum(&btp->bt_io_count) == 0);
+ percpu_counter_destroy(&btp->bt_io_count);
+ platform_flush_device(btp->bt_fd, btp->bt_bdev);
+ free(btp);
+}
@@ -590,26 +590,6 @@ out_unwind:
return error;
}
-static struct xfs_buftarg *
-libxfs_buftarg_alloc(
- struct xfs_mount *mp,
- dev_t dev)
-{
- struct xfs_buftarg *btp;
-
- btp = malloc(sizeof(*btp));
- if (!btp) {
- fprintf(stderr, _("%s: buftarg init failed\n"),
- progname);
- exit(1);
- }
- btp->bt_mount = mp;
- btp->bt_bdev = dev;
- btp->flags = 0;
-
- return btp;
-}
-
void
libxfs_buftarg_init(
struct xfs_mount *mp,
@@ -650,12 +630,24 @@ libxfs_buftarg_init(
return;
}
- mp->m_ddev_targp = libxfs_buftarg_alloc(mp, dev);
+ mp->m_ddev_targp = xfs_buftarg_alloc(mp, dev);
+ if (!mp->m_ddev_targp)
+ goto out_fail;
if (!logdev || logdev == dev)
mp->m_logdev_targp = mp->m_ddev_targp;
else
- mp->m_logdev_targp = libxfs_buftarg_alloc(mp, logdev);
- mp->m_rtdev_targp = libxfs_buftarg_alloc(mp, rtdev);
+ mp->m_logdev_targp = xfs_buftarg_alloc(mp, logdev);
+ if (!mp->m_logdev_targp)
+ goto out_fail;
+ if (rtdev) {
+ mp->m_rtdev_targp = xfs_buftarg_alloc(mp, rtdev);
+ if (!mp->m_rtdev_targp)
+ goto out_fail;
+ }
+ return;
+out_fail:
+ fprintf(stderr, _("%s: Failed to allocate buftarg\n"), progname);
+ exit(1);
}
/*
@@ -14,25 +14,10 @@
struct xfs_buf;
struct xfs_mount;
struct xfs_perag;
+struct xfs_buftarg;
-/*
- * IO verifier callbacks need the xfs_mount pointer, so we have to behave
- * somewhat like the kernel now for userspace IO in terms of having buftarg
- * based devices...
- */
-struct xfs_buftarg {
- struct xfs_mount *bt_mount;
- dev_t bt_bdev;
- unsigned int flags;
-};
-
-/* We purged a dirty buffer and lost a write. */
-#define XFS_BUFTARG_LOST_WRITE (1 << 0)
-/* A dirty buffer failed the write verifier. */
-#define XFS_BUFTARG_CORRUPT_WRITE (1 << 1)
-
-extern void libxfs_buftarg_init(struct xfs_mount *mp, dev_t ddev,
- dev_t logdev, dev_t rtdev);
+void libxfs_buftarg_init(struct xfs_mount *mp, dev_t ddev,
+ dev_t logdev, dev_t rtdev);
int libxfs_blkdev_issue_flush(struct xfs_buftarg *btp);
#define LIBXFS_BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT)
@@ -85,6 +85,7 @@ struct iomap;
* This mirrors the kernel include for xfs_buf.h - it's implicitly included in
* every files via a similar include in the kernel xfs_linux.h.
*/
+#include "xfs_buftarg.h"
#include "libxfs_io.h"
/* for all the support code that uses progname in error messages */
@@ -201,6 +202,8 @@ static inline bool WARN_ON(bool expr) {
}
#define WARN_ON_ONCE(e) WARN_ON(e)
+#define percpu_counter_init(x,v,gfp) (*x = v)
+#define percpu_counter_destroy(x) ((void) 0)
#define percpu_counter_read(x) (*x)
#define percpu_counter_read_positive(x) ((*x) > 0 ? (*x) : 0)
#define percpu_counter_sum(x) (*x)
new file mode 100644
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2019 Red Hat, Inc.
+ * All Rights Reserved.
+ */
+#ifndef __XFS_BUFTARG_H
+#define __XFS_BUFTARG_H
+
+struct xfs_mount;
+struct xfs_buf;
+struct xfs_buf_ops;
+
+/*
+ * The xfs_buftarg contains 2 notions of "sector size" -
+ *
+ * 1) The metadata sector size, which is the minimum unit and
+ * alignment of IO which will be performed by metadata operations.
+ * 2) The device logical sector size
+ *
+ * The first is specified at mkfs time, and is stored on-disk in the
+ * superblock's sb_sectsize.
+ *
+ * The latter is derived from the underlying device, and controls direct IO
+ * alignment constraints.
+ */
+struct xfs_buftarg {
+ dev_t bt_bdev;
+ int bt_fd; /* for read/write IO */
+ struct xfs_mount *bt_mount;
+ unsigned int bt_meta_sectorsize;
+ size_t bt_meta_sectormask;
+ size_t bt_logical_sectorsize;
+ size_t bt_logical_sectormask;
+
+ uint32_t bt_io_count;
+ unsigned int flags;
+};
+
+/* We purged a dirty buffer and lost a write. */
+#define XFS_BUFTARG_LOST_WRITE (1 << 0)
+/* A dirty buffer failed the write verifier. */
+#define XFS_BUFTARG_CORRUPT_WRITE (1 << 1)
+
+/*
+ * Handling of buftargs.
+ */
+struct xfs_buftarg *xfs_buftarg_alloc(struct xfs_mount *mp, dev_t bdev);
+void xfs_buftarg_free(struct xfs_buftarg *target);
+void xfs_buftarg_wait(struct xfs_buftarg *target);
+int xfs_buftarg_setsize(struct xfs_buftarg *target, unsigned int size);
+
+#define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev)
+
+#endif /* __XFS_BUFTARG_H */
@@ -2660,6 +2660,16 @@ _("size %lld of data subvolume is too small, minimum %lld blocks\n"),
reported by the device (%u).\n"),
cfg->sectorsize, xi->dbsize);
}
+
+ if (xi->disfile &&
+ xi->dsize * xi->dbsize < cfg->dblocks * cfg->blocksize) {
+ if (ftruncate(xi->dfd, cfg->dblocks * cfg->blocksize) < 0) {
+ fprintf(stderr,
+ _("%s: Growing the data section failed\n"),
+ progname);
+ exit(1);
+ }
+ }
}
/*
@@ -3185,6 +3195,7 @@ calculate_log_size(
struct cli_params *cli,
struct xfs_mount *mp)
{
+ struct libxfs_xinit *xi = cli->xi;
struct xfs_sb *sbp = &mp->m_sb;
int min_logblocks;
struct xfs_mount mount;
@@ -3192,7 +3203,7 @@ calculate_log_size(
/* we need a temporary mount to calculate the minimum log size. */
memset(&mount, 0, sizeof(mount));
mount.m_sb = *sbp;
- libxfs_mount(&mount, &mp->m_sb, 0, 0, 0, 0);
+ libxfs_mount(&mount, &mp->m_sb, xi->ddev, xi->logdev, xi->rtdev, 0);
min_logblocks = libxfs_log_calc_minimum_size(&mount);
libxfs_umount(&mount);
@@ -3352,8 +3363,10 @@ start_superblock_setup(
} else
sbp->sb_logsunit = 0;
- /* log reservation calculations depend on rt geometry */
+ /* log reservation calculations depends on geometry */
+ sbp->sb_dblocks = cfg->dblocks;
sbp->sb_rblocks = cfg->rtblocks;
+ sbp->sb_rextents = cfg->rtextents;
sbp->sb_rextsize = cfg->rtextblocks;
}
@@ -3390,8 +3403,6 @@ finish_superblock_setup(
memcpy(sbp->sb_fname, cfg->label, label_len);
}
- sbp->sb_dblocks = cfg->dblocks;
- sbp->sb_rextents = cfg->rtextents;
platform_uuid_copy(&sbp->sb_uuid, &cfg->uuid);
/* Only in memory; libxfs expects this as if read from disk */
platform_uuid_copy(&sbp->sb_meta_uuid, &cfg->uuid);
@@ -3414,7 +3425,6 @@ finish_superblock_setup(
sbp->sb_qflags = 0;
sbp->sb_unit = cfg->dsunit;
sbp->sb_width = cfg->dswidth;
-
}
/* Prepare an uncached buffer, ready to write something out. */
@@ -3524,7 +3534,8 @@ prepare_devices(
lsunit, XLOG_FMT, XLOG_INIT_CYCLE, false);
/* finally, check we can write the last block in the realtime area */
- if (mp->m_rtdev_targp->bt_bdev && cfg->rtblocks > 0) {
+ if (mp->m_rtdev_targp && mp->m_rtdev_targp->bt_bdev &&
+ cfg->rtblocks > 0) {
buf = alloc_write_buf(mp->m_rtdev_targp,
XFS_FSB_TO_BB(mp, cfg->rtblocks - 1LL),
BTOBB(cfg->blocksize));