summaryrefslogtreecommitdiffstats
path: root/libblkid/src/superblocks/gfs.c
blob: 18d978aa28c1e36e7b7e90ef42833f574e3589e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
 *
 * This file may be redistributed under the terms of the
 * GNU Lesser General Public License.
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>

#include "superblocks.h"

/* Common gfs/gfs2 constants: */
#define GFS_LOCKNAME_LEN        64

/* gfs1 constants: */
#define GFS_FORMAT_FS           1309
#define GFS_FORMAT_MULTI        1401

struct gfs2_meta_header {
	uint32_t mh_magic;
	uint32_t mh_type;
	uint64_t __pad0;          /* Was generation number in gfs1 */
	uint32_t mh_format;
	uint32_t __pad1;          /* Was incarnation number in gfs1 */
};

struct gfs2_inum {
	uint64_t no_formal_ino;
	uint64_t no_addr;
};

struct gfs2_sb {
	struct gfs2_meta_header sb_header;

	uint32_t sb_fs_format;
	uint32_t sb_multihost_format;
	uint32_t  __pad0;  /* Was superblock flags in gfs1 */

	uint32_t sb_bsize;
	uint32_t sb_bsize_shift;
	uint32_t __pad1;   /* Was journal segment size in gfs1 */

	struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */
	struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */
	struct gfs2_inum sb_root_dir;

	char sb_lockproto[GFS_LOCKNAME_LEN];
	char sb_locktable[GFS_LOCKNAME_LEN];

	struct gfs2_inum __pad3; /* Was quota inode in gfs1 */
	struct gfs2_inum __pad4; /* Was license inode in gfs1 */
	uint8_t sb_uuid[16]; /* The UUID maybe 0 for backwards compat */
} __attribute__((packed));



static int probe_gfs(blkid_probe pr, const struct blkid_idmag *mag)
{
	const struct gfs2_sb *sbd;

	sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb);
	if (!sbd)
		return errno ? -errno : 1;

	if (be32_to_cpu(sbd->sb_fs_format) == GFS_FORMAT_FS &&
	    be32_to_cpu(sbd->sb_multihost_format) == GFS_FORMAT_MULTI)
	{
		if (*sbd->sb_locktable)
			blkid_probe_set_label(pr,
				(unsigned char *) sbd->sb_locktable,
				sizeof(sbd->sb_locktable));

		blkid_probe_set_uuid(pr, sbd->sb_uuid);
		return 0;
	}

	return 1;
}

static inline int gfs2_format_is_valid(uint32_t format)
{
	return (format >= 1800 && format < 1900);
}
static inline int gfs2_multiformat_is_valid(uint32_t multi)
{
	return (multi >= 1900 && multi < 2000);
}

static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag)
{
	const struct gfs2_sb *sbd;

	sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb);
	if (!sbd)
		return errno ? -errno : 1;

	if (gfs2_format_is_valid(be32_to_cpu(sbd->sb_fs_format)) &&
	    gfs2_multiformat_is_valid(be32_to_cpu(sbd->sb_multihost_format)))
	{
		if (*sbd->sb_locktable)
			blkid_probe_set_label(pr,
				(unsigned char *) sbd->sb_locktable,
				sizeof(sbd->sb_locktable));
		blkid_probe_set_uuid(pr, sbd->sb_uuid);
		blkid_probe_set_version(pr, "1");
		blkid_probe_set_fsblocksize(pr, be32_to_cpu(sbd->sb_bsize));
		blkid_probe_set_block_size(pr, be32_to_cpu(sbd->sb_bsize));
		return 0;
	}
	return 1;
}

const struct blkid_idinfo gfs_idinfo =
{
	.name		= "gfs",
	.usage		= BLKID_USAGE_FILESYSTEM,
	.probefunc	= probe_gfs,
	.minsz		= 32 * 1024 * 1024,	/* minimal size of GFS journal */
	.magics		=
	{
		{ .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 },
		{ NULL }
	}
};

const struct blkid_idinfo gfs2_idinfo =
{
	.name		= "gfs2",
	.usage		= BLKID_USAGE_FILESYSTEM,
	.probefunc	= probe_gfs2,
	.minsz		= 32 * 1024 * 1024,	/* minimal size of GFS journal */
	.magics		=
	{
		{ .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 },
		{ NULL }
	}
};