aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/partitions/Kconfig251
-rw-r--r--fs/partitions/Makefile20
-rw-r--r--fs/partitions/acorn.c556
-rw-r--r--fs/partitions/acorn.h14
-rw-r--r--fs/partitions/amiga.c139
-rw-r--r--fs/partitions/amiga.h6
-rw-r--r--fs/partitions/atari.c149
-rw-r--r--fs/partitions/atari.h34
-rw-r--r--fs/partitions/check.c698
-rw-r--r--fs/partitions/check.h49
-rw-r--r--fs/partitions/efi.c686
-rw-r--r--fs/partitions/efi.h134
-rw-r--r--fs/partitions/ibm.c275
-rw-r--r--fs/partitions/ibm.h1
-rw-r--r--fs/partitions/karma.c57
-rw-r--r--fs/partitions/karma.h8
-rw-r--r--fs/partitions/ldm.c1568
-rw-r--r--fs/partitions/ldm.h215
-rw-r--r--fs/partitions/mac.c134
-rw-r--r--fs/partitions/mac.h44
-rw-r--r--fs/partitions/msdos.c552
-rw-r--r--fs/partitions/msdos.h8
-rw-r--r--fs/partitions/osf.c86
-rw-r--r--fs/partitions/osf.h7
-rw-r--r--fs/partitions/sgi.c82
-rw-r--r--fs/partitions/sgi.h8
-rw-r--r--fs/partitions/sun.c122
-rw-r--r--fs/partitions/sun.h8
-rw-r--r--fs/partitions/sysv68.c95
-rw-r--r--fs/partitions/sysv68.h1
-rw-r--r--fs/partitions/ultrix.c48
-rw-r--r--fs/partitions/ultrix.h5
-rw-r--r--fs/xfs/xfs_fs_subr.c96
-rw-r--r--fs/xfs/xfs_iget.c720
-rw-r--r--fs/xfs/xfs_qm_stats.c105
-rw-r--r--fs/xfs/xfs_qm_stats.h53
-rw-r--r--fs/xfs/xfs_rw.c175
-rw-r--r--fs/xfs/xfs_rw.h49
-rw-r--r--fs/xfs/xfs_sync.c1065
-rw-r--r--fs/xfs/xfs_sync.h51
-rw-r--r--fs/yaffs2/Kconfig161
-rw-r--r--fs/yaffs2/Makefile17
-rw-r--r--fs/yaffs2/yaffs_allocator.c396
-rw-r--r--fs/yaffs2/yaffs_allocator.h30
-rw-r--r--fs/yaffs2/yaffs_attribs.c124
-rw-r--r--fs/yaffs2/yaffs_attribs.h28
-rw-r--r--fs/yaffs2/yaffs_bitmap.c98
-rw-r--r--fs/yaffs2/yaffs_bitmap.h33
-rw-r--r--fs/yaffs2/yaffs_checkptrw.c415
-rw-r--r--fs/yaffs2/yaffs_checkptrw.h33
-rw-r--r--fs/yaffs2/yaffs_ecc.c298
-rw-r--r--fs/yaffs2/yaffs_ecc.h44
-rw-r--r--fs/yaffs2/yaffs_getblockinfo.h35
-rw-r--r--fs/yaffs2/yaffs_guts.c5164
-rw-r--r--fs/yaffs2/yaffs_guts.h915
-rw-r--r--fs/yaffs2/yaffs_linux.h41
-rw-r--r--fs/yaffs2/yaffs_mtdif.c54
-rw-r--r--fs/yaffs2/yaffs_mtdif.h23
-rw-r--r--fs/yaffs2/yaffs_mtdif1.c330
-rw-r--r--fs/yaffs2/yaffs_mtdif1.h29
-rw-r--r--fs/yaffs2/yaffs_mtdif2.c225
-rw-r--r--fs/yaffs2/yaffs_mtdif2.h29
-rw-r--r--fs/yaffs2/yaffs_nameval.c201
-rw-r--r--fs/yaffs2/yaffs_nameval.h28
-rw-r--r--fs/yaffs2/yaffs_nand.c127
-rw-r--r--fs/yaffs2/yaffs_nand.h38
-rw-r--r--fs/yaffs2/yaffs_packedtags1.c53
-rw-r--r--fs/yaffs2/yaffs_packedtags1.h39
-rw-r--r--fs/yaffs2/yaffs_packedtags2.c196
-rw-r--r--fs/yaffs2/yaffs_packedtags2.h47
-rw-r--r--fs/yaffs2/yaffs_tagscompat.c422
-rw-r--r--fs/yaffs2/yaffs_tagscompat.h36
-rw-r--r--fs/yaffs2/yaffs_tagsvalidity.c27
-rw-r--r--fs/yaffs2/yaffs_tagsvalidity.h23
-rw-r--r--fs/yaffs2/yaffs_trace.h57
-rw-r--r--fs/yaffs2/yaffs_verify.c535
-rw-r--r--fs/yaffs2/yaffs_verify.h43
-rw-r--r--fs/yaffs2/yaffs_vfs.c2790
-rw-r--r--fs/yaffs2/yaffs_yaffs1.c433
-rw-r--r--fs/yaffs2/yaffs_yaffs1.h22
-rw-r--r--fs/yaffs2/yaffs_yaffs2.c1598
-rw-r--r--fs/yaffs2/yaffs_yaffs2.h39
-rw-r--r--fs/yaffs2/yportenv.h70
83 files changed, 23720 insertions, 0 deletions
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
new file mode 100644
index 00000000000..cb5f0a3f1b0
--- /dev/null
+++ b/fs/partitions/Kconfig
@@ -0,0 +1,251 @@
1#
2# Partition configuration
3#
4config PARTITION_ADVANCED
5 bool "Advanced partition selection"
6 help
7 Say Y here if you would like to use hard disks under Linux which
8 were partitioned under an operating system running on a different
9 architecture than your Linux system.
10
11 Note that the answer to this question won't directly affect the
12 kernel: saying N will just cause the configurator to skip all
13 the questions about foreign partitioning schemes.
14
15 If unsure, say N.
16
17config ACORN_PARTITION
18 bool "Acorn partition support" if PARTITION_ADVANCED
19 default y if ARCH_ACORN
20 help
21 Support hard disks partitioned under Acorn operating systems.
22
23config ACORN_PARTITION_CUMANA
24 bool "Cumana partition support" if PARTITION_ADVANCED
25 default y if ARCH_ACORN
26 depends on ACORN_PARTITION
27 help
28 Say Y here if you would like to use hard disks under Linux which
29 were partitioned using the Cumana interface on Acorn machines.
30
31config ACORN_PARTITION_EESOX
32 bool "EESOX partition support" if PARTITION_ADVANCED
33 default y if ARCH_ACORN
34 depends on ACORN_PARTITION
35
36config ACORN_PARTITION_ICS
37 bool "ICS partition support" if PARTITION_ADVANCED
38 default y if ARCH_ACORN
39 depends on ACORN_PARTITION
40 help
41 Say Y here if you would like to use hard disks under Linux which
42 were partitioned using the ICS interface on Acorn machines.
43
44config ACORN_PARTITION_ADFS
45 bool "Native filecore partition support" if PARTITION_ADVANCED
46 default y if ARCH_ACORN
47 depends on ACORN_PARTITION
48 help
49 The Acorn Disc Filing System is the standard file system of the
50 RiscOS operating system which runs on Acorn's ARM-based Risc PC
51 systems and the Acorn Archimedes range of machines. If you say
52 `Y' here, Linux will support disk partitions created under ADFS.
53
54config ACORN_PARTITION_POWERTEC
55 bool "PowerTec partition support" if PARTITION_ADVANCED
56 default y if ARCH_ACORN
57 depends on ACORN_PARTITION
58 help
59 Support reading partition tables created on Acorn machines using
60 the PowerTec SCSI drive.
61
62config ACORN_PARTITION_RISCIX
63 bool "RISCiX partition support" if PARTITION_ADVANCED
64 default y if ARCH_ACORN
65 depends on ACORN_PARTITION
66 help
67 Once upon a time, there was a native Unix port for the Acorn series
68 of machines called RISCiX. If you say 'Y' here, Linux will be able
69 to read disks partitioned under RISCiX.
70
71config OSF_PARTITION
72 bool "Alpha OSF partition support" if PARTITION_ADVANCED
73 default y if ALPHA
74 help
75 Say Y here if you would like to use hard disks under Linux which
76 were partitioned on an Alpha machine.
77
78config AMIGA_PARTITION
79 bool "Amiga partition table support" if PARTITION_ADVANCED
80 default y if (AMIGA || AFFS_FS=y)
81 help
82 Say Y here if you would like to use hard disks under Linux which
83 were partitioned under AmigaOS.
84
85config ATARI_PARTITION
86 bool "Atari partition table support" if PARTITION_ADVANCED
87 default y if ATARI
88 help
89 Say Y here if you would like to use hard disks under Linux which
90 were partitioned under the Atari OS.
91
92config IBM_PARTITION
93 bool "IBM disk label and partition support"
94 depends on PARTITION_ADVANCED && S390
95 help
96 Say Y here if you would like to be able to read the hard disk
97 partition table format used by IBM DASD disks operating under CMS.
98 Otherwise, say N.
99
100config MAC_PARTITION
101 bool "Macintosh partition map support" if PARTITION_ADVANCED
102 default y if (MAC || PPC_PMAC)
103 help
104 Say Y here if you would like to use hard disks under Linux which
105 were partitioned on a Macintosh.
106
107config MSDOS_PARTITION
108 bool "PC BIOS (MSDOS partition tables) support" if PARTITION_ADVANCED
109 default y
110 help
111 Say Y here.
112
113config BSD_DISKLABEL
114 bool "BSD disklabel (FreeBSD partition tables) support"
115 depends on PARTITION_ADVANCED && MSDOS_PARTITION
116 help
117 FreeBSD uses its own hard disk partition scheme on your PC. It
118 requires only one entry in the primary partition table of your disk
119 and manages it similarly to DOS extended partitions, putting in its
120 first sector a new partition table in BSD disklabel format. Saying Y
121 here allows you to read these disklabels and further mount FreeBSD
122 partitions from within Linux if you have also said Y to "UFS
123 file system support", above. If you don't know what all this is
124 about, say N.
125
126config MINIX_SUBPARTITION
127 bool "Minix subpartition support"
128 depends on PARTITION_ADVANCED && MSDOS_PARTITION
129 help
130 Minix 2.0.0/2.0.2 subpartition table support for Linux.
131 Say Y here if you want to mount and use Minix 2.0.0/2.0.2
132 subpartitions.
133
134config SOLARIS_X86_PARTITION
135 bool "Solaris (x86) partition table support"
136 depends on PARTITION_ADVANCED && MSDOS_PARTITION
137 help
138 Like most systems, Solaris x86 uses its own hard disk partition
139 table format, incompatible with all others. Saying Y here allows you
140 to read these partition tables and further mount Solaris x86
141 partitions from within Linux if you have also said Y to "UFS
142 file system support", above.
143
144config UNIXWARE_DISKLABEL
145 bool "Unixware slices support"
146 depends on PARTITION_ADVANCED && MSDOS_PARTITION
147 ---help---
148 Like some systems, UnixWare uses its own slice table inside a
149 partition (VTOC - Virtual Table of Contents). Its format is
150 incompatible with all other OSes. Saying Y here allows you to read
151 VTOC and further mount UnixWare partitions read-only from within
152 Linux if you have also said Y to "UFS file system support" or
153 "System V and Coherent file system support", above.
154
155 This is mainly used to carry data from a UnixWare box to your
156 Linux box via a removable medium like magneto-optical, ZIP or
157 removable IDE drives. Note, however, that a good portable way to
158 transport files and directories between unixes (and even other
159 operating systems) is given by the tar program ("man tar" or
160 preferably "info tar").
161
162 If you don't know what all this is about, say N.
163
164config LDM_PARTITION
165 bool "Windows Logical Disk Manager (Dynamic Disk) support"
166 depends on PARTITION_ADVANCED
167 ---help---
168 Say Y here if you would like to use hard disks under Linux which
169 were partitioned using Windows 2000's/XP's or Vista's Logical Disk
170 Manager. They are also known as "Dynamic Disks".
171
172 Note this driver only supports Dynamic Disks with a protective MBR
173 label, i.e. DOS partition table. It does not support GPT labelled
174 Dynamic Disks yet as can be created with Vista.
175
176 Windows 2000 introduced the concept of Dynamic Disks to get around
177 the limitations of the PC's partitioning scheme. The Logical Disk
178 Manager allows the user to repartition a disk and create spanned,
179 mirrored, striped or RAID volumes, all without the need for
180 rebooting.
181
182 Normal partitions are now called Basic Disks under Windows 2000, XP,
183 and Vista.
184
185 For a fuller description read <file:Documentation/ldm.txt>.
186
187 If unsure, say N.
188
189config LDM_DEBUG
190 bool "Windows LDM extra logging"
191 depends on LDM_PARTITION
192 help
193 Say Y here if you would like LDM to log verbosely. This could be
194 helpful if the driver doesn't work as expected and you'd like to
195 report a bug.
196
197 If unsure, say N.
198
199config SGI_PARTITION
200 bool "SGI partition support" if PARTITION_ADVANCED
201 default y if DEFAULT_SGI_PARTITION
202 help
203 Say Y here if you would like to be able to read the hard disk
204 partition table format used by SGI machines.
205
206config ULTRIX_PARTITION
207 bool "Ultrix partition table support" if PARTITION_ADVANCED
208 default y if MACH_DECSTATION
209 help
210 Say Y here if you would like to be able to read the hard disk
211 partition table format used by DEC (now Compaq) Ultrix machines.
212 Otherwise, say N.
213
214config SUN_PARTITION
215 bool "Sun partition tables support" if PARTITION_ADVANCED
216 default y if (SPARC || SUN3 || SUN3X)
217 ---help---
218 Like most systems, SunOS uses its own hard disk partition table
219 format, incompatible with all others. Saying Y here allows you to
220 read these partition tables and further mount SunOS partitions from
221 within Linux if you have also said Y to "UFS file system support",
222 above. This is mainly used to carry data from a SPARC under SunOS to
223 your Linux box via a removable medium like magneto-optical or ZIP
224 drives; note however that a good portable way to transport files and
225 directories between unixes (and even other operating systems) is
226 given by the tar program ("man tar" or preferably "info tar"). If
227 you don't know what all this is about, say N.
228
229config KARMA_PARTITION
230 bool "Karma Partition support"
231 depends on PARTITION_ADVANCED
232 help
233 Say Y here if you would like to mount the Rio Karma MP3 player, as it
234 uses a proprietary partition table.
235
236config EFI_PARTITION
237 bool "EFI GUID Partition support"
238 depends on PARTITION_ADVANCED
239 select CRC32
240 help
241 Say Y here if you would like to use hard disks under Linux which
242 were partitioned using EFI GPT.
243
244config SYSV68_PARTITION
245 bool "SYSV68 partition table support" if PARTITION_ADVANCED
246 default y if VME
247 help
248 Say Y here if you would like to be able to read the hard disk
249 partition table format used by Motorola Delta machines (using
250 sysv68).
251 Otherwise, say N.
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
new file mode 100644
index 00000000000..03af8eac51d
--- /dev/null
+++ b/fs/partitions/Makefile
@@ -0,0 +1,20 @@
1#
2# Makefile for the linux kernel.
3#
4
5obj-$(CONFIG_BLOCK) := check.o
6
7obj-$(CONFIG_ACORN_PARTITION) += acorn.o
8obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
9obj-$(CONFIG_ATARI_PARTITION) += atari.o
10obj-$(CONFIG_MAC_PARTITION) += mac.o
11obj-$(CONFIG_LDM_PARTITION) += ldm.o
12obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
13obj-$(CONFIG_OSF_PARTITION) += osf.o
14obj-$(CONFIG_SGI_PARTITION) += sgi.o
15obj-$(CONFIG_SUN_PARTITION) += sun.o
16obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
17obj-$(CONFIG_IBM_PARTITION) += ibm.o
18obj-$(CONFIG_EFI_PARTITION) += efi.o
19obj-$(CONFIG_KARMA_PARTITION) += karma.o
20obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
new file mode 100644
index 00000000000..fbeb697374d
--- /dev/null
+++ b/fs/partitions/acorn.c
@@ -0,0 +1,556 @@
1/*
2 * linux/fs/partitions/acorn.c
3 *
4 * Copyright (c) 1996-2000 Russell King.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Scan ADFS partitions on hard disk drives. Unfortunately, there
11 * isn't a standard for partitioning drives on Acorn machines, so
12 * every single manufacturer of SCSI and IDE cards created their own
13 * method.
14 */
15#include <linux/buffer_head.h>
16#include <linux/adfs_fs.h>
17
18#include "check.h"
19#include "acorn.h"
20
21/*
22 * Partition types. (Oh for reusability)
23 */
24#define PARTITION_RISCIX_MFM 1
25#define PARTITION_RISCIX_SCSI 2
26#define PARTITION_LINUX 9
27
28#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
29 defined(CONFIG_ACORN_PARTITION_ADFS)
30static struct adfs_discrecord *
31adfs_partition(struct parsed_partitions *state, char *name, char *data,
32 unsigned long first_sector, int slot)
33{
34 struct adfs_discrecord *dr;
35 unsigned int nr_sects;
36
37 if (adfs_checkbblk(data))
38 return NULL;
39
40 dr = (struct adfs_discrecord *)(data + 0x1c0);
41
42 if (dr->disc_size == 0 && dr->disc_size_high == 0)
43 return NULL;
44
45 nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) |
46 (le32_to_cpu(dr->disc_size) >> 9);
47
48 if (name) {
49 strlcat(state->pp_buf, " [", PAGE_SIZE);
50 strlcat(state->pp_buf, name, PAGE_SIZE);
51 strlcat(state->pp_buf, "]", PAGE_SIZE);
52 }
53 put_partition(state, slot, first_sector, nr_sects);
54 return dr;
55}
56#endif
57
58#ifdef CONFIG_ACORN_PARTITION_RISCIX
59
60struct riscix_part {
61 __le32 start;
62 __le32 length;
63 __le32 one;
64 char name[16];
65};
66
67struct riscix_record {
68 __le32 magic;
69#define RISCIX_MAGIC cpu_to_le32(0x4a657320)
70 __le32 date;
71 struct riscix_part part[8];
72};
73
74#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
75 defined(CONFIG_ACORN_PARTITION_ADFS)
76static int riscix_partition(struct parsed_partitions *state,
77 unsigned long first_sect, int slot,
78 unsigned long nr_sects)
79{
80 Sector sect;
81 struct riscix_record *rr;
82
83 rr = read_part_sector(state, first_sect, &sect);
84 if (!rr)
85 return -1;
86
87 strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE);
88
89
90 if (rr->magic == RISCIX_MAGIC) {
91 unsigned long size = nr_sects > 2 ? 2 : nr_sects;
92 int part;
93
94 strlcat(state->pp_buf, " <", PAGE_SIZE);
95
96 put_partition(state, slot++, first_sect, size);
97 for (part = 0; part < 8; part++) {
98 if (rr->part[part].one &&
99 memcmp(rr->part[part].name, "All\0", 4)) {
100 put_partition(state, slot++,
101 le32_to_cpu(rr->part[part].start),
102 le32_to_cpu(rr->part[part].length));
103 strlcat(state->pp_buf, "(", PAGE_SIZE);
104 strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE);
105 strlcat(state->pp_buf, ")", PAGE_SIZE);
106 }
107 }
108
109 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
110 } else {
111 put_partition(state, slot++, first_sect, nr_sects);
112 }
113
114 put_dev_sector(sect);
115 return slot;
116}
117#endif
118#endif
119
120#define LINUX_NATIVE_MAGIC 0xdeafa1de
121#define LINUX_SWAP_MAGIC 0xdeafab1e
122
123struct linux_part {
124 __le32 magic;
125 __le32 start_sect;
126 __le32 nr_sects;
127};
128
129#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
130 defined(CONFIG_ACORN_PARTITION_ADFS)
131static int linux_partition(struct parsed_partitions *state,
132 unsigned long first_sect, int slot,
133 unsigned long nr_sects)
134{
135 Sector sect;
136 struct linux_part *linuxp;
137 unsigned long size = nr_sects > 2 ? 2 : nr_sects;
138
139 strlcat(state->pp_buf, " [Linux]", PAGE_SIZE);
140
141 put_partition(state, slot++, first_sect, size);
142
143 linuxp = read_part_sector(state, first_sect, &sect);
144 if (!linuxp)
145 return -1;
146
147 strlcat(state->pp_buf, " <", PAGE_SIZE);
148 while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) ||
149 linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) {
150 if (slot == state->limit)
151 break;
152 put_partition(state, slot++, first_sect +
153 le32_to_cpu(linuxp->start_sect),
154 le32_to_cpu(linuxp->nr_sects));
155 linuxp ++;
156 }
157 strlcat(state->pp_buf, " >", PAGE_SIZE);
158
159 put_dev_sector(sect);
160 return slot;
161}
162#endif
163
164#ifdef CONFIG_ACORN_PARTITION_CUMANA
165int adfspart_check_CUMANA(struct parsed_partitions *state)
166{
167 unsigned long first_sector = 0;
168 unsigned int start_blk = 0;
169 Sector sect;
170 unsigned char *data;
171 char *name = "CUMANA/ADFS";
172 int first = 1;
173 int slot = 1;
174
175 /*
176 * Try Cumana style partitions - sector 6 contains ADFS boot block
177 * with pointer to next 'drive'.
178 *
179 * There are unknowns in this code - is the 'cylinder number' of the
180 * next partition relative to the start of this one - I'm assuming
181 * it is.
182 *
183 * Also, which ID did Cumana use?
184 *
185 * This is totally unfinished, and will require more work to get it
186 * going. Hence it is totally untested.
187 */
188 do {
189 struct adfs_discrecord *dr;
190 unsigned int nr_sects;
191
192 data = read_part_sector(state, start_blk * 2 + 6, &sect);
193 if (!data)
194 return -1;
195
196 if (slot == state->limit)
197 break;
198
199 dr = adfs_partition(state, name, data, first_sector, slot++);
200 if (!dr)
201 break;
202
203 name = NULL;
204
205 nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) *
206 (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) *
207 dr->secspertrack;
208
209 if (!nr_sects)
210 break;
211
212 first = 0;
213 first_sector += nr_sects;
214 start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
215 nr_sects = 0; /* hmm - should be partition size */
216
217 switch (data[0x1fc] & 15) {
218 case 0: /* No partition / ADFS? */
219 break;
220
221#ifdef CONFIG_ACORN_PARTITION_RISCIX
222 case PARTITION_RISCIX_SCSI:
223 /* RISCiX - we don't know how to find the next one. */
224 slot = riscix_partition(state, first_sector, slot,
225 nr_sects);
226 break;
227#endif
228
229 case PARTITION_LINUX:
230 slot = linux_partition(state, first_sector, slot,
231 nr_sects);
232 break;
233 }
234 put_dev_sector(sect);
235 if (slot == -1)
236 return -1;
237 } while (1);
238 put_dev_sector(sect);
239 return first ? 0 : 1;
240}
241#endif
242
243#ifdef CONFIG_ACORN_PARTITION_ADFS
244/*
245 * Purpose: allocate ADFS partitions.
246 *
247 * Params : hd - pointer to gendisk structure to store partition info.
248 * dev - device number to access.
249 *
250 * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok.
251 *
252 * Alloc : hda = whole drive
253 * hda1 = ADFS partition on first drive.
254 * hda2 = non-ADFS partition.
255 */
256int adfspart_check_ADFS(struct parsed_partitions *state)
257{
258 unsigned long start_sect, nr_sects, sectscyl, heads;
259 Sector sect;
260 unsigned char *data;
261 struct adfs_discrecord *dr;
262 unsigned char id;
263 int slot = 1;
264
265 data = read_part_sector(state, 6, &sect);
266 if (!data)
267 return -1;
268
269 dr = adfs_partition(state, "ADFS", data, 0, slot++);
270 if (!dr) {
271 put_dev_sector(sect);
272 return 0;
273 }
274
275 heads = dr->heads + ((dr->lowsector >> 6) & 1);
276 sectscyl = dr->secspertrack * heads;
277 start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl;
278 id = data[0x1fc] & 15;
279 put_dev_sector(sect);
280
281 /*
282 * Work out start of non-adfs partition.
283 */
284 nr_sects = (state->bdev->bd_inode->i_size >> 9) - start_sect;
285
286 if (start_sect) {
287 switch (id) {
288#ifdef CONFIG_ACORN_PARTITION_RISCIX
289 case PARTITION_RISCIX_SCSI:
290 case PARTITION_RISCIX_MFM:
291 slot = riscix_partition(state, start_sect, slot,
292 nr_sects);
293 break;
294#endif
295
296 case PARTITION_LINUX:
297 slot = linux_partition(state, start_sect, slot,
298 nr_sects);
299 break;
300 }
301 }
302 strlcat(state->pp_buf, "\n", PAGE_SIZE);
303 return 1;
304}
305#endif
306
307#ifdef CONFIG_ACORN_PARTITION_ICS
308
309struct ics_part {
310 __le32 start;
311 __le32 size;
312};
313
314static int adfspart_check_ICSLinux(struct parsed_partitions *state,
315 unsigned long block)
316{
317 Sector sect;
318 unsigned char *data = read_part_sector(state, block, &sect);
319 int result = 0;
320
321 if (data) {
322 if (memcmp(data, "LinuxPart", 9) == 0)
323 result = 1;
324 put_dev_sector(sect);
325 }
326
327 return result;
328}
329
330/*
331 * Check for a valid ICS partition using the checksum.
332 */
333static inline int valid_ics_sector(const unsigned char *data)
334{
335 unsigned long sum;
336 int i;
337
338 for (i = 0, sum = 0x50617274; i < 508; i++)
339 sum += data[i];
340
341 sum -= le32_to_cpu(*(__le32 *)(&data[508]));
342
343 return sum == 0;
344}
345
346/*
347 * Purpose: allocate ICS partitions.
348 * Params : hd - pointer to gendisk structure to store partition info.
349 * dev - device number to access.
350 * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
351 * Alloc : hda = whole drive
352 * hda1 = ADFS partition 0 on first drive.
353 * hda2 = ADFS partition 1 on first drive.
354 * ..etc..
355 */
356int adfspart_check_ICS(struct parsed_partitions *state)
357{
358 const unsigned char *data;
359 const struct ics_part *p;
360 int slot;
361 Sector sect;
362
363 /*
364 * Try ICS style partitions - sector 0 contains partition info.
365 */
366 data = read_part_sector(state, 0, &sect);
367 if (!data)
368 return -1;
369
370 if (!valid_ics_sector(data)) {
371 put_dev_sector(sect);
372 return 0;
373 }
374
375 strlcat(state->pp_buf, " [ICS]", PAGE_SIZE);
376
377 for (slot = 1, p = (const struct ics_part *)data; p->size; p++) {
378 u32 start = le32_to_cpu(p->start);
379 s32 size = le32_to_cpu(p->size); /* yes, it's signed. */
380
381 if (slot == state->limit)
382 break;
383
384 /*
385 * Negative sizes tell the RISC OS ICS driver to ignore
386 * this partition - in effect it says that this does not
387 * contain an ADFS filesystem.
388 */
389 if (size < 0) {
390 size = -size;
391
392 /*
393 * Our own extension - We use the first sector
394 * of the partition to identify what type this
395 * partition is. We must not make this visible
396 * to the filesystem.
397 */
398 if (size > 1 && adfspart_check_ICSLinux(state, start)) {
399 start += 1;
400 size -= 1;
401 }
402 }
403
404 if (size)
405 put_partition(state, slot++, start, size);
406 }
407
408 put_dev_sector(sect);
409 strlcat(state->pp_buf, "\n", PAGE_SIZE);
410 return 1;
411}
412#endif
413
414#ifdef CONFIG_ACORN_PARTITION_POWERTEC
415struct ptec_part {
416 __le32 unused1;
417 __le32 unused2;
418 __le32 start;
419 __le32 size;
420 __le32 unused5;
421 char type[8];
422};
423
424static inline int valid_ptec_sector(const unsigned char *data)
425{
426 unsigned char checksum = 0x2a;
427 int i;
428
429 /*
430 * If it looks like a PC/BIOS partition, then it
431 * probably isn't PowerTec.
432 */
433 if (data[510] == 0x55 && data[511] == 0xaa)
434 return 0;
435
436 for (i = 0; i < 511; i++)
437 checksum += data[i];
438
439 return checksum == data[511];
440}
441
442/*
443 * Purpose: allocate ICS partitions.
444 * Params : hd - pointer to gendisk structure to store partition info.
445 * dev - device number to access.
446 * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
447 * Alloc : hda = whole drive
448 * hda1 = ADFS partition 0 on first drive.
449 * hda2 = ADFS partition 1 on first drive.
450 * ..etc..
451 */
452int adfspart_check_POWERTEC(struct parsed_partitions *state)
453{
454 Sector sect;
455 const unsigned char *data;
456 const struct ptec_part *p;
457 int slot = 1;
458 int i;
459
460 data = read_part_sector(state, 0, &sect);
461 if (!data)
462 return -1;
463
464 if (!valid_ptec_sector(data)) {
465 put_dev_sector(sect);
466 return 0;
467 }
468
469 strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE);
470
471 for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) {
472 u32 start = le32_to_cpu(p->start);
473 u32 size = le32_to_cpu(p->size);
474
475 if (size)
476 put_partition(state, slot++, start, size);
477 }
478
479 put_dev_sector(sect);
480 strlcat(state->pp_buf, "\n", PAGE_SIZE);
481 return 1;
482}
483#endif
484
485#ifdef CONFIG_ACORN_PARTITION_EESOX
486struct eesox_part {
487 char magic[6];
488 char name[10];
489 __le32 start;
490 __le32 unused6;
491 __le32 unused7;
492 __le32 unused8;
493};
494
495/*
496 * Guess who created this format?
497 */
498static const char eesox_name[] = {
499 'N', 'e', 'i', 'l', ' ',
500 'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' '
501};
502
503/*
504 * EESOX SCSI partition format.
505 *
506 * This is a goddamned awful partition format. We don't seem to store
507 * the size of the partition in this table, only the start addresses.
508 *
509 * There are two possibilities where the size comes from:
510 * 1. The individual ADFS boot block entries that are placed on the disk.
511 * 2. The start address of the next entry.
512 */
513int adfspart_check_EESOX(struct parsed_partitions *state)
514{
515 Sector sect;
516 const unsigned char *data;
517 unsigned char buffer[256];
518 struct eesox_part *p;
519 sector_t start = 0;
520 int i, slot = 1;
521
522 data = read_part_sector(state, 7, &sect);
523 if (!data)
524 return -1;
525
526 /*
527 * "Decrypt" the partition table. God knows why...
528 */
529 for (i = 0; i < 256; i++)
530 buffer[i] = data[i] ^ eesox_name[i & 15];
531
532 put_dev_sector(sect);
533
534 for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
535 sector_t next;
536
537 if (memcmp(p->magic, "Eesox", 6))
538 break;
539
540 next = le32_to_cpu(p->start);
541 if (i)
542 put_partition(state, slot++, start, next - start);
543 start = next;
544 }
545
546 if (i != 0) {
547 sector_t size;
548
549 size = get_capacity(state->bdev->bd_disk);
550 put_partition(state, slot++, start, size - start);
551 strlcat(state->pp_buf, "\n", PAGE_SIZE);
552 }
553
554 return i ? 1 : 0;
555}
556#endif
diff --git a/fs/partitions/acorn.h b/fs/partitions/acorn.h
new file mode 100644
index 00000000000..ede82852969
--- /dev/null
+++ b/fs/partitions/acorn.h
@@ -0,0 +1,14 @@
1/*
2 * linux/fs/partitions/acorn.h
3 *
4 * Copyright (C) 1996-2001 Russell King.
5 *
6 * I _hate_ this partitioning mess - why can't we have one defined
7 * format, and everyone stick to it?
8 */
9
10int adfspart_check_CUMANA(struct parsed_partitions *state);
11int adfspart_check_ADFS(struct parsed_partitions *state);
12int adfspart_check_ICS(struct parsed_partitions *state);
13int adfspart_check_POWERTEC(struct parsed_partitions *state);
14int adfspart_check_EESOX(struct parsed_partitions *state);
diff --git a/fs/partitions/amiga.c b/fs/partitions/amiga.c
new file mode 100644
index 00000000000..70cbf44a156
--- /dev/null
+++ b/fs/partitions/amiga.c
@@ -0,0 +1,139 @@
1/*
2 * fs/partitions/amiga.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 *
6 * Copyright (C) 1991-1998 Linus Torvalds
7 * Re-organised Feb 1998 Russell King
8 */
9
10#include <linux/types.h>
11#include <linux/affs_hardblocks.h>
12
13#include "check.h"
14#include "amiga.h"
15
16static __inline__ u32
17checksum_block(__be32 *m, int size)
18{
19 u32 sum = 0;
20
21 while (size--)
22 sum += be32_to_cpu(*m++);
23 return sum;
24}
25
26int amiga_partition(struct parsed_partitions *state)
27{
28 Sector sect;
29 unsigned char *data;
30 struct RigidDiskBlock *rdb;
31 struct PartitionBlock *pb;
32 int start_sect, nr_sects, blk, part, res = 0;
33 int blksize = 1; /* Multiplier for disk block size */
34 int slot = 1;
35 char b[BDEVNAME_SIZE];
36
37 for (blk = 0; ; blk++, put_dev_sector(sect)) {
38 if (blk == RDB_ALLOCATION_LIMIT)
39 goto rdb_done;
40 data = read_part_sector(state, blk, &sect);
41 if (!data) {
42 if (warn_no_part)
43 printk("Dev %s: unable to read RDB block %d\n",
44 bdevname(state->bdev, b), blk);
45 res = -1;
46 goto rdb_done;
47 }
48 if (*(__be32 *)data != cpu_to_be32(IDNAME_RIGIDDISK))
49 continue;
50
51 rdb = (struct RigidDiskBlock *)data;
52 if (checksum_block((__be32 *)data, be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F) == 0)
53 break;
54 /* Try again with 0xdc..0xdf zeroed, Windows might have
55 * trashed it.
56 */
57 *(__be32 *)(data+0xdc) = 0;
58 if (checksum_block((__be32 *)data,
59 be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) {
60 printk("Warning: Trashed word at 0xd0 in block %d "
61 "ignored in checksum calculation\n",blk);
62 break;
63 }
64
65 printk("Dev %s: RDB in block %d has bad checksum\n",
66 bdevname(state->bdev, b), blk);
67 }
68
69 /* blksize is blocks per 512 byte standard block */
70 blksize = be32_to_cpu( rdb->rdb_BlockBytes ) / 512;
71
72 {
73 char tmp[7 + 10 + 1 + 1];
74
75 /* Be more informative */
76 snprintf(tmp, sizeof(tmp), " RDSK (%d)", blksize * 512);
77 strlcat(state->pp_buf, tmp, PAGE_SIZE);
78 }
79 blk = be32_to_cpu(rdb->rdb_PartitionList);
80 put_dev_sector(sect);
81 for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) {
82 blk *= blksize; /* Read in terms partition table understands */
83 data = read_part_sector(state, blk, &sect);
84 if (!data) {
85 if (warn_no_part)
86 printk("Dev %s: unable to read partition block %d\n",
87 bdevname(state->bdev, b), blk);
88 res = -1;
89 goto rdb_done;
90 }
91 pb = (struct PartitionBlock *)data;
92 blk = be32_to_cpu(pb->pb_Next);
93 if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION))
94 continue;
95 if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 )
96 continue;
97
98 /* Tell Kernel about it */
99
100 nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
101 be32_to_cpu(pb->pb_Environment[9])) *
102 be32_to_cpu(pb->pb_Environment[3]) *
103 be32_to_cpu(pb->pb_Environment[5]) *
104 blksize;
105 if (!nr_sects)
106 continue;
107 start_sect = be32_to_cpu(pb->pb_Environment[9]) *
108 be32_to_cpu(pb->pb_Environment[3]) *
109 be32_to_cpu(pb->pb_Environment[5]) *
110 blksize;
111 put_partition(state,slot++,start_sect,nr_sects);
112 {
113 /* Be even more informative to aid mounting */
114 char dostype[4];
115 char tmp[42];
116
117 __be32 *dt = (__be32 *)dostype;
118 *dt = pb->pb_Environment[16];
119 if (dostype[3] < ' ')
120 snprintf(tmp, sizeof(tmp), " (%c%c%c^%c)",
121 dostype[0], dostype[1],
122 dostype[2], dostype[3] + '@' );
123 else
124 snprintf(tmp, sizeof(tmp), " (%c%c%c%c)",
125 dostype[0], dostype[1],
126 dostype[2], dostype[3]);
127 strlcat(state->pp_buf, tmp, PAGE_SIZE);
128 snprintf(tmp, sizeof(tmp), "(res %d spb %d)",
129 be32_to_cpu(pb->pb_Environment[6]),
130 be32_to_cpu(pb->pb_Environment[4]));
131 strlcat(state->pp_buf, tmp, PAGE_SIZE);
132 }
133 res = 1;
134 }
135 strlcat(state->pp_buf, "\n", PAGE_SIZE);
136
137rdb_done:
138 return res;
139}
diff --git a/fs/partitions/amiga.h b/fs/partitions/amiga.h
new file mode 100644
index 00000000000..d094585cada
--- /dev/null
+++ b/fs/partitions/amiga.h
@@ -0,0 +1,6 @@
1/*
2 * fs/partitions/amiga.h
3 */
4
5int amiga_partition(struct parsed_partitions *state);
6
diff --git a/fs/partitions/atari.c b/fs/partitions/atari.c
new file mode 100644
index 00000000000..9875b05e80a
--- /dev/null
+++ b/fs/partitions/atari.c
@@ -0,0 +1,149 @@
1/*
2 * fs/partitions/atari.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 *
6 * Copyright (C) 1991-1998 Linus Torvalds
7 * Re-organised Feb 1998 Russell King
8 */
9
10#include <linux/ctype.h>
11#include "check.h"
12#include "atari.h"
13
14/* ++guenther: this should be settable by the user ("make config")?.
15 */
16#define ICD_PARTS
17
18/* check if a partition entry looks valid -- Atari format is assumed if at
19 least one of the primary entries is ok this way */
20#define VALID_PARTITION(pi,hdsiz) \
21 (((pi)->flg & 1) && \
22 isalnum((pi)->id[0]) && isalnum((pi)->id[1]) && isalnum((pi)->id[2]) && \
23 be32_to_cpu((pi)->st) <= (hdsiz) && \
24 be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz))
25
26static inline int OK_id(char *s)
27{
28 return memcmp (s, "GEM", 3) == 0 || memcmp (s, "BGM", 3) == 0 ||
29 memcmp (s, "LNX", 3) == 0 || memcmp (s, "SWP", 3) == 0 ||
30 memcmp (s, "RAW", 3) == 0 ;
31}
32
33int atari_partition(struct parsed_partitions *state)
34{
35 Sector sect;
36 struct rootsector *rs;
37 struct partition_info *pi;
38 u32 extensect;
39 u32 hd_size;
40 int slot;
41#ifdef ICD_PARTS
42 int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
43#endif
44
45 rs = read_part_sector(state, 0, &sect);
46 if (!rs)
47 return -1;
48
49 /* Verify this is an Atari rootsector: */
50 hd_size = state->bdev->bd_inode->i_size >> 9;
51 if (!VALID_PARTITION(&rs->part[0], hd_size) &&
52 !VALID_PARTITION(&rs->part[1], hd_size) &&
53 !VALID_PARTITION(&rs->part[2], hd_size) &&
54 !VALID_PARTITION(&rs->part[3], hd_size)) {
55 /*
56 * if there's no valid primary partition, assume that no Atari
57 * format partition table (there's no reliable magic or the like
58 * :-()
59 */
60 put_dev_sector(sect);
61 return 0;
62 }
63
64 pi = &rs->part[0];
65 strlcat(state->pp_buf, " AHDI", PAGE_SIZE);
66 for (slot = 1; pi < &rs->part[4] && slot < state->limit; slot++, pi++) {
67 struct rootsector *xrs;
68 Sector sect2;
69 ulong partsect;
70
71 if ( !(pi->flg & 1) )
72 continue;
73 /* active partition */
74 if (memcmp (pi->id, "XGM", 3) != 0) {
75 /* we don't care about other id's */
76 put_partition (state, slot, be32_to_cpu(pi->st),
77 be32_to_cpu(pi->siz));
78 continue;
79 }
80 /* extension partition */
81#ifdef ICD_PARTS
82 part_fmt = 1;
83#endif
84 strlcat(state->pp_buf, " XGM<", PAGE_SIZE);
85 partsect = extensect = be32_to_cpu(pi->st);
86 while (1) {
87 xrs = read_part_sector(state, partsect, &sect2);
88 if (!xrs) {
89 printk (" block %ld read failed\n", partsect);
90 put_dev_sector(sect);
91 return -1;
92 }
93
94 /* ++roman: sanity check: bit 0 of flg field must be set */
95 if (!(xrs->part[0].flg & 1)) {
96 printk( "\nFirst sub-partition in extended partition is not valid!\n" );
97 put_dev_sector(sect2);
98 break;
99 }
100
101 put_partition(state, slot,
102 partsect + be32_to_cpu(xrs->part[0].st),
103 be32_to_cpu(xrs->part[0].siz));
104
105 if (!(xrs->part[1].flg & 1)) {
106 /* end of linked partition list */
107 put_dev_sector(sect2);
108 break;
109 }
110 if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
111 printk("\nID of extended partition is not XGM!\n");
112 put_dev_sector(sect2);
113 break;
114 }
115
116 partsect = be32_to_cpu(xrs->part[1].st) + extensect;
117 put_dev_sector(sect2);
118 if (++slot == state->limit) {
119 printk( "\nMaximum number of partitions reached!\n" );
120 break;
121 }
122 }
123 strlcat(state->pp_buf, " >", PAGE_SIZE);
124 }
125#ifdef ICD_PARTS
126 if ( part_fmt!=1 ) { /* no extended partitions -> test ICD-format */
127 pi = &rs->icdpart[0];
128 /* sanity check: no ICD format if first partition invalid */
129 if (OK_id(pi->id)) {
130 strlcat(state->pp_buf, " ICD<", PAGE_SIZE);
131 for (; pi < &rs->icdpart[8] && slot < state->limit; slot++, pi++) {
132 /* accept only GEM,BGM,RAW,LNX,SWP partitions */
133 if (!((pi->flg & 1) && OK_id(pi->id)))
134 continue;
135 part_fmt = 2;
136 put_partition (state, slot,
137 be32_to_cpu(pi->st),
138 be32_to_cpu(pi->siz));
139 }
140 strlcat(state->pp_buf, " >", PAGE_SIZE);
141 }
142 }
143#endif
144 put_dev_sector(sect);
145
146 strlcat(state->pp_buf, "\n", PAGE_SIZE);
147
148 return 1;
149}
diff --git a/fs/partitions/atari.h b/fs/partitions/atari.h
new file mode 100644
index 00000000000..fe2d32a89f3
--- /dev/null
+++ b/fs/partitions/atari.h
@@ -0,0 +1,34 @@
1/*
2 * fs/partitions/atari.h
3 * Moved by Russell King from:
4 *
5 * linux/include/linux/atari_rootsec.h
6 * definitions for Atari Rootsector layout
7 * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
8 *
9 * modified for ICD/Supra partitioning scheme restricted to at most 12
10 * partitions
11 * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
12 */
13
14struct partition_info
15{
16 u8 flg; /* bit 0: active; bit 7: bootable */
17 char id[3]; /* "GEM", "BGM", "XGM", or other */
18 __be32 st; /* start of partition */
19 __be32 siz; /* length of partition */
20};
21
22struct rootsector
23{
24 char unused[0x156]; /* room for boot code */
25 struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */
26 char unused2[0xc];
27 u32 hd_siz; /* size of disk in blocks */
28 struct partition_info part[4];
29 u32 bsl_st; /* start of bad sector list */
30 u32 bsl_cnt; /* length of bad sector list */
31 u16 checksum; /* checksum for bootable disks */
32} __attribute__((__packed__));
33
34int atari_partition(struct parsed_partitions *state);
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
new file mode 100644
index 00000000000..b4095cc7343
--- /dev/null
+++ b/fs/partitions/check.c
@@ -0,0 +1,698 @@
1/*
2 * fs/partitions/check.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 * Copyright (C) 1991-1998 Linus Torvalds
6 * Re-organised Feb 1998 Russell King
7 *
8 * We now have independent partition support from the
9 * block drivers, which allows all the partition code to
10 * be grouped in one location, and it to be mostly self
11 * contained.
12 *
13 * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
14 */
15
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/fs.h>
19#include <linux/slab.h>
20#include <linux/kmod.h>
21#include <linux/ctype.h>
22#include <linux/genhd.h>
23#include <linux/blktrace_api.h>
24
25#include "check.h"
26
27#include "acorn.h"
28#include "amiga.h"
29#include "atari.h"
30#include "ldm.h"
31#include "mac.h"
32#include "msdos.h"
33#include "osf.h"
34#include "sgi.h"
35#include "sun.h"
36#include "ibm.h"
37#include "ultrix.h"
38#include "efi.h"
39#include "karma.h"
40#include "sysv68.h"
41
42#ifdef CONFIG_BLK_DEV_MD
43extern void md_autodetect_dev(dev_t dev);
44#endif
45
46int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
47
48static int (*check_part[])(struct parsed_partitions *) = {
49 /*
50 * Probe partition formats with tables at disk address 0
51 * that also have an ADFS boot block at 0xdc0.
52 */
53#ifdef CONFIG_ACORN_PARTITION_ICS
54 adfspart_check_ICS,
55#endif
56#ifdef CONFIG_ACORN_PARTITION_POWERTEC
57 adfspart_check_POWERTEC,
58#endif
59#ifdef CONFIG_ACORN_PARTITION_EESOX
60 adfspart_check_EESOX,
61#endif
62
63 /*
64 * Now move on to formats that only have partition info at
65 * disk address 0xdc0. Since these may also have stale
66 * PC/BIOS partition tables, they need to come before
67 * the msdos entry.
68 */
69#ifdef CONFIG_ACORN_PARTITION_CUMANA
70 adfspart_check_CUMANA,
71#endif
72#ifdef CONFIG_ACORN_PARTITION_ADFS
73 adfspart_check_ADFS,
74#endif
75
76#ifdef CONFIG_EFI_PARTITION
77 efi_partition, /* this must come before msdos */
78#endif
79#ifdef CONFIG_SGI_PARTITION
80 sgi_partition,
81#endif
82#ifdef CONFIG_LDM_PARTITION
83 ldm_partition, /* this must come before msdos */
84#endif
85#ifdef CONFIG_MSDOS_PARTITION
86 msdos_partition,
87#endif
88#ifdef CONFIG_OSF_PARTITION
89 osf_partition,
90#endif
91#ifdef CONFIG_SUN_PARTITION
92 sun_partition,
93#endif
94#ifdef CONFIG_AMIGA_PARTITION
95 amiga_partition,
96#endif
97#ifdef CONFIG_ATARI_PARTITION
98 atari_partition,
99#endif
100#ifdef CONFIG_MAC_PARTITION
101 mac_partition,
102#endif
103#ifdef CONFIG_ULTRIX_PARTITION
104 ultrix_partition,
105#endif
106#ifdef CONFIG_IBM_PARTITION
107 ibm_partition,
108#endif
109#ifdef CONFIG_KARMA_PARTITION
110 karma_partition,
111#endif
112#ifdef CONFIG_SYSV68_PARTITION
113 sysv68_partition,
114#endif
115 NULL
116};
117
118/*
119 * disk_name() is used by partition check code and the genhd driver.
120 * It formats the devicename of the indicated disk into
121 * the supplied buffer (of size at least 32), and returns
122 * a pointer to that same buffer (for convenience).
123 */
124
125char *disk_name(struct gendisk *hd, int partno, char *buf)
126{
127 if (!partno)
128 snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
129 else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
130 snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
131 else
132 snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
133
134 return buf;
135}
136
137const char *bdevname(struct block_device *bdev, char *buf)
138{
139 return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf);
140}
141
142EXPORT_SYMBOL(bdevname);
143
144/*
145 * There's very little reason to use this, you should really
146 * have a struct block_device just about everywhere and use
147 * bdevname() instead.
148 */
149const char *__bdevname(dev_t dev, char *buffer)
150{
151 scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)",
152 MAJOR(dev), MINOR(dev));
153 return buffer;
154}
155
156EXPORT_SYMBOL(__bdevname);
157
158static struct parsed_partitions *
159check_partition(struct gendisk *hd, struct block_device *bdev)
160{
161 struct parsed_partitions *state;
162 int i, res, err;
163
164 state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
165 if (!state)
166 return NULL;
167 state->pp_buf = (char *)__get_free_page(GFP_KERNEL);
168 if (!state->pp_buf) {
169 kfree(state);
170 return NULL;
171 }
172 state->pp_buf[0] = '\0';
173
174 state->bdev = bdev;
175 disk_name(hd, 0, state->name);
176 snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name);
177 if (isdigit(state->name[strlen(state->name)-1]))
178 sprintf(state->name, "p");
179
180 state->limit = disk_max_parts(hd);
181 i = res = err = 0;
182 while (!res && check_part[i]) {
183 memset(&state->parts, 0, sizeof(state->parts));
184 res = check_part[i++](state);
185 if (res < 0) {
186 /* We have hit an I/O error which we don't report now.
187 * But record it, and let the others do their job.
188 */
189 err = res;
190 res = 0;
191 }
192
193 }
194 if (res > 0) {
195 printk(KERN_INFO "%s", state->pp_buf);
196
197 free_page((unsigned long)state->pp_buf);
198 return state;
199 }
200 if (state->access_beyond_eod)
201 err = -ENOSPC;
202 if (err)
203 /* The partition is unrecognized. So report I/O errors if there were any */
204 res = err;
205 if (!res)
206 strlcat(state->pp_buf, " unknown partition table\n", PAGE_SIZE);
207 else if (warn_no_part)
208 strlcat(state->pp_buf, " unable to read partition table\n", PAGE_SIZE);
209
210 printk(KERN_INFO "%s", state->pp_buf);
211
212 free_page((unsigned long)state->pp_buf);
213 kfree(state);
214 return ERR_PTR(res);
215}
216
217static ssize_t part_partition_show(struct device *dev,
218 struct device_attribute *attr, char *buf)
219{
220 struct hd_struct *p = dev_to_part(dev);
221
222 return sprintf(buf, "%d\n", p->partno);
223}
224
225static ssize_t part_start_show(struct device *dev,
226 struct device_attribute *attr, char *buf)
227{
228 struct hd_struct *p = dev_to_part(dev);
229
230 return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect);
231}
232
233ssize_t part_size_show(struct device *dev,
234 struct device_attribute *attr, char *buf)
235{
236 struct hd_struct *p = dev_to_part(dev);
237 return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
238}
239
240static ssize_t part_ro_show(struct device *dev,
241 struct device_attribute *attr, char *buf)
242{
243 struct hd_struct *p = dev_to_part(dev);
244 return sprintf(buf, "%d\n", p->policy ? 1 : 0);
245}
246
247static ssize_t part_alignment_offset_show(struct device *dev,
248 struct device_attribute *attr, char *buf)
249{
250 struct hd_struct *p = dev_to_part(dev);
251 return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset);
252}
253
254static ssize_t part_discard_alignment_show(struct device *dev,
255 struct device_attribute *attr, char *buf)
256{
257 struct hd_struct *p = dev_to_part(dev);
258 return sprintf(buf, "%u\n", p->discard_alignment);
259}
260
261ssize_t part_stat_show(struct device *dev,
262 struct device_attribute *attr, char *buf)
263{
264 struct hd_struct *p = dev_to_part(dev);
265 int cpu;
266
267 cpu = part_stat_lock();
268 part_round_stats(cpu, p);
269 part_stat_unlock();
270 return sprintf(buf,
271 "%8lu %8lu %8llu %8u "
272 "%8lu %8lu %8llu %8u "
273 "%8u %8u %8u"
274 "\n",
275 part_stat_read(p, ios[READ]),
276 part_stat_read(p, merges[READ]),
277 (unsigned long long)part_stat_read(p, sectors[READ]),
278 jiffies_to_msecs(part_stat_read(p, ticks[READ])),
279 part_stat_read(p, ios[WRITE]),
280 part_stat_read(p, merges[WRITE]),
281 (unsigned long long)part_stat_read(p, sectors[WRITE]),
282 jiffies_to_msecs(part_stat_read(p, ticks[WRITE])),
283 part_in_flight(p),
284 jiffies_to_msecs(part_stat_read(p, io_ticks)),
285 jiffies_to_msecs(part_stat_read(p, time_in_queue)));
286}
287
288ssize_t part_inflight_show(struct device *dev,
289 struct device_attribute *attr, char *buf)
290{
291 struct hd_struct *p = dev_to_part(dev);
292
293 return sprintf(buf, "%8u %8u\n", atomic_read(&p->in_flight[0]),
294 atomic_read(&p->in_flight[1]));
295}
296
297#ifdef CONFIG_FAIL_MAKE_REQUEST
298ssize_t part_fail_show(struct device *dev,
299 struct device_attribute *attr, char *buf)
300{
301 struct hd_struct *p = dev_to_part(dev);
302
303 return sprintf(buf, "%d\n", p->make_it_fail);
304}
305
306ssize_t part_fail_store(struct device *dev,
307 struct device_attribute *attr,
308 const char *buf, size_t count)
309{
310 struct hd_struct *p = dev_to_part(dev);
311 int i;
312
313 if (count > 0 && sscanf(buf, "%d", &i) > 0)
314 p->make_it_fail = (i == 0) ? 0 : 1;
315
316 return count;
317}
318#endif
319
320static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL);
321static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
322static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
323static DEVICE_ATTR(ro, S_IRUGO, part_ro_show, NULL);
324static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
325static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show,
326 NULL);
327static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
328static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
329#ifdef CONFIG_FAIL_MAKE_REQUEST
330static struct device_attribute dev_attr_fail =
331 __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
332#endif
333
334static struct attribute *part_attrs[] = {
335 &dev_attr_partition.attr,
336 &dev_attr_start.attr,
337 &dev_attr_size.attr,
338 &dev_attr_ro.attr,
339 &dev_attr_alignment_offset.attr,
340 &dev_attr_discard_alignment.attr,
341 &dev_attr_stat.attr,
342 &dev_attr_inflight.attr,
343#ifdef CONFIG_FAIL_MAKE_REQUEST
344 &dev_attr_fail.attr,
345#endif
346 NULL
347};
348
349static struct attribute_group part_attr_group = {
350 .attrs = part_attrs,
351};
352
353static const struct attribute_group *part_attr_groups[] = {
354 &part_attr_group,
355#ifdef CONFIG_BLK_DEV_IO_TRACE
356 &blk_trace_attr_group,
357#endif
358 NULL
359};
360
361static void part_release(struct device *dev)
362{
363 struct hd_struct *p = dev_to_part(dev);
364 free_part_stats(p);
365 free_part_info(p);
366 kfree(p);
367}
368
369static int part_uevent(struct device *dev, struct kobj_uevent_env *env)
370{
371 struct hd_struct *part = dev_to_part(dev);
372
373 add_uevent_var(env, "PARTN=%u", part->partno);
374 if (part->info && part->info->volname[0])
375 add_uevent_var(env, "PARTNAME=%s", part->info->volname);
376 return 0;
377}
378
379struct device_type part_type = {
380 .name = "partition",
381 .groups = part_attr_groups,
382 .release = part_release,
383 .uevent = part_uevent,
384};
385
386static void delete_partition_rcu_cb(struct rcu_head *head)
387{
388 struct hd_struct *part = container_of(head, struct hd_struct, rcu_head);
389
390 part->start_sect = 0;
391 part->nr_sects = 0;
392 part_stat_set_all(part, 0);
393 put_device(part_to_dev(part));
394}
395
396void __delete_partition(struct hd_struct *part)
397{
398 call_rcu(&part->rcu_head, delete_partition_rcu_cb);
399}
400
401void delete_partition(struct gendisk *disk, int partno)
402{
403 struct disk_part_tbl *ptbl = disk->part_tbl;
404 struct hd_struct *part;
405
406 if (partno >= ptbl->len)
407 return;
408
409 part = ptbl->part[partno];
410 if (!part)
411 return;
412
413 blk_free_devt(part_devt(part));
414 rcu_assign_pointer(ptbl->part[partno], NULL);
415 rcu_assign_pointer(ptbl->last_lookup, NULL);
416 kobject_put(part->holder_dir);
417 device_del(part_to_dev(part));
418
419 hd_struct_put(part);
420}
421
422static ssize_t whole_disk_show(struct device *dev,
423 struct device_attribute *attr, char *buf)
424{
425 return 0;
426}
427static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH,
428 whole_disk_show, NULL);
429
430struct hd_struct *add_partition(struct gendisk *disk, int partno,
431 sector_t start, sector_t len, int flags,
432 struct partition_meta_info *info)
433{
434 struct hd_struct *p;
435 dev_t devt = MKDEV(0, 0);
436 struct device *ddev = disk_to_dev(disk);
437 struct device *pdev;
438 struct disk_part_tbl *ptbl;
439 const char *dname;
440 int err;
441
442 err = disk_expand_part_tbl(disk, partno);
443 if (err)
444 return ERR_PTR(err);
445 ptbl = disk->part_tbl;
446
447 if (ptbl->part[partno])
448 return ERR_PTR(-EBUSY);
449
450 p = kzalloc(sizeof(*p), GFP_KERNEL);
451 if (!p)
452 return ERR_PTR(-EBUSY);
453
454 if (!init_part_stats(p)) {
455 err = -ENOMEM;
456 goto out_free;
457 }
458 pdev = part_to_dev(p);
459
460 p->start_sect = start;
461 p->alignment_offset =
462 queue_limit_alignment_offset(&disk->queue->limits, start);
463 p->discard_alignment =
464 queue_limit_discard_alignment(&disk->queue->limits, start);
465 p->nr_sects = len;
466 p->partno = partno;
467 p->policy = get_disk_ro(disk);
468
469 if (info) {
470 struct partition_meta_info *pinfo = alloc_part_info(disk);
471 if (!pinfo)
472 goto out_free_stats;
473 memcpy(pinfo, info, sizeof(*info));
474 p->info = pinfo;
475 }
476
477 dname = dev_name(ddev);
478 if (isdigit(dname[strlen(dname) - 1]))
479 dev_set_name(pdev, "%sp%d", dname, partno);
480 else
481 dev_set_name(pdev, "%s%d", dname, partno);
482
483 device_initialize(pdev);
484 pdev->class = &block_class;
485 pdev->type = &part_type;
486 pdev->parent = ddev;
487
488 err = blk_alloc_devt(p, &devt);
489 if (err)
490 goto out_free_info;
491 pdev->devt = devt;
492
493 /* delay uevent until 'holders' subdir is created */
494 dev_set_uevent_suppress(pdev, 1);
495 err = device_add(pdev);
496 if (err)
497 goto out_put;
498
499 err = -ENOMEM;
500 p->holder_dir = kobject_create_and_add("holders", &pdev->kobj);
501 if (!p->holder_dir)
502 goto out_del;
503
504 dev_set_uevent_suppress(pdev, 0);
505 if (flags & ADDPART_FLAG_WHOLEDISK) {
506 err = device_create_file(pdev, &dev_attr_whole_disk);
507 if (err)
508 goto out_del;
509 }
510
511 /* everything is up and running, commence */
512 rcu_assign_pointer(ptbl->part[partno], p);
513
514 /* suppress uevent if the disk suppresses it */
515 if (!dev_get_uevent_suppress(ddev))
516 kobject_uevent(&pdev->kobj, KOBJ_ADD);
517
518 hd_ref_init(p);
519 return p;
520
521out_free_info:
522 free_part_info(p);
523out_free_stats:
524 free_part_stats(p);
525out_free:
526 kfree(p);
527 return ERR_PTR(err);
528out_del:
529 kobject_put(p->holder_dir);
530 device_del(pdev);
531out_put:
532 put_device(pdev);
533 blk_free_devt(devt);
534 return ERR_PTR(err);
535}
536
537static bool disk_unlock_native_capacity(struct gendisk *disk)
538{
539 const struct block_device_operations *bdops = disk->fops;
540
541 if (bdops->unlock_native_capacity &&
542 !(disk->flags & GENHD_FL_NATIVE_CAPACITY)) {
543 printk(KERN_CONT "enabling native capacity\n");
544 bdops->unlock_native_capacity(disk);
545 disk->flags |= GENHD_FL_NATIVE_CAPACITY;
546 return true;
547 } else {
548 printk(KERN_CONT "truncated\n");
549 return false;
550 }
551}
552
553int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
554{
555 struct parsed_partitions *state = NULL;
556 struct disk_part_iter piter;
557 struct hd_struct *part;
558 int p, highest, res;
559rescan:
560 if (state && !IS_ERR(state)) {
561 kfree(state);
562 state = NULL;
563 }
564
565 if (bdev->bd_part_count)
566 return -EBUSY;
567 res = invalidate_partition(disk, 0);
568 if (res)
569 return res;
570
571 disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
572 while ((part = disk_part_iter_next(&piter)))
573 delete_partition(disk, part->partno);
574 disk_part_iter_exit(&piter);
575
576 if (disk->fops->revalidate_disk)
577 disk->fops->revalidate_disk(disk);
578 check_disk_size_change(disk, bdev);
579 bdev->bd_invalidated = 0;
580 if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
581 return 0;
582 if (IS_ERR(state)) {
583 /*
584 * I/O error reading the partition table. If any
585 * partition code tried to read beyond EOD, retry
586 * after unlocking native capacity.
587 */
588 if (PTR_ERR(state) == -ENOSPC) {
589 printk(KERN_WARNING "%s: partition table beyond EOD, ",
590 disk->disk_name);
591 if (disk_unlock_native_capacity(disk))
592 goto rescan;
593 }
594 return -EIO;
595 }
596 /*
597 * If any partition code tried to read beyond EOD, try
598 * unlocking native capacity even if partition table is
599 * successfully read as we could be missing some partitions.
600 */
601 if (state->access_beyond_eod) {
602 printk(KERN_WARNING
603 "%s: partition table partially beyond EOD, ",
604 disk->disk_name);
605 if (disk_unlock_native_capacity(disk))
606 goto rescan;
607 }
608
609 /* tell userspace that the media / partition table may have changed */
610 kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
611
612 /* Detect the highest partition number and preallocate
613 * disk->part_tbl. This is an optimization and not strictly
614 * necessary.
615 */
616 for (p = 1, highest = 0; p < state->limit; p++)
617 if (state->parts[p].size)
618 highest = p;
619
620 disk_expand_part_tbl(disk, highest);
621
622 /* add partitions */
623 for (p = 1; p < state->limit; p++) {
624 sector_t size, from;
625 struct partition_meta_info *info = NULL;
626
627 size = state->parts[p].size;
628 if (!size)
629 continue;
630
631 from = state->parts[p].from;
632 if (from >= get_capacity(disk)) {
633 printk(KERN_WARNING
634 "%s: p%d start %llu is beyond EOD, ",
635 disk->disk_name, p, (unsigned long long) from);
636 if (disk_unlock_native_capacity(disk))
637 goto rescan;
638 continue;
639 }
640
641 if (from + size > get_capacity(disk)) {
642 printk(KERN_WARNING
643 "%s: p%d size %llu extends beyond EOD, ",
644 disk->disk_name, p, (unsigned long long) size);
645
646 if (disk_unlock_native_capacity(disk)) {
647 /* free state and restart */
648 goto rescan;
649 } else {
650 /*
651 * we can not ignore partitions of broken tables
652 * created by for example camera firmware, but
653 * we limit them to the end of the disk to avoid
654 * creating invalid block devices
655 */
656 size = get_capacity(disk) - from;
657 }
658 }
659
660 if (state->parts[p].has_info)
661 info = &state->parts[p].info;
662 part = add_partition(disk, p, from, size,
663 state->parts[p].flags,
664 &state->parts[p].info);
665 if (IS_ERR(part)) {
666 printk(KERN_ERR " %s: p%d could not be added: %ld\n",
667 disk->disk_name, p, -PTR_ERR(part));
668 continue;
669 }
670#ifdef CONFIG_BLK_DEV_MD
671 if (state->parts[p].flags & ADDPART_FLAG_RAID)
672 md_autodetect_dev(part_to_dev(part)->devt);
673#endif
674 }
675 kfree(state);
676 return 0;
677}
678
679unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
680{
681 struct address_space *mapping = bdev->bd_inode->i_mapping;
682 struct page *page;
683
684 page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
685 NULL);
686 if (!IS_ERR(page)) {
687 if (PageError(page))
688 goto fail;
689 p->v = page;
690 return (unsigned char *)page_address(page) + ((n & ((1 << (PAGE_CACHE_SHIFT - 9)) - 1)) << 9);
691fail:
692 page_cache_release(page);
693 }
694 p->v = NULL;
695 return NULL;
696}
697
698EXPORT_SYMBOL(read_dev_sector);
diff --git a/fs/partitions/check.h b/fs/partitions/check.h
new file mode 100644
index 00000000000..d68bf4dc3bc
--- /dev/null
+++ b/fs/partitions/check.h
@@ -0,0 +1,49 @@
1#include <linux/pagemap.h>
2#include <linux/blkdev.h>
3#include <linux/genhd.h>
4
5/*
6 * add_gd_partition adds a partitions details to the devices partition
7 * description.
8 */
9struct parsed_partitions {
10 struct block_device *bdev;
11 char name[BDEVNAME_SIZE];
12 struct {
13 sector_t from;
14 sector_t size;
15 int flags;
16 bool has_info;
17 struct partition_meta_info info;
18 } parts[DISK_MAX_PARTS];
19 int next;
20 int limit;
21 bool access_beyond_eod;
22 char *pp_buf;
23};
24
25static inline void *read_part_sector(struct parsed_partitions *state,
26 sector_t n, Sector *p)
27{
28 if (n >= get_capacity(state->bdev->bd_disk)) {
29 state->access_beyond_eod = true;
30 return NULL;
31 }
32 return read_dev_sector(state->bdev, n, p);
33}
34
35static inline void
36put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
37{
38 if (n < p->limit) {
39 char tmp[1 + BDEVNAME_SIZE + 10 + 1];
40
41 p->parts[n].from = from;
42 p->parts[n].size = size;
43 snprintf(tmp, sizeof(tmp), " %s%d", p->name, n);
44 strlcat(p->pp_buf, tmp, PAGE_SIZE);
45 }
46}
47
48extern int warn_no_part;
49
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c
new file mode 100644
index 00000000000..30546cc8d03
--- /dev/null
+++ b/fs/partitions/efi.c
@@ -0,0 +1,686 @@
1/************************************************************
2 * EFI GUID Partition Table handling
3 *
4 * http://www.uefi.org/specs/
5 * http://www.intel.com/technology/efi/
6 *
7 * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
8 * Copyright 2000,2001,2002,2004 Dell Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 *
25 * TODO:
26 *
27 * Changelog:
28 * Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com>
29 * - test for valid PMBR and valid PGPT before ever reading
30 * AGPT, allow override with 'gpt' kernel command line option.
31 * - check for first/last_usable_lba outside of size of disk
32 *
33 * Tue Mar 26 2002 Matt Domsch <Matt_Domsch@dell.com>
34 * - Ported to 2.5.7-pre1 and 2.5.7-dj2
35 * - Applied patch to avoid fault in alternate header handling
36 * - cleaned up find_valid_gpt
37 * - On-disk structure and copy in memory is *always* LE now -
38 * swab fields as needed
39 * - remove print_gpt_header()
40 * - only use first max_p partition entries, to keep the kernel minor number
41 * and partition numbers tied.
42 *
43 * Mon Feb 04 2002 Matt Domsch <Matt_Domsch@dell.com>
44 * - Removed __PRIPTR_PREFIX - not being used
45 *
46 * Mon Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com>
47 * - Ported to 2.5.2-pre11 + library crc32 patch Linus applied
48 *
49 * Thu Dec 6 2001 Matt Domsch <Matt_Domsch@dell.com>
50 * - Added compare_gpts().
51 * - moved le_efi_guid_to_cpus() back into this file. GPT is the only
52 * thing that keeps EFI GUIDs on disk.
53 * - Changed gpt structure names and members to be simpler and more Linux-like.
54 *
55 * Wed Oct 17 2001 Matt Domsch <Matt_Domsch@dell.com>
56 * - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck
57 *
58 * Wed Oct 10 2001 Matt Domsch <Matt_Domsch@dell.com>
59 * - Changed function comments to DocBook style per Andreas Dilger suggestion.
60 *
61 * Mon Oct 08 2001 Matt Domsch <Matt_Domsch@dell.com>
62 * - Change read_lba() to use the page cache per Al Viro's work.
63 * - print u64s properly on all architectures
64 * - fixed debug_printk(), now Dprintk()
65 *
66 * Mon Oct 01 2001 Matt Domsch <Matt_Domsch@dell.com>
67 * - Style cleanups
68 * - made most functions static
69 * - Endianness addition
70 * - remove test for second alternate header, as it's not per spec,
71 * and is unnecessary. There's now a method to read/write the last
72 * sector of an odd-sized disk from user space. No tools have ever
73 * been released which used this code, so it's effectively dead.
74 * - Per Asit Mallick of Intel, added a test for a valid PMBR.
75 * - Added kernel command line option 'gpt' to override valid PMBR test.
76 *
77 * Wed Jun 6 2001 Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com>
78 * - added devfs volume UUID support (/dev/volumes/uuids) for
79 * mounting file systems by the partition GUID.
80 *
81 * Tue Dec 5 2000 Matt Domsch <Matt_Domsch@dell.com>
82 * - Moved crc32() to linux/lib, added efi_crc32().
83 *
84 * Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com>
85 * - Replaced Intel's CRC32 function with an equivalent
86 * non-license-restricted version.
87 *
88 * Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com>
89 * - Fixed the last_lba() call to return the proper last block
90 *
91 * Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com>
92 * - Thanks to Andries Brouwer for his debugging assistance.
93 * - Code works, detects all the partitions.
94 *
95 ************************************************************/
96#include <linux/crc32.h>
97#include <linux/ctype.h>
98#include <linux/math64.h>
99#include <linux/slab.h>
100#include "check.h"
101#include "efi.h"
102
103/* This allows a kernel command line option 'gpt' to override
104 * the test for invalid PMBR. Not __initdata because reloading
105 * the partition tables happens after init too.
106 */
107static int force_gpt;
108static u64 force_gpt_sector;
109static int __init
110force_gpt_fn(char *str)
111{
112 force_gpt = 1;
113 return 1;
114}
115__setup("gpt", force_gpt_fn);
116
117static int __init force_gpt_sector_fn(char *str)
118{
119 force_gpt_sector = simple_strtoull(str, NULL, 0);
120 return 1;
121}
122__setup("gpt_sector=", force_gpt_sector_fn);
123
124
125/**
126 * efi_crc32() - EFI version of crc32 function
127 * @buf: buffer to calculate crc32 of
128 * @len - length of buf
129 *
130 * Description: Returns EFI-style CRC32 value for @buf
131 *
132 * This function uses the little endian Ethernet polynomial
133 * but seeds the function with ~0, and xor's with ~0 at the end.
134 * Note, the EFI Specification, v1.02, has a reference to
135 * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
136 */
137static inline u32
138efi_crc32(const void *buf, unsigned long len)
139{
140 return (crc32(~0L, buf, len) ^ ~0L);
141}
142
143/**
144 * last_lba(): return number of last logical block of device
145 * @bdev: block device
146 *
147 * Description: Returns last LBA value on success, 0 on error.
148 * This is stored (by sd and ide-geometry) in
149 * the part[0] entry for this disk, and is the number of
150 * physical sectors available on the disk.
151 */
152static u64 last_lba(struct block_device *bdev)
153{
154 if (!bdev || !bdev->bd_inode)
155 return 0;
156 return div_u64(bdev->bd_inode->i_size,
157 bdev_logical_block_size(bdev)) - 1ULL;
158}
159
160static inline int
161pmbr_part_valid(struct partition *part)
162{
163 if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
164 le32_to_cpu(part->start_sect) == 1UL)
165 return 1;
166 return 0;
167}
168
169/**
170 * is_pmbr_valid(): test Protective MBR for validity
171 * @mbr: pointer to a legacy mbr structure
172 *
173 * Description: Returns 1 if PMBR is valid, 0 otherwise.
174 * Validity depends on two things:
175 * 1) MSDOS signature is in the last two bytes of the MBR
176 * 2) One partition of type 0xEE is found
177 */
178static int
179is_pmbr_valid(legacy_mbr *mbr)
180{
181 int i;
182 if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
183 return 0;
184 for (i = 0; i < 4; i++)
185 if (pmbr_part_valid(&mbr->partition_record[i]))
186 return 1;
187 return 0;
188}
189
190/**
191 * read_lba(): Read bytes from disk, starting at given LBA
192 * @state
193 * @lba
194 * @buffer
195 * @size_t
196 *
197 * Description: Reads @count bytes from @state->bdev into @buffer.
198 * Returns number of bytes read on success, 0 on error.
199 */
200static size_t read_lba(struct parsed_partitions *state,
201 u64 lba, u8 *buffer, size_t count)
202{
203 size_t totalreadcount = 0;
204 struct block_device *bdev = state->bdev;
205 sector_t n = lba * (bdev_logical_block_size(bdev) / 512);
206
207 if (!buffer || lba > last_lba(bdev))
208 return 0;
209
210 while (count) {
211 int copied = 512;
212 Sector sect;
213 unsigned char *data = read_part_sector(state, n++, &sect);
214 if (!data)
215 break;
216 if (copied > count)
217 copied = count;
218 memcpy(buffer, data, copied);
219 put_dev_sector(sect);
220 buffer += copied;
221 totalreadcount +=copied;
222 count -= copied;
223 }
224 return totalreadcount;
225}
226
227/**
228 * alloc_read_gpt_entries(): reads partition entries from disk
229 * @state
230 * @gpt - GPT header
231 *
232 * Description: Returns ptes on success, NULL on error.
233 * Allocates space for PTEs based on information found in @gpt.
234 * Notes: remember to free pte when you're done!
235 */
236static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state,
237 gpt_header *gpt)
238{
239 size_t count;
240 gpt_entry *pte;
241
242 if (!gpt)
243 return NULL;
244
245 count = le32_to_cpu(gpt->num_partition_entries) *
246 le32_to_cpu(gpt->sizeof_partition_entry);
247 if (!count)
248 return NULL;
249 pte = kzalloc(count, GFP_KERNEL);
250 if (!pte)
251 return NULL;
252
253 if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba),
254 (u8 *) pte,
255 count) < count) {
256 kfree(pte);
257 pte=NULL;
258 return NULL;
259 }
260 return pte;
261}
262
263/**
264 * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
265 * @state
266 * @lba is the Logical Block Address of the partition table
267 *
268 * Description: returns GPT header on success, NULL on error. Allocates
269 * and fills a GPT header starting at @ from @state->bdev.
270 * Note: remember to free gpt when finished with it.
271 */
272static gpt_header *alloc_read_gpt_header(struct parsed_partitions *state,
273 u64 lba)
274{
275 gpt_header *gpt;
276 unsigned ssz = bdev_logical_block_size(state->bdev);
277
278 gpt = kzalloc(ssz, GFP_KERNEL);
279 if (!gpt)
280 return NULL;
281
282 if (read_lba(state, lba, (u8 *) gpt, ssz) < ssz) {
283 kfree(gpt);
284 gpt=NULL;
285 return NULL;
286 }
287
288 return gpt;
289}
290
291/**
292 * is_gpt_valid() - tests one GPT header and PTEs for validity
293 * @state
294 * @lba is the logical block address of the GPT header to test
295 * @gpt is a GPT header ptr, filled on return.
296 * @ptes is a PTEs ptr, filled on return.
297 *
298 * Description: returns 1 if valid, 0 on error.
299 * If valid, returns pointers to newly allocated GPT header and PTEs.
300 */
301static int is_gpt_valid(struct parsed_partitions *state, u64 lba,
302 gpt_header **gpt, gpt_entry **ptes)
303{
304 u32 crc, origcrc;
305 u64 lastlba;
306
307 if (!ptes)
308 return 0;
309 if (!(*gpt = alloc_read_gpt_header(state, lba)))
310 return 0;
311
312 /* Check the GUID Partition Table signature */
313 if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
314 pr_debug("GUID Partition Table Header signature is wrong:"
315 "%lld != %lld\n",
316 (unsigned long long)le64_to_cpu((*gpt)->signature),
317 (unsigned long long)GPT_HEADER_SIGNATURE);
318 goto fail;
319 }
320
321 /* Check the GUID Partition Table header size */
322 if (le32_to_cpu((*gpt)->header_size) >
323 bdev_logical_block_size(state->bdev)) {
324 pr_debug("GUID Partition Table Header size is wrong: %u > %u\n",
325 le32_to_cpu((*gpt)->header_size),
326 bdev_logical_block_size(state->bdev));
327 goto fail;
328 }
329
330 /* Check the GUID Partition Table CRC */
331 origcrc = le32_to_cpu((*gpt)->header_crc32);
332 (*gpt)->header_crc32 = 0;
333 crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size));
334
335 if (crc != origcrc) {
336 pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n",
337 crc, origcrc);
338 goto fail;
339 }
340 (*gpt)->header_crc32 = cpu_to_le32(origcrc);
341
342 /* Check that the my_lba entry points to the LBA that contains
343 * the GUID Partition Table */
344 if (le64_to_cpu((*gpt)->my_lba) != lba) {
345 pr_debug("GPT my_lba incorrect: %lld != %lld\n",
346 (unsigned long long)le64_to_cpu((*gpt)->my_lba),
347 (unsigned long long)lba);
348 goto fail;
349 }
350
351 /* Check the first_usable_lba and last_usable_lba are
352 * within the disk.
353 */
354 lastlba = last_lba(state->bdev);
355 if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) {
356 pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n",
357 (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba),
358 (unsigned long long)lastlba);
359 goto fail;
360 }
361 if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) {
362 pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n",
363 (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
364 (unsigned long long)lastlba);
365 goto fail;
366 }
367
368 /* Check that sizeof_partition_entry has the correct value */
369 if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) {
370 pr_debug("GUID Partitition Entry Size check failed.\n");
371 goto fail;
372 }
373
374 if (!(*ptes = alloc_read_gpt_entries(state, *gpt)))
375 goto fail;
376
377 /* Check the GUID Partition Entry Array CRC */
378 crc = efi_crc32((const unsigned char *) (*ptes),
379 le32_to_cpu((*gpt)->num_partition_entries) *
380 le32_to_cpu((*gpt)->sizeof_partition_entry));
381
382 if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
383 pr_debug("GUID Partitition Entry Array CRC check failed.\n");
384 goto fail_ptes;
385 }
386
387 /* We're done, all's well */
388 return 1;
389
390 fail_ptes:
391 kfree(*ptes);
392 *ptes = NULL;
393 fail:
394 kfree(*gpt);
395 *gpt = NULL;
396 return 0;
397}
398
399/**
400 * is_pte_valid() - tests one PTE for validity
401 * @pte is the pte to check
402 * @lastlba is last lba of the disk
403 *
404 * Description: returns 1 if valid, 0 on error.
405 */
406static inline int
407is_pte_valid(const gpt_entry *pte, const u64 lastlba)
408{
409 if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
410 le64_to_cpu(pte->starting_lba) > lastlba ||
411 le64_to_cpu(pte->ending_lba) > lastlba)
412 return 0;
413 return 1;
414}
415
416/**
417 * compare_gpts() - Search disk for valid GPT headers and PTEs
418 * @pgpt is the primary GPT header
419 * @agpt is the alternate GPT header
420 * @lastlba is the last LBA number
421 * Description: Returns nothing. Sanity checks pgpt and agpt fields
422 * and prints warnings on discrepancies.
423 *
424 */
425static void
426compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
427{
428 int error_found = 0;
429 if (!pgpt || !agpt)
430 return;
431 if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
432 printk(KERN_WARNING
433 "GPT:Primary header LBA != Alt. header alternate_lba\n");
434 printk(KERN_WARNING "GPT:%lld != %lld\n",
435 (unsigned long long)le64_to_cpu(pgpt->my_lba),
436 (unsigned long long)le64_to_cpu(agpt->alternate_lba));
437 error_found++;
438 }
439 if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
440 printk(KERN_WARNING
441 "GPT:Primary header alternate_lba != Alt. header my_lba\n");
442 printk(KERN_WARNING "GPT:%lld != %lld\n",
443 (unsigned long long)le64_to_cpu(pgpt->alternate_lba),
444 (unsigned long long)le64_to_cpu(agpt->my_lba));
445 error_found++;
446 }
447 if (le64_to_cpu(pgpt->first_usable_lba) !=
448 le64_to_cpu(agpt->first_usable_lba)) {
449 printk(KERN_WARNING "GPT:first_usable_lbas don't match.\n");
450 printk(KERN_WARNING "GPT:%lld != %lld\n",
451 (unsigned long long)le64_to_cpu(pgpt->first_usable_lba),
452 (unsigned long long)le64_to_cpu(agpt->first_usable_lba));
453 error_found++;
454 }
455 if (le64_to_cpu(pgpt->last_usable_lba) !=
456 le64_to_cpu(agpt->last_usable_lba)) {
457 printk(KERN_WARNING "GPT:last_usable_lbas don't match.\n");
458 printk(KERN_WARNING "GPT:%lld != %lld\n",
459 (unsigned long long)le64_to_cpu(pgpt->last_usable_lba),
460 (unsigned long long)le64_to_cpu(agpt->last_usable_lba));
461 error_found++;
462 }
463 if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
464 printk(KERN_WARNING "GPT:disk_guids don't match.\n");
465 error_found++;
466 }
467 if (le32_to_cpu(pgpt->num_partition_entries) !=
468 le32_to_cpu(agpt->num_partition_entries)) {
469 printk(KERN_WARNING "GPT:num_partition_entries don't match: "
470 "0x%x != 0x%x\n",
471 le32_to_cpu(pgpt->num_partition_entries),
472 le32_to_cpu(agpt->num_partition_entries));
473 error_found++;
474 }
475 if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
476 le32_to_cpu(agpt->sizeof_partition_entry)) {
477 printk(KERN_WARNING
478 "GPT:sizeof_partition_entry values don't match: "
479 "0x%x != 0x%x\n",
480 le32_to_cpu(pgpt->sizeof_partition_entry),
481 le32_to_cpu(agpt->sizeof_partition_entry));
482 error_found++;
483 }
484 if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
485 le32_to_cpu(agpt->partition_entry_array_crc32)) {
486 printk(KERN_WARNING
487 "GPT:partition_entry_array_crc32 values don't match: "
488 "0x%x != 0x%x\n",
489 le32_to_cpu(pgpt->partition_entry_array_crc32),
490 le32_to_cpu(agpt->partition_entry_array_crc32));
491 error_found++;
492 }
493 if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
494 printk(KERN_WARNING
495 "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
496 printk(KERN_WARNING "GPT:%lld != %lld\n",
497 (unsigned long long)le64_to_cpu(pgpt->alternate_lba),
498 (unsigned long long)lastlba);
499 error_found++;
500 }
501
502 if (le64_to_cpu(agpt->my_lba) != lastlba) {
503 printk(KERN_WARNING
504 "GPT:Alternate GPT header not at the end of the disk.\n");
505 printk(KERN_WARNING "GPT:%lld != %lld\n",
506 (unsigned long long)le64_to_cpu(agpt->my_lba),
507 (unsigned long long)lastlba);
508 error_found++;
509 }
510
511 if (error_found)
512 printk(KERN_WARNING
513 "GPT: Use GNU Parted to correct GPT errors.\n");
514 return;
515}
516
517/**
518 * find_valid_gpt() - Search disk for valid GPT headers and PTEs
519 * @state
520 * @gpt is a GPT header ptr, filled on return.
521 * @ptes is a PTEs ptr, filled on return.
522 * Description: Returns 1 if valid, 0 on error.
523 * If valid, returns pointers to newly allocated GPT header and PTEs.
524 * Validity depends on PMBR being valid (or being overridden by the
525 * 'gpt' kernel command line option) and finding either the Primary
526 * GPT header and PTEs valid, or the Alternate GPT header and PTEs
527 * valid. If the Primary GPT header is not valid, the Alternate GPT header
528 * is not checked unless the 'gpt' kernel command line option is passed.
529 * This protects against devices which misreport their size, and forces
530 * the user to decide to use the Alternate GPT.
531 */
532static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
533 gpt_entry **ptes)
534{
535 int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
536 gpt_header *pgpt = NULL, *agpt = NULL;
537 gpt_entry *pptes = NULL, *aptes = NULL;
538 legacy_mbr *legacymbr;
539 u64 lastlba;
540
541 if (!ptes)
542 return 0;
543
544 lastlba = last_lba(state->bdev);
545 if (!force_gpt) {
546 /* This will be added to the EFI Spec. per Intel after v1.02. */
547 legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL);
548 if (legacymbr) {
549 read_lba(state, 0, (u8 *) legacymbr,
550 sizeof (*legacymbr));
551 good_pmbr = is_pmbr_valid(legacymbr);
552 kfree(legacymbr);
553 }
554 if (!good_pmbr)
555 goto fail;
556 }
557
558 good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA,
559 &pgpt, &pptes);
560 if (good_pgpt)
561 good_agpt = is_gpt_valid(state,
562 le64_to_cpu(pgpt->alternate_lba),
563 &agpt, &aptes);
564 if (!good_agpt && force_gpt)
565 good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes);
566
567 if (!good_agpt && force_gpt && force_gpt_sector)
568 good_agpt = is_gpt_valid(state, force_gpt_sector, &agpt, &aptes);
569
570 /* The obviously unsuccessful case */
571 if (!good_pgpt && !good_agpt)
572 goto fail;
573
574 compare_gpts(pgpt, agpt, lastlba);
575
576 /* The good cases */
577 if (good_pgpt) {
578 *gpt = pgpt;
579 *ptes = pptes;
580 kfree(agpt);
581 kfree(aptes);
582 if (!good_agpt) {
583 printk(KERN_WARNING
584 "Alternate GPT is invalid, "
585 "using primary GPT.\n");
586 }
587 return 1;
588 }
589 else if (good_agpt) {
590 *gpt = agpt;
591 *ptes = aptes;
592 kfree(pgpt);
593 kfree(pptes);
594 printk(KERN_WARNING
595 "Primary GPT is invalid, using alternate GPT.\n");
596 return 1;
597 }
598
599 fail:
600 kfree(pgpt);
601 kfree(agpt);
602 kfree(pptes);
603 kfree(aptes);
604 *gpt = NULL;
605 *ptes = NULL;
606 return 0;
607}
608
609/**
610 * efi_partition(struct parsed_partitions *state)
611 * @state
612 *
613 * Description: called from check.c, if the disk contains GPT
614 * partitions, sets up partition entries in the kernel.
615 *
616 * If the first block on the disk is a legacy MBR,
617 * it will get handled by msdos_partition().
618 * If it's a Protective MBR, we'll handle it here.
619 *
620 * We do not create a Linux partition for GPT, but
621 * only for the actual data partitions.
622 * Returns:
623 * -1 if unable to read the partition table
624 * 0 if this isn't our partition table
625 * 1 if successful
626 *
627 */
628int efi_partition(struct parsed_partitions *state)
629{
630 gpt_header *gpt = NULL;
631 gpt_entry *ptes = NULL;
632 u32 i;
633 unsigned ssz = bdev_logical_block_size(state->bdev) / 512;
634 u8 unparsed_guid[37];
635
636 if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) {
637 kfree(gpt);
638 kfree(ptes);
639 return 0;
640 }
641
642 pr_debug("GUID Partition Table is valid! Yea!\n");
643
644 for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
645 struct partition_meta_info *info;
646 unsigned label_count = 0;
647 unsigned label_max;
648 u64 start = le64_to_cpu(ptes[i].starting_lba);
649 u64 size = le64_to_cpu(ptes[i].ending_lba) -
650 le64_to_cpu(ptes[i].starting_lba) + 1ULL;
651
652 if (!is_pte_valid(&ptes[i], last_lba(state->bdev)))
653 continue;
654
655 put_partition(state, i+1, start * ssz, size * ssz);
656
657 /* If this is a RAID volume, tell md */
658 if (!efi_guidcmp(ptes[i].partition_type_guid,
659 PARTITION_LINUX_RAID_GUID))
660 state->parts[i + 1].flags = ADDPART_FLAG_RAID;
661
662 info = &state->parts[i + 1].info;
663 /* Instead of doing a manual swap to big endian, reuse the
664 * common ASCII hex format as the interim.
665 */
666 efi_guid_unparse(&ptes[i].unique_partition_guid, unparsed_guid);
667 part_pack_uuid(unparsed_guid, info->uuid);
668
669 /* Naively convert UTF16-LE to 7 bits. */
670 label_max = min(sizeof(info->volname) - 1,
671 sizeof(ptes[i].partition_name));
672 info->volname[label_max] = 0;
673 while (label_count < label_max) {
674 u8 c = ptes[i].partition_name[label_count] & 0xff;
675 if (c && !isprint(c))
676 c = '!';
677 info->volname[label_count] = c;
678 label_count++;
679 }
680 state->parts[i + 1].has_info = true;
681 }
682 kfree(ptes);
683 kfree(gpt);
684 strlcat(state->pp_buf, "\n", PAGE_SIZE);
685 return 1;
686}
diff --git a/fs/partitions/efi.h b/fs/partitions/efi.h
new file mode 100644
index 00000000000..b69ab729558
--- /dev/null
+++ b/fs/partitions/efi.h
@@ -0,0 +1,134 @@
1/************************************************************
2 * EFI GUID Partition Table
3 * Per Intel EFI Specification v1.02
4 * http://developer.intel.com/technology/efi/efi.htm
5 *
6 * By Matt Domsch <Matt_Domsch@dell.com> Fri Sep 22 22:15:56 CDT 2000
7 * Copyright 2000,2001 Dell Inc.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 ************************************************************/
24
25#ifndef FS_PART_EFI_H_INCLUDED
26#define FS_PART_EFI_H_INCLUDED
27
28#include <linux/types.h>
29#include <linux/fs.h>
30#include <linux/genhd.h>
31#include <linux/kernel.h>
32#include <linux/major.h>
33#include <linux/string.h>
34#include <linux/efi.h>
35
36#define MSDOS_MBR_SIGNATURE 0xaa55
37#define EFI_PMBR_OSTYPE_EFI 0xEF
38#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
39
40#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
41#define GPT_HEADER_REVISION_V1 0x00010000
42#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
43
44#define PARTITION_SYSTEM_GUID \
45 EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
46 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
47#define LEGACY_MBR_PARTITION_GUID \
48 EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
49 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
50#define PARTITION_MSFT_RESERVED_GUID \
51 EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
52 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
53#define PARTITION_BASIC_DATA_GUID \
54 EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
55 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
56#define PARTITION_LINUX_RAID_GUID \
57 EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
58 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
59#define PARTITION_LINUX_SWAP_GUID \
60 EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
61 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
62#define PARTITION_LINUX_LVM_GUID \
63 EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
64 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
65
66typedef struct _gpt_header {
67 __le64 signature;
68 __le32 revision;
69 __le32 header_size;
70 __le32 header_crc32;
71 __le32 reserved1;
72 __le64 my_lba;
73 __le64 alternate_lba;
74 __le64 first_usable_lba;
75 __le64 last_usable_lba;
76 efi_guid_t disk_guid;
77 __le64 partition_entry_lba;
78 __le32 num_partition_entries;
79 __le32 sizeof_partition_entry;
80 __le32 partition_entry_array_crc32;
81
82 /* The rest of the logical block is reserved by UEFI and must be zero.
83 * EFI standard handles this by:
84 *
85 * uint8_t reserved2[ BlockSize - 92 ];
86 */
87} __attribute__ ((packed)) gpt_header;
88
89typedef struct _gpt_entry_attributes {
90 u64 required_to_function:1;
91 u64 reserved:47;
92 u64 type_guid_specific:16;
93} __attribute__ ((packed)) gpt_entry_attributes;
94
95typedef struct _gpt_entry {
96 efi_guid_t partition_type_guid;
97 efi_guid_t unique_partition_guid;
98 __le64 starting_lba;
99 __le64 ending_lba;
100 gpt_entry_attributes attributes;
101 efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
102} __attribute__ ((packed)) gpt_entry;
103
104typedef struct _legacy_mbr {
105 u8 boot_code[440];
106 __le32 unique_mbr_signature;
107 __le16 unknown;
108 struct partition partition_record[4];
109 __le16 signature;
110} __attribute__ ((packed)) legacy_mbr;
111
112/* Functions */
113extern int efi_partition(struct parsed_partitions *state);
114
115#endif
116
117/*
118 * Overrides for Emacs so that we follow Linus's tabbing style.
119 * Emacs will notice this stuff at the end of the file and automatically
120 * adjust the settings for this buffer only. This must remain at the end
121 * of the file.
122 * --------------------------------------------------------------------------
123 * Local variables:
124 * c-indent-level: 4
125 * c-brace-imaginary-offset: 0
126 * c-brace-offset: -4
127 * c-argdecl-indent: 4
128 * c-label-offset: -4
129 * c-continued-statement-offset: 4
130 * c-continued-brace-offset: 0
131 * indent-tabs-mode: nil
132 * tab-width: 8
133 * End:
134 */
diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c
new file mode 100644
index 00000000000..d513a07f44b
--- /dev/null
+++ b/fs/partitions/ibm.c
@@ -0,0 +1,275 @@
1/*
2 * File...........: linux/fs/partitions/ibm.c
3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4 * Volker Sameske <sameske@de.ibm.com>
5 * Bugreports.to..: <Linux390@de.ibm.com>
6 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
7 */
8
9#include <linux/buffer_head.h>
10#include <linux/hdreg.h>
11#include <linux/slab.h>
12#include <asm/dasd.h>
13#include <asm/ebcdic.h>
14#include <asm/uaccess.h>
15#include <asm/vtoc.h>
16
17#include "check.h"
18#include "ibm.h"
19
20/*
21 * compute the block number from a
22 * cyl-cyl-head-head structure
23 */
24static sector_t
25cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) {
26
27 sector_t cyl;
28 __u16 head;
29
30 /*decode cylinder and heads for large volumes */
31 cyl = ptr->hh & 0xFFF0;
32 cyl <<= 12;
33 cyl |= ptr->cc;
34 head = ptr->hh & 0x000F;
35 return cyl * geo->heads * geo->sectors +
36 head * geo->sectors;
37}
38
39/*
40 * compute the block number from a
41 * cyl-cyl-head-head-block structure
42 */
43static sector_t
44cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {
45
46 sector_t cyl;
47 __u16 head;
48
49 /*decode cylinder and heads for large volumes */
50 cyl = ptr->hh & 0xFFF0;
51 cyl <<= 12;
52 cyl |= ptr->cc;
53 head = ptr->hh & 0x000F;
54 return cyl * geo->heads * geo->sectors +
55 head * geo->sectors +
56 ptr->b;
57}
58
59/*
60 */
61int ibm_partition(struct parsed_partitions *state)
62{
63 struct block_device *bdev = state->bdev;
64 int blocksize, res;
65 loff_t i_size, offset, size, fmt_size;
66 dasd_information2_t *info;
67 struct hd_geometry *geo;
68 char type[5] = {0,};
69 char name[7] = {0,};
70 union label_t {
71 struct vtoc_volume_label_cdl vol;
72 struct vtoc_volume_label_ldl lnx;
73 struct vtoc_cms_label cms;
74 } *label;
75 unsigned char *data;
76 Sector sect;
77 sector_t labelsect;
78 char tmp[64];
79
80 res = 0;
81 blocksize = bdev_logical_block_size(bdev);
82 if (blocksize <= 0)
83 goto out_exit;
84 i_size = i_size_read(bdev->bd_inode);
85 if (i_size == 0)
86 goto out_exit;
87
88 info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
89 if (info == NULL)
90 goto out_exit;
91 geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
92 if (geo == NULL)
93 goto out_nogeo;
94 label = kmalloc(sizeof(union label_t), GFP_KERNEL);
95 if (label == NULL)
96 goto out_nolab;
97
98 if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0 ||
99 ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
100 goto out_freeall;
101
102 /*
103 * Special case for FBA disks: label sector does not depend on
104 * blocksize.
105 */
106 if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
107 (info->cu_type == 0x3880 && info->dev_type == 0x3370))
108 labelsect = info->label_block;
109 else
110 labelsect = info->label_block * (blocksize >> 9);
111
112 /*
113 * Get volume label, extract name and type.
114 */
115 data = read_part_sector(state, labelsect, &sect);
116 if (data == NULL)
117 goto out_readerr;
118
119 memcpy(label, data, sizeof(union label_t));
120 put_dev_sector(sect);
121
122 if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
123 strncpy(type, label->vol.vollbl, 4);
124 strncpy(name, label->vol.volid, 6);
125 } else {
126 strncpy(type, label->lnx.vollbl, 4);
127 strncpy(name, label->lnx.volid, 6);
128 }
129 EBCASC(type, 4);
130 EBCASC(name, 6);
131
132 res = 1;
133
134 /*
135 * Three different formats: LDL, CDL and unformated disk
136 *
137 * identified by info->format
138 *
139 * unformated disks we do not have to care about
140 */
141 if (info->format == DASD_FORMAT_LDL) {
142 if (strncmp(type, "CMS1", 4) == 0) {
143 /*
144 * VM style CMS1 labeled disk
145 */
146 blocksize = label->cms.block_size;
147 if (label->cms.disk_offset != 0) {
148 snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
149 strlcat(state->pp_buf, tmp, PAGE_SIZE);
150 /* disk is reserved minidisk */
151 offset = label->cms.disk_offset;
152 size = (label->cms.block_count - 1)
153 * (blocksize >> 9);
154 } else {
155 snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
156 strlcat(state->pp_buf, tmp, PAGE_SIZE);
157 offset = (info->label_block + 1);
158 size = label->cms.block_count
159 * (blocksize >> 9);
160 }
161 put_partition(state, 1, offset*(blocksize >> 9),
162 size-offset*(blocksize >> 9));
163 } else {
164 if (strncmp(type, "LNX1", 4) == 0) {
165 snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
166 strlcat(state->pp_buf, tmp, PAGE_SIZE);
167 if (label->lnx.ldl_version == 0xf2) {
168 fmt_size = label->lnx.formatted_blocks
169 * (blocksize >> 9);
170 } else if (!strcmp(info->type, "ECKD")) {
171 /* formated w/o large volume support */
172 fmt_size = geo->cylinders * geo->heads
173 * geo->sectors * (blocksize >> 9);
174 } else {
175 /* old label and no usable disk geometry
176 * (e.g. DIAG) */
177 fmt_size = i_size >> 9;
178 }
179 size = i_size >> 9;
180 if (fmt_size < size)
181 size = fmt_size;
182 offset = (info->label_block + 1);
183 } else {
184 /* unlabeled disk */
185 strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
186 size = i_size >> 9;
187 offset = (info->label_block + 1);
188 }
189 put_partition(state, 1, offset*(blocksize >> 9),
190 size-offset*(blocksize >> 9));
191 }
192 } else if (info->format == DASD_FORMAT_CDL) {
193 /*
194 * New style CDL formatted disk
195 */
196 sector_t blk;
197 int counter;
198
199 /*
200 * check if VOL1 label is available
201 * if not, something is wrong, skipping partition detection
202 */
203 if (strncmp(type, "VOL1", 4) == 0) {
204 snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
205 strlcat(state->pp_buf, tmp, PAGE_SIZE);
206 /*
207 * get block number and read then go through format1
208 * labels
209 */
210 blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
211 counter = 0;
212 data = read_part_sector(state, blk * (blocksize/512),
213 &sect);
214 while (data != NULL) {
215 struct vtoc_format1_label f1;
216
217 memcpy(&f1, data,
218 sizeof(struct vtoc_format1_label));
219 put_dev_sector(sect);
220
221 /* skip FMT4 / FMT5 / FMT7 labels */
222 if (f1.DS1FMTID == _ascebc['4']
223 || f1.DS1FMTID == _ascebc['5']
224 || f1.DS1FMTID == _ascebc['7']
225 || f1.DS1FMTID == _ascebc['9']) {
226 blk++;
227 data = read_part_sector(state,
228 blk * (blocksize/512), &sect);
229 continue;
230 }
231
232 /* only FMT1 and 8 labels valid at this point */
233 if (f1.DS1FMTID != _ascebc['1'] &&
234 f1.DS1FMTID != _ascebc['8'])
235 break;
236
237 /* OK, we got valid partition data */
238 offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
239 size = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
240 offset + geo->sectors;
241 if (counter >= state->limit)
242 break;
243 put_partition(state, counter + 1,
244 offset * (blocksize >> 9),
245 size * (blocksize >> 9));
246 counter++;
247 blk++;
248 data = read_part_sector(state,
249 blk * (blocksize/512), &sect);
250 }
251
252 if (!data)
253 /* Are we not supposed to report this ? */
254 goto out_readerr;
255 } else
256 printk(KERN_WARNING "Warning, expected Label VOL1 not "
257 "found, treating as CDL formated Disk");
258
259 }
260
261 strlcat(state->pp_buf, "\n", PAGE_SIZE);
262 goto out_freeall;
263
264
265out_readerr:
266 res = -1;
267out_freeall:
268 kfree(label);
269out_nolab:
270 kfree(geo);
271out_nogeo:
272 kfree(info);
273out_exit:
274 return res;
275}
diff --git a/fs/partitions/ibm.h b/fs/partitions/ibm.h
new file mode 100644
index 00000000000..08fb0804a81
--- /dev/null
+++ b/fs/partitions/ibm.h
@@ -0,0 +1 @@
int ibm_partition(struct parsed_partitions *);
diff --git a/fs/partitions/karma.c b/fs/partitions/karma.c
new file mode 100644
index 00000000000..0ea19312706
--- /dev/null
+++ b/fs/partitions/karma.c
@@ -0,0 +1,57 @@
1/*
2 * fs/partitions/karma.c
3 * Rio Karma partition info.
4 *
5 * Copyright (C) 2006 Bob Copeland (me@bobcopeland.com)
6 * based on osf.c
7 */
8
9#include "check.h"
10#include "karma.h"
11
12int karma_partition(struct parsed_partitions *state)
13{
14 int i;
15 int slot = 1;
16 Sector sect;
17 unsigned char *data;
18 struct disklabel {
19 u8 d_reserved[270];
20 struct d_partition {
21 __le32 p_res;
22 u8 p_fstype;
23 u8 p_res2[3];
24 __le32 p_offset;
25 __le32 p_size;
26 } d_partitions[2];
27 u8 d_blank[208];
28 __le16 d_magic;
29 } __attribute__((packed)) *label;
30 struct d_partition *p;
31
32 data = read_part_sector(state, 0, &sect);
33 if (!data)
34 return -1;
35
36 label = (struct disklabel *)data;
37 if (le16_to_cpu(label->d_magic) != KARMA_LABEL_MAGIC) {
38 put_dev_sector(sect);
39 return 0;
40 }
41
42 p = label->d_partitions;
43 for (i = 0 ; i < 2; i++, p++) {
44 if (slot == state->limit)
45 break;
46
47 if (p->p_fstype == 0x4d && le32_to_cpu(p->p_size)) {
48 put_partition(state, slot, le32_to_cpu(p->p_offset),
49 le32_to_cpu(p->p_size));
50 }
51 slot++;
52 }
53 strlcat(state->pp_buf, "\n", PAGE_SIZE);
54 put_dev_sector(sect);
55 return 1;
56}
57
diff --git a/fs/partitions/karma.h b/fs/partitions/karma.h
new file mode 100644
index 00000000000..c764b2e9df2
--- /dev/null
+++ b/fs/partitions/karma.h
@@ -0,0 +1,8 @@
1/*
2 * fs/partitions/karma.h
3 */
4
5#define KARMA_LABEL_MAGIC 0xAB56
6
7int karma_partition(struct parsed_partitions *state);
8
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c
new file mode 100644
index 00000000000..af9fdf04676
--- /dev/null
+++ b/fs/partitions/ldm.c
@@ -0,0 +1,1568 @@
1/**
2 * ldm - Support for Windows Logical Disk Manager (Dynamic Disks)
3 *
4 * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
5 * Copyright (c) 2001-2007 Anton Altaparmakov
6 * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
7 *
8 * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads
9 *
10 * This program is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License as published by the Free Software
12 * Foundation; either version 2 of the License, or (at your option) any later
13 * version.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 * details.
19 *
20 * You should have received a copy of the GNU General Public License along with
21 * this program (in the main directory of the source in the file COPYING); if
22 * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23 * Boston, MA 02111-1307 USA
24 */
25
26#include <linux/slab.h>
27#include <linux/pagemap.h>
28#include <linux/stringify.h>
29#include <linux/kernel.h>
30#include "ldm.h"
31#include "check.h"
32#include "msdos.h"
33
34/**
35 * ldm_debug/info/error/crit - Output an error message
36 * @f: A printf format string containing the message
37 * @...: Variables to substitute into @f
38 *
39 * ldm_debug() writes a DEBUG level message to the syslog but only if the
40 * driver was compiled with debug enabled. Otherwise, the call turns into a NOP.
41 */
42#ifndef CONFIG_LDM_DEBUG
43#define ldm_debug(...) do {} while (0)
44#else
45#define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __func__, f, ##a)
46#endif
47
48#define ldm_crit(f, a...) _ldm_printk (KERN_CRIT, __func__, f, ##a)
49#define ldm_error(f, a...) _ldm_printk (KERN_ERR, __func__, f, ##a)
50#define ldm_info(f, a...) _ldm_printk (KERN_INFO, __func__, f, ##a)
51
52__attribute__ ((format (printf, 3, 4)))
53static void _ldm_printk (const char *level, const char *function,
54 const char *fmt, ...)
55{
56 static char buf[128];
57 va_list args;
58
59 va_start (args, fmt);
60 vsnprintf (buf, sizeof (buf), fmt, args);
61 va_end (args);
62
63 printk ("%s%s(): %s\n", level, function, buf);
64}
65
66/**
67 * ldm_parse_hexbyte - Convert a ASCII hex number to a byte
68 * @src: Pointer to at least 2 characters to convert.
69 *
70 * Convert a two character ASCII hex string to a number.
71 *
72 * Return: 0-255 Success, the byte was parsed correctly
73 * -1 Error, an invalid character was supplied
74 */
75static int ldm_parse_hexbyte (const u8 *src)
76{
77 unsigned int x; /* For correct wrapping */
78 int h;
79
80 /* high part */
81 x = h = hex_to_bin(src[0]);
82 if (h < 0)
83 return -1;
84
85 /* low part */
86 h = hex_to_bin(src[1]);
87 if (h < 0)
88 return -1;
89
90 return (x << 4) + h;
91}
92
93/**
94 * ldm_parse_guid - Convert GUID from ASCII to binary
95 * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
96 * @dest: Memory block to hold binary GUID (16 bytes)
97 *
98 * N.B. The GUID need not be NULL terminated.
99 *
100 * Return: 'true' @dest contains binary GUID
101 * 'false' @dest contents are undefined
102 */
103static bool ldm_parse_guid (const u8 *src, u8 *dest)
104{
105 static const int size[] = { 4, 2, 2, 2, 6 };
106 int i, j, v;
107
108 if (src[8] != '-' || src[13] != '-' ||
109 src[18] != '-' || src[23] != '-')
110 return false;
111
112 for (j = 0; j < 5; j++, src++)
113 for (i = 0; i < size[j]; i++, src+=2, *dest++ = v)
114 if ((v = ldm_parse_hexbyte (src)) < 0)
115 return false;
116
117 return true;
118}
119
120/**
121 * ldm_parse_privhead - Read the LDM Database PRIVHEAD structure
122 * @data: Raw database PRIVHEAD structure loaded from the device
123 * @ph: In-memory privhead structure in which to return parsed information
124 *
125 * This parses the LDM database PRIVHEAD structure supplied in @data and
126 * sets up the in-memory privhead structure @ph with the obtained information.
127 *
128 * Return: 'true' @ph contains the PRIVHEAD data
129 * 'false' @ph contents are undefined
130 */
131static bool ldm_parse_privhead(const u8 *data, struct privhead *ph)
132{
133 bool is_vista = false;
134
135 BUG_ON(!data || !ph);
136 if (MAGIC_PRIVHEAD != get_unaligned_be64(data)) {
137 ldm_error("Cannot find PRIVHEAD structure. LDM database is"
138 " corrupt. Aborting.");
139 return false;
140 }
141 ph->ver_major = get_unaligned_be16(data + 0x000C);
142 ph->ver_minor = get_unaligned_be16(data + 0x000E);
143 ph->logical_disk_start = get_unaligned_be64(data + 0x011B);
144 ph->logical_disk_size = get_unaligned_be64(data + 0x0123);
145 ph->config_start = get_unaligned_be64(data + 0x012B);
146 ph->config_size = get_unaligned_be64(data + 0x0133);
147 /* Version 2.11 is Win2k/XP and version 2.12 is Vista. */
148 if (ph->ver_major == 2 && ph->ver_minor == 12)
149 is_vista = true;
150 if (!is_vista && (ph->ver_major != 2 || ph->ver_minor != 11)) {
151 ldm_error("Expected PRIVHEAD version 2.11 or 2.12, got %d.%d."
152 " Aborting.", ph->ver_major, ph->ver_minor);
153 return false;
154 }
155 ldm_debug("PRIVHEAD version %d.%d (Windows %s).", ph->ver_major,
156 ph->ver_minor, is_vista ? "Vista" : "2000/XP");
157 if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */
158 /* Warn the user and continue, carefully. */
159 ldm_info("Database is normally %u bytes, it claims to "
160 "be %llu bytes.", LDM_DB_SIZE,
161 (unsigned long long)ph->config_size);
162 }
163 if ((ph->logical_disk_size == 0) || (ph->logical_disk_start +
164 ph->logical_disk_size > ph->config_start)) {
165 ldm_error("PRIVHEAD disk size doesn't match real disk size");
166 return false;
167 }
168 if (!ldm_parse_guid(data + 0x0030, ph->disk_id)) {
169 ldm_error("PRIVHEAD contains an invalid GUID.");
170 return false;
171 }
172 ldm_debug("Parsed PRIVHEAD successfully.");
173 return true;
174}
175
176/**
177 * ldm_parse_tocblock - Read the LDM Database TOCBLOCK structure
178 * @data: Raw database TOCBLOCK structure loaded from the device
179 * @toc: In-memory toc structure in which to return parsed information
180 *
181 * This parses the LDM Database TOCBLOCK (table of contents) structure supplied
182 * in @data and sets up the in-memory tocblock structure @toc with the obtained
183 * information.
184 *
185 * N.B. The *_start and *_size values returned in @toc are not range-checked.
186 *
187 * Return: 'true' @toc contains the TOCBLOCK data
188 * 'false' @toc contents are undefined
189 */
190static bool ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
191{
192 BUG_ON (!data || !toc);
193
194 if (MAGIC_TOCBLOCK != get_unaligned_be64(data)) {
195 ldm_crit ("Cannot find TOCBLOCK, database may be corrupt.");
196 return false;
197 }
198 strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name));
199 toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0;
200 toc->bitmap1_start = get_unaligned_be64(data + 0x2E);
201 toc->bitmap1_size = get_unaligned_be64(data + 0x36);
202
203 if (strncmp (toc->bitmap1_name, TOC_BITMAP1,
204 sizeof (toc->bitmap1_name)) != 0) {
205 ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.",
206 TOC_BITMAP1, toc->bitmap1_name);
207 return false;
208 }
209 strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name));
210 toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0;
211 toc->bitmap2_start = get_unaligned_be64(data + 0x50);
212 toc->bitmap2_size = get_unaligned_be64(data + 0x58);
213 if (strncmp (toc->bitmap2_name, TOC_BITMAP2,
214 sizeof (toc->bitmap2_name)) != 0) {
215 ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.",
216 TOC_BITMAP2, toc->bitmap2_name);
217 return false;
218 }
219 ldm_debug ("Parsed TOCBLOCK successfully.");
220 return true;
221}
222
223/**
224 * ldm_parse_vmdb - Read the LDM Database VMDB structure
225 * @data: Raw database VMDB structure loaded from the device
226 * @vm: In-memory vmdb structure in which to return parsed information
227 *
228 * This parses the LDM Database VMDB structure supplied in @data and sets up
229 * the in-memory vmdb structure @vm with the obtained information.
230 *
231 * N.B. The *_start, *_size and *_seq values will be range-checked later.
232 *
233 * Return: 'true' @vm contains VMDB info
234 * 'false' @vm contents are undefined
235 */
236static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
237{
238 BUG_ON (!data || !vm);
239
240 if (MAGIC_VMDB != get_unaligned_be32(data)) {
241 ldm_crit ("Cannot find the VMDB, database may be corrupt.");
242 return false;
243 }
244
245 vm->ver_major = get_unaligned_be16(data + 0x12);
246 vm->ver_minor = get_unaligned_be16(data + 0x14);
247 if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
248 ldm_error ("Expected VMDB version %d.%d, got %d.%d. "
249 "Aborting.", 4, 10, vm->ver_major, vm->ver_minor);
250 return false;
251 }
252
253 vm->vblk_size = get_unaligned_be32(data + 0x08);
254 if (vm->vblk_size == 0) {
255 ldm_error ("Illegal VBLK size");
256 return false;
257 }
258
259 vm->vblk_offset = get_unaligned_be32(data + 0x0C);
260 vm->last_vblk_seq = get_unaligned_be32(data + 0x04);
261
262 ldm_debug ("Parsed VMDB successfully.");
263 return true;
264}
265
266/**
267 * ldm_compare_privheads - Compare two privhead objects
268 * @ph1: First privhead
269 * @ph2: Second privhead
270 *
271 * This compares the two privhead structures @ph1 and @ph2.
272 *
273 * Return: 'true' Identical
274 * 'false' Different
275 */
276static bool ldm_compare_privheads (const struct privhead *ph1,
277 const struct privhead *ph2)
278{
279 BUG_ON (!ph1 || !ph2);
280
281 return ((ph1->ver_major == ph2->ver_major) &&
282 (ph1->ver_minor == ph2->ver_minor) &&
283 (ph1->logical_disk_start == ph2->logical_disk_start) &&
284 (ph1->logical_disk_size == ph2->logical_disk_size) &&
285 (ph1->config_start == ph2->config_start) &&
286 (ph1->config_size == ph2->config_size) &&
287 !memcmp (ph1->disk_id, ph2->disk_id, GUID_SIZE));
288}
289
290/**
291 * ldm_compare_tocblocks - Compare two tocblock objects
292 * @toc1: First toc
293 * @toc2: Second toc
294 *
295 * This compares the two tocblock structures @toc1 and @toc2.
296 *
297 * Return: 'true' Identical
298 * 'false' Different
299 */
300static bool ldm_compare_tocblocks (const struct tocblock *toc1,
301 const struct tocblock *toc2)
302{
303 BUG_ON (!toc1 || !toc2);
304
305 return ((toc1->bitmap1_start == toc2->bitmap1_start) &&
306 (toc1->bitmap1_size == toc2->bitmap1_size) &&
307 (toc1->bitmap2_start == toc2->bitmap2_start) &&
308 (toc1->bitmap2_size == toc2->bitmap2_size) &&
309 !strncmp (toc1->bitmap1_name, toc2->bitmap1_name,
310 sizeof (toc1->bitmap1_name)) &&
311 !strncmp (toc1->bitmap2_name, toc2->bitmap2_name,
312 sizeof (toc1->bitmap2_name)));
313}
314
315/**
316 * ldm_validate_privheads - Compare the primary privhead with its backups
317 * @state: Partition check state including device holding the LDM Database
318 * @ph1: Memory struct to fill with ph contents
319 *
320 * Read and compare all three privheads from disk.
321 *
322 * The privheads on disk show the size and location of the main disk area and
323 * the configuration area (the database). The values are range-checked against
324 * @hd, which contains the real size of the disk.
325 *
326 * Return: 'true' Success
327 * 'false' Error
328 */
329static bool ldm_validate_privheads(struct parsed_partitions *state,
330 struct privhead *ph1)
331{
332 static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 };
333 struct privhead *ph[3] = { ph1 };
334 Sector sect;
335 u8 *data;
336 bool result = false;
337 long num_sects;
338 int i;
339
340 BUG_ON (!state || !ph1);
341
342 ph[1] = kmalloc (sizeof (*ph[1]), GFP_KERNEL);
343 ph[2] = kmalloc (sizeof (*ph[2]), GFP_KERNEL);
344 if (!ph[1] || !ph[2]) {
345 ldm_crit ("Out of memory.");
346 goto out;
347 }
348
349 /* off[1 & 2] are relative to ph[0]->config_start */
350 ph[0]->config_start = 0;
351
352 /* Read and parse privheads */
353 for (i = 0; i < 3; i++) {
354 data = read_part_sector(state, ph[0]->config_start + off[i],
355 &sect);
356 if (!data) {
357 ldm_crit ("Disk read failed.");
358 goto out;
359 }
360 result = ldm_parse_privhead (data, ph[i]);
361 put_dev_sector (sect);
362 if (!result) {
363 ldm_error ("Cannot find PRIVHEAD %d.", i+1); /* Log again */
364 if (i < 2)
365 goto out; /* Already logged */
366 else
367 break; /* FIXME ignore for now, 3rd PH can fail on odd-sized disks */
368 }
369 }
370
371 num_sects = state->bdev->bd_inode->i_size >> 9;
372
373 if ((ph[0]->config_start > num_sects) ||
374 ((ph[0]->config_start + ph[0]->config_size) > num_sects)) {
375 ldm_crit ("Database extends beyond the end of the disk.");
376 goto out;
377 }
378
379 if ((ph[0]->logical_disk_start > ph[0]->config_start) ||
380 ((ph[0]->logical_disk_start + ph[0]->logical_disk_size)
381 > ph[0]->config_start)) {
382 ldm_crit ("Disk and database overlap.");
383 goto out;
384 }
385
386 if (!ldm_compare_privheads (ph[0], ph[1])) {
387 ldm_crit ("Primary and backup PRIVHEADs don't match.");
388 goto out;
389 }
390 /* FIXME ignore this for now
391 if (!ldm_compare_privheads (ph[0], ph[2])) {
392 ldm_crit ("Primary and backup PRIVHEADs don't match.");
393 goto out;
394 }*/
395 ldm_debug ("Validated PRIVHEADs successfully.");
396 result = true;
397out:
398 kfree (ph[1]);
399 kfree (ph[2]);
400 return result;
401}
402
403/**
404 * ldm_validate_tocblocks - Validate the table of contents and its backups
405 * @state: Partition check state including device holding the LDM Database
406 * @base: Offset, into @state->bdev, of the database
407 * @ldb: Cache of the database structures
408 *
409 * Find and compare the four tables of contents of the LDM Database stored on
410 * @state->bdev and return the parsed information into @toc1.
411 *
412 * The offsets and sizes of the configs are range-checked against a privhead.
413 *
414 * Return: 'true' @toc1 contains validated TOCBLOCK info
415 * 'false' @toc1 contents are undefined
416 */
417static bool ldm_validate_tocblocks(struct parsed_partitions *state,
418 unsigned long base, struct ldmdb *ldb)
419{
420 static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4};
421 struct tocblock *tb[4];
422 struct privhead *ph;
423 Sector sect;
424 u8 *data;
425 int i, nr_tbs;
426 bool result = false;
427
428 BUG_ON(!state || !ldb);
429 ph = &ldb->ph;
430 tb[0] = &ldb->toc;
431 tb[1] = kmalloc(sizeof(*tb[1]) * 3, GFP_KERNEL);
432 if (!tb[1]) {
433 ldm_crit("Out of memory.");
434 goto err;
435 }
436 tb[2] = (struct tocblock*)((u8*)tb[1] + sizeof(*tb[1]));
437 tb[3] = (struct tocblock*)((u8*)tb[2] + sizeof(*tb[2]));
438 /*
439 * Try to read and parse all four TOCBLOCKs.
440 *
441 * Windows Vista LDM v2.12 does not always have all four TOCBLOCKs so
442 * skip any that fail as long as we get at least one valid TOCBLOCK.
443 */
444 for (nr_tbs = i = 0; i < 4; i++) {
445 data = read_part_sector(state, base + off[i], &sect);
446 if (!data) {
447 ldm_error("Disk read failed for TOCBLOCK %d.", i);
448 continue;
449 }
450 if (ldm_parse_tocblock(data, tb[nr_tbs]))
451 nr_tbs++;
452 put_dev_sector(sect);
453 }
454 if (!nr_tbs) {
455 ldm_crit("Failed to find a valid TOCBLOCK.");
456 goto err;
457 }
458 /* Range check the TOCBLOCK against a privhead. */
459 if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) ||
460 ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) >
461 ph->config_size)) {
462 ldm_crit("The bitmaps are out of range. Giving up.");
463 goto err;
464 }
465 /* Compare all loaded TOCBLOCKs. */
466 for (i = 1; i < nr_tbs; i++) {
467 if (!ldm_compare_tocblocks(tb[0], tb[i])) {
468 ldm_crit("TOCBLOCKs 0 and %d do not match.", i);
469 goto err;
470 }
471 }
472 ldm_debug("Validated %d TOCBLOCKs successfully.", nr_tbs);
473 result = true;
474err:
475 kfree(tb[1]);
476 return result;
477}
478
479/**
480 * ldm_validate_vmdb - Read the VMDB and validate it
481 * @state: Partition check state including device holding the LDM Database
482 * @base: Offset, into @bdev, of the database
483 * @ldb: Cache of the database structures
484 *
485 * Find the vmdb of the LDM Database stored on @bdev and return the parsed
486 * information in @ldb.
487 *
488 * Return: 'true' @ldb contains validated VBDB info
489 * 'false' @ldb contents are undefined
490 */
491static bool ldm_validate_vmdb(struct parsed_partitions *state,
492 unsigned long base, struct ldmdb *ldb)
493{
494 Sector sect;
495 u8 *data;
496 bool result = false;
497 struct vmdb *vm;
498 struct tocblock *toc;
499
500 BUG_ON (!state || !ldb);
501
502 vm = &ldb->vm;
503 toc = &ldb->toc;
504
505 data = read_part_sector(state, base + OFF_VMDB, &sect);
506 if (!data) {
507 ldm_crit ("Disk read failed.");
508 return false;
509 }
510
511 if (!ldm_parse_vmdb (data, vm))
512 goto out; /* Already logged */
513
514 /* Are there uncommitted transactions? */
515 if (get_unaligned_be16(data + 0x10) != 0x01) {
516 ldm_crit ("Database is not in a consistent state. Aborting.");
517 goto out;
518 }
519
520 if (vm->vblk_offset != 512)
521 ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset);
522
523 /*
524 * The last_vblkd_seq can be before the end of the vmdb, just make sure
525 * it is not out of bounds.
526 */
527 if ((vm->vblk_size * vm->last_vblk_seq) > (toc->bitmap1_size << 9)) {
528 ldm_crit ("VMDB exceeds allowed size specified by TOCBLOCK. "
529 "Database is corrupt. Aborting.");
530 goto out;
531 }
532
533 result = true;
534out:
535 put_dev_sector (sect);
536 return result;
537}
538
539
540/**
541 * ldm_validate_partition_table - Determine whether bdev might be a dynamic disk
542 * @state: Partition check state including device holding the LDM Database
543 *
544 * This function provides a weak test to decide whether the device is a dynamic
545 * disk or not. It looks for an MS-DOS-style partition table containing at
546 * least one partition of type 0x42 (formerly SFS, now used by Windows for
547 * dynamic disks).
548 *
549 * N.B. The only possible error can come from the read_part_sector and that is
550 * only likely to happen if the underlying device is strange. If that IS
551 * the case we should return zero to let someone else try.
552 *
553 * Return: 'true' @state->bdev is a dynamic disk
554 * 'false' @state->bdev is not a dynamic disk, or an error occurred
555 */
556static bool ldm_validate_partition_table(struct parsed_partitions *state)
557{
558 Sector sect;
559 u8 *data;
560 struct partition *p;
561 int i;
562 bool result = false;
563
564 BUG_ON(!state);
565
566 data = read_part_sector(state, 0, &sect);
567 if (!data) {
568 ldm_info ("Disk read failed.");
569 return false;
570 }
571
572 if (*(__le16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC))
573 goto out;
574
575 p = (struct partition*)(data + 0x01BE);
576 for (i = 0; i < 4; i++, p++)
577 if (SYS_IND (p) == LDM_PARTITION) {
578 result = true;
579 break;
580 }
581
582 if (result)
583 ldm_debug ("Found W2K dynamic disk partition type.");
584
585out:
586 put_dev_sector (sect);
587 return result;
588}
589
590/**
591 * ldm_get_disk_objid - Search a linked list of vblk's for a given Disk Id
592 * @ldb: Cache of the database structures
593 *
594 * The LDM Database contains a list of all partitions on all dynamic disks.
595 * The primary PRIVHEAD, at the beginning of the physical disk, tells us
596 * the GUID of this disk. This function searches for the GUID in a linked
597 * list of vblk's.
598 *
599 * Return: Pointer, A matching vblk was found
600 * NULL, No match, or an error
601 */
602static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb)
603{
604 struct list_head *item;
605
606 BUG_ON (!ldb);
607
608 list_for_each (item, &ldb->v_disk) {
609 struct vblk *v = list_entry (item, struct vblk, list);
610 if (!memcmp (v->vblk.disk.disk_id, ldb->ph.disk_id, GUID_SIZE))
611 return v;
612 }
613
614 return NULL;
615}
616
617/**
618 * ldm_create_data_partitions - Create data partitions for this device
619 * @pp: List of the partitions parsed so far
620 * @ldb: Cache of the database structures
621 *
622 * The database contains ALL the partitions for ALL disk groups, so we need to
623 * filter out this specific disk. Using the disk's object id, we can find all
624 * the partitions in the database that belong to this disk.
625 *
626 * Add each partition in our database, to the parsed_partitions structure.
627 *
628 * N.B. This function creates the partitions in the order it finds partition
629 * objects in the linked list.
630 *
631 * Return: 'true' Partition created
632 * 'false' Error, probably a range checking problem
633 */
634static bool ldm_create_data_partitions (struct parsed_partitions *pp,
635 const struct ldmdb *ldb)
636{
637 struct list_head *item;
638 struct vblk *vb;
639 struct vblk *disk;
640 struct vblk_part *part;
641 int part_num = 1;
642
643 BUG_ON (!pp || !ldb);
644
645 disk = ldm_get_disk_objid (ldb);
646 if (!disk) {
647 ldm_crit ("Can't find the ID of this disk in the database.");
648 return false;
649 }
650
651 strlcat(pp->pp_buf, " [LDM]", PAGE_SIZE);
652
653 /* Create the data partitions */
654 list_for_each (item, &ldb->v_part) {
655 vb = list_entry (item, struct vblk, list);
656 part = &vb->vblk.part;
657
658 if (part->disk_id != disk->obj_id)
659 continue;
660
661 put_partition (pp, part_num, ldb->ph.logical_disk_start +
662 part->start, part->size);
663 part_num++;
664 }
665
666 strlcat(pp->pp_buf, "\n", PAGE_SIZE);
667 return true;
668}
669
670
671/**
672 * ldm_relative - Calculate the next relative offset
673 * @buffer: Block of data being worked on
674 * @buflen: Size of the block of data
675 * @base: Size of the previous fixed width fields
676 * @offset: Cumulative size of the previous variable-width fields
677 *
678 * Because many of the VBLK fields are variable-width, it's necessary
679 * to calculate each offset based on the previous one and the length
680 * of the field it pointed to.
681 *
682 * Return: -1 Error, the calculated offset exceeded the size of the buffer
683 * n OK, a range-checked offset into buffer
684 */
685static int ldm_relative(const u8 *buffer, int buflen, int base, int offset)
686{
687
688 base += offset;
689 if (!buffer || offset < 0 || base > buflen) {
690 if (!buffer)
691 ldm_error("!buffer");
692 if (offset < 0)
693 ldm_error("offset (%d) < 0", offset);
694 if (base > buflen)
695 ldm_error("base (%d) > buflen (%d)", base, buflen);
696 return -1;
697 }
698 if (base + buffer[base] >= buflen) {
699 ldm_error("base (%d) + buffer[base] (%d) >= buflen (%d)", base,
700 buffer[base], buflen);
701 return -1;
702 }
703 return buffer[base] + offset + 1;
704}
705
706/**
707 * ldm_get_vnum - Convert a variable-width, big endian number, into cpu order
708 * @block: Pointer to the variable-width number to convert
709 *
710 * Large numbers in the LDM Database are often stored in a packed format. Each
711 * number is prefixed by a one byte width marker. All numbers in the database
712 * are stored in big-endian byte order. This function reads one of these
713 * numbers and returns the result
714 *
715 * N.B. This function DOES NOT perform any range checking, though the most
716 * it will read is eight bytes.
717 *
718 * Return: n A number
719 * 0 Zero, or an error occurred
720 */
721static u64 ldm_get_vnum (const u8 *block)
722{
723 u64 tmp = 0;
724 u8 length;
725
726 BUG_ON (!block);
727
728 length = *block++;
729
730 if (length && length <= 8)
731 while (length--)
732 tmp = (tmp << 8) | *block++;
733 else
734 ldm_error ("Illegal length %d.", length);
735
736 return tmp;
737}
738
739/**
740 * ldm_get_vstr - Read a length-prefixed string into a buffer
741 * @block: Pointer to the length marker
742 * @buffer: Location to copy string to
743 * @buflen: Size of the output buffer
744 *
745 * Many of the strings in the LDM Database are not NULL terminated. Instead
746 * they are prefixed by a one byte length marker. This function copies one of
747 * these strings into a buffer.
748 *
749 * N.B. This function DOES NOT perform any range checking on the input.
750 * If the buffer is too small, the output will be truncated.
751 *
752 * Return: 0, Error and @buffer contents are undefined
753 * n, String length in characters (excluding NULL)
754 * buflen-1, String was truncated.
755 */
756static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen)
757{
758 int length;
759
760 BUG_ON (!block || !buffer);
761
762 length = block[0];
763 if (length >= buflen) {
764 ldm_error ("Truncating string %d -> %d.", length, buflen);
765 length = buflen - 1;
766 }
767 memcpy (buffer, block + 1, length);
768 buffer[length] = 0;
769 return length;
770}
771
772
773/**
774 * ldm_parse_cmp3 - Read a raw VBLK Component object into a vblk structure
775 * @buffer: Block of data being worked on
776 * @buflen: Size of the block of data
777 * @vb: In-memory vblk in which to return information
778 *
779 * Read a raw VBLK Component object (version 3) into a vblk structure.
780 *
781 * Return: 'true' @vb contains a Component VBLK
782 * 'false' @vb contents are not defined
783 */
784static bool ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
785{
786 int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len;
787 struct vblk_comp *comp;
788
789 BUG_ON (!buffer || !vb);
790
791 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
792 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
793 r_vstate = ldm_relative (buffer, buflen, 0x18, r_name);
794 r_child = ldm_relative (buffer, buflen, 0x1D, r_vstate);
795 r_parent = ldm_relative (buffer, buflen, 0x2D, r_child);
796
797 if (buffer[0x12] & VBLK_FLAG_COMP_STRIPE) {
798 r_stripe = ldm_relative (buffer, buflen, 0x2E, r_parent);
799 r_cols = ldm_relative (buffer, buflen, 0x2E, r_stripe);
800 len = r_cols;
801 } else {
802 r_stripe = 0;
803 r_cols = 0;
804 len = r_parent;
805 }
806 if (len < 0)
807 return false;
808
809 len += VBLK_SIZE_CMP3;
810 if (len != get_unaligned_be32(buffer + 0x14))
811 return false;
812
813 comp = &vb->vblk.comp;
814 ldm_get_vstr (buffer + 0x18 + r_name, comp->state,
815 sizeof (comp->state));
816 comp->type = buffer[0x18 + r_vstate];
817 comp->children = ldm_get_vnum (buffer + 0x1D + r_vstate);
818 comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child);
819 comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0;
820
821 return true;
822}
823
824/**
825 * ldm_parse_dgr3 - Read a raw VBLK Disk Group object into a vblk structure
826 * @buffer: Block of data being worked on
827 * @buflen: Size of the block of data
828 * @vb: In-memory vblk in which to return information
829 *
830 * Read a raw VBLK Disk Group object (version 3) into a vblk structure.
831 *
832 * Return: 'true' @vb contains a Disk Group VBLK
833 * 'false' @vb contents are not defined
834 */
835static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
836{
837 int r_objid, r_name, r_diskid, r_id1, r_id2, len;
838 struct vblk_dgrp *dgrp;
839
840 BUG_ON (!buffer || !vb);
841
842 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
843 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
844 r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
845
846 if (buffer[0x12] & VBLK_FLAG_DGR3_IDS) {
847 r_id1 = ldm_relative (buffer, buflen, 0x24, r_diskid);
848 r_id2 = ldm_relative (buffer, buflen, 0x24, r_id1);
849 len = r_id2;
850 } else {
851 r_id1 = 0;
852 r_id2 = 0;
853 len = r_diskid;
854 }
855 if (len < 0)
856 return false;
857
858 len += VBLK_SIZE_DGR3;
859 if (len != get_unaligned_be32(buffer + 0x14))
860 return false;
861
862 dgrp = &vb->vblk.dgrp;
863 ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id,
864 sizeof (dgrp->disk_id));
865 return true;
866}
867
868/**
869 * ldm_parse_dgr4 - Read a raw VBLK Disk Group object into a vblk structure
870 * @buffer: Block of data being worked on
871 * @buflen: Size of the block of data
872 * @vb: In-memory vblk in which to return information
873 *
874 * Read a raw VBLK Disk Group object (version 4) into a vblk structure.
875 *
876 * Return: 'true' @vb contains a Disk Group VBLK
877 * 'false' @vb contents are not defined
878 */
879static bool ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
880{
881 char buf[64];
882 int r_objid, r_name, r_id1, r_id2, len;
883 struct vblk_dgrp *dgrp;
884
885 BUG_ON (!buffer || !vb);
886
887 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
888 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
889
890 if (buffer[0x12] & VBLK_FLAG_DGR4_IDS) {
891 r_id1 = ldm_relative (buffer, buflen, 0x44, r_name);
892 r_id2 = ldm_relative (buffer, buflen, 0x44, r_id1);
893 len = r_id2;
894 } else {
895 r_id1 = 0;
896 r_id2 = 0;
897 len = r_name;
898 }
899 if (len < 0)
900 return false;
901
902 len += VBLK_SIZE_DGR4;
903 if (len != get_unaligned_be32(buffer + 0x14))
904 return false;
905
906 dgrp = &vb->vblk.dgrp;
907
908 ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf));
909 return true;
910}
911
912/**
913 * ldm_parse_dsk3 - Read a raw VBLK Disk object into a vblk structure
914 * @buffer: Block of data being worked on
915 * @buflen: Size of the block of data
916 * @vb: In-memory vblk in which to return information
917 *
918 * Read a raw VBLK Disk object (version 3) into a vblk structure.
919 *
920 * Return: 'true' @vb contains a Disk VBLK
921 * 'false' @vb contents are not defined
922 */
923static bool ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
924{
925 int r_objid, r_name, r_diskid, r_altname, len;
926 struct vblk_disk *disk;
927
928 BUG_ON (!buffer || !vb);
929
930 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
931 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
932 r_diskid = ldm_relative (buffer, buflen, 0x18, r_name);
933 r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid);
934 len = r_altname;
935 if (len < 0)
936 return false;
937
938 len += VBLK_SIZE_DSK3;
939 if (len != get_unaligned_be32(buffer + 0x14))
940 return false;
941
942 disk = &vb->vblk.disk;
943 ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name,
944 sizeof (disk->alt_name));
945 if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id))
946 return false;
947
948 return true;
949}
950
951/**
952 * ldm_parse_dsk4 - Read a raw VBLK Disk object into a vblk structure
953 * @buffer: Block of data being worked on
954 * @buflen: Size of the block of data
955 * @vb: In-memory vblk in which to return information
956 *
957 * Read a raw VBLK Disk object (version 4) into a vblk structure.
958 *
959 * Return: 'true' @vb contains a Disk VBLK
960 * 'false' @vb contents are not defined
961 */
962static bool ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
963{
964 int r_objid, r_name, len;
965 struct vblk_disk *disk;
966
967 BUG_ON (!buffer || !vb);
968
969 r_objid = ldm_relative (buffer, buflen, 0x18, 0);
970 r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
971 len = r_name;
972 if (len < 0)
973 return false;
974
975 len += VBLK_SIZE_DSK4;
976 if (len != get_unaligned_be32(buffer + 0x14))
977 return false;
978
979 disk = &vb->vblk.disk;
980 memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE);
981 return true;
982}
983
984/**
985 * ldm_parse_prt3 - Read a raw VBLK Partition object into a vblk structure
986 * @buffer: Block of data being worked on
987 * @buflen: Size of the block of data
988 * @vb: In-memory vblk in which to return information
989 *
990 * Read a raw VBLK Partition object (version 3) into a vblk structure.
991 *
992 * Return: 'true' @vb contains a Partition VBLK
993 * 'false' @vb contents are not defined
994 */
995static bool ldm_parse_prt3(const u8 *buffer, int buflen, struct vblk *vb)
996{
997 int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len;
998 struct vblk_part *part;
999
1000 BUG_ON(!buffer || !vb);
1001 r_objid = ldm_relative(buffer, buflen, 0x18, 0);
1002 if (r_objid < 0) {
1003 ldm_error("r_objid %d < 0", r_objid);
1004 return false;
1005 }
1006 r_name = ldm_relative(buffer, buflen, 0x18, r_objid);
1007 if (r_name < 0) {
1008 ldm_error("r_name %d < 0", r_name);
1009 return false;
1010 }
1011 r_size = ldm_relative(buffer, buflen, 0x34, r_name);
1012 if (r_size < 0) {
1013 ldm_error("r_size %d < 0", r_size);
1014 return false;
1015 }
1016 r_parent = ldm_relative(buffer, buflen, 0x34, r_size);
1017 if (r_parent < 0) {
1018 ldm_error("r_parent %d < 0", r_parent);
1019 return false;
1020 }
1021 r_diskid = ldm_relative(buffer, buflen, 0x34, r_parent);
1022 if (r_diskid < 0) {
1023 ldm_error("r_diskid %d < 0", r_diskid);
1024 return false;
1025 }
1026 if (buffer[0x12] & VBLK_FLAG_PART_INDEX) {
1027 r_index = ldm_relative(buffer, buflen, 0x34, r_diskid);
1028 if (r_index < 0) {
1029 ldm_error("r_index %d < 0", r_index);
1030 return false;
1031 }
1032 len = r_index;
1033 } else {
1034 r_index = 0;
1035 len = r_diskid;
1036 }
1037 if (len < 0) {
1038 ldm_error("len %d < 0", len);
1039 return false;
1040 }
1041 len += VBLK_SIZE_PRT3;
1042 if (len > get_unaligned_be32(buffer + 0x14)) {
1043 ldm_error("len %d > BE32(buffer + 0x14) %d", len,
1044 get_unaligned_be32(buffer + 0x14));
1045 return false;
1046 }
1047 part = &vb->vblk.part;
1048 part->start = get_unaligned_be64(buffer + 0x24 + r_name);
1049 part->volume_offset = get_unaligned_be64(buffer + 0x2C + r_name);
1050 part->size = ldm_get_vnum(buffer + 0x34 + r_name);
1051 part->parent_id = ldm_get_vnum(buffer + 0x34 + r_size);
1052 part->disk_id = ldm_get_vnum(buffer + 0x34 + r_parent);
1053 if (vb->flags & VBLK_FLAG_PART_INDEX)
1054 part->partnum = buffer[0x35 + r_diskid];
1055 else
1056 part->partnum = 0;
1057 return true;
1058}
1059
1060/**
1061 * ldm_parse_vol5 - Read a raw VBLK Volume object into a vblk structure
1062 * @buffer: Block of data being worked on
1063 * @buflen: Size of the block of data
1064 * @vb: In-memory vblk in which to return information
1065 *
1066 * Read a raw VBLK Volume object (version 5) into a vblk structure.
1067 *
1068 * Return: 'true' @vb contains a Volume VBLK
1069 * 'false' @vb contents are not defined
1070 */
1071static bool ldm_parse_vol5(const u8 *buffer, int buflen, struct vblk *vb)
1072{
1073 int r_objid, r_name, r_vtype, r_disable_drive_letter, r_child, r_size;
1074 int r_id1, r_id2, r_size2, r_drive, len;
1075 struct vblk_volu *volu;
1076
1077 BUG_ON(!buffer || !vb);
1078 r_objid = ldm_relative(buffer, buflen, 0x18, 0);
1079 if (r_objid < 0) {
1080 ldm_error("r_objid %d < 0", r_objid);
1081 return false;
1082 }
1083 r_name = ldm_relative(buffer, buflen, 0x18, r_objid);
1084 if (r_name < 0) {
1085 ldm_error("r_name %d < 0", r_name);
1086 return false;
1087 }
1088 r_vtype = ldm_relative(buffer, buflen, 0x18, r_name);
1089 if (r_vtype < 0) {
1090 ldm_error("r_vtype %d < 0", r_vtype);
1091 return false;
1092 }
1093 r_disable_drive_letter = ldm_relative(buffer, buflen, 0x18, r_vtype);
1094 if (r_disable_drive_letter < 0) {
1095 ldm_error("r_disable_drive_letter %d < 0",
1096 r_disable_drive_letter);
1097 return false;
1098 }
1099 r_child = ldm_relative(buffer, buflen, 0x2D, r_disable_drive_letter);
1100 if (r_child < 0) {
1101 ldm_error("r_child %d < 0", r_child);
1102 return false;
1103 }
1104 r_size = ldm_relative(buffer, buflen, 0x3D, r_child);
1105 if (r_size < 0) {
1106 ldm_error("r_size %d < 0", r_size);
1107 return false;
1108 }
1109 if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) {
1110 r_id1 = ldm_relative(buffer, buflen, 0x52, r_size);
1111 if (r_id1 < 0) {
1112 ldm_error("r_id1 %d < 0", r_id1);
1113 return false;
1114 }
1115 } else
1116 r_id1 = r_size;
1117 if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) {
1118 r_id2 = ldm_relative(buffer, buflen, 0x52, r_id1);
1119 if (r_id2 < 0) {
1120 ldm_error("r_id2 %d < 0", r_id2);
1121 return false;
1122 }
1123 } else
1124 r_id2 = r_id1;
1125 if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) {
1126 r_size2 = ldm_relative(buffer, buflen, 0x52, r_id2);
1127 if (r_size2 < 0) {
1128 ldm_error("r_size2 %d < 0", r_size2);
1129 return false;
1130 }
1131 } else
1132 r_size2 = r_id2;
1133 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1134 r_drive = ldm_relative(buffer, buflen, 0x52, r_size2);
1135 if (r_drive < 0) {
1136 ldm_error("r_drive %d < 0", r_drive);
1137 return false;
1138 }
1139 } else
1140 r_drive = r_size2;
1141 len = r_drive;
1142 if (len < 0) {
1143 ldm_error("len %d < 0", len);
1144 return false;
1145 }
1146 len += VBLK_SIZE_VOL5;
1147 if (len > get_unaligned_be32(buffer + 0x14)) {
1148 ldm_error("len %d > BE32(buffer + 0x14) %d", len,
1149 get_unaligned_be32(buffer + 0x14));
1150 return false;
1151 }
1152 volu = &vb->vblk.volu;
1153 ldm_get_vstr(buffer + 0x18 + r_name, volu->volume_type,
1154 sizeof(volu->volume_type));
1155 memcpy(volu->volume_state, buffer + 0x18 + r_disable_drive_letter,
1156 sizeof(volu->volume_state));
1157 volu->size = ldm_get_vnum(buffer + 0x3D + r_child);
1158 volu->partition_type = buffer[0x41 + r_size];
1159 memcpy(volu->guid, buffer + 0x42 + r_size, sizeof(volu->guid));
1160 if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
1161 ldm_get_vstr(buffer + 0x52 + r_size, volu->drive_hint,
1162 sizeof(volu->drive_hint));
1163 }
1164 return true;
1165}
1166
1167/**
1168 * ldm_parse_vblk - Read a raw VBLK object into a vblk structure
1169 * @buf: Block of data being worked on
1170 * @len: Size of the block of data
1171 * @vb: In-memory vblk in which to return information
1172 *
1173 * Read a raw VBLK object into a vblk structure. This function just reads the
1174 * information common to all VBLK types, then delegates the rest of the work to
1175 * helper functions: ldm_parse_*.
1176 *
1177 * Return: 'true' @vb contains a VBLK
1178 * 'false' @vb contents are not defined
1179 */
1180static bool ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
1181{
1182 bool result = false;
1183 int r_objid;
1184
1185 BUG_ON (!buf || !vb);
1186
1187 r_objid = ldm_relative (buf, len, 0x18, 0);
1188 if (r_objid < 0) {
1189 ldm_error ("VBLK header is corrupt.");
1190 return false;
1191 }
1192
1193 vb->flags = buf[0x12];
1194 vb->type = buf[0x13];
1195 vb->obj_id = ldm_get_vnum (buf + 0x18);
1196 ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name));
1197
1198 switch (vb->type) {
1199 case VBLK_CMP3: result = ldm_parse_cmp3 (buf, len, vb); break;
1200 case VBLK_DSK3: result = ldm_parse_dsk3 (buf, len, vb); break;
1201 case VBLK_DSK4: result = ldm_parse_dsk4 (buf, len, vb); break;
1202 case VBLK_DGR3: result = ldm_parse_dgr3 (buf, len, vb); break;
1203 case VBLK_DGR4: result = ldm_parse_dgr4 (buf, len, vb); break;
1204 case VBLK_PRT3: result = ldm_parse_prt3 (buf, len, vb); break;
1205 case VBLK_VOL5: result = ldm_parse_vol5 (buf, len, vb); break;
1206 }
1207
1208 if (result)
1209 ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.",
1210 (unsigned long long) vb->obj_id, vb->type);
1211 else
1212 ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).",
1213 (unsigned long long) vb->obj_id, vb->type);
1214
1215 return result;
1216}
1217
1218
1219/**
1220 * ldm_ldmdb_add - Adds a raw VBLK entry to the ldmdb database
1221 * @data: Raw VBLK to add to the database
1222 * @len: Size of the raw VBLK
1223 * @ldb: Cache of the database structures
1224 *
1225 * The VBLKs are sorted into categories. Partitions are also sorted by offset.
1226 *
1227 * N.B. This function does not check the validity of the VBLKs.
1228 *
1229 * Return: 'true' The VBLK was added
1230 * 'false' An error occurred
1231 */
1232static bool ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
1233{
1234 struct vblk *vb;
1235 struct list_head *item;
1236
1237 BUG_ON (!data || !ldb);
1238
1239 vb = kmalloc (sizeof (*vb), GFP_KERNEL);
1240 if (!vb) {
1241 ldm_crit ("Out of memory.");
1242 return false;
1243 }
1244
1245 if (!ldm_parse_vblk (data, len, vb)) {
1246 kfree(vb);
1247 return false; /* Already logged */
1248 }
1249
1250 /* Put vblk into the correct list. */
1251 switch (vb->type) {
1252 case VBLK_DGR3:
1253 case VBLK_DGR4:
1254 list_add (&vb->list, &ldb->v_dgrp);
1255 break;
1256 case VBLK_DSK3:
1257 case VBLK_DSK4:
1258 list_add (&vb->list, &ldb->v_disk);
1259 break;
1260 case VBLK_VOL5:
1261 list_add (&vb->list, &ldb->v_volu);
1262 break;
1263 case VBLK_CMP3:
1264 list_add (&vb->list, &ldb->v_comp);
1265 break;
1266 case VBLK_PRT3:
1267 /* Sort by the partition's start sector. */
1268 list_for_each (item, &ldb->v_part) {
1269 struct vblk *v = list_entry (item, struct vblk, list);
1270 if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) &&
1271 (v->vblk.part.start > vb->vblk.part.start)) {
1272 list_add_tail (&vb->list, &v->list);
1273 return true;
1274 }
1275 }
1276 list_add_tail (&vb->list, &ldb->v_part);
1277 break;
1278 }
1279 return true;
1280}
1281
1282/**
1283 * ldm_frag_add - Add a VBLK fragment to a list
1284 * @data: Raw fragment to be added to the list
1285 * @size: Size of the raw fragment
1286 * @frags: Linked list of VBLK fragments
1287 *
1288 * Fragmented VBLKs may not be consecutive in the database, so they are placed
1289 * in a list so they can be pieced together later.
1290 *
1291 * Return: 'true' Success, the VBLK was added to the list
1292 * 'false' Error, a problem occurred
1293 */
1294static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags)
1295{
1296 struct frag *f;
1297 struct list_head *item;
1298 int rec, num, group;
1299
1300 BUG_ON (!data || !frags);
1301
1302 if (size < 2 * VBLK_SIZE_HEAD) {
1303 ldm_error("Value of size is to small.");
1304 return false;
1305 }
1306
1307 group = get_unaligned_be32(data + 0x08);
1308 rec = get_unaligned_be16(data + 0x0C);
1309 num = get_unaligned_be16(data + 0x0E);
1310 if ((num < 1) || (num > 4)) {
1311 ldm_error ("A VBLK claims to have %d parts.", num);
1312 return false;
1313 }
1314 if (rec >= num) {
1315 ldm_error("REC value (%d) exceeds NUM value (%d)", rec, num);
1316 return false;
1317 }
1318
1319 list_for_each (item, frags) {
1320 f = list_entry (item, struct frag, list);
1321 if (f->group == group)
1322 goto found;
1323 }
1324
1325 f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL);
1326 if (!f) {
1327 ldm_crit ("Out of memory.");
1328 return false;
1329 }
1330
1331 f->group = group;
1332 f->num = num;
1333 f->rec = rec;
1334 f->map = 0xFF << num;
1335
1336 list_add_tail (&f->list, frags);
1337found:
1338 if (rec >= f->num) {
1339 ldm_error("REC value (%d) exceeds NUM value (%d)", rec, f->num);
1340 return false;
1341 }
1342
1343 if (f->map & (1 << rec)) {
1344 ldm_error ("Duplicate VBLK, part %d.", rec);
1345 f->map &= 0x7F; /* Mark the group as broken */
1346 return false;
1347 }
1348
1349 f->map |= (1 << rec);
1350
1351 data += VBLK_SIZE_HEAD;
1352 size -= VBLK_SIZE_HEAD;
1353
1354 memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);
1355
1356 return true;
1357}
1358
1359/**
1360 * ldm_frag_free - Free a linked list of VBLK fragments
1361 * @list: Linked list of fragments
1362 *
1363 * Free a linked list of VBLK fragments
1364 *
1365 * Return: none
1366 */
1367static void ldm_frag_free (struct list_head *list)
1368{
1369 struct list_head *item, *tmp;
1370
1371 BUG_ON (!list);
1372
1373 list_for_each_safe (item, tmp, list)
1374 kfree (list_entry (item, struct frag, list));
1375}
1376
1377/**
1378 * ldm_frag_commit - Validate fragmented VBLKs and add them to the database
1379 * @frags: Linked list of VBLK fragments
1380 * @ldb: Cache of the database structures
1381 *
1382 * Now that all the fragmented VBLKs have been collected, they must be added to
1383 * the database for later use.
1384 *
1385 * Return: 'true' All the fragments we added successfully
1386 * 'false' One or more of the fragments we invalid
1387 */
1388static bool ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
1389{
1390 struct frag *f;
1391 struct list_head *item;
1392
1393 BUG_ON (!frags || !ldb);
1394
1395 list_for_each (item, frags) {
1396 f = list_entry (item, struct frag, list);
1397
1398 if (f->map != 0xFF) {
1399 ldm_error ("VBLK group %d is incomplete (0x%02x).",
1400 f->group, f->map);
1401 return false;
1402 }
1403
1404 if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb))
1405 return false; /* Already logged */
1406 }
1407 return true;
1408}
1409
1410/**
1411 * ldm_get_vblks - Read the on-disk database of VBLKs into memory
1412 * @state: Partition check state including device holding the LDM Database
1413 * @base: Offset, into @state->bdev, of the database
1414 * @ldb: Cache of the database structures
1415 *
1416 * To use the information from the VBLKs, they need to be read from the disk,
1417 * unpacked and validated. We cache them in @ldb according to their type.
1418 *
1419 * Return: 'true' All the VBLKs were read successfully
1420 * 'false' An error occurred
1421 */
1422static bool ldm_get_vblks(struct parsed_partitions *state, unsigned long base,
1423 struct ldmdb *ldb)
1424{
1425 int size, perbuf, skip, finish, s, v, recs;
1426 u8 *data = NULL;
1427 Sector sect;
1428 bool result = false;
1429 LIST_HEAD (frags);
1430
1431 BUG_ON(!state || !ldb);
1432
1433 size = ldb->vm.vblk_size;
1434 perbuf = 512 / size;
1435 skip = ldb->vm.vblk_offset >> 9; /* Bytes to sectors */
1436 finish = (size * ldb->vm.last_vblk_seq) >> 9;
1437
1438 for (s = skip; s < finish; s++) { /* For each sector */
1439 data = read_part_sector(state, base + OFF_VMDB + s, &sect);
1440 if (!data) {
1441 ldm_crit ("Disk read failed.");
1442 goto out;
1443 }
1444
1445 for (v = 0; v < perbuf; v++, data+=size) { /* For each vblk */
1446 if (MAGIC_VBLK != get_unaligned_be32(data)) {
1447 ldm_error ("Expected to find a VBLK.");
1448 goto out;
1449 }
1450
1451 recs = get_unaligned_be16(data + 0x0E); /* Number of records */
1452 if (recs == 1) {
1453 if (!ldm_ldmdb_add (data, size, ldb))
1454 goto out; /* Already logged */
1455 } else if (recs > 1) {
1456 if (!ldm_frag_add (data, size, &frags))
1457 goto out; /* Already logged */
1458 }
1459 /* else Record is not in use, ignore it. */
1460 }
1461 put_dev_sector (sect);
1462 data = NULL;
1463 }
1464
1465 result = ldm_frag_commit (&frags, ldb); /* Failures, already logged */
1466out:
1467 if (data)
1468 put_dev_sector (sect);
1469 ldm_frag_free (&frags);
1470
1471 return result;
1472}
1473
1474/**
1475 * ldm_free_vblks - Free a linked list of vblk's
1476 * @lh: Head of a linked list of struct vblk
1477 *
1478 * Free a list of vblk's and free the memory used to maintain the list.
1479 *
1480 * Return: none
1481 */
1482static void ldm_free_vblks (struct list_head *lh)
1483{
1484 struct list_head *item, *tmp;
1485
1486 BUG_ON (!lh);
1487
1488 list_for_each_safe (item, tmp, lh)
1489 kfree (list_entry (item, struct vblk, list));
1490}
1491
1492
1493/**
1494 * ldm_partition - Find out whether a device is a dynamic disk and handle it
1495 * @state: Partition check state including device holding the LDM Database
1496 *
1497 * This determines whether the device @bdev is a dynamic disk and if so creates
1498 * the partitions necessary in the gendisk structure pointed to by @hd.
1499 *
1500 * We create a dummy device 1, which contains the LDM database, and then create
1501 * each partition described by the LDM database in sequence as devices 2+. For
1502 * example, if the device is hda, we would have: hda1: LDM database, hda2, hda3,
1503 * and so on: the actual data containing partitions.
1504 *
1505 * Return: 1 Success, @state->bdev is a dynamic disk and we handled it
1506 * 0 Success, @state->bdev is not a dynamic disk
1507 * -1 An error occurred before enough information had been read
1508 * Or @state->bdev is a dynamic disk, but it may be corrupted
1509 */
1510int ldm_partition(struct parsed_partitions *state)
1511{
1512 struct ldmdb *ldb;
1513 unsigned long base;
1514 int result = -1;
1515
1516 BUG_ON(!state);
1517
1518 /* Look for signs of a Dynamic Disk */
1519 if (!ldm_validate_partition_table(state))
1520 return 0;
1521
1522 ldb = kmalloc (sizeof (*ldb), GFP_KERNEL);
1523 if (!ldb) {
1524 ldm_crit ("Out of memory.");
1525 goto out;
1526 }
1527
1528 /* Parse and check privheads. */
1529 if (!ldm_validate_privheads(state, &ldb->ph))
1530 goto out; /* Already logged */
1531
1532 /* All further references are relative to base (database start). */
1533 base = ldb->ph.config_start;
1534
1535 /* Parse and check tocs and vmdb. */
1536 if (!ldm_validate_tocblocks(state, base, ldb) ||
1537 !ldm_validate_vmdb(state, base, ldb))
1538 goto out; /* Already logged */
1539
1540 /* Initialize vblk lists in ldmdb struct */
1541 INIT_LIST_HEAD (&ldb->v_dgrp);
1542 INIT_LIST_HEAD (&ldb->v_disk);
1543 INIT_LIST_HEAD (&ldb->v_volu);
1544 INIT_LIST_HEAD (&ldb->v_comp);
1545 INIT_LIST_HEAD (&ldb->v_part);
1546
1547 if (!ldm_get_vblks(state, base, ldb)) {
1548 ldm_crit ("Failed to read the VBLKs from the database.");
1549 goto cleanup;
1550 }
1551
1552 /* Finally, create the data partition devices. */
1553 if (ldm_create_data_partitions(state, ldb)) {
1554 ldm_debug ("Parsed LDM database successfully.");
1555 result = 1;
1556 }
1557 /* else Already logged */
1558
1559cleanup:
1560 ldm_free_vblks (&ldb->v_dgrp);
1561 ldm_free_vblks (&ldb->v_disk);
1562 ldm_free_vblks (&ldb->v_volu);
1563 ldm_free_vblks (&ldb->v_comp);
1564 ldm_free_vblks (&ldb->v_part);
1565out:
1566 kfree (ldb);
1567 return result;
1568}
diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h
new file mode 100644
index 00000000000..374242c0971
--- /dev/null
+++ b/fs/partitions/ldm.h
@@ -0,0 +1,215 @@
1/**
2 * ldm - Part of the Linux-NTFS project.
3 *
4 * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
5 * Copyright (c) 2001-2007 Anton Altaparmakov
6 * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
7 *
8 * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program (in the main directory of the Linux-NTFS source
22 * in the file COPYING); if not, write to the Free Software Foundation,
23 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#ifndef _FS_PT_LDM_H_
27#define _FS_PT_LDM_H_
28
29#include <linux/types.h>
30#include <linux/list.h>
31#include <linux/genhd.h>
32#include <linux/fs.h>
33#include <asm/unaligned.h>
34#include <asm/byteorder.h>
35
36struct parsed_partitions;
37
38/* Magic numbers in CPU format. */
39#define MAGIC_VMDB 0x564D4442 /* VMDB */
40#define MAGIC_VBLK 0x56424C4B /* VBLK */
41#define MAGIC_PRIVHEAD 0x5052495648454144ULL /* PRIVHEAD */
42#define MAGIC_TOCBLOCK 0x544F43424C4F434BULL /* TOCBLOCK */
43
44/* The defined vblk types. */
45#define VBLK_VOL5 0x51 /* Volume, version 5 */
46#define VBLK_CMP3 0x32 /* Component, version 3 */
47#define VBLK_PRT3 0x33 /* Partition, version 3 */
48#define VBLK_DSK3 0x34 /* Disk, version 3 */
49#define VBLK_DSK4 0x44 /* Disk, version 4 */
50#define VBLK_DGR3 0x35 /* Disk Group, version 3 */
51#define VBLK_DGR4 0x45 /* Disk Group, version 4 */
52
53/* vblk flags indicating extra information will be present */
54#define VBLK_FLAG_COMP_STRIPE 0x10
55#define VBLK_FLAG_PART_INDEX 0x08
56#define VBLK_FLAG_DGR3_IDS 0x08
57#define VBLK_FLAG_DGR4_IDS 0x08
58#define VBLK_FLAG_VOLU_ID1 0x08
59#define VBLK_FLAG_VOLU_ID2 0x20
60#define VBLK_FLAG_VOLU_SIZE 0x80
61#define VBLK_FLAG_VOLU_DRIVE 0x02
62
63/* size of a vblk's static parts */
64#define VBLK_SIZE_HEAD 16
65#define VBLK_SIZE_CMP3 22 /* Name and version */
66#define VBLK_SIZE_DGR3 12
67#define VBLK_SIZE_DGR4 44
68#define VBLK_SIZE_DSK3 12
69#define VBLK_SIZE_DSK4 45
70#define VBLK_SIZE_PRT3 28
71#define VBLK_SIZE_VOL5 58
72
73/* component types */
74#define COMP_STRIPE 0x01 /* Stripe-set */
75#define COMP_BASIC 0x02 /* Basic disk */
76#define COMP_RAID 0x03 /* Raid-set */
77
78/* Other constants. */
79#define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */
80
81#define OFF_PRIV1 6 /* Offset of the first privhead
82 relative to the start of the
83 device in sectors */
84
85/* Offsets to structures within the LDM Database in sectors. */
86#define OFF_PRIV2 1856 /* Backup private headers. */
87#define OFF_PRIV3 2047
88
89#define OFF_TOCB1 1 /* Tables of contents. */
90#define OFF_TOCB2 2
91#define OFF_TOCB3 2045
92#define OFF_TOCB4 2046
93
94#define OFF_VMDB 17 /* List of partitions. */
95
96#define LDM_PARTITION 0x42 /* Formerly SFS (Landis). */
97
98#define TOC_BITMAP1 "config" /* Names of the two defined */
99#define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */
100
101/* Borrowed from msdos.c */
102#define SYS_IND(p) (get_unaligned(&(p)->sys_ind))
103
104struct frag { /* VBLK Fragment handling */
105 struct list_head list;
106 u32 group;
107 u8 num; /* Total number of records */
108 u8 rec; /* This is record number n */
109 u8 map; /* Which portions are in use */
110 u8 data[0];
111};
112
113/* In memory LDM database structures. */
114
115#define GUID_SIZE 16
116
117struct privhead { /* Offsets and sizes are in sectors. */
118 u16 ver_major;
119 u16 ver_minor;
120 u64 logical_disk_start;
121 u64 logical_disk_size;
122 u64 config_start;
123 u64 config_size;
124 u8 disk_id[GUID_SIZE];
125};
126
127struct tocblock { /* We have exactly two bitmaps. */
128 u8 bitmap1_name[16];
129 u64 bitmap1_start;
130 u64 bitmap1_size;
131 u8 bitmap2_name[16];
132 u64 bitmap2_start;
133 u64 bitmap2_size;
134};
135
136struct vmdb { /* VMDB: The database header */
137 u16 ver_major;
138 u16 ver_minor;
139 u32 vblk_size;
140 u32 vblk_offset;
141 u32 last_vblk_seq;
142};
143
144struct vblk_comp { /* VBLK Component */
145 u8 state[16];
146 u64 parent_id;
147 u8 type;
148 u8 children;
149 u16 chunksize;
150};
151
152struct vblk_dgrp { /* VBLK Disk Group */
153 u8 disk_id[64];
154};
155
156struct vblk_disk { /* VBLK Disk */
157 u8 disk_id[GUID_SIZE];
158 u8 alt_name[128];
159};
160
161struct vblk_part { /* VBLK Partition */
162 u64 start;
163 u64 size; /* start, size and vol_off in sectors */
164 u64 volume_offset;
165 u64 parent_id;
166 u64 disk_id;
167 u8 partnum;
168};
169
170struct vblk_volu { /* VBLK Volume */
171 u8 volume_type[16];
172 u8 volume_state[16];
173 u8 guid[16];
174 u8 drive_hint[4];
175 u64 size;
176 u8 partition_type;
177};
178
179struct vblk_head { /* VBLK standard header */
180 u32 group;
181 u16 rec;
182 u16 nrec;
183};
184
185struct vblk { /* Generalised VBLK */
186 u8 name[64];
187 u64 obj_id;
188 u32 sequence;
189 u8 flags;
190 u8 type;
191 union {
192 struct vblk_comp comp;
193 struct vblk_dgrp dgrp;
194 struct vblk_disk disk;
195 struct vblk_part part;
196 struct vblk_volu volu;
197 } vblk;
198 struct list_head list;
199};
200
201struct ldmdb { /* Cache of the database */
202 struct privhead ph;
203 struct tocblock toc;
204 struct vmdb vm;
205 struct list_head v_dgrp;
206 struct list_head v_disk;
207 struct list_head v_volu;
208 struct list_head v_comp;
209 struct list_head v_part;
210};
211
212int ldm_partition(struct parsed_partitions *state);
213
214#endif /* _FS_PT_LDM_H_ */
215
diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c
new file mode 100644
index 00000000000..11f688bd76c
--- /dev/null
+++ b/fs/partitions/mac.c
@@ -0,0 +1,134 @@
1/*
2 * fs/partitions/mac.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 * Copyright (C) 1991-1998 Linus Torvalds
6 * Re-organised Feb 1998 Russell King
7 */
8
9#include <linux/ctype.h>
10#include "check.h"
11#include "mac.h"
12
13#ifdef CONFIG_PPC_PMAC
14#include <asm/machdep.h>
15extern void note_bootable_part(dev_t dev, int part, int goodness);
16#endif
17
18/*
19 * Code to understand MacOS partition tables.
20 */
21
22static inline void mac_fix_string(char *stg, int len)
23{
24 int i;
25
26 for (i = len - 1; i >= 0 && stg[i] == ' '; i--)
27 stg[i] = 0;
28}
29
30int mac_partition(struct parsed_partitions *state)
31{
32 Sector sect;
33 unsigned char *data;
34 int slot, blocks_in_map;
35 unsigned secsize;
36#ifdef CONFIG_PPC_PMAC
37 int found_root = 0;
38 int found_root_goodness = 0;
39#endif
40 struct mac_partition *part;
41 struct mac_driver_desc *md;
42
43 /* Get 0th block and look at the first partition map entry. */
44 md = read_part_sector(state, 0, &sect);
45 if (!md)
46 return -1;
47 if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
48 put_dev_sector(sect);
49 return 0;
50 }
51 secsize = be16_to_cpu(md->block_size);
52 put_dev_sector(sect);
53 data = read_part_sector(state, secsize/512, &sect);
54 if (!data)
55 return -1;
56 part = (struct mac_partition *) (data + secsize%512);
57 if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
58 put_dev_sector(sect);
59 return 0; /* not a MacOS disk */
60 }
61 blocks_in_map = be32_to_cpu(part->map_count);
62 if (blocks_in_map < 0 || blocks_in_map >= DISK_MAX_PARTS) {
63 put_dev_sector(sect);
64 return 0;
65 }
66 strlcat(state->pp_buf, " [mac]", PAGE_SIZE);
67 for (slot = 1; slot <= blocks_in_map; ++slot) {
68 int pos = slot * secsize;
69 put_dev_sector(sect);
70 data = read_part_sector(state, pos/512, &sect);
71 if (!data)
72 return -1;
73 part = (struct mac_partition *) (data + pos%512);
74 if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
75 break;
76 put_partition(state, slot,
77 be32_to_cpu(part->start_block) * (secsize/512),
78 be32_to_cpu(part->block_count) * (secsize/512));
79
80 if (!strnicmp(part->type, "Linux_RAID", 10))
81 state->parts[slot].flags = ADDPART_FLAG_RAID;
82#ifdef CONFIG_PPC_PMAC
83 /*
84 * If this is the first bootable partition, tell the
85 * setup code, in case it wants to make this the root.
86 */
87 if (machine_is(powermac)) {
88 int goodness = 0;
89
90 mac_fix_string(part->processor, 16);
91 mac_fix_string(part->name, 32);
92 mac_fix_string(part->type, 32);
93
94 if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
95 && strcasecmp(part->processor, "powerpc") == 0)
96 goodness++;
97
98 if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
99 || (strnicmp(part->type, "Linux", 5) == 0
100 && strcasecmp(part->type, "Linux_swap") != 0)) {
101 int i, l;
102
103 goodness++;
104 l = strlen(part->name);
105 if (strcmp(part->name, "/") == 0)
106 goodness++;
107 for (i = 0; i <= l - 4; ++i) {
108 if (strnicmp(part->name + i, "root",
109 4) == 0) {
110 goodness += 2;
111 break;
112 }
113 }
114 if (strnicmp(part->name, "swap", 4) == 0)
115 goodness--;
116 }
117
118 if (goodness > found_root_goodness) {
119 found_root = slot;
120 found_root_goodness = goodness;
121 }
122 }
123#endif /* CONFIG_PPC_PMAC */
124 }
125#ifdef CONFIG_PPC_PMAC
126 if (found_root_goodness)
127 note_bootable_part(state->bdev->bd_dev, found_root,
128 found_root_goodness);
129#endif
130
131 put_dev_sector(sect);
132 strlcat(state->pp_buf, "\n", PAGE_SIZE);
133 return 1;
134}
diff --git a/fs/partitions/mac.h b/fs/partitions/mac.h
new file mode 100644
index 00000000000..3c7d9843638
--- /dev/null
+++ b/fs/partitions/mac.h
@@ -0,0 +1,44 @@
1/*
2 * fs/partitions/mac.h
3 */
4
5#define MAC_PARTITION_MAGIC 0x504d
6
7/* type field value for A/UX or other Unix partitions */
8#define APPLE_AUX_TYPE "Apple_UNIX_SVR2"
9
10struct mac_partition {
11 __be16 signature; /* expected to be MAC_PARTITION_MAGIC */
12 __be16 res1;
13 __be32 map_count; /* # blocks in partition map */
14 __be32 start_block; /* absolute starting block # of partition */
15 __be32 block_count; /* number of blocks in partition */
16 char name[32]; /* partition name */
17 char type[32]; /* string type description */
18 __be32 data_start; /* rel block # of first data block */
19 __be32 data_count; /* number of data blocks */
20 __be32 status; /* partition status bits */
21 __be32 boot_start;
22 __be32 boot_size;
23 __be32 boot_load;
24 __be32 boot_load2;
25 __be32 boot_entry;
26 __be32 boot_entry2;
27 __be32 boot_cksum;
28 char processor[16]; /* identifies ISA of boot */
29 /* there is more stuff after this that we don't need */
30};
31
32#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */
33
34#define MAC_DRIVER_MAGIC 0x4552
35
36/* Driver descriptor structure, in block 0 */
37struct mac_driver_desc {
38 __be16 signature; /* expected to be MAC_DRIVER_MAGIC */
39 __be16 block_size;
40 __be32 block_count;
41 /* ... more stuff */
42};
43
44int mac_partition(struct parsed_partitions *state);
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
new file mode 100644
index 00000000000..5f79a6677c6
--- /dev/null
+++ b/fs/partitions/msdos.c
@@ -0,0 +1,552 @@
1/*
2 * fs/partitions/msdos.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 * Copyright (C) 1991-1998 Linus Torvalds
6 *
7 * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
8 * in the early extended-partition checks and added DM partitions
9 *
10 * Support for DiskManager v6.0x added by Mark Lord,
11 * with information provided by OnTrack. This now works for linux fdisk
12 * and LILO, as well as loadlin and bootln. Note that disks other than
13 * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
14 *
15 * More flexible handling of extended partitions - aeb, 950831
16 *
17 * Check partition table on IDE disks for common CHS translations
18 *
19 * Re-organised Feb 1998 Russell King
20 */
21#include <linux/msdos_fs.h>
22
23#include "check.h"
24#include "msdos.h"
25#include "efi.h"
26
27/*
28 * Many architectures don't like unaligned accesses, while
29 * the nr_sects and start_sect partition table entries are
30 * at a 2 (mod 4) address.
31 */
32#include <asm/unaligned.h>
33
34#define SYS_IND(p) get_unaligned(&p->sys_ind)
35
36static inline sector_t nr_sects(struct partition *p)
37{
38 return (sector_t)get_unaligned_le32(&p->nr_sects);
39}
40
41static inline sector_t start_sect(struct partition *p)
42{
43 return (sector_t)get_unaligned_le32(&p->start_sect);
44}
45
46static inline int is_extended_partition(struct partition *p)
47{
48 return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
49 SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
50 SYS_IND(p) == LINUX_EXTENDED_PARTITION);
51}
52
53#define MSDOS_LABEL_MAGIC1 0x55
54#define MSDOS_LABEL_MAGIC2 0xAA
55
56static inline int
57msdos_magic_present(unsigned char *p)
58{
59 return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
60}
61
62/* Value is EBCDIC 'IBMA' */
63#define AIX_LABEL_MAGIC1 0xC9
64#define AIX_LABEL_MAGIC2 0xC2
65#define AIX_LABEL_MAGIC3 0xD4
66#define AIX_LABEL_MAGIC4 0xC1
67static int aix_magic_present(struct parsed_partitions *state, unsigned char *p)
68{
69 struct partition *pt = (struct partition *) (p + 0x1be);
70 Sector sect;
71 unsigned char *d;
72 int slot, ret = 0;
73
74 if (!(p[0] == AIX_LABEL_MAGIC1 &&
75 p[1] == AIX_LABEL_MAGIC2 &&
76 p[2] == AIX_LABEL_MAGIC3 &&
77 p[3] == AIX_LABEL_MAGIC4))
78 return 0;
79 /* Assume the partition table is valid if Linux partitions exists */
80 for (slot = 1; slot <= 4; slot++, pt++) {
81 if (pt->sys_ind == LINUX_SWAP_PARTITION ||
82 pt->sys_ind == LINUX_RAID_PARTITION ||
83 pt->sys_ind == LINUX_DATA_PARTITION ||
84 pt->sys_ind == LINUX_LVM_PARTITION ||
85 is_extended_partition(pt))
86 return 0;
87 }
88 d = read_part_sector(state, 7, &sect);
89 if (d) {
90 if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M')
91 ret = 1;
92 put_dev_sector(sect);
93 };
94 return ret;
95}
96
97/*
98 * Create devices for each logical partition in an extended partition.
99 * The logical partitions form a linked list, with each entry being
100 * a partition table with two entries. The first entry
101 * is the real data partition (with a start relative to the partition
102 * table start). The second is a pointer to the next logical partition
103 * (with a start relative to the entire extended partition).
104 * We do not create a Linux partition for the partition tables, but
105 * only for the actual data partitions.
106 */
107
108static void parse_extended(struct parsed_partitions *state,
109 sector_t first_sector, sector_t first_size)
110{
111 struct partition *p;
112 Sector sect;
113 unsigned char *data;
114 sector_t this_sector, this_size;
115 sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
116 int loopct = 0; /* number of links followed
117 without finding a data partition */
118 int i;
119
120 this_sector = first_sector;
121 this_size = first_size;
122
123 while (1) {
124 if (++loopct > 100)
125 return;
126 if (state->next == state->limit)
127 return;
128 data = read_part_sector(state, this_sector, &sect);
129 if (!data)
130 return;
131
132 if (!msdos_magic_present(data + 510))
133 goto done;
134
135 p = (struct partition *) (data + 0x1be);
136
137 /*
138 * Usually, the first entry is the real data partition,
139 * the 2nd entry is the next extended partition, or empty,
140 * and the 3rd and 4th entries are unused.
141 * However, DRDOS sometimes has the extended partition as
142 * the first entry (when the data partition is empty),
143 * and OS/2 seems to use all four entries.
144 */
145
146 /*
147 * First process the data partition(s)
148 */
149 for (i=0; i<4; i++, p++) {
150 sector_t offs, size, next;
151 if (!nr_sects(p) || is_extended_partition(p))
152 continue;
153
154 /* Check the 3rd and 4th entries -
155 these sometimes contain random garbage */
156 offs = start_sect(p)*sector_size;
157 size = nr_sects(p)*sector_size;
158 next = this_sector + offs;
159 if (i >= 2) {
160 if (offs + size > this_size)
161 continue;
162 if (next < first_sector)
163 continue;
164 if (next + size > first_sector + first_size)
165 continue;
166 }
167
168 put_partition(state, state->next, next, size);
169 if (SYS_IND(p) == LINUX_RAID_PARTITION)
170 state->parts[state->next].flags = ADDPART_FLAG_RAID;
171 loopct = 0;
172 if (++state->next == state->limit)
173 goto done;
174 }
175 /*
176 * Next, process the (first) extended partition, if present.
177 * (So far, there seems to be no reason to make
178 * parse_extended() recursive and allow a tree
179 * of extended partitions.)
180 * It should be a link to the next logical partition.
181 */
182 p -= 4;
183 for (i=0; i<4; i++, p++)
184 if (nr_sects(p) && is_extended_partition(p))
185 break;
186 if (i == 4)
187 goto done; /* nothing left to do */
188
189 this_sector = first_sector + start_sect(p) * sector_size;
190 this_size = nr_sects(p) * sector_size;
191 put_dev_sector(sect);
192 }
193done:
194 put_dev_sector(sect);
195}
196
197/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
198 indicates linux swap. Be careful before believing this is Solaris. */
199
200static void parse_solaris_x86(struct parsed_partitions *state,
201 sector_t offset, sector_t size, int origin)
202{
203#ifdef CONFIG_SOLARIS_X86_PARTITION
204 Sector sect;
205 struct solaris_x86_vtoc *v;
206 int i;
207 short max_nparts;
208
209 v = read_part_sector(state, offset + 1, &sect);
210 if (!v)
211 return;
212 if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
213 put_dev_sector(sect);
214 return;
215 }
216 {
217 char tmp[1 + BDEVNAME_SIZE + 10 + 11 + 1];
218
219 snprintf(tmp, sizeof(tmp), " %s%d: <solaris:", state->name, origin);
220 strlcat(state->pp_buf, tmp, PAGE_SIZE);
221 }
222 if (le32_to_cpu(v->v_version) != 1) {
223 char tmp[64];
224
225 snprintf(tmp, sizeof(tmp), " cannot handle version %d vtoc>\n",
226 le32_to_cpu(v->v_version));
227 strlcat(state->pp_buf, tmp, PAGE_SIZE);
228 put_dev_sector(sect);
229 return;
230 }
231 /* Ensure we can handle previous case of VTOC with 8 entries gracefully */
232 max_nparts = le16_to_cpu (v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8;
233 for (i=0; i<max_nparts && state->next<state->limit; i++) {
234 struct solaris_x86_slice *s = &v->v_slice[i];
235 char tmp[3 + 10 + 1 + 1];
236
237 if (s->s_size == 0)
238 continue;
239 snprintf(tmp, sizeof(tmp), " [s%d]", i);
240 strlcat(state->pp_buf, tmp, PAGE_SIZE);
241 /* solaris partitions are relative to current MS-DOS
242 * one; must add the offset of the current partition */
243 put_partition(state, state->next++,
244 le32_to_cpu(s->s_start)+offset,
245 le32_to_cpu(s->s_size));
246 }
247 put_dev_sector(sect);
248 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
249#endif
250}
251
252#if defined(CONFIG_BSD_DISKLABEL)
253/*
254 * Create devices for BSD partitions listed in a disklabel, under a
255 * dos-like partition. See parse_extended() for more information.
256 */
257static void parse_bsd(struct parsed_partitions *state,
258 sector_t offset, sector_t size, int origin, char *flavour,
259 int max_partitions)
260{
261 Sector sect;
262 struct bsd_disklabel *l;
263 struct bsd_partition *p;
264 char tmp[64];
265
266 l = read_part_sector(state, offset + 1, &sect);
267 if (!l)
268 return;
269 if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
270 put_dev_sector(sect);
271 return;
272 }
273
274 snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour);
275 strlcat(state->pp_buf, tmp, PAGE_SIZE);
276
277 if (le16_to_cpu(l->d_npartitions) < max_partitions)
278 max_partitions = le16_to_cpu(l->d_npartitions);
279 for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
280 sector_t bsd_start, bsd_size;
281
282 if (state->next == state->limit)
283 break;
284 if (p->p_fstype == BSD_FS_UNUSED)
285 continue;
286 bsd_start = le32_to_cpu(p->p_offset);
287 bsd_size = le32_to_cpu(p->p_size);
288 if (offset == bsd_start && size == bsd_size)
289 /* full parent partition, we have it already */
290 continue;
291 if (offset > bsd_start || offset+size < bsd_start+bsd_size) {
292 strlcat(state->pp_buf, "bad subpartition - ignored\n", PAGE_SIZE);
293 continue;
294 }
295 put_partition(state, state->next++, bsd_start, bsd_size);
296 }
297 put_dev_sector(sect);
298 if (le16_to_cpu(l->d_npartitions) > max_partitions) {
299 snprintf(tmp, sizeof(tmp), " (ignored %d more)",
300 le16_to_cpu(l->d_npartitions) - max_partitions);
301 strlcat(state->pp_buf, tmp, PAGE_SIZE);
302 }
303 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
304}
305#endif
306
307static void parse_freebsd(struct parsed_partitions *state,
308 sector_t offset, sector_t size, int origin)
309{
310#ifdef CONFIG_BSD_DISKLABEL
311 parse_bsd(state, offset, size, origin, "bsd", BSD_MAXPARTITIONS);
312#endif
313}
314
315static void parse_netbsd(struct parsed_partitions *state,
316 sector_t offset, sector_t size, int origin)
317{
318#ifdef CONFIG_BSD_DISKLABEL
319 parse_bsd(state, offset, size, origin, "netbsd", BSD_MAXPARTITIONS);
320#endif
321}
322
323static void parse_openbsd(struct parsed_partitions *state,
324 sector_t offset, sector_t size, int origin)
325{
326#ifdef CONFIG_BSD_DISKLABEL
327 parse_bsd(state, offset, size, origin, "openbsd",
328 OPENBSD_MAXPARTITIONS);
329#endif
330}
331
332/*
333 * Create devices for Unixware partitions listed in a disklabel, under a
334 * dos-like partition. See parse_extended() for more information.
335 */
336static void parse_unixware(struct parsed_partitions *state,
337 sector_t offset, sector_t size, int origin)
338{
339#ifdef CONFIG_UNIXWARE_DISKLABEL
340 Sector sect;
341 struct unixware_disklabel *l;
342 struct unixware_slice *p;
343
344 l = read_part_sector(state, offset + 29, &sect);
345 if (!l)
346 return;
347 if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
348 le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
349 put_dev_sector(sect);
350 return;
351 }
352 {
353 char tmp[1 + BDEVNAME_SIZE + 10 + 12 + 1];
354
355 snprintf(tmp, sizeof(tmp), " %s%d: <unixware:", state->name, origin);
356 strlcat(state->pp_buf, tmp, PAGE_SIZE);
357 }
358 p = &l->vtoc.v_slice[1];
359 /* I omit the 0th slice as it is the same as whole disk. */
360 while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
361 if (state->next == state->limit)
362 break;
363
364 if (p->s_label != UNIXWARE_FS_UNUSED)
365 put_partition(state, state->next++,
366 le32_to_cpu(p->start_sect),
367 le32_to_cpu(p->nr_sects));
368 p++;
369 }
370 put_dev_sector(sect);
371 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
372#endif
373}
374
375/*
376 * Minix 2.0.0/2.0.2 subpartition support.
377 * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
378 * Rajeev V. Pillai <rajeevvp@yahoo.com>
379 */
380static void parse_minix(struct parsed_partitions *state,
381 sector_t offset, sector_t size, int origin)
382{
383#ifdef CONFIG_MINIX_SUBPARTITION
384 Sector sect;
385 unsigned char *data;
386 struct partition *p;
387 int i;
388
389 data = read_part_sector(state, offset, &sect);
390 if (!data)
391 return;
392
393 p = (struct partition *)(data + 0x1be);
394
395 /* The first sector of a Minix partition can have either
396 * a secondary MBR describing its subpartitions, or
397 * the normal boot sector. */
398 if (msdos_magic_present (data + 510) &&
399 SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
400 char tmp[1 + BDEVNAME_SIZE + 10 + 9 + 1];
401
402 snprintf(tmp, sizeof(tmp), " %s%d: <minix:", state->name, origin);
403 strlcat(state->pp_buf, tmp, PAGE_SIZE);
404 for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
405 if (state->next == state->limit)
406 break;
407 /* add each partition in use */
408 if (SYS_IND(p) == MINIX_PARTITION)
409 put_partition(state, state->next++,
410 start_sect(p), nr_sects(p));
411 }
412 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
413 }
414 put_dev_sector(sect);
415#endif /* CONFIG_MINIX_SUBPARTITION */
416}
417
418static struct {
419 unsigned char id;
420 void (*parse)(struct parsed_partitions *, sector_t, sector_t, int);
421} subtypes[] = {
422 {FREEBSD_PARTITION, parse_freebsd},
423 {NETBSD_PARTITION, parse_netbsd},
424 {OPENBSD_PARTITION, parse_openbsd},
425 {MINIX_PARTITION, parse_minix},
426 {UNIXWARE_PARTITION, parse_unixware},
427 {SOLARIS_X86_PARTITION, parse_solaris_x86},
428 {NEW_SOLARIS_X86_PARTITION, parse_solaris_x86},
429 {0, NULL},
430};
431
432int msdos_partition(struct parsed_partitions *state)
433{
434 sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
435 Sector sect;
436 unsigned char *data;
437 struct partition *p;
438 struct fat_boot_sector *fb;
439 int slot;
440
441 data = read_part_sector(state, 0, &sect);
442 if (!data)
443 return -1;
444 if (!msdos_magic_present(data + 510)) {
445 put_dev_sector(sect);
446 return 0;
447 }
448
449 if (aix_magic_present(state, data)) {
450 put_dev_sector(sect);
451 strlcat(state->pp_buf, " [AIX]", PAGE_SIZE);
452 return 0;
453 }
454
455 /*
456 * Now that the 55aa signature is present, this is probably
457 * either the boot sector of a FAT filesystem or a DOS-type
458 * partition table. Reject this in case the boot indicator
459 * is not 0 or 0x80.
460 */
461 p = (struct partition *) (data + 0x1be);
462 for (slot = 1; slot <= 4; slot++, p++) {
463 if (p->boot_ind != 0 && p->boot_ind != 0x80) {
464 /*
465 * Even without a valid boot inidicator value
466 * its still possible this is valid FAT filesystem
467 * without a partition table.
468 */
469 fb = (struct fat_boot_sector *) data;
470 if (slot == 1 && fb->reserved && fb->fats
471 && fat_valid_media(fb->media)) {
472 strlcat(state->pp_buf, "\n", PAGE_SIZE);
473 put_dev_sector(sect);
474 return 1;
475 } else {
476 put_dev_sector(sect);
477 return 0;
478 }
479 }
480 }
481
482#ifdef CONFIG_EFI_PARTITION
483 p = (struct partition *) (data + 0x1be);
484 for (slot = 1 ; slot <= 4 ; slot++, p++) {
485 /* If this is an EFI GPT disk, msdos should ignore it. */
486 if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
487 put_dev_sector(sect);
488 return 0;
489 }
490 }
491#endif
492 p = (struct partition *) (data + 0x1be);
493
494 /*
495 * Look for partitions in two passes:
496 * First find the primary and DOS-type extended partitions.
497 * On the second pass look inside *BSD, Unixware and Solaris partitions.
498 */
499
500 state->next = 5;
501 for (slot = 1 ; slot <= 4 ; slot++, p++) {
502 sector_t start = start_sect(p)*sector_size;
503 sector_t size = nr_sects(p)*sector_size;
504 if (!size)
505 continue;
506 if (is_extended_partition(p)) {
507 /*
508 * prevent someone doing mkfs or mkswap on an
509 * extended partition, but leave room for LILO
510 * FIXME: this uses one logical sector for > 512b
511 * sector, although it may not be enough/proper.
512 */
513 sector_t n = 2;
514 n = min(size, max(sector_size, n));
515 put_partition(state, slot, start, n);
516
517 strlcat(state->pp_buf, " <", PAGE_SIZE);
518 parse_extended(state, start, size);
519 strlcat(state->pp_buf, " >", PAGE_SIZE);
520 continue;
521 }
522 put_partition(state, slot, start, size);
523 if (SYS_IND(p) == LINUX_RAID_PARTITION)
524 state->parts[slot].flags = ADDPART_FLAG_RAID;
525 if (SYS_IND(p) == DM6_PARTITION)
526 strlcat(state->pp_buf, "[DM]", PAGE_SIZE);
527 if (SYS_IND(p) == EZD_PARTITION)
528 strlcat(state->pp_buf, "[EZD]", PAGE_SIZE);
529 }
530
531 strlcat(state->pp_buf, "\n", PAGE_SIZE);
532
533 /* second pass - output for each on a separate line */
534 p = (struct partition *) (0x1be + data);
535 for (slot = 1 ; slot <= 4 ; slot++, p++) {
536 unsigned char id = SYS_IND(p);
537 int n;
538
539 if (!nr_sects(p))
540 continue;
541
542 for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
543 ;
544
545 if (!subtypes[n].parse)
546 continue;
547 subtypes[n].parse(state, start_sect(p) * sector_size,
548 nr_sects(p) * sector_size, slot);
549 }
550 put_dev_sector(sect);
551 return 1;
552}
diff --git a/fs/partitions/msdos.h b/fs/partitions/msdos.h
new file mode 100644
index 00000000000..38c781c490b
--- /dev/null
+++ b/fs/partitions/msdos.h
@@ -0,0 +1,8 @@
1/*
2 * fs/partitions/msdos.h
3 */
4
5#define MSDOS_LABEL_MAGIC 0xAA55
6
7int msdos_partition(struct parsed_partitions *state);
8
diff --git a/fs/partitions/osf.c b/fs/partitions/osf.c
new file mode 100644
index 00000000000..764b86a0196
--- /dev/null
+++ b/fs/partitions/osf.c
@@ -0,0 +1,86 @@
1/*
2 * fs/partitions/osf.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 *
6 * Copyright (C) 1991-1998 Linus Torvalds
7 * Re-organised Feb 1998 Russell King
8 */
9
10#include "check.h"
11#include "osf.h"
12
13#define MAX_OSF_PARTITIONS 18
14
15int osf_partition(struct parsed_partitions *state)
16{
17 int i;
18 int slot = 1;
19 unsigned int npartitions;
20 Sector sect;
21 unsigned char *data;
22 struct disklabel {
23 __le32 d_magic;
24 __le16 d_type,d_subtype;
25 u8 d_typename[16];
26 u8 d_packname[16];
27 __le32 d_secsize;
28 __le32 d_nsectors;
29 __le32 d_ntracks;
30 __le32 d_ncylinders;
31 __le32 d_secpercyl;
32 __le32 d_secprtunit;
33 __le16 d_sparespertrack;
34 __le16 d_sparespercyl;
35 __le32 d_acylinders;
36 __le16 d_rpm, d_interleave, d_trackskew, d_cylskew;
37 __le32 d_headswitch, d_trkseek, d_flags;
38 __le32 d_drivedata[5];
39 __le32 d_spare[5];
40 __le32 d_magic2;
41 __le16 d_checksum;
42 __le16 d_npartitions;
43 __le32 d_bbsize, d_sbsize;
44 struct d_partition {
45 __le32 p_size;
46 __le32 p_offset;
47 __le32 p_fsize;
48 u8 p_fstype;
49 u8 p_frag;
50 __le16 p_cpg;
51 } d_partitions[MAX_OSF_PARTITIONS];
52 } * label;
53 struct d_partition * partition;
54
55 data = read_part_sector(state, 0, &sect);
56 if (!data)
57 return -1;
58
59 label = (struct disklabel *) (data+64);
60 partition = label->d_partitions;
61 if (le32_to_cpu(label->d_magic) != DISKLABELMAGIC) {
62 put_dev_sector(sect);
63 return 0;
64 }
65 if (le32_to_cpu(label->d_magic2) != DISKLABELMAGIC) {
66 put_dev_sector(sect);
67 return 0;
68 }
69 npartitions = le16_to_cpu(label->d_npartitions);
70 if (npartitions > MAX_OSF_PARTITIONS) {
71 put_dev_sector(sect);
72 return 0;
73 }
74 for (i = 0 ; i < npartitions; i++, partition++) {
75 if (slot == state->limit)
76 break;
77 if (le32_to_cpu(partition->p_size))
78 put_partition(state, slot,
79 le32_to_cpu(partition->p_offset),
80 le32_to_cpu(partition->p_size));
81 slot++;
82 }
83 strlcat(state->pp_buf, "\n", PAGE_SIZE);
84 put_dev_sector(sect);
85 return 1;
86}
diff --git a/fs/partitions/osf.h b/fs/partitions/osf.h
new file mode 100644
index 00000000000..20ed2315ec1
--- /dev/null
+++ b/fs/partitions/osf.h
@@ -0,0 +1,7 @@
1/*
2 * fs/partitions/osf.h
3 */
4
5#define DISKLABELMAGIC (0x82564557UL)
6
7int osf_partition(struct parsed_partitions *state);
diff --git a/fs/partitions/sgi.c b/fs/partitions/sgi.c
new file mode 100644
index 00000000000..ea8a86dceaf
--- /dev/null
+++ b/fs/partitions/sgi.c
@@ -0,0 +1,82 @@
1/*
2 * fs/partitions/sgi.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 */
6
7#include "check.h"
8#include "sgi.h"
9
10struct sgi_disklabel {
11 __be32 magic_mushroom; /* Big fat spliff... */
12 __be16 root_part_num; /* Root partition number */
13 __be16 swap_part_num; /* Swap partition number */
14 s8 boot_file[16]; /* Name of boot file for ARCS */
15 u8 _unused0[48]; /* Device parameter useless crapola.. */
16 struct sgi_volume {
17 s8 name[8]; /* Name of volume */
18 __be32 block_num; /* Logical block number */
19 __be32 num_bytes; /* How big, in bytes */
20 } volume[15];
21 struct sgi_partition {
22 __be32 num_blocks; /* Size in logical blocks */
23 __be32 first_block; /* First logical block */
24 __be32 type; /* Type of this partition */
25 } partitions[16];
26 __be32 csum; /* Disk label checksum */
27 __be32 _unused1; /* Padding */
28};
29
30int sgi_partition(struct parsed_partitions *state)
31{
32 int i, csum;
33 __be32 magic;
34 int slot = 1;
35 unsigned int start, blocks;
36 __be32 *ui, cs;
37 Sector sect;
38 struct sgi_disklabel *label;
39 struct sgi_partition *p;
40 char b[BDEVNAME_SIZE];
41
42 label = read_part_sector(state, 0, &sect);
43 if (!label)
44 return -1;
45 p = &label->partitions[0];
46 magic = label->magic_mushroom;
47 if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) {
48 /*printk("Dev %s SGI disklabel: bad magic %08x\n",
49 bdevname(bdev, b), be32_to_cpu(magic));*/
50 put_dev_sector(sect);
51 return 0;
52 }
53 ui = ((__be32 *) (label + 1)) - 1;
54 for(csum = 0; ui >= ((__be32 *) label);) {
55 cs = *ui--;
56 csum += be32_to_cpu(cs);
57 }
58 if(csum) {
59 printk(KERN_WARNING "Dev %s SGI disklabel: csum bad, label corrupted\n",
60 bdevname(state->bdev, b));
61 put_dev_sector(sect);
62 return 0;
63 }
64 /* All SGI disk labels have 16 partitions, disks under Linux only
65 * have 15 minor's. Luckily there are always a few zero length
66 * partitions which we don't care about so we never overflow the
67 * current_minor.
68 */
69 for(i = 0; i < 16; i++, p++) {
70 blocks = be32_to_cpu(p->num_blocks);
71 start = be32_to_cpu(p->first_block);
72 if (blocks) {
73 put_partition(state, slot, start, blocks);
74 if (be32_to_cpu(p->type) == LINUX_RAID_PARTITION)
75 state->parts[slot].flags = ADDPART_FLAG_RAID;
76 }
77 slot++;
78 }
79 strlcat(state->pp_buf, "\n", PAGE_SIZE);
80 put_dev_sector(sect);
81 return 1;
82}
diff --git a/fs/partitions/sgi.h b/fs/partitions/sgi.h
new file mode 100644
index 00000000000..b9553ebdd5a
--- /dev/null
+++ b/fs/partitions/sgi.h
@@ -0,0 +1,8 @@
1/*
2 * fs/partitions/sgi.h
3 */
4
5extern int sgi_partition(struct parsed_partitions *state);
6
7#define SGI_LABEL_MAGIC 0x0be5a941
8
diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c
new file mode 100644
index 00000000000..b5b6fcfb3d3
--- /dev/null
+++ b/fs/partitions/sun.c
@@ -0,0 +1,122 @@
1/*
2 * fs/partitions/sun.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 *
6 * Copyright (C) 1991-1998 Linus Torvalds
7 * Re-organised Feb 1998 Russell King
8 */
9
10#include "check.h"
11#include "sun.h"
12
13int sun_partition(struct parsed_partitions *state)
14{
15 int i;
16 __be16 csum;
17 int slot = 1;
18 __be16 *ush;
19 Sector sect;
20 struct sun_disklabel {
21 unsigned char info[128]; /* Informative text string */
22 struct sun_vtoc {
23 __be32 version; /* Layout version */
24 char volume[8]; /* Volume name */
25 __be16 nparts; /* Number of partitions */
26 struct sun_info { /* Partition hdrs, sec 2 */
27 __be16 id;
28 __be16 flags;
29 } infos[8];
30 __be16 padding; /* Alignment padding */
31 __be32 bootinfo[3]; /* Info needed by mboot */
32 __be32 sanity; /* To verify vtoc sanity */
33 __be32 reserved[10]; /* Free space */
34 __be32 timestamp[8]; /* Partition timestamp */
35 } vtoc;
36 __be32 write_reinstruct; /* sectors to skip, writes */
37 __be32 read_reinstruct; /* sectors to skip, reads */
38 unsigned char spare[148]; /* Padding */
39 __be16 rspeed; /* Disk rotational speed */
40 __be16 pcylcount; /* Physical cylinder count */
41 __be16 sparecyl; /* extra sects per cylinder */
42 __be16 obs1; /* gap1 */
43 __be16 obs2; /* gap2 */
44 __be16 ilfact; /* Interleave factor */
45 __be16 ncyl; /* Data cylinder count */
46 __be16 nacyl; /* Alt. cylinder count */
47 __be16 ntrks; /* Tracks per cylinder */
48 __be16 nsect; /* Sectors per track */
49 __be16 obs3; /* bhead - Label head offset */
50 __be16 obs4; /* ppart - Physical Partition */
51 struct sun_partition {
52 __be32 start_cylinder;
53 __be32 num_sectors;
54 } partitions[8];
55 __be16 magic; /* Magic number */
56 __be16 csum; /* Label xor'd checksum */
57 } * label;
58 struct sun_partition *p;
59 unsigned long spc;
60 char b[BDEVNAME_SIZE];
61 int use_vtoc;
62 int nparts;
63
64 label = read_part_sector(state, 0, &sect);
65 if (!label)
66 return -1;
67
68 p = label->partitions;
69 if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
70/* printk(KERN_INFO "Dev %s Sun disklabel: bad magic %04x\n",
71 bdevname(bdev, b), be16_to_cpu(label->magic)); */
72 put_dev_sector(sect);
73 return 0;
74 }
75 /* Look at the checksum */
76 ush = ((__be16 *) (label+1)) - 1;
77 for (csum = 0; ush >= ((__be16 *) label);)
78 csum ^= *ush--;
79 if (csum) {
80 printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
81 bdevname(state->bdev, b));
82 put_dev_sector(sect);
83 return 0;
84 }
85
86 /* Check to see if we can use the VTOC table */
87 use_vtoc = ((be32_to_cpu(label->vtoc.sanity) == SUN_VTOC_SANITY) &&
88 (be32_to_cpu(label->vtoc.version) == 1) &&
89 (be16_to_cpu(label->vtoc.nparts) <= 8));
90
91 /* Use 8 partition entries if not specified in validated VTOC */
92 nparts = (use_vtoc) ? be16_to_cpu(label->vtoc.nparts) : 8;
93
94 /*
95 * So that old Linux-Sun partitions continue to work,
96 * alow the VTOC to be used under the additional condition ...
97 */
98 use_vtoc = use_vtoc || !(label->vtoc.sanity ||
99 label->vtoc.version || label->vtoc.nparts);
100 spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
101 for (i = 0; i < nparts; i++, p++) {
102 unsigned long st_sector;
103 unsigned int num_sectors;
104
105 st_sector = be32_to_cpu(p->start_cylinder) * spc;
106 num_sectors = be32_to_cpu(p->num_sectors);
107 if (num_sectors) {
108 put_partition(state, slot, st_sector, num_sectors);
109 state->parts[slot].flags = 0;
110 if (use_vtoc) {
111 if (be16_to_cpu(label->vtoc.infos[i].id) == LINUX_RAID_PARTITION)
112 state->parts[slot].flags |= ADDPART_FLAG_RAID;
113 else if (be16_to_cpu(label->vtoc.infos[i].id) == SUN_WHOLE_DISK)
114 state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK;
115 }
116 }
117 slot++;
118 }
119 strlcat(state->pp_buf, "\n", PAGE_SIZE);
120 put_dev_sector(sect);
121 return 1;
122}
diff --git a/fs/partitions/sun.h b/fs/partitions/sun.h
new file mode 100644
index 00000000000..2424baa8319
--- /dev/null
+++ b/fs/partitions/sun.h
@@ -0,0 +1,8 @@
1/*
2 * fs/partitions/sun.h
3 */
4
5#define SUN_LABEL_MAGIC 0xDABE
6#define SUN_VTOC_SANITY 0x600DDEEE
7
8int sun_partition(struct parsed_partitions *state);
diff --git a/fs/partitions/sysv68.c b/fs/partitions/sysv68.c
new file mode 100644
index 00000000000..9627ccffc1c
--- /dev/null
+++ b/fs/partitions/sysv68.c
@@ -0,0 +1,95 @@
1/*
2 * fs/partitions/sysv68.c
3 *
4 * Copyright (C) 2007 Philippe De Muyter <phdm@macqel.be>
5 */
6
7#include "check.h"
8#include "sysv68.h"
9
10/*
11 * Volume ID structure: on first 256-bytes sector of disk
12 */
13
14struct volumeid {
15 u8 vid_unused[248];
16 u8 vid_mac[8]; /* ASCII string "MOTOROLA" */
17};
18
19/*
20 * config block: second 256-bytes sector on disk
21 */
22
23struct dkconfig {
24 u8 ios_unused0[128];
25 __be32 ios_slcblk; /* Slice table block number */
26 __be16 ios_slccnt; /* Number of entries in slice table */
27 u8 ios_unused1[122];
28};
29
30/*
31 * combined volumeid and dkconfig block
32 */
33
34struct dkblk0 {
35 struct volumeid dk_vid;
36 struct dkconfig dk_ios;
37};
38
39/*
40 * Slice Table Structure
41 */
42
43struct slice {
44 __be32 nblocks; /* slice size (in blocks) */
45 __be32 blkoff; /* block offset of slice */
46};
47
48
49int sysv68_partition(struct parsed_partitions *state)
50{
51 int i, slices;
52 int slot = 1;
53 Sector sect;
54 unsigned char *data;
55 struct dkblk0 *b;
56 struct slice *slice;
57 char tmp[64];
58
59 data = read_part_sector(state, 0, &sect);
60 if (!data)
61 return -1;
62
63 b = (struct dkblk0 *)data;
64 if (memcmp(b->dk_vid.vid_mac, "MOTOROLA", sizeof(b->dk_vid.vid_mac))) {
65 put_dev_sector(sect);
66 return 0;
67 }
68 slices = be16_to_cpu(b->dk_ios.ios_slccnt);
69 i = be32_to_cpu(b->dk_ios.ios_slcblk);
70 put_dev_sector(sect);
71
72 data = read_part_sector(state, i, &sect);
73 if (!data)
74 return -1;
75
76 slices -= 1; /* last slice is the whole disk */
77 snprintf(tmp, sizeof(tmp), "sysV68: %s(s%u)", state->name, slices);
78 strlcat(state->pp_buf, tmp, PAGE_SIZE);
79 slice = (struct slice *)data;
80 for (i = 0; i < slices; i++, slice++) {
81 if (slot == state->limit)
82 break;
83 if (be32_to_cpu(slice->nblocks)) {
84 put_partition(state, slot,
85 be32_to_cpu(slice->blkoff),
86 be32_to_cpu(slice->nblocks));
87 snprintf(tmp, sizeof(tmp), "(s%u)", i);
88 strlcat(state->pp_buf, tmp, PAGE_SIZE);
89 }
90 slot++;
91 }
92 strlcat(state->pp_buf, "\n", PAGE_SIZE);
93 put_dev_sector(sect);
94 return 1;
95}
diff --git a/fs/partitions/sysv68.h b/fs/partitions/sysv68.h
new file mode 100644
index 00000000000..bf2f5ffa97a
--- /dev/null
+++ b/fs/partitions/sysv68.h
@@ -0,0 +1 @@
extern int sysv68_partition(struct parsed_partitions *state);
diff --git a/fs/partitions/ultrix.c b/fs/partitions/ultrix.c
new file mode 100644
index 00000000000..8dbaf9f77a9
--- /dev/null
+++ b/fs/partitions/ultrix.c
@@ -0,0 +1,48 @@
1/*
2 * fs/partitions/ultrix.c
3 *
4 * Code extracted from drivers/block/genhd.c
5 *
6 * Re-organised Jul 1999 Russell King
7 */
8
9#include "check.h"
10#include "ultrix.h"
11
12int ultrix_partition(struct parsed_partitions *state)
13{
14 int i;
15 Sector sect;
16 unsigned char *data;
17 struct ultrix_disklabel {
18 s32 pt_magic; /* magic no. indicating part. info exits */
19 s32 pt_valid; /* set by driver if pt is current */
20 struct pt_info {
21 s32 pi_nblocks; /* no. of sectors */
22 u32 pi_blkoff; /* block offset for start */
23 } pt_part[8];
24 } *label;
25
26#define PT_MAGIC 0x032957 /* Partition magic number */
27#define PT_VALID 1 /* Indicates if struct is valid */
28
29 data = read_part_sector(state, (16384 - sizeof(*label))/512, &sect);
30 if (!data)
31 return -1;
32
33 label = (struct ultrix_disklabel *)(data + 512 - sizeof(*label));
34
35 if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) {
36 for (i=0; i<8; i++)
37 if (label->pt_part[i].pi_nblocks)
38 put_partition(state, i+1,
39 label->pt_part[i].pi_blkoff,
40 label->pt_part[i].pi_nblocks);
41 put_dev_sector(sect);
42 strlcat(state->pp_buf, "\n", PAGE_SIZE);
43 return 1;
44 } else {
45 put_dev_sector(sect);
46 return 0;
47 }
48}
diff --git a/fs/partitions/ultrix.h b/fs/partitions/ultrix.h
new file mode 100644
index 00000000000..a3cc00b2bde
--- /dev/null
+++ b/fs/partitions/ultrix.h
@@ -0,0 +1,5 @@
1/*
2 * fs/partitions/ultrix.h
3 */
4
5int ultrix_partition(struct parsed_partitions *state);
diff --git a/fs/xfs/xfs_fs_subr.c b/fs/xfs/xfs_fs_subr.c
new file mode 100644
index 00000000000..ed88ed16811
--- /dev/null
+++ b/fs/xfs/xfs_fs_subr.c
@@ -0,0 +1,96 @@
1/*
2 * Copyright (c) 2000-2002,2005-2006 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include "xfs.h"
19#include "xfs_vnodeops.h"
20#include "xfs_bmap_btree.h"
21#include "xfs_inode.h"
22#include "xfs_trace.h"
23
24/*
25 * note: all filemap functions return negative error codes. These
26 * need to be inverted before returning to the xfs core functions.
27 */
28void
29xfs_tosspages(
30 xfs_inode_t *ip,
31 xfs_off_t first,
32 xfs_off_t last,
33 int fiopt)
34{
35 /* can't toss partial tail pages, so mask them out */
36 last &= ~(PAGE_SIZE - 1);
37 truncate_inode_pages_range(VFS_I(ip)->i_mapping, first, last - 1);
38}
39
40int
41xfs_flushinval_pages(
42 xfs_inode_t *ip,
43 xfs_off_t first,
44 xfs_off_t last,
45 int fiopt)
46{
47 struct address_space *mapping = VFS_I(ip)->i_mapping;
48 int ret = 0;
49
50 trace_xfs_pagecache_inval(ip, first, last);
51
52 xfs_iflags_clear(ip, XFS_ITRUNCATED);
53 ret = filemap_write_and_wait_range(mapping, first,
54 last == -1 ? LLONG_MAX : last);
55 if (!ret)
56 truncate_inode_pages_range(mapping, first, last);
57 return -ret;
58}
59
60int
61xfs_flush_pages(
62 xfs_inode_t *ip,
63 xfs_off_t first,
64 xfs_off_t last,
65 uint64_t flags,
66 int fiopt)
67{
68 struct address_space *mapping = VFS_I(ip)->i_mapping;
69 int ret = 0;
70 int ret2;
71
72 xfs_iflags_clear(ip, XFS_ITRUNCATED);
73 ret = -filemap_fdatawrite_range(mapping, first,
74 last == -1 ? LLONG_MAX : last);
75 if (flags & XBF_ASYNC)
76 return ret;
77 ret2 = xfs_wait_on_pages(ip, first, last);
78 if (!ret)
79 ret = ret2;
80 return ret;
81}
82
83int
84xfs_wait_on_pages(
85 xfs_inode_t *ip,
86 xfs_off_t first,
87 xfs_off_t last)
88{
89 struct address_space *mapping = VFS_I(ip)->i_mapping;
90
91 if (mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) {
92 return -filemap_fdatawait_range(mapping, first,
93 last == -1 ? ip->i_size - 1 : last);
94 }
95 return 0;
96}
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
new file mode 100644
index 00000000000..7759812c1bb
--- /dev/null
+++ b/fs/xfs/xfs_iget.c
@@ -0,0 +1,720 @@
1/*
2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include "xfs.h"
19#include "xfs_fs.h"
20#include "xfs_types.h"
21#include "xfs_acl.h"
22#include "xfs_bit.h"
23#include "xfs_log.h"
24#include "xfs_inum.h"
25#include "xfs_trans.h"
26#include "xfs_sb.h"
27#include "xfs_ag.h"
28#include "xfs_mount.h"
29#include "xfs_bmap_btree.h"
30#include "xfs_alloc_btree.h"
31#include "xfs_ialloc_btree.h"
32#include "xfs_dinode.h"
33#include "xfs_inode.h"
34#include "xfs_btree.h"
35#include "xfs_ialloc.h"
36#include "xfs_quota.h"
37#include "xfs_utils.h"
38#include "xfs_trans_priv.h"
39#include "xfs_inode_item.h"
40#include "xfs_bmap.h"
41#include "xfs_trace.h"
42
43
44/*
45 * Define xfs inode iolock lockdep classes. We need to ensure that all active
46 * inodes are considered the same for lockdep purposes, including inodes that
47 * are recycled through the XFS_IRECLAIMABLE state. This is the the only way to
48 * guarantee the locks are considered the same when there are multiple lock
49 * initialisation siteѕ. Also, define a reclaimable inode class so it is
50 * obvious in lockdep reports which class the report is against.
51 */
52static struct lock_class_key xfs_iolock_active;
53struct lock_class_key xfs_iolock_reclaimable;
54
55/*
56 * Allocate and initialise an xfs_inode.
57 */
58STATIC struct xfs_inode *
59xfs_inode_alloc(
60 struct xfs_mount *mp,
61 xfs_ino_t ino)
62{
63 struct xfs_inode *ip;
64
65 /*
66 * if this didn't occur in transactions, we could use
67 * KM_MAYFAIL and return NULL here on ENOMEM. Set the
68 * code up to do this anyway.
69 */
70 ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP);
71 if (!ip)
72 return NULL;
73 if (inode_init_always(mp->m_super, VFS_I(ip))) {
74 kmem_zone_free(xfs_inode_zone, ip);
75 return NULL;
76 }
77
78 ASSERT(atomic_read(&ip->i_iocount) == 0);
79 ASSERT(atomic_read(&ip->i_pincount) == 0);
80 ASSERT(!spin_is_locked(&ip->i_flags_lock));
81 ASSERT(completion_done(&ip->i_flush));
82 ASSERT(ip->i_ino == 0);
83
84 mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
85 lockdep_set_class_and_name(&ip->i_iolock.mr_lock,
86 &xfs_iolock_active, "xfs_iolock_active");
87
88 /* initialise the xfs inode */
89 ip->i_ino = ino;
90 ip->i_mount = mp;
91 memset(&ip->i_imap, 0, sizeof(struct xfs_imap));
92 ip->i_afp = NULL;
93 memset(&ip->i_df, 0, sizeof(xfs_ifork_t));
94 ip->i_flags = 0;
95 ip->i_update_core = 0;
96 ip->i_delayed_blks = 0;
97 memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
98 ip->i_size = 0;
99 ip->i_new_size = 0;
100
101 return ip;
102}
103
104STATIC void
105xfs_inode_free_callback(
106 struct rcu_head *head)
107{
108 struct inode *inode = container_of(head, struct inode, i_rcu);
109 struct xfs_inode *ip = XFS_I(inode);
110
111 INIT_LIST_HEAD(&inode->i_dentry);
112 kmem_zone_free(xfs_inode_zone, ip);
113}
114
115void
116xfs_inode_free(
117 struct xfs_inode *ip)
118{
119 switch (ip->i_d.di_mode & S_IFMT) {
120 case S_IFREG:
121 case S_IFDIR:
122 case S_IFLNK:
123 xfs_idestroy_fork(ip, XFS_DATA_FORK);
124 break;
125 }
126
127 if (ip->i_afp)
128 xfs_idestroy_fork(ip, XFS_ATTR_FORK);
129
130 if (ip->i_itemp) {
131 /*
132 * Only if we are shutting down the fs will we see an
133 * inode still in the AIL. If it is there, we should remove
134 * it to prevent a use-after-free from occurring.
135 */
136 xfs_log_item_t *lip = &ip->i_itemp->ili_item;
137 struct xfs_ail *ailp = lip->li_ailp;
138
139 ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) ||
140 XFS_FORCED_SHUTDOWN(ip->i_mount));
141 if (lip->li_flags & XFS_LI_IN_AIL) {
142 spin_lock(&ailp->xa_lock);
143 if (lip->li_flags & XFS_LI_IN_AIL)
144 xfs_trans_ail_delete(ailp, lip);
145 else
146 spin_unlock(&ailp->xa_lock);
147 }
148 xfs_inode_item_destroy(ip);
149 ip->i_itemp = NULL;
150 }
151
152 /* asserts to verify all state is correct here */
153 ASSERT(atomic_read(&ip->i_iocount) == 0);
154 ASSERT(atomic_read(&ip->i_pincount) == 0);
155 ASSERT(!spin_is_locked(&ip->i_flags_lock));
156 ASSERT(completion_done(&ip->i_flush));
157
158 /*
159 * Because we use RCU freeing we need to ensure the inode always
160 * appears to be reclaimed with an invalid inode number when in the
161 * free state. The ip->i_flags_lock provides the barrier against lookup
162 * races.
163 */
164 spin_lock(&ip->i_flags_lock);
165 ip->i_flags = XFS_IRECLAIM;
166 ip->i_ino = 0;
167 spin_unlock(&ip->i_flags_lock);
168
169 call_rcu(&VFS_I(ip)->i_rcu, xfs_inode_free_callback);
170}
171
172/*
173 * Check the validity of the inode we just found it the cache
174 */
175static int
176xfs_iget_cache_hit(
177 struct xfs_perag *pag,
178 struct xfs_inode *ip,
179 xfs_ino_t ino,
180 int flags,
181 int lock_flags) __releases(RCU)
182{
183 struct inode *inode = VFS_I(ip);
184 struct xfs_mount *mp = ip->i_mount;
185 int error;
186
187 /*
188 * check for re-use of an inode within an RCU grace period due to the
189 * radix tree nodes not being updated yet. We monitor for this by
190 * setting the inode number to zero before freeing the inode structure.
191 * If the inode has been reallocated and set up, then the inode number
192 * will not match, so check for that, too.
193 */
194 spin_lock(&ip->i_flags_lock);
195 if (ip->i_ino != ino) {
196 trace_xfs_iget_skip(ip);
197 XFS_STATS_INC(xs_ig_frecycle);
198 error = EAGAIN;
199 goto out_error;
200 }
201
202
203 /*
204 * If we are racing with another cache hit that is currently
205 * instantiating this inode or currently recycling it out of
206 * reclaimabe state, wait for the initialisation to complete
207 * before continuing.
208 *
209 * XXX(hch): eventually we should do something equivalent to
210 * wait_on_inode to wait for these flags to be cleared
211 * instead of polling for it.
212 */
213 if (ip->i_flags & (XFS_INEW|XFS_IRECLAIM)) {
214 trace_xfs_iget_skip(ip);
215 XFS_STATS_INC(xs_ig_frecycle);
216 error = EAGAIN;
217 goto out_error;
218 }
219
220 /*
221 * If lookup is racing with unlink return an error immediately.
222 */
223 if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) {
224 error = ENOENT;
225 goto out_error;
226 }
227
228 /*
229 * If IRECLAIMABLE is set, we've torn down the VFS inode already.
230 * Need to carefully get it back into useable state.
231 */
232 if (ip->i_flags & XFS_IRECLAIMABLE) {
233 trace_xfs_iget_reclaim(ip);
234
235 /*
236 * We need to set XFS_IRECLAIM to prevent xfs_reclaim_inode
237 * from stomping over us while we recycle the inode. We can't
238 * clear the radix tree reclaimable tag yet as it requires
239 * pag_ici_lock to be held exclusive.
240 */
241 ip->i_flags |= XFS_IRECLAIM;
242
243 spin_unlock(&ip->i_flags_lock);
244 rcu_read_unlock();
245
246 error = -inode_init_always(mp->m_super, inode);
247 if (error) {
248 /*
249 * Re-initializing the inode failed, and we are in deep
250 * trouble. Try to re-add it to the reclaim list.
251 */
252 rcu_read_lock();
253 spin_lock(&ip->i_flags_lock);
254
255 ip->i_flags &= ~(XFS_INEW | XFS_IRECLAIM);
256 ASSERT(ip->i_flags & XFS_IRECLAIMABLE);
257 trace_xfs_iget_reclaim_fail(ip);
258 goto out_error;
259 }
260
261 spin_lock(&pag->pag_ici_lock);
262 spin_lock(&ip->i_flags_lock);
263
264 /*
265 * Clear the per-lifetime state in the inode as we are now
266 * effectively a new inode and need to return to the initial
267 * state before reuse occurs.
268 */
269 ip->i_flags &= ~XFS_IRECLAIM_RESET_FLAGS;
270 ip->i_flags |= XFS_INEW;
271 __xfs_inode_clear_reclaim_tag(mp, pag, ip);
272 inode->i_state = I_NEW;
273
274 ASSERT(!rwsem_is_locked(&ip->i_iolock.mr_lock));
275 mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
276 lockdep_set_class_and_name(&ip->i_iolock.mr_lock,
277 &xfs_iolock_active, "xfs_iolock_active");
278
279 spin_unlock(&ip->i_flags_lock);
280 spin_unlock(&pag->pag_ici_lock);
281 } else {
282 /* If the VFS inode is being torn down, pause and try again. */
283 if (!igrab(inode)) {
284 trace_xfs_iget_skip(ip);
285 error = EAGAIN;
286 goto out_error;
287 }
288
289 /* We've got a live one. */
290 spin_unlock(&ip->i_flags_lock);
291 rcu_read_unlock();
292 trace_xfs_iget_hit(ip);
293 }
294
295 if (lock_flags != 0)
296 xfs_ilock(ip, lock_flags);
297
298 xfs_iflags_clear(ip, XFS_ISTALE);
299 XFS_STATS_INC(xs_ig_found);
300
301 return 0;
302
303out_error:
304 spin_unlock(&ip->i_flags_lock);
305 rcu_read_unlock();
306 return error;
307}
308
309
310static int
311xfs_iget_cache_miss(
312 struct xfs_mount *mp,
313 struct xfs_perag *pag,
314 xfs_trans_t *tp,
315 xfs_ino_t ino,
316 struct xfs_inode **ipp,
317 int flags,
318 int lock_flags)
319{
320 struct xfs_inode *ip;
321 int error;
322 xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ino);
323
324 ip = xfs_inode_alloc(mp, ino);
325 if (!ip)
326 return ENOMEM;
327
328 error = xfs_iread(mp, tp, ip, flags);
329 if (error)
330 goto out_destroy;
331
332 trace_xfs_iget_miss(ip);
333
334 if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
335 error = ENOENT;
336 goto out_destroy;
337 }
338
339 /*
340 * Preload the radix tree so we can insert safely under the
341 * write spinlock. Note that we cannot sleep inside the preload
342 * region.
343 */
344 if (radix_tree_preload(GFP_KERNEL)) {
345 error = EAGAIN;
346 goto out_destroy;
347 }
348
349 /*
350 * Because the inode hasn't been added to the radix-tree yet it can't
351 * be found by another thread, so we can do the non-sleeping lock here.
352 */
353 if (lock_flags) {
354 if (!xfs_ilock_nowait(ip, lock_flags))
355 BUG();
356 }
357
358 spin_lock(&pag->pag_ici_lock);
359
360 /* insert the new inode */
361 error = radix_tree_insert(&pag->pag_ici_root, agino, ip);
362 if (unlikely(error)) {
363 WARN_ON(error != -EEXIST);
364 XFS_STATS_INC(xs_ig_dup);
365 error = EAGAIN;
366 goto out_preload_end;
367 }
368
369 /* These values _must_ be set before releasing the radix tree lock! */
370 ip->i_udquot = ip->i_gdquot = NULL;
371 xfs_iflags_set(ip, XFS_INEW);
372
373 spin_unlock(&pag->pag_ici_lock);
374 radix_tree_preload_end();
375
376 *ipp = ip;
377 return 0;
378
379out_preload_end:
380 spin_unlock(&pag->pag_ici_lock);
381 radix_tree_preload_end();
382 if (lock_flags)
383 xfs_iunlock(ip, lock_flags);
384out_destroy:
385 __destroy_inode(VFS_I(ip));
386 xfs_inode_free(ip);
387 return error;
388}
389
390/*
391 * Look up an inode by number in the given file system.
392 * The inode is looked up in the cache held in each AG.
393 * If the inode is found in the cache, initialise the vfs inode
394 * if necessary.
395 *
396 * If it is not in core, read it in from the file system's device,
397 * add it to the cache and initialise the vfs inode.
398 *
399 * The inode is locked according to the value of the lock_flags parameter.
400 * This flag parameter indicates how and if the inode's IO lock and inode lock
401 * should be taken.
402 *
403 * mp -- the mount point structure for the current file system. It points
404 * to the inode hash table.
405 * tp -- a pointer to the current transaction if there is one. This is
406 * simply passed through to the xfs_iread() call.
407 * ino -- the number of the inode desired. This is the unique identifier
408 * within the file system for the inode being requested.
409 * lock_flags -- flags indicating how to lock the inode. See the comment
410 * for xfs_ilock() for a list of valid values.
411 */
412int
413xfs_iget(
414 xfs_mount_t *mp,
415 xfs_trans_t *tp,
416 xfs_ino_t ino,
417 uint flags,
418 uint lock_flags,
419 xfs_inode_t **ipp)
420{
421 xfs_inode_t *ip;
422 int error;
423 xfs_perag_t *pag;
424 xfs_agino_t agino;
425
426 /* reject inode numbers outside existing AGs */
427 if (!ino || XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount)
428 return EINVAL;
429
430 /* get the perag structure and ensure that it's inode capable */
431 pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino));
432 agino = XFS_INO_TO_AGINO(mp, ino);
433
434again:
435 error = 0;
436 rcu_read_lock();
437 ip = radix_tree_lookup(&pag->pag_ici_root, agino);
438
439 if (ip) {
440 error = xfs_iget_cache_hit(pag, ip, ino, flags, lock_flags);
441 if (error)
442 goto out_error_or_again;
443 } else {
444 rcu_read_unlock();
445 XFS_STATS_INC(xs_ig_missed);
446
447 error = xfs_iget_cache_miss(mp, pag, tp, ino, &ip,
448 flags, lock_flags);
449 if (error)
450 goto out_error_or_again;
451 }
452 xfs_perag_put(pag);
453
454 *ipp = ip;
455
456 ASSERT(ip->i_df.if_ext_max ==
457 XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));
458 /*
459 * If we have a real type for an on-disk inode, we can set ops(&unlock)
460 * now. If it's a new inode being created, xfs_ialloc will handle it.
461 */
462 if (xfs_iflags_test(ip, XFS_INEW) && ip->i_d.di_mode != 0)
463 xfs_setup_inode(ip);
464 return 0;
465
466out_error_or_again:
467 if (error == EAGAIN) {
468 delay(1);
469 goto again;
470 }
471 xfs_perag_put(pag);
472 return error;
473}
474
475/*
476 * This is a wrapper routine around the xfs_ilock() routine
477 * used to centralize some grungy code. It is used in places
478 * that wish to lock the inode solely for reading the extents.
479 * The reason these places can't just call xfs_ilock(SHARED)
480 * is that the inode lock also guards to bringing in of the
481 * extents from disk for a file in b-tree format. If the inode
482 * is in b-tree format, then we need to lock the inode exclusively
483 * until the extents are read in. Locking it exclusively all
484 * the time would limit our parallelism unnecessarily, though.
485 * What we do instead is check to see if the extents have been
486 * read in yet, and only lock the inode exclusively if they
487 * have not.
488 *
489 * The function returns a value which should be given to the
490 * corresponding xfs_iunlock_map_shared(). This value is
491 * the mode in which the lock was actually taken.
492 */
493uint
494xfs_ilock_map_shared(
495 xfs_inode_t *ip)
496{
497 uint lock_mode;
498
499 if ((ip->i_d.di_format == XFS_DINODE_FMT_BTREE) &&
500 ((ip->i_df.if_flags & XFS_IFEXTENTS) == 0)) {
501 lock_mode = XFS_ILOCK_EXCL;
502 } else {
503 lock_mode = XFS_ILOCK_SHARED;
504 }
505
506 xfs_ilock(ip, lock_mode);
507
508 return lock_mode;
509}
510
511/*
512 * This is simply the unlock routine to go with xfs_ilock_map_shared().
513 * All it does is call xfs_iunlock() with the given lock_mode.
514 */
515void
516xfs_iunlock_map_shared(
517 xfs_inode_t *ip,
518 unsigned int lock_mode)
519{
520 xfs_iunlock(ip, lock_mode);
521}
522
523/*
524 * The xfs inode contains 2 locks: a multi-reader lock called the
525 * i_iolock and a multi-reader lock called the i_lock. This routine
526 * allows either or both of the locks to be obtained.
527 *
528 * The 2 locks should always be ordered so that the IO lock is
529 * obtained first in order to prevent deadlock.
530 *
531 * ip -- the inode being locked
532 * lock_flags -- this parameter indicates the inode's locks
533 * to be locked. It can be:
534 * XFS_IOLOCK_SHARED,
535 * XFS_IOLOCK_EXCL,
536 * XFS_ILOCK_SHARED,
537 * XFS_ILOCK_EXCL,
538 * XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED,
539 * XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL,
540 * XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED,
541 * XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL
542 */
543void
544xfs_ilock(
545 xfs_inode_t *ip,
546 uint lock_flags)
547{
548 /*
549 * You can't set both SHARED and EXCL for the same lock,
550 * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
551 * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
552 */
553 ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
554 (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
555 ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
556 (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
557 ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
558
559 if (lock_flags & XFS_IOLOCK_EXCL)
560 mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
561 else if (lock_flags & XFS_IOLOCK_SHARED)
562 mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
563
564 if (lock_flags & XFS_ILOCK_EXCL)
565 mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
566 else if (lock_flags & XFS_ILOCK_SHARED)
567 mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
568
569 trace_xfs_ilock(ip, lock_flags, _RET_IP_);
570}
571
572/*
573 * This is just like xfs_ilock(), except that the caller
574 * is guaranteed not to sleep. It returns 1 if it gets
575 * the requested locks and 0 otherwise. If the IO lock is
576 * obtained but the inode lock cannot be, then the IO lock
577 * is dropped before returning.
578 *
579 * ip -- the inode being locked
580 * lock_flags -- this parameter indicates the inode's locks to be
581 * to be locked. See the comment for xfs_ilock() for a list
582 * of valid values.
583 */
584int
585xfs_ilock_nowait(
586 xfs_inode_t *ip,
587 uint lock_flags)
588{
589 /*
590 * You can't set both SHARED and EXCL for the same lock,
591 * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
592 * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
593 */
594 ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
595 (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
596 ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
597 (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
598 ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
599
600 if (lock_flags & XFS_IOLOCK_EXCL) {
601 if (!mrtryupdate(&ip->i_iolock))
602 goto out;
603 } else if (lock_flags & XFS_IOLOCK_SHARED) {
604 if (!mrtryaccess(&ip->i_iolock))
605 goto out;
606 }
607 if (lock_flags & XFS_ILOCK_EXCL) {
608 if (!mrtryupdate(&ip->i_lock))
609 goto out_undo_iolock;
610 } else if (lock_flags & XFS_ILOCK_SHARED) {
611 if (!mrtryaccess(&ip->i_lock))
612 goto out_undo_iolock;
613 }
614 trace_xfs_ilock_nowait(ip, lock_flags, _RET_IP_);
615 return 1;
616
617 out_undo_iolock:
618 if (lock_flags & XFS_IOLOCK_EXCL)
619 mrunlock_excl(&ip->i_iolock);
620 else if (lock_flags & XFS_IOLOCK_SHARED)
621 mrunlock_shared(&ip->i_iolock);
622 out:
623 return 0;
624}
625
626/*
627 * xfs_iunlock() is used to drop the inode locks acquired with
628 * xfs_ilock() and xfs_ilock_nowait(). The caller must pass
629 * in the flags given to xfs_ilock() or xfs_ilock_nowait() so
630 * that we know which locks to drop.
631 *
632 * ip -- the inode being unlocked
633 * lock_flags -- this parameter indicates the inode's locks to be
634 * to be unlocked. See the comment for xfs_ilock() for a list
635 * of valid values for this parameter.
636 *
637 */
638void
639xfs_iunlock(
640 xfs_inode_t *ip,
641 uint lock_flags)
642{
643 /*
644 * You can't set both SHARED and EXCL for the same lock,
645 * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
646 * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
647 */
648 ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
649 (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
650 ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
651 (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
652 ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY |
653 XFS_LOCK_DEP_MASK)) == 0);
654 ASSERT(lock_flags != 0);
655
656 if (lock_flags & XFS_IOLOCK_EXCL)
657 mrunlock_excl(&ip->i_iolock);
658 else if (lock_flags & XFS_IOLOCK_SHARED)
659 mrunlock_shared(&ip->i_iolock);
660
661 if (lock_flags & XFS_ILOCK_EXCL)
662 mrunlock_excl(&ip->i_lock);
663 else if (lock_flags & XFS_ILOCK_SHARED)
664 mrunlock_shared(&ip->i_lock);
665
666 if ((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) &&
667 !(lock_flags & XFS_IUNLOCK_NONOTIFY) && ip->i_itemp) {
668 /*
669 * Let the AIL know that this item has been unlocked in case
670 * it is in the AIL and anyone is waiting on it. Don't do
671 * this if the caller has asked us not to.
672 */
673 xfs_trans_unlocked_item(ip->i_itemp->ili_item.li_ailp,
674 (xfs_log_item_t*)(ip->i_itemp));
675 }
676 trace_xfs_iunlock(ip, lock_flags, _RET_IP_);
677}
678
679/*
680 * give up write locks. the i/o lock cannot be held nested
681 * if it is being demoted.
682 */
683void
684xfs_ilock_demote(
685 xfs_inode_t *ip,
686 uint lock_flags)
687{
688 ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL));
689 ASSERT((lock_flags & ~(XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)) == 0);
690
691 if (lock_flags & XFS_ILOCK_EXCL)
692 mrdemote(&ip->i_lock);
693 if (lock_flags & XFS_IOLOCK_EXCL)
694 mrdemote(&ip->i_iolock);
695
696 trace_xfs_ilock_demote(ip, lock_flags, _RET_IP_);
697}
698
699#ifdef DEBUG
700int
701xfs_isilocked(
702 xfs_inode_t *ip,
703 uint lock_flags)
704{
705 if (lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) {
706 if (!(lock_flags & XFS_ILOCK_SHARED))
707 return !!ip->i_lock.mr_writer;
708 return rwsem_is_locked(&ip->i_lock.mr_lock);
709 }
710
711 if (lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) {
712 if (!(lock_flags & XFS_IOLOCK_SHARED))
713 return !!ip->i_iolock.mr_writer;
714 return rwsem_is_locked(&ip->i_iolock.mr_lock);
715 }
716
717 ASSERT(0);
718 return 0;
719}
720#endif
diff --git a/fs/xfs/xfs_qm_stats.c b/fs/xfs/xfs_qm_stats.c
new file mode 100644
index 00000000000..8671a0b3264
--- /dev/null
+++ b/fs/xfs/xfs_qm_stats.c
@@ -0,0 +1,105 @@
1/*
2 * Copyright (c) 2000-2003 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include "xfs.h"
19#include "xfs_fs.h"
20#include "xfs_bit.h"
21#include "xfs_log.h"
22#include "xfs_inum.h"
23#include "xfs_trans.h"
24#include "xfs_sb.h"
25#include "xfs_ag.h"
26#include "xfs_alloc.h"
27#include "xfs_quota.h"
28#include "xfs_mount.h"
29#include "xfs_bmap_btree.h"
30#include "xfs_inode.h"
31#include "xfs_itable.h"
32#include "xfs_bmap.h"
33#include "xfs_rtalloc.h"
34#include "xfs_error.h"
35#include "xfs_attr.h"
36#include "xfs_buf_item.h"
37#include "xfs_qm.h"
38
39struct xqmstats xqmstats;
40
41static int xqm_proc_show(struct seq_file *m, void *v)
42{
43 /* maximum; incore; ratio free to inuse; freelist */
44 seq_printf(m, "%d\t%d\t%d\t%u\n",
45 ndquot,
46 xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0,
47 xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0,
48 xfs_Gqm? xfs_Gqm->qm_dqfrlist_cnt : 0);
49 return 0;
50}
51
52static int xqm_proc_open(struct inode *inode, struct file *file)
53{
54 return single_open(file, xqm_proc_show, NULL);
55}
56
57static const struct file_operations xqm_proc_fops = {
58 .owner = THIS_MODULE,
59 .open = xqm_proc_open,
60 .read = seq_read,
61 .llseek = seq_lseek,
62 .release = single_release,
63};
64
65static int xqmstat_proc_show(struct seq_file *m, void *v)
66{
67 /* quota performance statistics */
68 seq_printf(m, "qm %u %u %u %u %u %u %u %u\n",
69 xqmstats.xs_qm_dqreclaims,
70 xqmstats.xs_qm_dqreclaim_misses,
71 xqmstats.xs_qm_dquot_dups,
72 xqmstats.xs_qm_dqcachemisses,
73 xqmstats.xs_qm_dqcachehits,
74 xqmstats.xs_qm_dqwants,
75 xqmstats.xs_qm_dqshake_reclaims,
76 xqmstats.xs_qm_dqinact_reclaims);
77 return 0;
78}
79
80static int xqmstat_proc_open(struct inode *inode, struct file *file)
81{
82 return single_open(file, xqmstat_proc_show, NULL);
83}
84
85static const struct file_operations xqmstat_proc_fops = {
86 .owner = THIS_MODULE,
87 .open = xqmstat_proc_open,
88 .read = seq_read,
89 .llseek = seq_lseek,
90 .release = single_release,
91};
92
93void
94xfs_qm_init_procfs(void)
95{
96 proc_create("fs/xfs/xqmstat", 0, NULL, &xqmstat_proc_fops);
97 proc_create("fs/xfs/xqm", 0, NULL, &xqm_proc_fops);
98}
99
100void
101xfs_qm_cleanup_procfs(void)
102{
103 remove_proc_entry("fs/xfs/xqm", NULL);
104 remove_proc_entry("fs/xfs/xqmstat", NULL);
105}
diff --git a/fs/xfs/xfs_qm_stats.h b/fs/xfs/xfs_qm_stats.h
new file mode 100644
index 00000000000..5b964fc0dc0
--- /dev/null
+++ b/fs/xfs/xfs_qm_stats.h
@@ -0,0 +1,53 @@
1/*
2 * Copyright (c) 2002 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#ifndef __XFS_QM_STATS_H__
19#define __XFS_QM_STATS_H__
20
21#if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF)
22
23/*
24 * XQM global statistics
25 */
26struct xqmstats {
27 __uint32_t xs_qm_dqreclaims;
28 __uint32_t xs_qm_dqreclaim_misses;
29 __uint32_t xs_qm_dquot_dups;
30 __uint32_t xs_qm_dqcachemisses;
31 __uint32_t xs_qm_dqcachehits;
32 __uint32_t xs_qm_dqwants;
33 __uint32_t xs_qm_dqshake_reclaims;
34 __uint32_t xs_qm_dqinact_reclaims;
35};
36
37extern struct xqmstats xqmstats;
38
39# define XQM_STATS_INC(count) ( (count)++ )
40
41extern void xfs_qm_init_procfs(void);
42extern void xfs_qm_cleanup_procfs(void);
43
44#else
45
46# define XQM_STATS_INC(count) do { } while (0)
47
48static inline void xfs_qm_init_procfs(void) { };
49static inline void xfs_qm_cleanup_procfs(void) { };
50
51#endif
52
53#endif /* __XFS_QM_STATS_H__ */
diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c
new file mode 100644
index 00000000000..c96a8a05ac0
--- /dev/null
+++ b/fs/xfs/xfs_rw.c
@@ -0,0 +1,175 @@
1/*
2 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include "xfs.h"
19#include "xfs_fs.h"
20#include "xfs_types.h"
21#include "xfs_bit.h"
22#include "xfs_log.h"
23#include "xfs_inum.h"
24#include "xfs_trans.h"
25#include "xfs_sb.h"
26#include "xfs_ag.h"
27#include "xfs_mount.h"
28#include "xfs_bmap_btree.h"
29#include "xfs_dinode.h"
30#include "xfs_inode.h"
31#include "xfs_error.h"
32#include "xfs_rw.h"
33
34/*
35 * Force a shutdown of the filesystem instantly while keeping
36 * the filesystem consistent. We don't do an unmount here; just shutdown
37 * the shop, make sure that absolutely nothing persistent happens to
38 * this filesystem after this point.
39 */
40void
41xfs_do_force_shutdown(
42 xfs_mount_t *mp,
43 int flags,
44 char *fname,
45 int lnnum)
46{
47 int logerror;
48
49 logerror = flags & SHUTDOWN_LOG_IO_ERROR;
50
51 if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
52 xfs_notice(mp,
53 "%s(0x%x) called from line %d of file %s. Return address = 0x%p",
54 __func__, flags, lnnum, fname, __return_address);
55 }
56 /*
57 * No need to duplicate efforts.
58 */
59 if (XFS_FORCED_SHUTDOWN(mp) && !logerror)
60 return;
61
62 /*
63 * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't
64 * queue up anybody new on the log reservations, and wakes up
65 * everybody who's sleeping on log reservations to tell them
66 * the bad news.
67 */
68 if (xfs_log_force_umount(mp, logerror))
69 return;
70
71 if (flags & SHUTDOWN_CORRUPT_INCORE) {
72 xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT,
73 "Corruption of in-memory data detected. Shutting down filesystem");
74 if (XFS_ERRLEVEL_HIGH <= xfs_error_level)
75 xfs_stack_trace();
76 } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
77 if (logerror) {
78 xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR,
79 "Log I/O Error Detected. Shutting down filesystem");
80 } else if (flags & SHUTDOWN_DEVICE_REQ) {
81 xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
82 "All device paths lost. Shutting down filesystem");
83 } else if (!(flags & SHUTDOWN_REMOTE_REQ)) {
84 xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
85 "I/O Error Detected. Shutting down filesystem");
86 }
87 }
88 if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
89 xfs_alert(mp,
90 "Please umount the filesystem and rectify the problem(s)");
91 }
92}
93
94/*
95 * Prints out an ALERT message about I/O error.
96 */
97void
98xfs_ioerror_alert(
99 char *func,
100 struct xfs_mount *mp,
101 xfs_buf_t *bp,
102 xfs_daddr_t blkno)
103{
104 xfs_alert(mp,
105 "I/O error occurred: meta-data dev %s block 0x%llx"
106 " (\"%s\") error %d buf count %zd",
107 xfs_buf_target_name(bp->b_target),
108 (__uint64_t)blkno, func,
109 bp->b_error, XFS_BUF_COUNT(bp));
110}
111
112/*
113 * This isn't an absolute requirement, but it is
114 * just a good idea to call xfs_read_buf instead of
115 * directly doing a read_buf call. For one, we shouldn't
116 * be doing this disk read if we are in SHUTDOWN state anyway,
117 * so this stops that from happening. Secondly, this does all
118 * the error checking stuff and the brelse if appropriate for
119 * the caller, so the code can be a little leaner.
120 */
121
122int
123xfs_read_buf(
124 struct xfs_mount *mp,
125 xfs_buftarg_t *target,
126 xfs_daddr_t blkno,
127 int len,
128 uint flags,
129 xfs_buf_t **bpp)
130{
131 xfs_buf_t *bp;
132 int error;
133
134 if (!flags)
135 flags = XBF_LOCK | XBF_MAPPED;
136
137 bp = xfs_buf_read(target, blkno, len, flags);
138 if (!bp)
139 return XFS_ERROR(EIO);
140 error = bp->b_error;
141 if (!error && !XFS_FORCED_SHUTDOWN(mp)) {
142 *bpp = bp;
143 } else {
144 *bpp = NULL;
145 if (error) {
146 xfs_ioerror_alert("xfs_read_buf", mp, bp, XFS_BUF_ADDR(bp));
147 } else {
148 error = XFS_ERROR(EIO);
149 }
150 if (bp) {
151 XFS_BUF_UNDONE(bp);
152 XFS_BUF_UNDELAYWRITE(bp);
153 XFS_BUF_STALE(bp);
154 /*
155 * brelse clears B_ERROR and b_error
156 */
157 xfs_buf_relse(bp);
158 }
159 }
160 return (error);
161}
162
163/*
164 * helper function to extract extent size hint from inode
165 */
166xfs_extlen_t
167xfs_get_extsz_hint(
168 struct xfs_inode *ip)
169{
170 if ((ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) && ip->i_d.di_extsize)
171 return ip->i_d.di_extsize;
172 if (XFS_IS_REALTIME_INODE(ip))
173 return ip->i_mount->m_sb.sb_rextsize;
174 return 0;
175}
diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h
new file mode 100644
index 00000000000..11c41ec6ed7
--- /dev/null
+++ b/fs/xfs/xfs_rw.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#ifndef __XFS_RW_H__
19#define __XFS_RW_H__
20
21struct xfs_buf;
22struct xfs_inode;
23struct xfs_mount;
24
25/*
26 * Convert the given file system block to a disk block.
27 * We have to treat it differently based on whether the
28 * file is a real time file or not, because the bmap code
29 * does.
30 */
31static inline xfs_daddr_t
32xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
33{
34 return (XFS_IS_REALTIME_INODE(ip) ? \
35 (xfs_daddr_t)XFS_FSB_TO_BB((ip)->i_mount, (fsb)) : \
36 XFS_FSB_TO_DADDR((ip)->i_mount, (fsb)));
37}
38
39/*
40 * Prototypes for functions in xfs_rw.c.
41 */
42extern int xfs_read_buf(struct xfs_mount *mp, xfs_buftarg_t *btp,
43 xfs_daddr_t blkno, int len, uint flags,
44 struct xfs_buf **bpp);
45extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp,
46 xfs_buf_t *bp, xfs_daddr_t blkno);
47extern xfs_extlen_t xfs_get_extsz_hint(struct xfs_inode *ip);
48
49#endif /* __XFS_RW_H__ */
diff --git a/fs/xfs/xfs_sync.c b/fs/xfs/xfs_sync.c
new file mode 100644
index 00000000000..4604f90f86a
--- /dev/null
+++ b/fs/xfs/xfs_sync.c
@@ -0,0 +1,1065 @@
1/*
2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include "xfs.h"
19#include "xfs_fs.h"
20#include "xfs_types.h"
21#include "xfs_bit.h"
22#include "xfs_log.h"
23#include "xfs_inum.h"
24#include "xfs_trans.h"
25#include "xfs_trans_priv.h"
26#include "xfs_sb.h"
27#include "xfs_ag.h"
28#include "xfs_mount.h"
29#include "xfs_bmap_btree.h"
30#include "xfs_inode.h"
31#include "xfs_dinode.h"
32#include "xfs_error.h"
33#include "xfs_filestream.h"
34#include "xfs_vnodeops.h"
35#include "xfs_inode_item.h"
36#include "xfs_quota.h"
37#include "xfs_trace.h"
38#include "xfs_fsops.h"
39
40#include <linux/kthread.h>
41#include <linux/freezer.h>
42
43struct workqueue_struct *xfs_syncd_wq; /* sync workqueue */
44
45/*
46 * The inode lookup is done in batches to keep the amount of lock traffic and
47 * radix tree lookups to a minimum. The batch size is a trade off between
48 * lookup reduction and stack usage. This is in the reclaim path, so we can't
49 * be too greedy.
50 */
51#define XFS_LOOKUP_BATCH 32
52
53STATIC int
54xfs_inode_ag_walk_grab(
55 struct xfs_inode *ip)
56{
57 struct inode *inode = VFS_I(ip);
58
59 ASSERT(rcu_read_lock_held());
60
61 /*
62 * check for stale RCU freed inode
63 *
64 * If the inode has been reallocated, it doesn't matter if it's not in
65 * the AG we are walking - we are walking for writeback, so if it
66 * passes all the "valid inode" checks and is dirty, then we'll write
67 * it back anyway. If it has been reallocated and still being
68 * initialised, the XFS_INEW check below will catch it.
69 */
70 spin_lock(&ip->i_flags_lock);
71 if (!ip->i_ino)
72 goto out_unlock_noent;
73
74 /* avoid new or reclaimable inodes. Leave for reclaim code to flush */
75 if (__xfs_iflags_test(ip, XFS_INEW | XFS_IRECLAIMABLE | XFS_IRECLAIM))
76 goto out_unlock_noent;
77 spin_unlock(&ip->i_flags_lock);
78
79 /* nothing to sync during shutdown */
80 if (XFS_FORCED_SHUTDOWN(ip->i_mount))
81 return EFSCORRUPTED;
82
83 /* If we can't grab the inode, it must on it's way to reclaim. */
84 if (!igrab(inode))
85 return ENOENT;
86
87 if (is_bad_inode(inode)) {
88 IRELE(ip);
89 return ENOENT;
90 }
91
92 /* inode is valid */
93 return 0;
94
95out_unlock_noent:
96 spin_unlock(&ip->i_flags_lock);
97 return ENOENT;
98}
99
100STATIC int
101xfs_inode_ag_walk(
102 struct xfs_mount *mp,
103 struct xfs_perag *pag,
104 int (*execute)(struct xfs_inode *ip,
105 struct xfs_perag *pag, int flags),
106 int flags)
107{
108 uint32_t first_index;
109 int last_error = 0;
110 int skipped;
111 int done;
112 int nr_found;
113
114restart:
115 done = 0;
116 skipped = 0;
117 first_index = 0;
118 nr_found = 0;
119 do {
120 struct xfs_inode *batch[XFS_LOOKUP_BATCH];
121 int error = 0;
122 int i;
123
124 rcu_read_lock();
125 nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
126 (void **)batch, first_index,
127 XFS_LOOKUP_BATCH);
128 if (!nr_found) {
129 rcu_read_unlock();
130 break;
131 }
132
133 /*
134 * Grab the inodes before we drop the lock. if we found
135 * nothing, nr == 0 and the loop will be skipped.
136 */
137 for (i = 0; i < nr_found; i++) {
138 struct xfs_inode *ip = batch[i];
139
140 if (done || xfs_inode_ag_walk_grab(ip))
141 batch[i] = NULL;
142
143 /*
144 * Update the index for the next lookup. Catch
145 * overflows into the next AG range which can occur if
146 * we have inodes in the last block of the AG and we
147 * are currently pointing to the last inode.
148 *
149 * Because we may see inodes that are from the wrong AG
150 * due to RCU freeing and reallocation, only update the
151 * index if it lies in this AG. It was a race that lead
152 * us to see this inode, so another lookup from the
153 * same index will not find it again.
154 */
155 if (XFS_INO_TO_AGNO(mp, ip->i_ino) != pag->pag_agno)
156 continue;
157 first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
158 if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino))
159 done = 1;
160 }
161
162 /* unlock now we've grabbed the inodes. */
163 rcu_read_unlock();
164
165 for (i = 0; i < nr_found; i++) {
166 if (!batch[i])
167 continue;
168 error = execute(batch[i], pag, flags);
169 IRELE(batch[i]);
170 if (error == EAGAIN) {
171 skipped++;
172 continue;
173 }
174 if (error && last_error != EFSCORRUPTED)
175 last_error = error;
176 }
177
178 /* bail out if the filesystem is corrupted. */
179 if (error == EFSCORRUPTED)
180 break;
181
182 cond_resched();
183
184 } while (nr_found && !done);
185
186 if (skipped) {
187 delay(1);
188 goto restart;
189 }
190 return last_error;
191}
192
193int
194xfs_inode_ag_iterator(
195 struct xfs_mount *mp,
196 int (*execute)(struct xfs_inode *ip,
197 struct xfs_perag *pag, int flags),
198 int flags)
199{
200 struct xfs_perag *pag;
201 int error = 0;
202 int last_error = 0;
203 xfs_agnumber_t ag;
204
205 ag = 0;
206 while ((pag = xfs_perag_get(mp, ag))) {
207 ag = pag->pag_agno + 1;
208 error = xfs_inode_ag_walk(mp, pag, execute, flags);
209 xfs_perag_put(pag);
210 if (error) {
211 last_error = error;
212 if (error == EFSCORRUPTED)
213 break;
214 }
215 }
216 return XFS_ERROR(last_error);
217}
218
219STATIC int
220xfs_sync_inode_data(
221 struct xfs_inode *ip,
222 struct xfs_perag *pag,
223 int flags)
224{
225 struct inode *inode = VFS_I(ip);
226 struct address_space *mapping = inode->i_mapping;
227 int error = 0;
228
229 if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
230 goto out_wait;
231
232 if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) {
233 if (flags & SYNC_TRYLOCK)
234 goto out_wait;
235 xfs_ilock(ip, XFS_IOLOCK_SHARED);
236 }
237
238 error = xfs_flush_pages(ip, 0, -1, (flags & SYNC_WAIT) ?
239 0 : XBF_ASYNC, FI_NONE);
240 xfs_iunlock(ip, XFS_IOLOCK_SHARED);
241
242 out_wait:
243 if (flags & SYNC_WAIT)
244 xfs_ioend_wait(ip);
245 return error;
246}
247
248STATIC int
249xfs_sync_inode_attr(
250 struct xfs_inode *ip,
251 struct xfs_perag *pag,
252 int flags)
253{
254 int error = 0;
255
256 xfs_ilock(ip, XFS_ILOCK_SHARED);
257 if (xfs_inode_clean(ip))
258 goto out_unlock;
259 if (!xfs_iflock_nowait(ip)) {
260 if (!(flags & SYNC_WAIT))
261 goto out_unlock;
262 xfs_iflock(ip);
263 }
264
265 if (xfs_inode_clean(ip)) {
266 xfs_ifunlock(ip);
267 goto out_unlock;
268 }
269
270 error = xfs_iflush(ip, flags);
271
272 /*
273 * We don't want to try again on non-blocking flushes that can't run
274 * again immediately. If an inode really must be written, then that's
275 * what the SYNC_WAIT flag is for.
276 */
277 if (error == EAGAIN) {
278 ASSERT(!(flags & SYNC_WAIT));
279 error = 0;
280 }
281
282 out_unlock:
283 xfs_iunlock(ip, XFS_ILOCK_SHARED);
284 return error;
285}
286
287/*
288 * Write out pagecache data for the whole filesystem.
289 */
290STATIC int
291xfs_sync_data(
292 struct xfs_mount *mp,
293 int flags)
294{
295 int error;
296
297 ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0);
298
299 error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags);
300 if (error)
301 return XFS_ERROR(error);
302
303 xfs_log_force(mp, (flags & SYNC_WAIT) ? XFS_LOG_SYNC : 0);
304 return 0;
305}
306
307/*
308 * Write out inode metadata (attributes) for the whole filesystem.
309 */
310STATIC int
311xfs_sync_attr(
312 struct xfs_mount *mp,
313 int flags)
314{
315 ASSERT((flags & ~SYNC_WAIT) == 0);
316
317 return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags);
318}
319
320STATIC int
321xfs_sync_fsdata(
322 struct xfs_mount *mp)
323{
324 struct xfs_buf *bp;
325
326 /*
327 * If the buffer is pinned then push on the log so we won't get stuck
328 * waiting in the write for someone, maybe ourselves, to flush the log.
329 *
330 * Even though we just pushed the log above, we did not have the
331 * superblock buffer locked at that point so it can become pinned in
332 * between there and here.
333 */
334 bp = xfs_getsb(mp, 0);
335 if (xfs_buf_ispinned(bp))
336 xfs_log_force(mp, 0);
337
338 return xfs_bwrite(mp, bp);
339}
340
341/*
342 * When remounting a filesystem read-only or freezing the filesystem, we have
343 * two phases to execute. This first phase is syncing the data before we
344 * quiesce the filesystem, and the second is flushing all the inodes out after
345 * we've waited for all the transactions created by the first phase to
346 * complete. The second phase ensures that the inodes are written to their
347 * location on disk rather than just existing in transactions in the log. This
348 * means after a quiesce there is no log replay required to write the inodes to
349 * disk (this is the main difference between a sync and a quiesce).
350 */
351/*
352 * First stage of freeze - no writers will make progress now we are here,
353 * so we flush delwri and delalloc buffers here, then wait for all I/O to
354 * complete. Data is frozen at that point. Metadata is not frozen,
355 * transactions can still occur here so don't bother flushing the buftarg
356 * because it'll just get dirty again.
357 */
358int
359xfs_quiesce_data(
360 struct xfs_mount *mp)
361{
362 int error, error2 = 0;
363
364 xfs_qm_sync(mp, SYNC_TRYLOCK);
365 xfs_qm_sync(mp, SYNC_WAIT);
366
367 /* force out the newly dirtied log buffers */
368 xfs_log_force(mp, XFS_LOG_SYNC);
369
370 /* write superblock and hoover up shutdown errors */
371 error = xfs_sync_fsdata(mp);
372
373 /* make sure all delwri buffers are written out */
374 xfs_flush_buftarg(mp->m_ddev_targp, 1);
375
376 /* mark the log as covered if needed */
377 if (xfs_log_need_covered(mp))
378 error2 = xfs_fs_log_dummy(mp);
379
380 /* flush data-only devices */
381 if (mp->m_rtdev_targp)
382 XFS_bflush(mp->m_rtdev_targp);
383
384 return error ? error : error2;
385}
386
387STATIC void
388xfs_quiesce_fs(
389 struct xfs_mount *mp)
390{
391 int count = 0, pincount;
392
393 xfs_reclaim_inodes(mp, 0);
394 xfs_flush_buftarg(mp->m_ddev_targp, 0);
395
396 /*
397 * This loop must run at least twice. The first instance of the loop
398 * will flush most meta data but that will generate more meta data
399 * (typically directory updates). Which then must be flushed and
400 * logged before we can write the unmount record. We also so sync
401 * reclaim of inodes to catch any that the above delwri flush skipped.
402 */
403 do {
404 xfs_reclaim_inodes(mp, SYNC_WAIT);
405 xfs_sync_attr(mp, SYNC_WAIT);
406 pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
407 if (!pincount) {
408 delay(50);
409 count++;
410 }
411 } while (count < 2);
412}
413
414/*
415 * Second stage of a quiesce. The data is already synced, now we have to take
416 * care of the metadata. New transactions are already blocked, so we need to
417 * wait for any remaining transactions to drain out before proceeding.
418 */
419void
420xfs_quiesce_attr(
421 struct xfs_mount *mp)
422{
423 int error = 0;
424
425 /* wait for all modifications to complete */
426 while (atomic_read(&mp->m_active_trans) > 0)
427 delay(100);
428
429 /* flush inodes and push all remaining buffers out to disk */
430 xfs_quiesce_fs(mp);
431
432 /*
433 * Just warn here till VFS can correctly support
434 * read-only remount without racing.
435 */
436 WARN_ON(atomic_read(&mp->m_active_trans) != 0);
437
438 /* Push the superblock and write an unmount record */
439 error = xfs_log_sbcount(mp);
440 if (error)
441 xfs_warn(mp, "xfs_attr_quiesce: failed to log sb changes. "
442 "Frozen image may not be consistent.");
443 xfs_log_unmount_write(mp);
444 xfs_unmountfs_writesb(mp);
445}
446
447static void
448xfs_syncd_queue_sync(
449 struct xfs_mount *mp)
450{
451 queue_delayed_work(xfs_syncd_wq, &mp->m_sync_work,
452 msecs_to_jiffies(xfs_syncd_centisecs * 10));
453}
454
455/*
456 * Every sync period we need to unpin all items, reclaim inodes and sync
457 * disk quotas. We might need to cover the log to indicate that the
458 * filesystem is idle and not frozen.
459 */
460STATIC void
461xfs_sync_worker(
462 struct work_struct *work)
463{
464 struct xfs_mount *mp = container_of(to_delayed_work(work),
465 struct xfs_mount, m_sync_work);
466 int error;
467
468 if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
469 /* dgc: errors ignored here */
470 if (mp->m_super->s_frozen == SB_UNFROZEN &&
471 xfs_log_need_covered(mp))
472 error = xfs_fs_log_dummy(mp);
473 else
474 xfs_log_force(mp, 0);
475 error = xfs_qm_sync(mp, SYNC_TRYLOCK);
476
477 /* start pushing all the metadata that is currently dirty */
478 xfs_ail_push_all(mp->m_ail);
479 }
480
481 /* queue us up again */
482 xfs_syncd_queue_sync(mp);
483}
484
485/*
486 * Queue a new inode reclaim pass if there are reclaimable inodes and there
487 * isn't a reclaim pass already in progress. By default it runs every 5s based
488 * on the xfs syncd work default of 30s. Perhaps this should have it's own
489 * tunable, but that can be done if this method proves to be ineffective or too
490 * aggressive.
491 */
492static void
493xfs_syncd_queue_reclaim(
494 struct xfs_mount *mp)
495{
496
497 /*
498 * We can have inodes enter reclaim after we've shut down the syncd
499 * workqueue during unmount, so don't allow reclaim work to be queued
500 * during unmount.
501 */
502 if (!(mp->m_super->s_flags & MS_ACTIVE))
503 return;
504
505 rcu_read_lock();
506 if (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_RECLAIM_TAG)) {
507 queue_delayed_work(xfs_syncd_wq, &mp->m_reclaim_work,
508 msecs_to_jiffies(xfs_syncd_centisecs / 6 * 10));
509 }
510 rcu_read_unlock();
511}
512
513/*
514 * This is a fast pass over the inode cache to try to get reclaim moving on as
515 * many inodes as possible in a short period of time. It kicks itself every few
516 * seconds, as well as being kicked by the inode cache shrinker when memory
517 * goes low. It scans as quickly as possible avoiding locked inodes or those
518 * already being flushed, and once done schedules a future pass.
519 */
520STATIC void
521xfs_reclaim_worker(
522 struct work_struct *work)
523{
524 struct xfs_mount *mp = container_of(to_delayed_work(work),
525 struct xfs_mount, m_reclaim_work);
526
527 xfs_reclaim_inodes(mp, SYNC_TRYLOCK);
528 xfs_syncd_queue_reclaim(mp);
529}
530
531/*
532 * Flush delayed allocate data, attempting to free up reserved space
533 * from existing allocations. At this point a new allocation attempt
534 * has failed with ENOSPC and we are in the process of scratching our
535 * heads, looking about for more room.
536 *
537 * Queue a new data flush if there isn't one already in progress and
538 * wait for completion of the flush. This means that we only ever have one
539 * inode flush in progress no matter how many ENOSPC events are occurring and
540 * so will prevent the system from bogging down due to every concurrent
541 * ENOSPC event scanning all the active inodes in the system for writeback.
542 */
543void
544xfs_flush_inodes(
545 struct xfs_inode *ip)
546{
547 struct xfs_mount *mp = ip->i_mount;
548
549 queue_work(xfs_syncd_wq, &mp->m_flush_work);
550 flush_work_sync(&mp->m_flush_work);
551}
552
553STATIC void
554xfs_flush_worker(
555 struct work_struct *work)
556{
557 struct xfs_mount *mp = container_of(work,
558 struct xfs_mount, m_flush_work);
559
560 xfs_sync_data(mp, SYNC_TRYLOCK);
561 xfs_sync_data(mp, SYNC_TRYLOCK | SYNC_WAIT);
562}
563
564int
565xfs_syncd_init(
566 struct xfs_mount *mp)
567{
568 INIT_WORK(&mp->m_flush_work, xfs_flush_worker);
569 INIT_DELAYED_WORK(&mp->m_sync_work, xfs_sync_worker);
570 INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);
571
572 xfs_syncd_queue_sync(mp);
573 xfs_syncd_queue_reclaim(mp);
574
575 return 0;
576}
577
578void
579xfs_syncd_stop(
580 struct xfs_mount *mp)
581{
582 cancel_delayed_work_sync(&mp->m_sync_work);
583 cancel_delayed_work_sync(&mp->m_reclaim_work);
584 cancel_work_sync(&mp->m_flush_work);
585}
586
587void
588__xfs_inode_set_reclaim_tag(
589 struct xfs_perag *pag,
590 struct xfs_inode *ip)
591{
592 radix_tree_tag_set(&pag->pag_ici_root,
593 XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino),
594 XFS_ICI_RECLAIM_TAG);
595
596 if (!pag->pag_ici_reclaimable) {
597 /* propagate the reclaim tag up into the perag radix tree */
598 spin_lock(&ip->i_mount->m_perag_lock);
599 radix_tree_tag_set(&ip->i_mount->m_perag_tree,
600 XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino),
601 XFS_ICI_RECLAIM_TAG);
602 spin_unlock(&ip->i_mount->m_perag_lock);
603
604 /* schedule periodic background inode reclaim */
605 xfs_syncd_queue_reclaim(ip->i_mount);
606
607 trace_xfs_perag_set_reclaim(ip->i_mount, pag->pag_agno,
608 -1, _RET_IP_);
609 }
610 pag->pag_ici_reclaimable++;
611}
612
613/*
614 * We set the inode flag atomically with the radix tree tag.
615 * Once we get tag lookups on the radix tree, this inode flag
616 * can go away.
617 */
618void
619xfs_inode_set_reclaim_tag(
620 xfs_inode_t *ip)
621{
622 struct xfs_mount *mp = ip->i_mount;
623 struct xfs_perag *pag;
624
625 pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
626 spin_lock(&pag->pag_ici_lock);
627 spin_lock(&ip->i_flags_lock);
628 __xfs_inode_set_reclaim_tag(pag, ip);
629 __xfs_iflags_set(ip, XFS_IRECLAIMABLE);
630 spin_unlock(&ip->i_flags_lock);
631 spin_unlock(&pag->pag_ici_lock);
632 xfs_perag_put(pag);
633}
634
635STATIC void
636__xfs_inode_clear_reclaim(
637 xfs_perag_t *pag,
638 xfs_inode_t *ip)
639{
640 pag->pag_ici_reclaimable--;
641 if (!pag->pag_ici_reclaimable) {
642 /* clear the reclaim tag from the perag radix tree */
643 spin_lock(&ip->i_mount->m_perag_lock);
644 radix_tree_tag_clear(&ip->i_mount->m_perag_tree,
645 XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino),
646 XFS_ICI_RECLAIM_TAG);
647 spin_unlock(&ip->i_mount->m_perag_lock);
648 trace_xfs_perag_clear_reclaim(ip->i_mount, pag->pag_agno,
649 -1, _RET_IP_);
650 }
651}
652
653void
654__xfs_inode_clear_reclaim_tag(
655 xfs_mount_t *mp,
656 xfs_perag_t *pag,
657 xfs_inode_t *ip)
658{
659 radix_tree_tag_clear(&pag->pag_ici_root,
660 XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
661 __xfs_inode_clear_reclaim(pag, ip);
662}
663
664/*
665 * Grab the inode for reclaim exclusively.
666 * Return 0 if we grabbed it, non-zero otherwise.
667 */
668STATIC int
669xfs_reclaim_inode_grab(
670 struct xfs_inode *ip,
671 int flags)
672{
673 ASSERT(rcu_read_lock_held());
674
675 /* quick check for stale RCU freed inode */
676 if (!ip->i_ino)
677 return 1;
678
679 /*
680 * do some unlocked checks first to avoid unnecessary lock traffic.
681 * The first is a flush lock check, the second is a already in reclaim
682 * check. Only do these checks if we are not going to block on locks.
683 */
684 if ((flags & SYNC_TRYLOCK) &&
685 (!ip->i_flush.done || __xfs_iflags_test(ip, XFS_IRECLAIM))) {
686 return 1;
687 }
688
689 /*
690 * The radix tree lock here protects a thread in xfs_iget from racing
691 * with us starting reclaim on the inode. Once we have the
692 * XFS_IRECLAIM flag set it will not touch us.
693 *
694 * Due to RCU lookup, we may find inodes that have been freed and only
695 * have XFS_IRECLAIM set. Indeed, we may see reallocated inodes that
696 * aren't candidates for reclaim at all, so we must check the
697 * XFS_IRECLAIMABLE is set first before proceeding to reclaim.
698 */
699 spin_lock(&ip->i_flags_lock);
700 if (!__xfs_iflags_test(ip, XFS_IRECLAIMABLE) ||
701 __xfs_iflags_test(ip, XFS_IRECLAIM)) {
702 /* not a reclaim candidate. */
703 spin_unlock(&ip->i_flags_lock);
704 return 1;
705 }
706 __xfs_iflags_set(ip, XFS_IRECLAIM);
707 spin_unlock(&ip->i_flags_lock);
708 return 0;
709}
710
711/*
712 * Inodes in different states need to be treated differently, and the return
713 * value of xfs_iflush is not sufficient to get this right. The following table
714 * lists the inode states and the reclaim actions necessary for non-blocking
715 * reclaim:
716 *
717 *
718 * inode state iflush ret required action
719 * --------------- ---------- ---------------
720 * bad - reclaim
721 * shutdown EIO unpin and reclaim
722 * clean, unpinned 0 reclaim
723 * stale, unpinned 0 reclaim
724 * clean, pinned(*) 0 requeue
725 * stale, pinned EAGAIN requeue
726 * dirty, delwri ok 0 requeue
727 * dirty, delwri blocked EAGAIN requeue
728 * dirty, sync flush 0 reclaim
729 *
730 * (*) dgc: I don't think the clean, pinned state is possible but it gets
731 * handled anyway given the order of checks implemented.
732 *
733 * As can be seen from the table, the return value of xfs_iflush() is not
734 * sufficient to correctly decide the reclaim action here. The checks in
735 * xfs_iflush() might look like duplicates, but they are not.
736 *
737 * Also, because we get the flush lock first, we know that any inode that has
738 * been flushed delwri has had the flush completed by the time we check that
739 * the inode is clean. The clean inode check needs to be done before flushing
740 * the inode delwri otherwise we would loop forever requeuing clean inodes as
741 * we cannot tell apart a successful delwri flush and a clean inode from the
742 * return value of xfs_iflush().
743 *
744 * Note that because the inode is flushed delayed write by background
745 * writeback, the flush lock may already be held here and waiting on it can
746 * result in very long latencies. Hence for sync reclaims, where we wait on the
747 * flush lock, the caller should push out delayed write inodes first before
748 * trying to reclaim them to minimise the amount of time spent waiting. For
749 * background relaim, we just requeue the inode for the next pass.
750 *
751 * Hence the order of actions after gaining the locks should be:
752 * bad => reclaim
753 * shutdown => unpin and reclaim
754 * pinned, delwri => requeue
755 * pinned, sync => unpin
756 * stale => reclaim
757 * clean => reclaim
758 * dirty, delwri => flush and requeue
759 * dirty, sync => flush, wait and reclaim
760 */
761STATIC int
762xfs_reclaim_inode(
763 struct xfs_inode *ip,
764 struct xfs_perag *pag,
765 int sync_mode)
766{
767 int error;
768
769restart:
770 error = 0;
771 xfs_ilock(ip, XFS_ILOCK_EXCL);
772 if (!xfs_iflock_nowait(ip)) {
773 if (!(sync_mode & SYNC_WAIT))
774 goto out;
775 xfs_iflock(ip);
776 }
777
778 if (is_bad_inode(VFS_I(ip)))
779 goto reclaim;
780 if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
781 xfs_iunpin_wait(ip);
782 goto reclaim;
783 }
784 if (xfs_ipincount(ip)) {
785 if (!(sync_mode & SYNC_WAIT)) {
786 xfs_ifunlock(ip);
787 goto out;
788 }
789 xfs_iunpin_wait(ip);
790 }
791 if (xfs_iflags_test(ip, XFS_ISTALE))
792 goto reclaim;
793 if (xfs_inode_clean(ip))
794 goto reclaim;
795
796 /*
797 * Now we have an inode that needs flushing.
798 *
799 * We do a nonblocking flush here even if we are doing a SYNC_WAIT
800 * reclaim as we can deadlock with inode cluster removal.
801 * xfs_ifree_cluster() can lock the inode buffer before it locks the
802 * ip->i_lock, and we are doing the exact opposite here. As a result,
803 * doing a blocking xfs_itobp() to get the cluster buffer will result
804 * in an ABBA deadlock with xfs_ifree_cluster().
805 *
806 * As xfs_ifree_cluser() must gather all inodes that are active in the
807 * cache to mark them stale, if we hit this case we don't actually want
808 * to do IO here - we want the inode marked stale so we can simply
809 * reclaim it. Hence if we get an EAGAIN error on a SYNC_WAIT flush,
810 * just unlock the inode, back off and try again. Hopefully the next
811 * pass through will see the stale flag set on the inode.
812 */
813 error = xfs_iflush(ip, SYNC_TRYLOCK | sync_mode);
814 if (sync_mode & SYNC_WAIT) {
815 if (error == EAGAIN) {
816 xfs_iunlock(ip, XFS_ILOCK_EXCL);
817 /* backoff longer than in xfs_ifree_cluster */
818 delay(2);
819 goto restart;
820 }
821 xfs_iflock(ip);
822 goto reclaim;
823 }
824
825 /*
826 * When we have to flush an inode but don't have SYNC_WAIT set, we
827 * flush the inode out using a delwri buffer and wait for the next
828 * call into reclaim to find it in a clean state instead of waiting for
829 * it now. We also don't return errors here - if the error is transient
830 * then the next reclaim pass will flush the inode, and if the error
831 * is permanent then the next sync reclaim will reclaim the inode and
832 * pass on the error.
833 */
834 if (error && error != EAGAIN && !XFS_FORCED_SHUTDOWN(ip->i_mount)) {
835 xfs_warn(ip->i_mount,
836 "inode 0x%llx background reclaim flush failed with %d",
837 (long long)ip->i_ino, error);
838 }
839out:
840 xfs_iflags_clear(ip, XFS_IRECLAIM);
841 xfs_iunlock(ip, XFS_ILOCK_EXCL);
842 /*
843 * We could return EAGAIN here to make reclaim rescan the inode tree in
844 * a short while. However, this just burns CPU time scanning the tree
845 * waiting for IO to complete and xfssyncd never goes back to the idle
846 * state. Instead, return 0 to let the next scheduled background reclaim
847 * attempt to reclaim the inode again.
848 */
849 return 0;
850
851reclaim:
852 xfs_ifunlock(ip);
853 xfs_iunlock(ip, XFS_ILOCK_EXCL);
854
855 XFS_STATS_INC(xs_ig_reclaims);
856 /*
857 * Remove the inode from the per-AG radix tree.
858 *
859 * Because radix_tree_delete won't complain even if the item was never
860 * added to the tree assert that it's been there before to catch
861 * problems with the inode life time early on.
862 */
863 spin_lock(&pag->pag_ici_lock);
864 if (!radix_tree_delete(&pag->pag_ici_root,
865 XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino)))
866 ASSERT(0);
867 __xfs_inode_clear_reclaim(pag, ip);
868 spin_unlock(&pag->pag_ici_lock);
869
870 /*
871 * Here we do an (almost) spurious inode lock in order to coordinate
872 * with inode cache radix tree lookups. This is because the lookup
873 * can reference the inodes in the cache without taking references.
874 *
875 * We make that OK here by ensuring that we wait until the inode is
876 * unlocked after the lookup before we go ahead and free it. We get
877 * both the ilock and the iolock because the code may need to drop the
878 * ilock one but will still hold the iolock.
879 */
880 xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
881 xfs_qm_dqdetach(ip);
882 xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
883
884 xfs_inode_free(ip);
885 return error;
886
887}
888
889/*
890 * Walk the AGs and reclaim the inodes in them. Even if the filesystem is
891 * corrupted, we still want to try to reclaim all the inodes. If we don't,
892 * then a shut down during filesystem unmount reclaim walk leak all the
893 * unreclaimed inodes.
894 */
895int
896xfs_reclaim_inodes_ag(
897 struct xfs_mount *mp,
898 int flags,
899 int *nr_to_scan)
900{
901 struct xfs_perag *pag;
902 int error = 0;
903 int last_error = 0;
904 xfs_agnumber_t ag;
905 int trylock = flags & SYNC_TRYLOCK;
906 int skipped;
907
908restart:
909 ag = 0;
910 skipped = 0;
911 while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) {
912 unsigned long first_index = 0;
913 int done = 0;
914 int nr_found = 0;
915
916 ag = pag->pag_agno + 1;
917
918 if (trylock) {
919 if (!mutex_trylock(&pag->pag_ici_reclaim_lock)) {
920 skipped++;
921 xfs_perag_put(pag);
922 continue;
923 }
924 first_index = pag->pag_ici_reclaim_cursor;
925 } else
926 mutex_lock(&pag->pag_ici_reclaim_lock);
927
928 do {
929 struct xfs_inode *batch[XFS_LOOKUP_BATCH];
930 int i;
931
932 rcu_read_lock();
933 nr_found = radix_tree_gang_lookup_tag(
934 &pag->pag_ici_root,
935 (void **)batch, first_index,
936 XFS_LOOKUP_BATCH,
937 XFS_ICI_RECLAIM_TAG);
938 if (!nr_found) {
939 done = 1;
940 rcu_read_unlock();
941 break;
942 }
943
944 /*
945 * Grab the inodes before we drop the lock. if we found
946 * nothing, nr == 0 and the loop will be skipped.
947 */
948 for (i = 0; i < nr_found; i++) {
949 struct xfs_inode *ip = batch[i];
950
951 if (done || xfs_reclaim_inode_grab(ip, flags))
952 batch[i] = NULL;
953
954 /*
955 * Update the index for the next lookup. Catch
956 * overflows into the next AG range which can
957 * occur if we have inodes in the last block of
958 * the AG and we are currently pointing to the
959 * last inode.
960 *
961 * Because we may see inodes that are from the
962 * wrong AG due to RCU freeing and
963 * reallocation, only update the index if it
964 * lies in this AG. It was a race that lead us
965 * to see this inode, so another lookup from
966 * the same index will not find it again.
967 */
968 if (XFS_INO_TO_AGNO(mp, ip->i_ino) !=
969 pag->pag_agno)
970 continue;
971 first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
972 if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino))
973 done = 1;
974 }
975
976 /* unlock now we've grabbed the inodes. */
977 rcu_read_unlock();
978
979 for (i = 0; i < nr_found; i++) {
980 if (!batch[i])
981 continue;
982 error = xfs_reclaim_inode(batch[i], pag, flags);
983 if (error && last_error != EFSCORRUPTED)
984 last_error = error;
985 }
986
987 *nr_to_scan -= XFS_LOOKUP_BATCH;
988
989 cond_resched();
990
991 } while (nr_found && !done && *nr_to_scan > 0);
992
993 if (trylock && !done)
994 pag->pag_ici_reclaim_cursor = first_index;
995 else
996 pag->pag_ici_reclaim_cursor = 0;
997 mutex_unlock(&pag->pag_ici_reclaim_lock);
998 xfs_perag_put(pag);
999 }
1000
1001 /*
1002 * if we skipped any AG, and we still have scan count remaining, do
1003 * another pass this time using blocking reclaim semantics (i.e
1004 * waiting on the reclaim locks and ignoring the reclaim cursors). This
1005 * ensure that when we get more reclaimers than AGs we block rather
1006 * than spin trying to execute reclaim.
1007 */
1008 if (skipped && (flags & SYNC_WAIT) && *nr_to_scan > 0) {
1009 trylock = 0;
1010 goto restart;
1011 }
1012 return XFS_ERROR(last_error);
1013}
1014
1015int
1016xfs_reclaim_inodes(
1017 xfs_mount_t *mp,
1018 int mode)
1019{
1020 int nr_to_scan = INT_MAX;
1021
1022 return xfs_reclaim_inodes_ag(mp, mode, &nr_to_scan);
1023}
1024
1025/*
1026 * Scan a certain number of inodes for reclaim.
1027 *
1028 * When called we make sure that there is a background (fast) inode reclaim in
1029 * progress, while we will throttle the speed of reclaim via doing synchronous
1030 * reclaim of inodes. That means if we come across dirty inodes, we wait for
1031 * them to be cleaned, which we hope will not be very long due to the
1032 * background walker having already kicked the IO off on those dirty inodes.
1033 */
1034void
1035xfs_reclaim_inodes_nr(
1036 struct xfs_mount *mp,
1037 int nr_to_scan)
1038{
1039 /* kick background reclaimer and push the AIL */
1040 xfs_syncd_queue_reclaim(mp);
1041 xfs_ail_push_all(mp->m_ail);
1042
1043 xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan);
1044}
1045
1046/*
1047 * Return the number of reclaimable inodes in the filesystem for
1048 * the shrinker to determine how much to reclaim.
1049 */
1050int
1051xfs_reclaim_inodes_count(
1052 struct xfs_mount *mp)
1053{
1054 struct xfs_perag *pag;
1055 xfs_agnumber_t ag = 0;
1056 int reclaimable = 0;
1057
1058 while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) {
1059 ag = pag->pag_agno + 1;
1060 reclaimable += pag->pag_ici_reclaimable;
1061 xfs_perag_put(pag);
1062 }
1063 return reclaimable;
1064}
1065
diff --git a/fs/xfs/xfs_sync.h b/fs/xfs/xfs_sync.h
new file mode 100644
index 00000000000..941202e7ac6
--- /dev/null
+++ b/fs/xfs/xfs_sync.h
@@ -0,0 +1,51 @@
1/*
2 * Copyright (c) 2000-2006 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#ifndef XFS_SYNC_H
19#define XFS_SYNC_H 1
20
21struct xfs_mount;
22struct xfs_perag;
23
24#define SYNC_WAIT 0x0001 /* wait for i/o to complete */
25#define SYNC_TRYLOCK 0x0002 /* only try to lock inodes */
26
27extern struct workqueue_struct *xfs_syncd_wq; /* sync workqueue */
28
29int xfs_syncd_init(struct xfs_mount *mp);
30void xfs_syncd_stop(struct xfs_mount *mp);
31
32int xfs_quiesce_data(struct xfs_mount *mp);
33void xfs_quiesce_attr(struct xfs_mount *mp);
34
35void xfs_flush_inodes(struct xfs_inode *ip);
36
37int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
38int xfs_reclaim_inodes_count(struct xfs_mount *mp);
39void xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);
40
41void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
42void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip);
43void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag,
44 struct xfs_inode *ip);
45
46int xfs_sync_inode_grab(struct xfs_inode *ip);
47int xfs_inode_ag_iterator(struct xfs_mount *mp,
48 int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags),
49 int flags);
50
51#endif
diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig
new file mode 100644
index 00000000000..63541405999
--- /dev/null
+++ b/fs/yaffs2/Kconfig
@@ -0,0 +1,161 @@
1#
2# YAFFS file system configurations
3#
4
5config YAFFS_FS
6 tristate "YAFFS2 file system support"
7 default n
8 depends on MTD_BLOCK
9 select YAFFS_YAFFS1
10 select YAFFS_YAFFS2
11 help
12 YAFFS2, or Yet Another Flash Filing System, is a filing system
13 optimised for NAND Flash chips.
14
15 To compile the YAFFS2 file system support as a module, choose M
16 here: the module will be called yaffs2.
17
18 If unsure, say N.
19
20 Further information on YAFFS2 is available at
21 <http://www.aleph1.co.uk/yaffs/>.
22
23config YAFFS_YAFFS1
24 bool "512 byte / page devices"
25 depends on YAFFS_FS
26 default y
27 help
28 Enable YAFFS1 support -- yaffs for 512 byte / page devices
29
30 Not needed for 2K-page devices.
31
32 If unsure, say Y.
33
34config YAFFS_9BYTE_TAGS
35 bool "Use older-style on-NAND data format with pageStatus byte"
36 depends on YAFFS_YAFFS1
37 default n
38 help
39
40 Older-style on-NAND data format has a "pageStatus" byte to record
41 chunk/page state. This byte is zero when the page is discarded.
42 Choose this option if you have existing on-NAND data using this
43 format that you need to continue to support. New data written
44 also uses the older-style format. Note: Use of this option
45 generally requires that MTD's oob layout be adjusted to use the
46 older-style format. See notes on tags formats and MTD versions
47 in yaffs_mtdif1.c.
48
49 If unsure, say N.
50
51config YAFFS_DOES_ECC
52 bool "Lets Yaffs do its own ECC"
53 depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
54 default n
55 help
56 This enables Yaffs to use its own ECC functions instead of using
57 the ones from the generic MTD-NAND driver.
58
59 If unsure, say N.
60
61config YAFFS_ECC_WRONG_ORDER
62 bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
63 depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
64 default n
65 help
66 This makes yaffs_ecc.c use the same ecc byte order as Steven
67 Hill's nand_ecc.c. If not set, then you get the same ecc byte
68 order as SmartMedia.
69
70 If unsure, say N.
71
72config YAFFS_YAFFS2
73 bool "2048 byte (or larger) / page devices"
74 depends on YAFFS_FS
75 default y
76 help
77 Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
78
79 If unsure, say Y.
80
81config YAFFS_AUTO_YAFFS2
82 bool "Autoselect yaffs2 format"
83 depends on YAFFS_YAFFS2
84 default y
85 help
86 Without this, you need to explicitely use yaffs2 as the file
87 system type. With this, you can say "yaffs" and yaffs or yaffs2
88 will be used depending on the device page size (yaffs on
89 512-byte page devices, yaffs2 on 2K page devices).
90
91 If unsure, say Y.
92
93config YAFFS_DISABLE_TAGS_ECC
94 bool "Disable YAFFS from doing ECC on tags by default"
95 depends on YAFFS_FS && YAFFS_YAFFS2
96 default n
97 help
98 This defaults Yaffs to using its own ECC calculations on tags instead of
99 just relying on the MTD.
100 This behavior can also be overridden with tags_ecc_on and
101 tags_ecc_off mount options.
102
103 If unsure, say N.
104
105config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
106 bool "Force chunk erase check"
107 depends on YAFFS_FS
108 default n
109 help
110 Normally YAFFS only checks chunks before writing until an erased
111 chunk is found. This helps to detect any partially written
112 chunks that might have happened due to power loss.
113
114 Enabling this forces on the test that chunks are erased in flash
115 before writing to them. This takes more time but is potentially
116 a bit more secure.
117
118 Suggest setting Y during development and ironing out driver
119 issues etc. Suggest setting to N if you want faster writing.
120
121 If unsure, say Y.
122
123config YAFFS_EMPTY_LOST_AND_FOUND
124 bool "Empty lost and found on boot"
125 depends on YAFFS_FS
126 default n
127 help
128 If this is enabled then the contents of lost and found is
129 automatically dumped at mount.
130
131 If unsure, say N.
132
133config YAFFS_DISABLE_BLOCK_REFRESHING
134 bool "Disable yaffs2 block refreshing"
135 depends on YAFFS_FS
136 default n
137 help
138 If this is set, then block refreshing is disabled.
139 Block refreshing infrequently refreshes the oldest block in
140 a yaffs2 file system. This mechanism helps to refresh flash to
141 mitigate against data loss. This is particularly useful for MLC.
142
143 If unsure, say N.
144
145config YAFFS_DISABLE_BACKGROUND
146 bool "Disable yaffs2 background processing"
147 depends on YAFFS_FS
148 default n
149 help
150 If this is set, then background processing is disabled.
151 Background processing makes many foreground activities faster.
152
153 If unsure, say N.
154
155config YAFFS_XATTR
156 bool "Enable yaffs2 xattr support"
157 depends on YAFFS_FS
158 default y
159 help
160 If this is set then yaffs2 will provide xattr support.
161 If unsure, say Y.
diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile
new file mode 100644
index 00000000000..e63a28aa3ed
--- /dev/null
+++ b/fs/yaffs2/Makefile
@@ -0,0 +1,17 @@
1#
2# Makefile for the linux YAFFS filesystem routines.
3#
4
5obj-$(CONFIG_YAFFS_FS) += yaffs.o
6
7yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
8yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
9yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
10yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
11yaffs-y += yaffs_nameval.o yaffs_attribs.o
12yaffs-y += yaffs_allocator.o
13yaffs-y += yaffs_yaffs1.o
14yaffs-y += yaffs_yaffs2.o
15yaffs-y += yaffs_bitmap.o
16yaffs-y += yaffs_verify.o
17
diff --git a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c
new file mode 100644
index 00000000000..f9cd5becd8f
--- /dev/null
+++ b/fs/yaffs2/yaffs_allocator.c
@@ -0,0 +1,396 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_allocator.h"
15#include "yaffs_guts.h"
16#include "yaffs_trace.h"
17#include "yportenv.h"
18
19#ifdef CONFIG_YAFFS_KMALLOC_ALLOCATOR
20
21void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
22{
23 dev = dev;
24}
25
26void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
27{
28 dev = dev;
29}
30
31struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
32{
33 return (struct yaffs_tnode *)kmalloc(dev->tnode_size, GFP_NOFS);
34}
35
36void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
37{
38 dev = dev;
39 kfree(tn);
40}
41
42void yaffs_init_raw_objs(struct yaffs_dev *dev)
43{
44 dev = dev;
45}
46
47void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
48{
49 dev = dev;
50}
51
52struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
53{
54 dev = dev;
55 return (struct yaffs_obj *)kmalloc(sizeof(struct yaffs_obj));
56}
57
58void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
59{
60
61 dev = dev;
62 kfree(obj);
63}
64
65#else
66
67struct yaffs_tnode_list {
68 struct yaffs_tnode_list *next;
69 struct yaffs_tnode *tnodes;
70};
71
72struct yaffs_obj_list {
73 struct yaffs_obj_list *next;
74 struct yaffs_obj *objects;
75};
76
77struct yaffs_allocator {
78 int n_tnodes_created;
79 struct yaffs_tnode *free_tnodes;
80 int n_free_tnodes;
81 struct yaffs_tnode_list *alloc_tnode_list;
82
83 int n_obj_created;
84 struct yaffs_obj *free_objs;
85 int n_free_objects;
86
87 struct yaffs_obj_list *allocated_obj_list;
88};
89
90static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
91{
92
93 struct yaffs_allocator *allocator =
94 (struct yaffs_allocator *)dev->allocator;
95
96 struct yaffs_tnode_list *tmp;
97
98 if (!allocator) {
99 YBUG();
100 return;
101 }
102
103 while (allocator->alloc_tnode_list) {
104 tmp = allocator->alloc_tnode_list->next;
105
106 kfree(allocator->alloc_tnode_list->tnodes);
107 kfree(allocator->alloc_tnode_list);
108 allocator->alloc_tnode_list = tmp;
109
110 }
111
112 allocator->free_tnodes = NULL;
113 allocator->n_free_tnodes = 0;
114 allocator->n_tnodes_created = 0;
115}
116
117static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
118{
119 struct yaffs_allocator *allocator = dev->allocator;
120
121 if (allocator) {
122 allocator->alloc_tnode_list = NULL;
123 allocator->free_tnodes = NULL;
124 allocator->n_free_tnodes = 0;
125 allocator->n_tnodes_created = 0;
126 } else {
127 YBUG();
128 }
129}
130
131static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
132{
133 struct yaffs_allocator *allocator =
134 (struct yaffs_allocator *)dev->allocator;
135 int i;
136 struct yaffs_tnode *new_tnodes;
137 u8 *mem;
138 struct yaffs_tnode *curr;
139 struct yaffs_tnode *next;
140 struct yaffs_tnode_list *tnl;
141
142 if (!allocator) {
143 YBUG();
144 return YAFFS_FAIL;
145 }
146
147 if (n_tnodes < 1)
148 return YAFFS_OK;
149
150 /* make these things */
151
152 new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
153 mem = (u8 *) new_tnodes;
154
155 if (!new_tnodes) {
156 yaffs_trace(YAFFS_TRACE_ERROR,
157 "yaffs: Could not allocate Tnodes");
158 return YAFFS_FAIL;
159 }
160
161 /* New hookup for wide tnodes */
162 for (i = 0; i < n_tnodes - 1; i++) {
163 curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
164 next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
165 curr->internal[0] = next;
166 }
167
168 curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
169 curr->internal[0] = allocator->free_tnodes;
170 allocator->free_tnodes = (struct yaffs_tnode *)mem;
171
172 allocator->n_free_tnodes += n_tnodes;
173 allocator->n_tnodes_created += n_tnodes;
174
175 /* Now add this bunch of tnodes to a list for freeing up.
176 * NB If we can't add this to the management list it isn't fatal
177 * but it just means we can't free this bunch of tnodes later.
178 */
179
180 tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
181 if (!tnl) {
182 yaffs_trace(YAFFS_TRACE_ERROR,
183 "Could not add tnodes to management list");
184 return YAFFS_FAIL;
185 } else {
186 tnl->tnodes = new_tnodes;
187 tnl->next = allocator->alloc_tnode_list;
188 allocator->alloc_tnode_list = tnl;
189 }
190
191 yaffs_trace(YAFFS_TRACE_ALLOCATE,"Tnodes added");
192
193 return YAFFS_OK;
194}
195
196struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
197{
198 struct yaffs_allocator *allocator =
199 (struct yaffs_allocator *)dev->allocator;
200 struct yaffs_tnode *tn = NULL;
201
202 if (!allocator) {
203 YBUG();
204 return NULL;
205 }
206
207 /* If there are none left make more */
208 if (!allocator->free_tnodes)
209 yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
210
211 if (allocator->free_tnodes) {
212 tn = allocator->free_tnodes;
213 allocator->free_tnodes = allocator->free_tnodes->internal[0];
214 allocator->n_free_tnodes--;
215 }
216
217 return tn;
218}
219
220/* FreeTnode frees up a tnode and puts it back on the free list */
221void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
222{
223 struct yaffs_allocator *allocator = dev->allocator;
224
225 if (!allocator) {
226 YBUG();
227 return;
228 }
229
230 if (tn) {
231 tn->internal[0] = allocator->free_tnodes;
232 allocator->free_tnodes = tn;
233 allocator->n_free_tnodes++;
234 }
235 dev->checkpoint_blocks_required = 0; /* force recalculation */
236}
237
238static void yaffs_init_raw_objs(struct yaffs_dev *dev)
239{
240 struct yaffs_allocator *allocator = dev->allocator;
241
242 if (allocator) {
243 allocator->allocated_obj_list = NULL;
244 allocator->free_objs = NULL;
245 allocator->n_free_objects = 0;
246 } else {
247 YBUG();
248 }
249}
250
251static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
252{
253 struct yaffs_allocator *allocator = dev->allocator;
254 struct yaffs_obj_list *tmp;
255
256 if (!allocator) {
257 YBUG();
258 return;
259 }
260
261 while (allocator->allocated_obj_list) {
262 tmp = allocator->allocated_obj_list->next;
263 kfree(allocator->allocated_obj_list->objects);
264 kfree(allocator->allocated_obj_list);
265
266 allocator->allocated_obj_list = tmp;
267 }
268
269 allocator->free_objs = NULL;
270 allocator->n_free_objects = 0;
271 allocator->n_obj_created = 0;
272}
273
274static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
275{
276 struct yaffs_allocator *allocator = dev->allocator;
277
278 int i;
279 struct yaffs_obj *new_objs;
280 struct yaffs_obj_list *list;
281
282 if (!allocator) {
283 YBUG();
284 return YAFFS_FAIL;
285 }
286
287 if (n_obj < 1)
288 return YAFFS_OK;
289
290 /* make these things */
291 new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
292 list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
293
294 if (!new_objs || !list) {
295 if (new_objs) {
296 kfree(new_objs);
297 new_objs = NULL;
298 }
299 if (list) {
300 kfree(list);
301 list = NULL;
302 }
303 yaffs_trace(YAFFS_TRACE_ALLOCATE,
304 "Could not allocate more objects");
305 return YAFFS_FAIL;
306 }
307
308 /* Hook them into the free list */
309 for (i = 0; i < n_obj - 1; i++) {
310 new_objs[i].siblings.next =
311 (struct list_head *)(&new_objs[i + 1]);
312 }
313
314 new_objs[n_obj - 1].siblings.next = (void *)allocator->free_objs;
315 allocator->free_objs = new_objs;
316 allocator->n_free_objects += n_obj;
317 allocator->n_obj_created += n_obj;
318
319 /* Now add this bunch of Objects to a list for freeing up. */
320
321 list->objects = new_objs;
322 list->next = allocator->allocated_obj_list;
323 allocator->allocated_obj_list = list;
324
325 return YAFFS_OK;
326}
327
328struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
329{
330 struct yaffs_obj *obj = NULL;
331 struct yaffs_allocator *allocator = dev->allocator;
332
333 if (!allocator) {
334 YBUG();
335 return obj;
336 }
337
338 /* If there are none left make more */
339 if (!allocator->free_objs)
340 yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
341
342 if (allocator->free_objs) {
343 obj = allocator->free_objs;
344 allocator->free_objs =
345 (struct yaffs_obj *)(allocator->free_objs->siblings.next);
346 allocator->n_free_objects--;
347 }
348
349 return obj;
350}
351
352void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
353{
354
355 struct yaffs_allocator *allocator = dev->allocator;
356
357 if (!allocator)
358 YBUG();
359 else {
360 /* Link into the free list. */
361 obj->siblings.next = (struct list_head *)(allocator->free_objs);
362 allocator->free_objs = obj;
363 allocator->n_free_objects++;
364 }
365}
366
367void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
368{
369 if (dev->allocator) {
370 yaffs_deinit_raw_tnodes(dev);
371 yaffs_deinit_raw_objs(dev);
372
373 kfree(dev->allocator);
374 dev->allocator = NULL;
375 } else {
376 YBUG();
377 }
378}
379
380void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
381{
382 struct yaffs_allocator *allocator;
383
384 if (!dev->allocator) {
385 allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
386 if (allocator) {
387 dev->allocator = allocator;
388 yaffs_init_raw_tnodes(dev);
389 yaffs_init_raw_objs(dev);
390 }
391 } else {
392 YBUG();
393 }
394}
395
396#endif
diff --git a/fs/yaffs2/yaffs_allocator.h b/fs/yaffs2/yaffs_allocator.h
new file mode 100644
index 00000000000..4d5f2aec89f
--- /dev/null
+++ b/fs/yaffs2/yaffs_allocator.h
@@ -0,0 +1,30 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_ALLOCATOR_H__
17#define __YAFFS_ALLOCATOR_H__
18
19#include "yaffs_guts.h"
20
21void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
22void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
23
24struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
25void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
26
27struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
28void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
29
30#endif
diff --git a/fs/yaffs2/yaffs_attribs.c b/fs/yaffs2/yaffs_attribs.c
new file mode 100644
index 00000000000..9b47d376310
--- /dev/null
+++ b/fs/yaffs2/yaffs_attribs.c
@@ -0,0 +1,124 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_guts.h"
15#include "yaffs_attribs.h"
16
17void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
18{
19 obj->yst_uid = oh->yst_uid;
20 obj->yst_gid = oh->yst_gid;
21 obj->yst_atime = oh->yst_atime;
22 obj->yst_mtime = oh->yst_mtime;
23 obj->yst_ctime = oh->yst_ctime;
24 obj->yst_rdev = oh->yst_rdev;
25}
26
27void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
28{
29 oh->yst_uid = obj->yst_uid;
30 oh->yst_gid = obj->yst_gid;
31 oh->yst_atime = obj->yst_atime;
32 oh->yst_mtime = obj->yst_mtime;
33 oh->yst_ctime = obj->yst_ctime;
34 oh->yst_rdev = obj->yst_rdev;
35
36}
37
38void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
39{
40 obj->yst_mtime = Y_CURRENT_TIME;
41 if (do_a)
42 obj->yst_atime = obj->yst_mtime;
43 if (do_c)
44 obj->yst_ctime = obj->yst_mtime;
45}
46
47void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
48{
49 yaffs_load_current_time(obj, 1, 1);
50 obj->yst_rdev = rdev;
51 obj->yst_uid = uid;
52 obj->yst_gid = gid;
53}
54
55loff_t yaffs_get_file_size(struct yaffs_obj *obj)
56{
57 YCHAR *alias = NULL;
58 obj = yaffs_get_equivalent_obj(obj);
59
60 switch (obj->variant_type) {
61 case YAFFS_OBJECT_TYPE_FILE:
62 return obj->variant.file_variant.file_size;
63 case YAFFS_OBJECT_TYPE_SYMLINK:
64 alias = obj->variant.symlink_variant.alias;
65 if (!alias)
66 return 0;
67 return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
68 default:
69 return 0;
70 }
71}
72
73int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
74{
75 unsigned int valid = attr->ia_valid;
76
77 if (valid & ATTR_MODE)
78 obj->yst_mode = attr->ia_mode;
79 if (valid & ATTR_UID)
80 obj->yst_uid = attr->ia_uid;
81 if (valid & ATTR_GID)
82 obj->yst_gid = attr->ia_gid;
83
84 if (valid & ATTR_ATIME)
85 obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
86 if (valid & ATTR_CTIME)
87 obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
88 if (valid & ATTR_MTIME)
89 obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
90
91 if (valid & ATTR_SIZE)
92 yaffs_resize_file(obj, attr->ia_size);
93
94 yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
95
96 return YAFFS_OK;
97
98}
99
100int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
101{
102 unsigned int valid = 0;
103
104 attr->ia_mode = obj->yst_mode;
105 valid |= ATTR_MODE;
106 attr->ia_uid = obj->yst_uid;
107 valid |= ATTR_UID;
108 attr->ia_gid = obj->yst_gid;
109 valid |= ATTR_GID;
110
111 Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
112 valid |= ATTR_ATIME;
113 Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
114 valid |= ATTR_CTIME;
115 Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
116 valid |= ATTR_MTIME;
117
118 attr->ia_size = yaffs_get_file_size(obj);
119 valid |= ATTR_SIZE;
120
121 attr->ia_valid = valid;
122
123 return YAFFS_OK;
124}
diff --git a/fs/yaffs2/yaffs_attribs.h b/fs/yaffs2/yaffs_attribs.h
new file mode 100644
index 00000000000..33d541d6944
--- /dev/null
+++ b/fs/yaffs2/yaffs_attribs.h
@@ -0,0 +1,28 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_ATTRIBS_H__
17#define __YAFFS_ATTRIBS_H__
18
19#include "yaffs_guts.h"
20
21void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
22void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
23void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
24void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
25int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
26int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
27
28#endif
diff --git a/fs/yaffs2/yaffs_bitmap.c b/fs/yaffs2/yaffs_bitmap.c
new file mode 100644
index 00000000000..7df42cd0066
--- /dev/null
+++ b/fs/yaffs2/yaffs_bitmap.c
@@ -0,0 +1,98 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_bitmap.h"
15#include "yaffs_trace.h"
16/*
17 * Chunk bitmap manipulations
18 */
19
20static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
21{
22 if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
23 yaffs_trace(YAFFS_TRACE_ERROR,
24 "BlockBits block %d is not valid",
25 blk);
26 YBUG();
27 }
28 return dev->chunk_bits +
29 (dev->chunk_bit_stride * (blk - dev->internal_start_block));
30}
31
32void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
33{
34 if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
35 chunk < 0 || chunk >= dev->param.chunks_per_block) {
36 yaffs_trace(YAFFS_TRACE_ERROR,
37 "Chunk Id (%d:%d) invalid",
38 blk, chunk);
39 YBUG();
40 }
41}
42
43void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
44{
45 u8 *blk_bits = yaffs_block_bits(dev, blk);
46
47 memset(blk_bits, 0, dev->chunk_bit_stride);
48}
49
50void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
51{
52 u8 *blk_bits = yaffs_block_bits(dev, blk);
53
54 yaffs_verify_chunk_bit_id(dev, blk, chunk);
55
56 blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
57}
58
59void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
60{
61 u8 *blk_bits = yaffs_block_bits(dev, blk);
62
63 yaffs_verify_chunk_bit_id(dev, blk, chunk);
64
65 blk_bits[chunk / 8] |= (1 << (chunk & 7));
66}
67
68int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
69{
70 u8 *blk_bits = yaffs_block_bits(dev, blk);
71 yaffs_verify_chunk_bit_id(dev, blk, chunk);
72
73 return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
74}
75
76int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
77{
78 u8 *blk_bits = yaffs_block_bits(dev, blk);
79 int i;
80 for (i = 0; i < dev->chunk_bit_stride; i++) {
81 if (*blk_bits)
82 return 1;
83 blk_bits++;
84 }
85 return 0;
86}
87
88int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
89{
90 u8 *blk_bits = yaffs_block_bits(dev, blk);
91 int i;
92 int n = 0;
93
94 for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
95 n += hweight8(*blk_bits);
96
97 return n;
98}
diff --git a/fs/yaffs2/yaffs_bitmap.h b/fs/yaffs2/yaffs_bitmap.h
new file mode 100644
index 00000000000..cf9ea58da0d
--- /dev/null
+++ b/fs/yaffs2/yaffs_bitmap.h
@@ -0,0 +1,33 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16/*
17 * Chunk bitmap manipulations
18 */
19
20#ifndef __YAFFS_BITMAP_H__
21#define __YAFFS_BITMAP_H__
22
23#include "yaffs_guts.h"
24
25void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
26void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
27void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
28void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
29int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
30int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
31int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
32
33#endif
diff --git a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c
new file mode 100644
index 00000000000..4e40f437e65
--- /dev/null
+++ b/fs/yaffs2/yaffs_checkptrw.c
@@ -0,0 +1,415 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_checkptrw.h"
15#include "yaffs_getblockinfo.h"
16
17static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
18{
19 int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
20
21 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
22 "checkpt blocks_avail = %d", blocks_avail);
23
24 return (blocks_avail <= 0) ? 0 : 1;
25}
26
27static int yaffs_checkpt_erase(struct yaffs_dev *dev)
28{
29 int i;
30
31 if (!dev->param.erase_fn)
32 return 0;
33 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
34 "checking blocks %d to %d",
35 dev->internal_start_block, dev->internal_end_block);
36
37 for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
38 struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
39 if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
40 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
41 "erasing checkpt block %d", i);
42
43 dev->n_erasures++;
44
45 if (dev->param.
46 erase_fn(dev,
47 i - dev->block_offset /* realign */ )) {
48 bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
49 dev->n_erased_blocks++;
50 dev->n_free_chunks +=
51 dev->param.chunks_per_block;
52 } else {
53 dev->param.bad_block_fn(dev, i);
54 bi->block_state = YAFFS_BLOCK_STATE_DEAD;
55 }
56 }
57 }
58
59 dev->blocks_in_checkpt = 0;
60
61 return 1;
62}
63
64static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
65{
66 int i;
67 int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
68 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
69 "allocating checkpt block: erased %d reserved %d avail %d next %d ",
70 dev->n_erased_blocks, dev->param.n_reserved_blocks,
71 blocks_avail, dev->checkpt_next_block);
72
73 if (dev->checkpt_next_block >= 0 &&
74 dev->checkpt_next_block <= dev->internal_end_block &&
75 blocks_avail > 0) {
76
77 for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
78 i++) {
79 struct yaffs_block_info *bi =
80 yaffs_get_block_info(dev, i);
81 if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
82 dev->checkpt_next_block = i + 1;
83 dev->checkpt_cur_block = i;
84 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
85 "allocating checkpt block %d", i);
86 return;
87 }
88 }
89 }
90 yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
91
92 dev->checkpt_next_block = -1;
93 dev->checkpt_cur_block = -1;
94}
95
96static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
97{
98 int i;
99 struct yaffs_ext_tags tags;
100
101 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
102 "find next checkpt block: start: blocks %d next %d",
103 dev->blocks_in_checkpt, dev->checkpt_next_block);
104
105 if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
106 for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
107 i++) {
108 int chunk = i * dev->param.chunks_per_block;
109 int realigned_chunk = chunk - dev->chunk_offset;
110
111 dev->param.read_chunk_tags_fn(dev, realigned_chunk,
112 NULL, &tags);
113 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
114 "find next checkpt block: search: block %d oid %d seq %d eccr %d",
115 i, tags.obj_id, tags.seq_number,
116 tags.ecc_result);
117
118 if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
119 /* Right kind of block */
120 dev->checkpt_next_block = tags.obj_id;
121 dev->checkpt_cur_block = i;
122 dev->checkpt_block_list[dev->
123 blocks_in_checkpt] = i;
124 dev->blocks_in_checkpt++;
125 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
126 "found checkpt block %d", i);
127 return;
128 }
129 }
130
131 yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
132
133 dev->checkpt_next_block = -1;
134 dev->checkpt_cur_block = -1;
135}
136
137int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
138{
139
140 dev->checkpt_open_write = writing;
141
142 /* Got the functions we need? */
143 if (!dev->param.write_chunk_tags_fn ||
144 !dev->param.read_chunk_tags_fn ||
145 !dev->param.erase_fn || !dev->param.bad_block_fn)
146 return 0;
147
148 if (writing && !yaffs2_checkpt_space_ok(dev))
149 return 0;
150
151 if (!dev->checkpt_buffer)
152 dev->checkpt_buffer =
153 kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
154 if (!dev->checkpt_buffer)
155 return 0;
156
157 dev->checkpt_page_seq = 0;
158 dev->checkpt_byte_count = 0;
159 dev->checkpt_sum = 0;
160 dev->checkpt_xor = 0;
161 dev->checkpt_cur_block = -1;
162 dev->checkpt_cur_chunk = -1;
163 dev->checkpt_next_block = dev->internal_start_block;
164
165 /* Erase all the blocks in the checkpoint area */
166 if (writing) {
167 memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
168 dev->checkpt_byte_offs = 0;
169 return yaffs_checkpt_erase(dev);
170 } else {
171 int i;
172 /* Set to a value that will kick off a read */
173 dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
174 /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
175 * going to be way more than we need */
176 dev->blocks_in_checkpt = 0;
177 dev->checkpt_max_blocks =
178 (dev->internal_end_block - dev->internal_start_block) / 16 +
179 2;
180 dev->checkpt_block_list =
181 kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
182 if (!dev->checkpt_block_list)
183 return 0;
184
185 for (i = 0; i < dev->checkpt_max_blocks; i++)
186 dev->checkpt_block_list[i] = -1;
187 }
188
189 return 1;
190}
191
192int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
193{
194 u32 composite_sum;
195 composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF);
196 *sum = composite_sum;
197 return 1;
198}
199
200static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
201{
202 int chunk;
203 int realigned_chunk;
204
205 struct yaffs_ext_tags tags;
206
207 if (dev->checkpt_cur_block < 0) {
208 yaffs2_checkpt_find_erased_block(dev);
209 dev->checkpt_cur_chunk = 0;
210 }
211
212 if (dev->checkpt_cur_block < 0)
213 return 0;
214
215 tags.is_deleted = 0;
216 tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
217 tags.chunk_id = dev->checkpt_page_seq + 1;
218 tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
219 tags.n_bytes = dev->data_bytes_per_chunk;
220 if (dev->checkpt_cur_chunk == 0) {
221 /* First chunk we write for the block? Set block state to
222 checkpoint */
223 struct yaffs_block_info *bi =
224 yaffs_get_block_info(dev, dev->checkpt_cur_block);
225 bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
226 dev->blocks_in_checkpt++;
227 }
228
229 chunk =
230 dev->checkpt_cur_block * dev->param.chunks_per_block +
231 dev->checkpt_cur_chunk;
232
233 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
234 "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
235 chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
236 tags.obj_id, tags.chunk_id);
237
238 realigned_chunk = chunk - dev->chunk_offset;
239
240 dev->n_page_writes++;
241
242 dev->param.write_chunk_tags_fn(dev, realigned_chunk,
243 dev->checkpt_buffer, &tags);
244 dev->checkpt_byte_offs = 0;
245 dev->checkpt_page_seq++;
246 dev->checkpt_cur_chunk++;
247 if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
248 dev->checkpt_cur_chunk = 0;
249 dev->checkpt_cur_block = -1;
250 }
251 memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
252
253 return 1;
254}
255
256int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
257{
258 int i = 0;
259 int ok = 1;
260
261 u8 *data_bytes = (u8 *) data;
262
263 if (!dev->checkpt_buffer)
264 return 0;
265
266 if (!dev->checkpt_open_write)
267 return -1;
268
269 while (i < n_bytes && ok) {
270 dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
271 dev->checkpt_sum += *data_bytes;
272 dev->checkpt_xor ^= *data_bytes;
273
274 dev->checkpt_byte_offs++;
275 i++;
276 data_bytes++;
277 dev->checkpt_byte_count++;
278
279 if (dev->checkpt_byte_offs < 0 ||
280 dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
281 ok = yaffs2_checkpt_flush_buffer(dev);
282 }
283
284 return i;
285}
286
287int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
288{
289 int i = 0;
290 int ok = 1;
291 struct yaffs_ext_tags tags;
292
293 int chunk;
294 int realigned_chunk;
295
296 u8 *data_bytes = (u8 *) data;
297
298 if (!dev->checkpt_buffer)
299 return 0;
300
301 if (dev->checkpt_open_write)
302 return -1;
303
304 while (i < n_bytes && ok) {
305
306 if (dev->checkpt_byte_offs < 0 ||
307 dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
308
309 if (dev->checkpt_cur_block < 0) {
310 yaffs2_checkpt_find_block(dev);
311 dev->checkpt_cur_chunk = 0;
312 }
313
314 if (dev->checkpt_cur_block < 0)
315 ok = 0;
316 else {
317 chunk = dev->checkpt_cur_block *
318 dev->param.chunks_per_block +
319 dev->checkpt_cur_chunk;
320
321 realigned_chunk = chunk - dev->chunk_offset;
322
323 dev->n_page_reads++;
324
325 /* read in the next chunk */
326 dev->param.read_chunk_tags_fn(dev,
327 realigned_chunk,
328 dev->
329 checkpt_buffer,
330 &tags);
331
332 if (tags.chunk_id != (dev->checkpt_page_seq + 1)
333 || tags.ecc_result > YAFFS_ECC_RESULT_FIXED
334 || tags.seq_number !=
335 YAFFS_SEQUENCE_CHECKPOINT_DATA)
336 ok = 0;
337
338 dev->checkpt_byte_offs = 0;
339 dev->checkpt_page_seq++;
340 dev->checkpt_cur_chunk++;
341
342 if (dev->checkpt_cur_chunk >=
343 dev->param.chunks_per_block)
344 dev->checkpt_cur_block = -1;
345 }
346 }
347
348 if (ok) {
349 *data_bytes =
350 dev->checkpt_buffer[dev->checkpt_byte_offs];
351 dev->checkpt_sum += *data_bytes;
352 dev->checkpt_xor ^= *data_bytes;
353 dev->checkpt_byte_offs++;
354 i++;
355 data_bytes++;
356 dev->checkpt_byte_count++;
357 }
358 }
359
360 return i;
361}
362
363int yaffs_checkpt_close(struct yaffs_dev *dev)
364{
365
366 if (dev->checkpt_open_write) {
367 if (dev->checkpt_byte_offs != 0)
368 yaffs2_checkpt_flush_buffer(dev);
369 } else if (dev->checkpt_block_list) {
370 int i;
371 for (i = 0;
372 i < dev->blocks_in_checkpt
373 && dev->checkpt_block_list[i] >= 0; i++) {
374 int blk = dev->checkpt_block_list[i];
375 struct yaffs_block_info *bi = NULL;
376 if (dev->internal_start_block <= blk
377 && blk <= dev->internal_end_block)
378 bi = yaffs_get_block_info(dev, blk);
379 if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
380 bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
381 else {
382 /* Todo this looks odd... */
383 }
384 }
385 kfree(dev->checkpt_block_list);
386 dev->checkpt_block_list = NULL;
387 }
388
389 dev->n_free_chunks -=
390 dev->blocks_in_checkpt * dev->param.chunks_per_block;
391 dev->n_erased_blocks -= dev->blocks_in_checkpt;
392
393 yaffs_trace(YAFFS_TRACE_CHECKPOINT,"checkpoint byte count %d",
394 dev->checkpt_byte_count);
395
396 if (dev->checkpt_buffer) {
397 /* free the buffer */
398 kfree(dev->checkpt_buffer);
399 dev->checkpt_buffer = NULL;
400 return 1;
401 } else {
402 return 0;
403 }
404}
405
406int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
407{
408 /* Erase the checkpoint data */
409
410 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
411 "checkpoint invalidate of %d blocks",
412 dev->blocks_in_checkpt);
413
414 return yaffs_checkpt_erase(dev);
415}
diff --git a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h
new file mode 100644
index 00000000000..361c6067717
--- /dev/null
+++ b/fs/yaffs2/yaffs_checkptrw.h
@@ -0,0 +1,33 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_CHECKPTRW_H__
17#define __YAFFS_CHECKPTRW_H__
18
19#include "yaffs_guts.h"
20
21int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
22
23int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
24
25int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
26
27int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
28
29int yaffs_checkpt_close(struct yaffs_dev *dev);
30
31int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
32
33#endif
diff --git a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c
new file mode 100644
index 00000000000..e95a8069a8c
--- /dev/null
+++ b/fs/yaffs2/yaffs_ecc.c
@@ -0,0 +1,298 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14/*
15 * This code implements the ECC algorithm used in SmartMedia.
16 *
17 * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
18 * The two unused bit are set to 1.
19 * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
20 * blocks are used on a 512-byte NAND page.
21 *
22 */
23
24/* Table generated by gen-ecc.c
25 * Using a table means we do not have to calculate p1..p4 and p1'..p4'
26 * for each byte of data. These are instead provided in a table in bits7..2.
27 * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
28 * this bytes influence on the line parity.
29 */
30
31#include "yportenv.h"
32
33#include "yaffs_ecc.h"
34
35static const unsigned char column_parity_table[] = {
36 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
37 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
38 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
39 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
40 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
41 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
42 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
43 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
44 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
45 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
46 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
47 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
48 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
49 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
50 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
51 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
52 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
53 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
54 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
55 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
56 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
57 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
58 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
59 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
60 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
61 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
62 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
63 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
64 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
65 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
66 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
67 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
68};
69
70
71/* Calculate the ECC for a 256-byte block of data */
72void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc)
73{
74 unsigned int i;
75
76 unsigned char col_parity = 0;
77 unsigned char line_parity = 0;
78 unsigned char line_parity_prime = 0;
79 unsigned char t;
80 unsigned char b;
81
82 for (i = 0; i < 256; i++) {
83 b = column_parity_table[*data++];
84 col_parity ^= b;
85
86 if (b & 0x01) { /* odd number of bits in the byte */
87 line_parity ^= i;
88 line_parity_prime ^= ~i;
89 }
90 }
91
92 ecc[2] = (~col_parity) | 0x03;
93
94 t = 0;
95 if (line_parity & 0x80)
96 t |= 0x80;
97 if (line_parity_prime & 0x80)
98 t |= 0x40;
99 if (line_parity & 0x40)
100 t |= 0x20;
101 if (line_parity_prime & 0x40)
102 t |= 0x10;
103 if (line_parity & 0x20)
104 t |= 0x08;
105 if (line_parity_prime & 0x20)
106 t |= 0x04;
107 if (line_parity & 0x10)
108 t |= 0x02;
109 if (line_parity_prime & 0x10)
110 t |= 0x01;
111 ecc[1] = ~t;
112
113 t = 0;
114 if (line_parity & 0x08)
115 t |= 0x80;
116 if (line_parity_prime & 0x08)
117 t |= 0x40;
118 if (line_parity & 0x04)
119 t |= 0x20;
120 if (line_parity_prime & 0x04)
121 t |= 0x10;
122 if (line_parity & 0x02)
123 t |= 0x08;
124 if (line_parity_prime & 0x02)
125 t |= 0x04;
126 if (line_parity & 0x01)
127 t |= 0x02;
128 if (line_parity_prime & 0x01)
129 t |= 0x01;
130 ecc[0] = ~t;
131
132#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
133 /* Swap the bytes into the wrong order */
134 t = ecc[0];
135 ecc[0] = ecc[1];
136 ecc[1] = t;
137#endif
138}
139
140/* Correct the ECC on a 256 byte block of data */
141
142int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
143 const unsigned char *test_ecc)
144{
145 unsigned char d0, d1, d2; /* deltas */
146
147 d0 = read_ecc[0] ^ test_ecc[0];
148 d1 = read_ecc[1] ^ test_ecc[1];
149 d2 = read_ecc[2] ^ test_ecc[2];
150
151 if ((d0 | d1 | d2) == 0)
152 return 0; /* no error */
153
154 if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
155 ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
156 ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
157 /* Single bit (recoverable) error in data */
158
159 unsigned byte;
160 unsigned bit;
161
162#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
163 /* swap the bytes to correct for the wrong order */
164 unsigned char t;
165
166 t = d0;
167 d0 = d1;
168 d1 = t;
169#endif
170
171 bit = byte = 0;
172
173 if (d1 & 0x80)
174 byte |= 0x80;
175 if (d1 & 0x20)
176 byte |= 0x40;
177 if (d1 & 0x08)
178 byte |= 0x20;
179 if (d1 & 0x02)
180 byte |= 0x10;
181 if (d0 & 0x80)
182 byte |= 0x08;
183 if (d0 & 0x20)
184 byte |= 0x04;
185 if (d0 & 0x08)
186 byte |= 0x02;
187 if (d0 & 0x02)
188 byte |= 0x01;
189
190 if (d2 & 0x80)
191 bit |= 0x04;
192 if (d2 & 0x20)
193 bit |= 0x02;
194 if (d2 & 0x08)
195 bit |= 0x01;
196
197 data[byte] ^= (1 << bit);
198
199 return 1; /* Corrected the error */
200 }
201
202 if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
203 /* Reccoverable error in ecc */
204
205 read_ecc[0] = test_ecc[0];
206 read_ecc[1] = test_ecc[1];
207 read_ecc[2] = test_ecc[2];
208
209 return 1; /* Corrected the error */
210 }
211
212 /* Unrecoverable error */
213
214 return -1;
215
216}
217
218/*
219 * ECCxxxOther does ECC calcs on arbitrary n bytes of data
220 */
221void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
222 struct yaffs_ecc_other *ecc_other)
223{
224 unsigned int i;
225
226 unsigned char col_parity = 0;
227 unsigned line_parity = 0;
228 unsigned line_parity_prime = 0;
229 unsigned char b;
230
231 for (i = 0; i < n_bytes; i++) {
232 b = column_parity_table[*data++];
233 col_parity ^= b;
234
235 if (b & 0x01) {
236 /* odd number of bits in the byte */
237 line_parity ^= i;
238 line_parity_prime ^= ~i;
239 }
240
241 }
242
243 ecc_other->col_parity = (col_parity >> 2) & 0x3f;
244 ecc_other->line_parity = line_parity;
245 ecc_other->line_parity_prime = line_parity_prime;
246}
247
248int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
249 struct yaffs_ecc_other *read_ecc,
250 const struct yaffs_ecc_other *test_ecc)
251{
252 unsigned char delta_col; /* column parity delta */
253 unsigned delta_line; /* line parity delta */
254 unsigned delta_line_prime; /* line parity delta */
255 unsigned bit;
256
257 delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
258 delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
259 delta_line_prime =
260 read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
261
262 if ((delta_col | delta_line | delta_line_prime) == 0)
263 return 0; /* no error */
264
265 if (delta_line == ~delta_line_prime &&
266 (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
267 /* Single bit (recoverable) error in data */
268
269 bit = 0;
270
271 if (delta_col & 0x20)
272 bit |= 0x04;
273 if (delta_col & 0x08)
274 bit |= 0x02;
275 if (delta_col & 0x02)
276 bit |= 0x01;
277
278 if (delta_line >= n_bytes)
279 return -1;
280
281 data[delta_line] ^= (1 << bit);
282
283 return 1; /* corrected */
284 }
285
286 if ((hweight32(delta_line) +
287 hweight32(delta_line_prime) +
288 hweight8(delta_col)) == 1) {
289 /* Reccoverable error in ecc */
290
291 *read_ecc = *test_ecc;
292 return 1; /* corrected */
293 }
294
295 /* Unrecoverable error */
296
297 return -1;
298}
diff --git a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h
new file mode 100644
index 00000000000..b0c461d699e
--- /dev/null
+++ b/fs/yaffs2/yaffs_ecc.h
@@ -0,0 +1,44 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16/*
17 * This code implements the ECC algorithm used in SmartMedia.
18 *
19 * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
20 * The two unused bit are set to 1.
21 * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
22 * blocks are used on a 512-byte NAND page.
23 *
24 */
25
26#ifndef __YAFFS_ECC_H__
27#define __YAFFS_ECC_H__
28
29struct yaffs_ecc_other {
30 unsigned char col_parity;
31 unsigned line_parity;
32 unsigned line_parity_prime;
33};
34
35void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc);
36int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
37 const unsigned char *test_ecc);
38
39void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
40 struct yaffs_ecc_other *ecc);
41int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
42 struct yaffs_ecc_other *read_ecc,
43 const struct yaffs_ecc_other *test_ecc);
44#endif
diff --git a/fs/yaffs2/yaffs_getblockinfo.h b/fs/yaffs2/yaffs_getblockinfo.h
new file mode 100644
index 00000000000..d87acbde997
--- /dev/null
+++ b/fs/yaffs2/yaffs_getblockinfo.h
@@ -0,0 +1,35 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_GETBLOCKINFO_H__
17#define __YAFFS_GETBLOCKINFO_H__
18
19#include "yaffs_guts.h"
20#include "yaffs_trace.h"
21
22/* Function to manipulate block info */
23static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
24 *dev, int blk)
25{
26 if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
27 yaffs_trace(YAFFS_TRACE_ERROR,
28 "**>> yaffs: get_block_info block %d is not valid",
29 blk);
30 YBUG();
31 }
32 return &dev->block_info[blk - dev->internal_start_block];
33}
34
35#endif
diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
new file mode 100644
index 00000000000..f4ae9deed72
--- /dev/null
+++ b/fs/yaffs2/yaffs_guts.c
@@ -0,0 +1,5164 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yportenv.h"
15#include "yaffs_trace.h"
16
17#include "yaffs_guts.h"
18#include "yaffs_tagsvalidity.h"
19#include "yaffs_getblockinfo.h"
20
21#include "yaffs_tagscompat.h"
22
23#include "yaffs_nand.h"
24
25#include "yaffs_yaffs1.h"
26#include "yaffs_yaffs2.h"
27#include "yaffs_bitmap.h"
28#include "yaffs_verify.h"
29
30#include "yaffs_nand.h"
31#include "yaffs_packedtags2.h"
32
33#include "yaffs_nameval.h"
34#include "yaffs_allocator.h"
35
36#include "yaffs_attribs.h"
37
38/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
39#define YAFFS_GC_GOOD_ENOUGH 2
40#define YAFFS_GC_PASSIVE_THRESHOLD 4
41
42#include "yaffs_ecc.h"
43
44/* Forward declarations */
45
46static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
47 const u8 * buffer, int n_bytes, int use_reserve);
48
49
50
51/* Function to calculate chunk and offset */
52
53static void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
54 int *chunk_out, u32 * offset_out)
55{
56 int chunk;
57 u32 offset;
58
59 chunk = (u32) (addr >> dev->chunk_shift);
60
61 if (dev->chunk_div == 1) {
62 /* easy power of 2 case */
63 offset = (u32) (addr & dev->chunk_mask);
64 } else {
65 /* Non power-of-2 case */
66
67 loff_t chunk_base;
68
69 chunk /= dev->chunk_div;
70
71 chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
72 offset = (u32) (addr - chunk_base);
73 }
74
75 *chunk_out = chunk;
76 *offset_out = offset;
77}
78
79/* Function to return the number of shifts for a power of 2 greater than or
80 * equal to the given number
81 * Note we don't try to cater for all possible numbers and this does not have to
82 * be hellishly efficient.
83 */
84
85static u32 calc_shifts_ceiling(u32 x)
86{
87 int extra_bits;
88 int shifts;
89
90 shifts = extra_bits = 0;
91
92 while (x > 1) {
93 if (x & 1)
94 extra_bits++;
95 x >>= 1;
96 shifts++;
97 }
98
99 if (extra_bits)
100 shifts++;
101
102 return shifts;
103}
104
105/* Function to return the number of shifts to get a 1 in bit 0
106 */
107
108static u32 calc_shifts(u32 x)
109{
110 u32 shifts;
111
112 shifts = 0;
113
114 if (!x)
115 return 0;
116
117 while (!(x & 1)) {
118 x >>= 1;
119 shifts++;
120 }
121
122 return shifts;
123}
124
125/*
126 * Temporary buffer manipulations.
127 */
128
129static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
130{
131 int i;
132 u8 *buf = (u8 *) 1;
133
134 memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
135
136 for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
137 dev->temp_buffer[i].line = 0; /* not in use */
138 dev->temp_buffer[i].buffer = buf =
139 kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
140 }
141
142 return buf ? YAFFS_OK : YAFFS_FAIL;
143}
144
145u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev, int line_no)
146{
147 int i, j;
148
149 dev->temp_in_use++;
150 if (dev->temp_in_use > dev->max_temp)
151 dev->max_temp = dev->temp_in_use;
152
153 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
154 if (dev->temp_buffer[i].line == 0) {
155 dev->temp_buffer[i].line = line_no;
156 if ((i + 1) > dev->max_temp) {
157 dev->max_temp = i + 1;
158 for (j = 0; j <= i; j++)
159 dev->temp_buffer[j].max_line =
160 dev->temp_buffer[j].line;
161 }
162
163 return dev->temp_buffer[i].buffer;
164 }
165 }
166
167 yaffs_trace(YAFFS_TRACE_BUFFERS,
168 "Out of temp buffers at line %d, other held by lines:",
169 line_no);
170 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
171 yaffs_trace(YAFFS_TRACE_BUFFERS," %d", dev->temp_buffer[i].line);
172
173 /*
174 * If we got here then we have to allocate an unmanaged one
175 * This is not good.
176 */
177
178 dev->unmanaged_buffer_allocs++;
179 return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
180
181}
182
183void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 * buffer, int line_no)
184{
185 int i;
186
187 dev->temp_in_use--;
188
189 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
190 if (dev->temp_buffer[i].buffer == buffer) {
191 dev->temp_buffer[i].line = 0;
192 return;
193 }
194 }
195
196 if (buffer) {
197 /* assume it is an unmanaged one. */
198 yaffs_trace(YAFFS_TRACE_BUFFERS,
199 "Releasing unmanaged temp buffer in line %d",
200 line_no);
201 kfree(buffer);
202 dev->unmanaged_buffer_deallocs++;
203 }
204
205}
206
207/*
208 * Determine if we have a managed buffer.
209 */
210int yaffs_is_managed_tmp_buffer(struct yaffs_dev *dev, const u8 * buffer)
211{
212 int i;
213
214 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
215 if (dev->temp_buffer[i].buffer == buffer)
216 return 1;
217 }
218
219 for (i = 0; i < dev->param.n_caches; i++) {
220 if (dev->cache[i].data == buffer)
221 return 1;
222 }
223
224 if (buffer == dev->checkpt_buffer)
225 return 1;
226
227 yaffs_trace(YAFFS_TRACE_ALWAYS,
228 "yaffs: unmaged buffer detected.");
229 return 0;
230}
231
232/*
233 * Functions for robustisizing TODO
234 *
235 */
236
237static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
238 const u8 * data,
239 const struct yaffs_ext_tags *tags)
240{
241 dev = dev;
242 nand_chunk = nand_chunk;
243 data = data;
244 tags = tags;
245}
246
247static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
248 const struct yaffs_ext_tags *tags)
249{
250 dev = dev;
251 nand_chunk = nand_chunk;
252 tags = tags;
253}
254
255void yaffs_handle_chunk_error(struct yaffs_dev *dev,
256 struct yaffs_block_info *bi)
257{
258 if (!bi->gc_prioritise) {
259 bi->gc_prioritise = 1;
260 dev->has_pending_prioritised_gc = 1;
261 bi->chunk_error_strikes++;
262
263 if (bi->chunk_error_strikes > 3) {
264 bi->needs_retiring = 1; /* Too many stikes, so retire this */
265 yaffs_trace(YAFFS_TRACE_ALWAYS, "yaffs: Block struck out");
266
267 }
268 }
269}
270
271static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
272 int erased_ok)
273{
274 int flash_block = nand_chunk / dev->param.chunks_per_block;
275 struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
276
277 yaffs_handle_chunk_error(dev, bi);
278
279 if (erased_ok) {
280 /* Was an actual write failure, so mark the block for retirement */
281 bi->needs_retiring = 1;
282 yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
283 "**>> Block %d needs retiring", flash_block);
284 }
285
286 /* Delete the chunk */
287 yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
288 yaffs_skip_rest_of_block(dev);
289}
290
291/*
292 * Verification code
293 */
294
295/*
296 * Simple hash function. Needs to have a reasonable spread
297 */
298
299static inline int yaffs_hash_fn(int n)
300{
301 n = abs(n);
302 return n % YAFFS_NOBJECT_BUCKETS;
303}
304
305/*
306 * Access functions to useful fake objects.
307 * Note that root might have a presence in NAND if permissions are set.
308 */
309
310struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
311{
312 return dev->root_dir;
313}
314
315struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
316{
317 return dev->lost_n_found;
318}
319
320/*
321 * Erased NAND checking functions
322 */
323
324int yaffs_check_ff(u8 * buffer, int n_bytes)
325{
326 /* Horrible, slow implementation */
327 while (n_bytes--) {
328 if (*buffer != 0xFF)
329 return 0;
330 buffer++;
331 }
332 return 1;
333}
334
335static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
336{
337 int retval = YAFFS_OK;
338 u8 *data = yaffs_get_temp_buffer(dev, __LINE__);
339 struct yaffs_ext_tags tags;
340 int result;
341
342 result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
343
344 if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
345 retval = YAFFS_FAIL;
346
347 if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
348 tags.chunk_used) {
349 yaffs_trace(YAFFS_TRACE_NANDACCESS, "Chunk %d not erased", nand_chunk);
350 retval = YAFFS_FAIL;
351 }
352
353 yaffs_release_temp_buffer(dev, data, __LINE__);
354
355 return retval;
356
357}
358
359static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
360 int nand_chunk,
361 const u8 * data,
362 struct yaffs_ext_tags *tags)
363{
364 int retval = YAFFS_OK;
365 struct yaffs_ext_tags temp_tags;
366 u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
367 int result;
368
369 result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
370 if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
371 temp_tags.obj_id != tags->obj_id ||
372 temp_tags.chunk_id != tags->chunk_id ||
373 temp_tags.n_bytes != tags->n_bytes)
374 retval = YAFFS_FAIL;
375
376 yaffs_release_temp_buffer(dev, buffer, __LINE__);
377
378 return retval;
379}
380
381
382int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
383{
384 int reserved_chunks;
385 int reserved_blocks = dev->param.n_reserved_blocks;
386 int checkpt_blocks;
387
388 checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
389
390 reserved_chunks =
391 ((reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block);
392
393 return (dev->n_free_chunks > (reserved_chunks + n_chunks));
394}
395
396static int yaffs_find_alloc_block(struct yaffs_dev *dev)
397{
398 int i;
399
400 struct yaffs_block_info *bi;
401
402 if (dev->n_erased_blocks < 1) {
403 /* Hoosterman we've got a problem.
404 * Can't get space to gc
405 */
406 yaffs_trace(YAFFS_TRACE_ERROR,
407 "yaffs tragedy: no more erased blocks" );
408
409 return -1;
410 }
411
412 /* Find an empty block. */
413
414 for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
415 dev->alloc_block_finder++;
416 if (dev->alloc_block_finder < dev->internal_start_block
417 || dev->alloc_block_finder > dev->internal_end_block) {
418 dev->alloc_block_finder = dev->internal_start_block;
419 }
420
421 bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
422
423 if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
424 bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
425 dev->seq_number++;
426 bi->seq_number = dev->seq_number;
427 dev->n_erased_blocks--;
428 yaffs_trace(YAFFS_TRACE_ALLOCATE,
429 "Allocated block %d, seq %d, %d left" ,
430 dev->alloc_block_finder, dev->seq_number,
431 dev->n_erased_blocks);
432 return dev->alloc_block_finder;
433 }
434 }
435
436 yaffs_trace(YAFFS_TRACE_ALWAYS,
437 "yaffs tragedy: no more erased blocks, but there should have been %d",
438 dev->n_erased_blocks);
439
440 return -1;
441}
442
443static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
444 struct yaffs_block_info **block_ptr)
445{
446 int ret_val;
447 struct yaffs_block_info *bi;
448
449 if (dev->alloc_block < 0) {
450 /* Get next block to allocate off */
451 dev->alloc_block = yaffs_find_alloc_block(dev);
452 dev->alloc_page = 0;
453 }
454
455 if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
456 /* Not enough space to allocate unless we're allowed to use the reserve. */
457 return -1;
458 }
459
460 if (dev->n_erased_blocks < dev->param.n_reserved_blocks
461 && dev->alloc_page == 0)
462 yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
463
464 /* Next page please.... */
465 if (dev->alloc_block >= 0) {
466 bi = yaffs_get_block_info(dev, dev->alloc_block);
467
468 ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
469 dev->alloc_page;
470 bi->pages_in_use++;
471 yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
472
473 dev->alloc_page++;
474
475 dev->n_free_chunks--;
476
477 /* If the block is full set the state to full */
478 if (dev->alloc_page >= dev->param.chunks_per_block) {
479 bi->block_state = YAFFS_BLOCK_STATE_FULL;
480 dev->alloc_block = -1;
481 }
482
483 if (block_ptr)
484 *block_ptr = bi;
485
486 return ret_val;
487 }
488
489 yaffs_trace(YAFFS_TRACE_ERROR, "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" );
490
491 return -1;
492}
493
494static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
495{
496 int n;
497
498 n = dev->n_erased_blocks * dev->param.chunks_per_block;
499
500 if (dev->alloc_block > 0)
501 n += (dev->param.chunks_per_block - dev->alloc_page);
502
503 return n;
504
505}
506
507/*
508 * yaffs_skip_rest_of_block() skips over the rest of the allocation block
509 * if we don't want to write to it.
510 */
511void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
512{
513 if (dev->alloc_block > 0) {
514 struct yaffs_block_info *bi =
515 yaffs_get_block_info(dev, dev->alloc_block);
516 if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
517 bi->block_state = YAFFS_BLOCK_STATE_FULL;
518 dev->alloc_block = -1;
519 }
520 }
521}
522
523static int yaffs_write_new_chunk(struct yaffs_dev *dev,
524 const u8 * data,
525 struct yaffs_ext_tags *tags, int use_reserver)
526{
527 int attempts = 0;
528 int write_ok = 0;
529 int chunk;
530
531 yaffs2_checkpt_invalidate(dev);
532
533 do {
534 struct yaffs_block_info *bi = 0;
535 int erased_ok = 0;
536
537 chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
538 if (chunk < 0) {
539 /* no space */
540 break;
541 }
542
543 /* First check this chunk is erased, if it needs
544 * checking. The checking policy (unless forced
545 * always on) is as follows:
546 *
547 * Check the first page we try to write in a block.
548 * If the check passes then we don't need to check any
549 * more. If the check fails, we check again...
550 * If the block has been erased, we don't need to check.
551 *
552 * However, if the block has been prioritised for gc,
553 * then we think there might be something odd about
554 * this block and stop using it.
555 *
556 * Rationale: We should only ever see chunks that have
557 * not been erased if there was a partially written
558 * chunk due to power loss. This checking policy should
559 * catch that case with very few checks and thus save a
560 * lot of checks that are most likely not needed.
561 *
562 * Mods to the above
563 * If an erase check fails or the write fails we skip the
564 * rest of the block.
565 */
566
567 /* let's give it a try */
568 attempts++;
569
570 if (dev->param.always_check_erased)
571 bi->skip_erased_check = 0;
572
573 if (!bi->skip_erased_check) {
574 erased_ok = yaffs_check_chunk_erased(dev, chunk);
575 if (erased_ok != YAFFS_OK) {
576 yaffs_trace(YAFFS_TRACE_ERROR,
577 "**>> yaffs chunk %d was not erased",
578 chunk);
579
580 /* If not erased, delete this one,
581 * skip rest of block and
582 * try another chunk */
583 yaffs_chunk_del(dev, chunk, 1, __LINE__);
584 yaffs_skip_rest_of_block(dev);
585 continue;
586 }
587 }
588
589 write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
590
591 if (!bi->skip_erased_check)
592 write_ok =
593 yaffs_verify_chunk_written(dev, chunk, data, tags);
594
595 if (write_ok != YAFFS_OK) {
596 /* Clean up aborted write, skip to next block and
597 * try another chunk */
598 yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
599 continue;
600 }
601
602 bi->skip_erased_check = 1;
603
604 /* Copy the data into the robustification buffer */
605 yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
606
607 } while (write_ok != YAFFS_OK &&
608 (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
609
610 if (!write_ok)
611 chunk = -1;
612
613 if (attempts > 1) {
614 yaffs_trace(YAFFS_TRACE_ERROR,
615 "**>> yaffs write required %d attempts",
616 attempts);
617 dev->n_retired_writes += (attempts - 1);
618 }
619
620 return chunk;
621}
622
623/*
624 * Block retiring for handling a broken block.
625 */
626
627static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
628{
629 struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
630
631 yaffs2_checkpt_invalidate(dev);
632
633 yaffs2_clear_oldest_dirty_seq(dev, bi);
634
635 if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
636 if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
637 yaffs_trace(YAFFS_TRACE_ALWAYS,
638 "yaffs: Failed to mark bad and erase block %d",
639 flash_block);
640 } else {
641 struct yaffs_ext_tags tags;
642 int chunk_id =
643 flash_block * dev->param.chunks_per_block;
644
645 u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
646
647 memset(buffer, 0xff, dev->data_bytes_per_chunk);
648 yaffs_init_tags(&tags);
649 tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
650 if (dev->param.write_chunk_tags_fn(dev, chunk_id -
651 dev->chunk_offset,
652 buffer,
653 &tags) != YAFFS_OK)
654 yaffs_trace(YAFFS_TRACE_ALWAYS,
655 "yaffs: Failed to write bad block marker to block %d",
656 flash_block);
657
658 yaffs_release_temp_buffer(dev, buffer, __LINE__);
659 }
660 }
661
662 bi->block_state = YAFFS_BLOCK_STATE_DEAD;
663 bi->gc_prioritise = 0;
664 bi->needs_retiring = 0;
665
666 dev->n_retired_blocks++;
667}
668
669/*---------------- Name handling functions ------------*/
670
671static u16 yaffs_calc_name_sum(const YCHAR * name)
672{
673 u16 sum = 0;
674 u16 i = 1;
675
676 const YUCHAR *bname = (const YUCHAR *)name;
677 if (bname) {
678 while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH / 2))) {
679
680 /* 0x1f mask is case insensitive */
681 sum += ((*bname) & 0x1f) * i;
682 i++;
683 bname++;
684 }
685 }
686 return sum;
687}
688
689void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
690{
691#ifndef CONFIG_YAFFS_NO_SHORT_NAMES
692 memset(obj->short_name, 0, sizeof(obj->short_name));
693 if (name &&
694 strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
695 YAFFS_SHORT_NAME_LENGTH)
696 strcpy(obj->short_name, name);
697 else
698 obj->short_name[0] = _Y('\0');
699#endif
700 obj->sum = yaffs_calc_name_sum(name);
701}
702
703void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
704 const struct yaffs_obj_hdr *oh)
705{
706#ifdef CONFIG_YAFFS_AUTO_UNICODE
707 YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
708 memset(tmp_name, 0, sizeof(tmp_name));
709 yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
710 YAFFS_MAX_NAME_LENGTH + 1);
711 yaffs_set_obj_name(obj, tmp_name);
712#else
713 yaffs_set_obj_name(obj, oh->name);
714#endif
715}
716
717/*-------------------- TNODES -------------------
718
719 * List of spare tnodes
720 * The list is hooked together using the first pointer
721 * in the tnode.
722 */
723
724struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
725{
726 struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
727 if (tn) {
728 memset(tn, 0, dev->tnode_size);
729 dev->n_tnodes++;
730 }
731
732 dev->checkpoint_blocks_required = 0; /* force recalculation */
733
734 return tn;
735}
736
737/* FreeTnode frees up a tnode and puts it back on the free list */
738static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
739{
740 yaffs_free_raw_tnode(dev, tn);
741 dev->n_tnodes--;
742 dev->checkpoint_blocks_required = 0; /* force recalculation */
743}
744
745static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
746{
747 yaffs_deinit_raw_tnodes_and_objs(dev);
748 dev->n_obj = 0;
749 dev->n_tnodes = 0;
750}
751
752void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
753 unsigned pos, unsigned val)
754{
755 u32 *map = (u32 *) tn;
756 u32 bit_in_map;
757 u32 bit_in_word;
758 u32 word_in_map;
759 u32 mask;
760
761 pos &= YAFFS_TNODES_LEVEL0_MASK;
762 val >>= dev->chunk_grp_bits;
763
764 bit_in_map = pos * dev->tnode_width;
765 word_in_map = bit_in_map / 32;
766 bit_in_word = bit_in_map & (32 - 1);
767
768 mask = dev->tnode_mask << bit_in_word;
769
770 map[word_in_map] &= ~mask;
771 map[word_in_map] |= (mask & (val << bit_in_word));
772
773 if (dev->tnode_width > (32 - bit_in_word)) {
774 bit_in_word = (32 - bit_in_word);
775 word_in_map++;;
776 mask =
777 dev->tnode_mask >> ( /*dev->tnode_width - */ bit_in_word);
778 map[word_in_map] &= ~mask;
779 map[word_in_map] |= (mask & (val >> bit_in_word));
780 }
781}
782
783u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
784 unsigned pos)
785{
786 u32 *map = (u32 *) tn;
787 u32 bit_in_map;
788 u32 bit_in_word;
789 u32 word_in_map;
790 u32 val;
791
792 pos &= YAFFS_TNODES_LEVEL0_MASK;
793
794 bit_in_map = pos * dev->tnode_width;
795 word_in_map = bit_in_map / 32;
796 bit_in_word = bit_in_map & (32 - 1);
797
798 val = map[word_in_map] >> bit_in_word;
799
800 if (dev->tnode_width > (32 - bit_in_word)) {
801 bit_in_word = (32 - bit_in_word);
802 word_in_map++;;
803 val |= (map[word_in_map] << bit_in_word);
804 }
805
806 val &= dev->tnode_mask;
807 val <<= dev->chunk_grp_bits;
808
809 return val;
810}
811
812/* ------------------- End of individual tnode manipulation -----------------*/
813
814/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
815 * The look up tree is represented by the top tnode and the number of top_level
816 * in the tree. 0 means only the level 0 tnode is in the tree.
817 */
818
819/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
820struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
821 struct yaffs_file_var *file_struct,
822 u32 chunk_id)
823{
824 struct yaffs_tnode *tn = file_struct->top;
825 u32 i;
826 int required_depth;
827 int level = file_struct->top_level;
828
829 dev = dev;
830
831 /* Check sane level and chunk Id */
832 if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
833 return NULL;
834
835 if (chunk_id > YAFFS_MAX_CHUNK_ID)
836 return NULL;
837
838 /* First check we're tall enough (ie enough top_level) */
839
840 i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
841 required_depth = 0;
842 while (i) {
843 i >>= YAFFS_TNODES_INTERNAL_BITS;
844 required_depth++;
845 }
846
847 if (required_depth > file_struct->top_level)
848 return NULL; /* Not tall enough, so we can't find it */
849
850 /* Traverse down to level 0 */
851 while (level > 0 && tn) {
852 tn = tn->internal[(chunk_id >>
853 (YAFFS_TNODES_LEVEL0_BITS +
854 (level - 1) *
855 YAFFS_TNODES_INTERNAL_BITS)) &
856 YAFFS_TNODES_INTERNAL_MASK];
857 level--;
858 }
859
860 return tn;
861}
862
863/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
864 * This happens in two steps:
865 * 1. If the tree isn't tall enough, then make it taller.
866 * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
867 *
868 * Used when modifying the tree.
869 *
870 * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
871 * be plugged into the ttree.
872 */
873
874struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
875 struct yaffs_file_var *file_struct,
876 u32 chunk_id,
877 struct yaffs_tnode *passed_tn)
878{
879 int required_depth;
880 int i;
881 int l;
882 struct yaffs_tnode *tn;
883
884 u32 x;
885
886 /* Check sane level and page Id */
887 if (file_struct->top_level < 0
888 || file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
889 return NULL;
890
891 if (chunk_id > YAFFS_MAX_CHUNK_ID)
892 return NULL;
893
894 /* First check we're tall enough (ie enough top_level) */
895
896 x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
897 required_depth = 0;
898 while (x) {
899 x >>= YAFFS_TNODES_INTERNAL_BITS;
900 required_depth++;
901 }
902
903 if (required_depth > file_struct->top_level) {
904 /* Not tall enough, gotta make the tree taller */
905 for (i = file_struct->top_level; i < required_depth; i++) {
906
907 tn = yaffs_get_tnode(dev);
908
909 if (tn) {
910 tn->internal[0] = file_struct->top;
911 file_struct->top = tn;
912 file_struct->top_level++;
913 } else {
914 yaffs_trace(YAFFS_TRACE_ERROR, "yaffs: no more tnodes");
915 return NULL;
916 }
917 }
918 }
919
920 /* Traverse down to level 0, adding anything we need */
921
922 l = file_struct->top_level;
923 tn = file_struct->top;
924
925 if (l > 0) {
926 while (l > 0 && tn) {
927 x = (chunk_id >>
928 (YAFFS_TNODES_LEVEL0_BITS +
929 (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
930 YAFFS_TNODES_INTERNAL_MASK;
931
932 if ((l > 1) && !tn->internal[x]) {
933 /* Add missing non-level-zero tnode */
934 tn->internal[x] = yaffs_get_tnode(dev);
935 if (!tn->internal[x])
936 return NULL;
937 } else if (l == 1) {
938 /* Looking from level 1 at level 0 */
939 if (passed_tn) {
940 /* If we already have one, then release it. */
941 if (tn->internal[x])
942 yaffs_free_tnode(dev,
943 tn->
944 internal[x]);
945 tn->internal[x] = passed_tn;
946
947 } else if (!tn->internal[x]) {
948 /* Don't have one, none passed in */
949 tn->internal[x] = yaffs_get_tnode(dev);
950 if (!tn->internal[x])
951 return NULL;
952 }
953 }
954
955 tn = tn->internal[x];
956 l--;
957 }
958 } else {
959 /* top is level 0 */
960 if (passed_tn) {
961 memcpy(tn, passed_tn,
962 (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
963 yaffs_free_tnode(dev, passed_tn);
964 }
965 }
966
967 return tn;
968}
969
970static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
971 int chunk_obj)
972{
973 return (tags->chunk_id == chunk_obj &&
974 tags->obj_id == obj_id && !tags->is_deleted) ? 1 : 0;
975
976}
977
978static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
979 struct yaffs_ext_tags *tags, int obj_id,
980 int inode_chunk)
981{
982 int j;
983
984 for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
985 if (yaffs_check_chunk_bit
986 (dev, the_chunk / dev->param.chunks_per_block,
987 the_chunk % dev->param.chunks_per_block)) {
988
989 if (dev->chunk_grp_size == 1)
990 return the_chunk;
991 else {
992 yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
993 tags);
994 if (yaffs_tags_match(tags, obj_id, inode_chunk)) {
995 /* found it; */
996 return the_chunk;
997 }
998 }
999 }
1000 the_chunk++;
1001 }
1002 return -1;
1003}
1004
1005static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
1006 struct yaffs_ext_tags *tags)
1007{
1008 /*Get the Tnode, then get the level 0 offset chunk offset */
1009 struct yaffs_tnode *tn;
1010 int the_chunk = -1;
1011 struct yaffs_ext_tags local_tags;
1012 int ret_val = -1;
1013
1014 struct yaffs_dev *dev = in->my_dev;
1015
1016 if (!tags) {
1017 /* Passed a NULL, so use our own tags space */
1018 tags = &local_tags;
1019 }
1020
1021 tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
1022
1023 if (tn) {
1024 the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
1025
1026 ret_val =
1027 yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
1028 inode_chunk);
1029 }
1030 return ret_val;
1031}
1032
1033static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
1034 struct yaffs_ext_tags *tags)
1035{
1036 /* Get the Tnode, then get the level 0 offset chunk offset */
1037 struct yaffs_tnode *tn;
1038 int the_chunk = -1;
1039 struct yaffs_ext_tags local_tags;
1040
1041 struct yaffs_dev *dev = in->my_dev;
1042 int ret_val = -1;
1043
1044 if (!tags) {
1045 /* Passed a NULL, so use our own tags space */
1046 tags = &local_tags;
1047 }
1048
1049 tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
1050
1051 if (tn) {
1052
1053 the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
1054
1055 ret_val =
1056 yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
1057 inode_chunk);
1058
1059 /* Delete the entry in the filestructure (if found) */
1060 if (ret_val != -1)
1061 yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
1062 }
1063
1064 return ret_val;
1065}
1066
1067int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
1068 int nand_chunk, int in_scan)
1069{
1070 /* NB in_scan is zero unless scanning.
1071 * For forward scanning, in_scan is > 0;
1072 * for backward scanning in_scan is < 0
1073 *
1074 * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
1075 */
1076
1077 struct yaffs_tnode *tn;
1078 struct yaffs_dev *dev = in->my_dev;
1079 int existing_cunk;
1080 struct yaffs_ext_tags existing_tags;
1081 struct yaffs_ext_tags new_tags;
1082 unsigned existing_serial, new_serial;
1083
1084 if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
1085 /* Just ignore an attempt at putting a chunk into a non-file during scanning
1086 * If it is not during Scanning then something went wrong!
1087 */
1088 if (!in_scan) {
1089 yaffs_trace(YAFFS_TRACE_ERROR,
1090 "yaffs tragedy:attempt to put data chunk into a non-file"
1091 );
1092 YBUG();
1093 }
1094
1095 yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
1096 return YAFFS_OK;
1097 }
1098
1099 tn = yaffs_add_find_tnode_0(dev,
1100 &in->variant.file_variant,
1101 inode_chunk, NULL);
1102 if (!tn)
1103 return YAFFS_FAIL;
1104
1105 if (!nand_chunk)
1106 /* Dummy insert, bail now */
1107 return YAFFS_OK;
1108
1109 existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
1110
1111 if (in_scan != 0) {
1112 /* If we're scanning then we need to test for duplicates
1113 * NB This does not need to be efficient since it should only ever
1114 * happen when the power fails during a write, then only one
1115 * chunk should ever be affected.
1116 *
1117 * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
1118 * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
1119 */
1120
1121 if (existing_cunk > 0) {
1122 /* NB Right now existing chunk will not be real chunk_id if the chunk group size > 1
1123 * thus we have to do a FindChunkInFile to get the real chunk id.
1124 *
1125 * We have a duplicate now we need to decide which one to use:
1126 *
1127 * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
1128 * Forward scanning YAFFS2: The new one is what we use, dump the old one.
1129 * YAFFS1: Get both sets of tags and compare serial numbers.
1130 */
1131
1132 if (in_scan > 0) {
1133 /* Only do this for forward scanning */
1134 yaffs_rd_chunk_tags_nand(dev,
1135 nand_chunk,
1136 NULL, &new_tags);
1137
1138 /* Do a proper find */
1139 existing_cunk =
1140 yaffs_find_chunk_in_file(in, inode_chunk,
1141 &existing_tags);
1142 }
1143
1144 if (existing_cunk <= 0) {
1145 /*Hoosterman - how did this happen? */
1146
1147 yaffs_trace(YAFFS_TRACE_ERROR,
1148 "yaffs tragedy: existing chunk < 0 in scan"
1149 );
1150
1151 }
1152
1153 /* NB The deleted flags should be false, otherwise the chunks will
1154 * not be loaded during a scan
1155 */
1156
1157 if (in_scan > 0) {
1158 new_serial = new_tags.serial_number;
1159 existing_serial = existing_tags.serial_number;
1160 }
1161
1162 if ((in_scan > 0) &&
1163 (existing_cunk <= 0 ||
1164 ((existing_serial + 1) & 3) == new_serial)) {
1165 /* Forward scanning.
1166 * Use new
1167 * Delete the old one and drop through to update the tnode
1168 */
1169 yaffs_chunk_del(dev, existing_cunk, 1,
1170 __LINE__);
1171 } else {
1172 /* Backward scanning or we want to use the existing one
1173 * Use existing.
1174 * Delete the new one and return early so that the tnode isn't changed
1175 */
1176 yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
1177 return YAFFS_OK;
1178 }
1179 }
1180
1181 }
1182
1183 if (existing_cunk == 0)
1184 in->n_data_chunks++;
1185
1186 yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
1187
1188 return YAFFS_OK;
1189}
1190
1191static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
1192{
1193 struct yaffs_block_info *the_block;
1194 unsigned block_no;
1195
1196 yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
1197
1198 block_no = chunk / dev->param.chunks_per_block;
1199 the_block = yaffs_get_block_info(dev, block_no);
1200 if (the_block) {
1201 the_block->soft_del_pages++;
1202 dev->n_free_chunks++;
1203 yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
1204 }
1205}
1206
1207/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
1208 * All soft deleting does is increment the block's softdelete count and pulls the chunk out
1209 * of the tnode.
1210 * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
1211 */
1212
1213static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
1214 u32 level, int chunk_offset)
1215{
1216 int i;
1217 int the_chunk;
1218 int all_done = 1;
1219 struct yaffs_dev *dev = in->my_dev;
1220
1221 if (tn) {
1222 if (level > 0) {
1223
1224 for (i = YAFFS_NTNODES_INTERNAL - 1; all_done && i >= 0;
1225 i--) {
1226 if (tn->internal[i]) {
1227 all_done =
1228 yaffs_soft_del_worker(in,
1229 tn->internal
1230 [i],
1231 level - 1,
1232 (chunk_offset
1233 <<
1234 YAFFS_TNODES_INTERNAL_BITS)
1235 + i);
1236 if (all_done) {
1237 yaffs_free_tnode(dev,
1238 tn->internal
1239 [i]);
1240 tn->internal[i] = NULL;
1241 } else {
1242 /* Hoosterman... how could this happen? */
1243 }
1244 }
1245 }
1246 return (all_done) ? 1 : 0;
1247 } else if (level == 0) {
1248
1249 for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
1250 the_chunk = yaffs_get_group_base(dev, tn, i);
1251 if (the_chunk) {
1252 /* Note this does not find the real chunk, only the chunk group.
1253 * We make an assumption that a chunk group is not larger than
1254 * a block.
1255 */
1256 yaffs_soft_del_chunk(dev, the_chunk);
1257 yaffs_load_tnode_0(dev, tn, i, 0);
1258 }
1259
1260 }
1261 return 1;
1262
1263 }
1264
1265 }
1266
1267 return 1;
1268
1269}
1270
1271static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
1272{
1273 struct yaffs_dev *dev = obj->my_dev;
1274 struct yaffs_obj *parent;
1275
1276 yaffs_verify_obj_in_dir(obj);
1277 parent = obj->parent;
1278
1279 yaffs_verify_dir(parent);
1280
1281 if (dev && dev->param.remove_obj_fn)
1282 dev->param.remove_obj_fn(obj);
1283
1284 list_del_init(&obj->siblings);
1285 obj->parent = NULL;
1286
1287 yaffs_verify_dir(parent);
1288}
1289
1290void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
1291{
1292 if (!directory) {
1293 yaffs_trace(YAFFS_TRACE_ALWAYS,
1294 "tragedy: Trying to add an object to a null pointer directory"
1295 );
1296 YBUG();
1297 return;
1298 }
1299 if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
1300 yaffs_trace(YAFFS_TRACE_ALWAYS,
1301 "tragedy: Trying to add an object to a non-directory"
1302 );
1303 YBUG();
1304 }
1305
1306 if (obj->siblings.prev == NULL) {
1307 /* Not initialised */
1308 YBUG();
1309 }
1310
1311 yaffs_verify_dir(directory);
1312
1313 yaffs_remove_obj_from_dir(obj);
1314
1315 /* Now add it */
1316 list_add(&obj->siblings, &directory->variant.dir_variant.children);
1317 obj->parent = directory;
1318
1319 if (directory == obj->my_dev->unlinked_dir
1320 || directory == obj->my_dev->del_dir) {
1321 obj->unlinked = 1;
1322 obj->my_dev->n_unlinked_files++;
1323 obj->rename_allowed = 0;
1324 }
1325
1326 yaffs_verify_dir(directory);
1327 yaffs_verify_obj_in_dir(obj);
1328}
1329
1330static int yaffs_change_obj_name(struct yaffs_obj *obj,
1331 struct yaffs_obj *new_dir,
1332 const YCHAR * new_name, int force, int shadows)
1333{
1334 int unlink_op;
1335 int del_op;
1336
1337 struct yaffs_obj *existing_target;
1338
1339 if (new_dir == NULL)
1340 new_dir = obj->parent; /* use the old directory */
1341
1342 if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
1343 yaffs_trace(YAFFS_TRACE_ALWAYS,
1344 "tragedy: yaffs_change_obj_name: new_dir is not a directory"
1345 );
1346 YBUG();
1347 }
1348
1349 /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
1350 if (obj->my_dev->param.is_yaffs2)
1351 unlink_op = (new_dir == obj->my_dev->unlinked_dir);
1352 else
1353 unlink_op = (new_dir == obj->my_dev->unlinked_dir
1354 && obj->variant_type == YAFFS_OBJECT_TYPE_FILE);
1355
1356 del_op = (new_dir == obj->my_dev->del_dir);
1357
1358 existing_target = yaffs_find_by_name(new_dir, new_name);
1359
1360 /* If the object is a file going into the unlinked directory,
1361 * then it is OK to just stuff it in since duplicate names are allowed.
1362 * else only proceed if the new name does not exist and if we're putting
1363 * it into a directory.
1364 */
1365 if ((unlink_op ||
1366 del_op ||
1367 force ||
1368 (shadows > 0) ||
1369 !existing_target) &&
1370 new_dir->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
1371 yaffs_set_obj_name(obj, new_name);
1372 obj->dirty = 1;
1373
1374 yaffs_add_obj_to_dir(new_dir, obj);
1375
1376 if (unlink_op)
1377 obj->unlinked = 1;
1378
1379 /* If it is a deletion then we mark it as a shrink for gc purposes. */
1380 if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >=
1381 0)
1382 return YAFFS_OK;
1383 }
1384
1385 return YAFFS_FAIL;
1386}
1387
1388/*------------------------ Short Operations Cache ----------------------------------------
1389 * In many situations where there is no high level buffering a lot of
1390 * reads might be short sequential reads, and a lot of writes may be short
1391 * sequential writes. eg. scanning/writing a jpeg file.
1392 * In these cases, a short read/write cache can provide a huge perfomance
1393 * benefit with dumb-as-a-rock code.
1394 * In Linux, the page cache provides read buffering and the short op cache
1395 * provides write buffering.
1396 *
1397 * There are a limited number (~10) of cache chunks per device so that we don't
1398 * need a very intelligent search.
1399 */
1400
1401static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
1402{
1403 struct yaffs_dev *dev = obj->my_dev;
1404 int i;
1405 struct yaffs_cache *cache;
1406 int n_caches = obj->my_dev->param.n_caches;
1407
1408 for (i = 0; i < n_caches; i++) {
1409 cache = &dev->cache[i];
1410 if (cache->object == obj && cache->dirty)
1411 return 1;
1412 }
1413
1414 return 0;
1415}
1416
1417static void yaffs_flush_file_cache(struct yaffs_obj *obj)
1418{
1419 struct yaffs_dev *dev = obj->my_dev;
1420 int lowest = -99; /* Stop compiler whining. */
1421 int i;
1422 struct yaffs_cache *cache;
1423 int chunk_written = 0;
1424 int n_caches = obj->my_dev->param.n_caches;
1425
1426 if (n_caches > 0) {
1427 do {
1428 cache = NULL;
1429
1430 /* Find the dirty cache for this object with the lowest chunk id. */
1431 for (i = 0; i < n_caches; i++) {
1432 if (dev->cache[i].object == obj &&
1433 dev->cache[i].dirty) {
1434 if (!cache
1435 || dev->cache[i].chunk_id <
1436 lowest) {
1437 cache = &dev->cache[i];
1438 lowest = cache->chunk_id;
1439 }
1440 }
1441 }
1442
1443 if (cache && !cache->locked) {
1444 /* Write it out and free it up */
1445
1446 chunk_written =
1447 yaffs_wr_data_obj(cache->object,
1448 cache->chunk_id,
1449 cache->data,
1450 cache->n_bytes, 1);
1451 cache->dirty = 0;
1452 cache->object = NULL;
1453 }
1454
1455 } while (cache && chunk_written > 0);
1456
1457 if (cache)
1458 /* Hoosterman, disk full while writing cache out. */
1459 yaffs_trace(YAFFS_TRACE_ERROR,
1460 "yaffs tragedy: no space during cache write");
1461
1462 }
1463
1464}
1465
1466/*yaffs_flush_whole_cache(dev)
1467 *
1468 *
1469 */
1470
1471void yaffs_flush_whole_cache(struct yaffs_dev *dev)
1472{
1473 struct yaffs_obj *obj;
1474 int n_caches = dev->param.n_caches;
1475 int i;
1476
1477 /* Find a dirty object in the cache and flush it...
1478 * until there are no further dirty objects.
1479 */
1480 do {
1481 obj = NULL;
1482 for (i = 0; i < n_caches && !obj; i++) {
1483 if (dev->cache[i].object && dev->cache[i].dirty)
1484 obj = dev->cache[i].object;
1485
1486 }
1487 if (obj)
1488 yaffs_flush_file_cache(obj);
1489
1490 } while (obj);
1491
1492}
1493
1494/* Grab us a cache chunk for use.
1495 * First look for an empty one.
1496 * Then look for the least recently used non-dirty one.
1497 * Then look for the least recently used dirty one...., flush and look again.
1498 */
1499static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
1500{
1501 int i;
1502
1503 if (dev->param.n_caches > 0) {
1504 for (i = 0; i < dev->param.n_caches; i++) {
1505 if (!dev->cache[i].object)
1506 return &dev->cache[i];
1507 }
1508 }
1509
1510 return NULL;
1511}
1512
1513static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
1514{
1515 struct yaffs_cache *cache;
1516 struct yaffs_obj *the_obj;
1517 int usage;
1518 int i;
1519 int pushout;
1520
1521 if (dev->param.n_caches > 0) {
1522 /* Try find a non-dirty one... */
1523
1524 cache = yaffs_grab_chunk_worker(dev);
1525
1526 if (!cache) {
1527 /* They were all dirty, find the last recently used object and flush
1528 * its cache, then find again.
1529 * NB what's here is not very accurate, we actually flush the object
1530 * the last recently used page.
1531 */
1532
1533 /* With locking we can't assume we can use entry zero */
1534
1535 the_obj = NULL;
1536 usage = -1;
1537 cache = NULL;
1538 pushout = -1;
1539
1540 for (i = 0; i < dev->param.n_caches; i++) {
1541 if (dev->cache[i].object &&
1542 !dev->cache[i].locked &&
1543 (dev->cache[i].last_use < usage
1544 || !cache)) {
1545 usage = dev->cache[i].last_use;
1546 the_obj = dev->cache[i].object;
1547 cache = &dev->cache[i];
1548 pushout = i;
1549 }
1550 }
1551
1552 if (!cache || cache->dirty) {
1553 /* Flush and try again */
1554 yaffs_flush_file_cache(the_obj);
1555 cache = yaffs_grab_chunk_worker(dev);
1556 }
1557
1558 }
1559 return cache;
1560 } else {
1561 return NULL;
1562 }
1563}
1564
1565/* Find a cached chunk */
1566static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
1567 int chunk_id)
1568{
1569 struct yaffs_dev *dev = obj->my_dev;
1570 int i;
1571 if (dev->param.n_caches > 0) {
1572 for (i = 0; i < dev->param.n_caches; i++) {
1573 if (dev->cache[i].object == obj &&
1574 dev->cache[i].chunk_id == chunk_id) {
1575 dev->cache_hits++;
1576
1577 return &dev->cache[i];
1578 }
1579 }
1580 }
1581 return NULL;
1582}
1583
1584/* Mark the chunk for the least recently used algorithym */
1585static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
1586 int is_write)
1587{
1588
1589 if (dev->param.n_caches > 0) {
1590 if (dev->cache_last_use < 0 || dev->cache_last_use > 100000000) {
1591 /* Reset the cache usages */
1592 int i;
1593 for (i = 1; i < dev->param.n_caches; i++)
1594 dev->cache[i].last_use = 0;
1595
1596 dev->cache_last_use = 0;
1597 }
1598
1599 dev->cache_last_use++;
1600
1601 cache->last_use = dev->cache_last_use;
1602
1603 if (is_write)
1604 cache->dirty = 1;
1605 }
1606}
1607
1608/* Invalidate a single cache page.
1609 * Do this when a whole page gets written,
1610 * ie the short cache for this page is no longer valid.
1611 */
1612static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
1613{
1614 if (object->my_dev->param.n_caches > 0) {
1615 struct yaffs_cache *cache =
1616 yaffs_find_chunk_cache(object, chunk_id);
1617
1618 if (cache)
1619 cache->object = NULL;
1620 }
1621}
1622
1623/* Invalidate all the cache pages associated with this object
1624 * Do this whenever ther file is deleted or resized.
1625 */
1626static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
1627{
1628 int i;
1629 struct yaffs_dev *dev = in->my_dev;
1630
1631 if (dev->param.n_caches > 0) {
1632 /* Invalidate it. */
1633 for (i = 0; i < dev->param.n_caches; i++) {
1634 if (dev->cache[i].object == in)
1635 dev->cache[i].object = NULL;
1636 }
1637 }
1638}
1639
1640static void yaffs_unhash_obj(struct yaffs_obj *obj)
1641{
1642 int bucket;
1643 struct yaffs_dev *dev = obj->my_dev;
1644
1645 /* If it is still linked into the bucket list, free from the list */
1646 if (!list_empty(&obj->hash_link)) {
1647 list_del_init(&obj->hash_link);
1648 bucket = yaffs_hash_fn(obj->obj_id);
1649 dev->obj_bucket[bucket].count--;
1650 }
1651}
1652
1653/* FreeObject frees up a Object and puts it back on the free list */
1654static void yaffs_free_obj(struct yaffs_obj *obj)
1655{
1656 struct yaffs_dev *dev = obj->my_dev;
1657
1658 yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
1659 obj, obj->my_inode);
1660
1661 if (!obj)
1662 YBUG();
1663 if (obj->parent)
1664 YBUG();
1665 if (!list_empty(&obj->siblings))
1666 YBUG();
1667
1668 if (obj->my_inode) {
1669 /* We're still hooked up to a cached inode.
1670 * Don't delete now, but mark for later deletion
1671 */
1672 obj->defered_free = 1;
1673 return;
1674 }
1675
1676 yaffs_unhash_obj(obj);
1677
1678 yaffs_free_raw_obj(dev, obj);
1679 dev->n_obj--;
1680 dev->checkpoint_blocks_required = 0; /* force recalculation */
1681}
1682
1683void yaffs_handle_defered_free(struct yaffs_obj *obj)
1684{
1685 if (obj->defered_free)
1686 yaffs_free_obj(obj);
1687}
1688
1689static int yaffs_generic_obj_del(struct yaffs_obj *in)
1690{
1691
1692 /* First off, invalidate the file's data in the cache, without flushing. */
1693 yaffs_invalidate_whole_cache(in);
1694
1695 if (in->my_dev->param.is_yaffs2 && (in->parent != in->my_dev->del_dir)) {
1696 /* Move to the unlinked directory so we have a record that it was deleted. */
1697 yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
1698 0);
1699
1700 }
1701
1702 yaffs_remove_obj_from_dir(in);
1703 yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
1704 in->hdr_chunk = 0;
1705
1706 yaffs_free_obj(in);
1707 return YAFFS_OK;
1708
1709}
1710
1711static void yaffs_soft_del_file(struct yaffs_obj *obj)
1712{
1713 if (obj->deleted &&
1714 obj->variant_type == YAFFS_OBJECT_TYPE_FILE && !obj->soft_del) {
1715 if (obj->n_data_chunks <= 0) {
1716 /* Empty file with no duplicate object headers,
1717 * just delete it immediately */
1718 yaffs_free_tnode(obj->my_dev,
1719 obj->variant.file_variant.top);
1720 obj->variant.file_variant.top = NULL;
1721 yaffs_trace(YAFFS_TRACE_TRACING,
1722 "yaffs: Deleting empty file %d",
1723 obj->obj_id);
1724 yaffs_generic_obj_del(obj);
1725 } else {
1726 yaffs_soft_del_worker(obj,
1727 obj->variant.file_variant.top,
1728 obj->variant.
1729 file_variant.top_level, 0);
1730 obj->soft_del = 1;
1731 }
1732 }
1733}
1734
1735/* Pruning removes any part of the file structure tree that is beyond the
1736 * bounds of the file (ie that does not point to chunks).
1737 *
1738 * A file should only get pruned when its size is reduced.
1739 *
1740 * Before pruning, the chunks must be pulled from the tree and the
1741 * level 0 tnode entries must be zeroed out.
1742 * Could also use this for file deletion, but that's probably better handled
1743 * by a special case.
1744 *
1745 * This function is recursive. For levels > 0 the function is called again on
1746 * any sub-tree. For level == 0 we just check if the sub-tree has data.
1747 * If there is no data in a subtree then it is pruned.
1748 */
1749
1750static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
1751 struct yaffs_tnode *tn, u32 level,
1752 int del0)
1753{
1754 int i;
1755 int has_data;
1756
1757 if (tn) {
1758 has_data = 0;
1759
1760 if (level > 0) {
1761 for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
1762 if (tn->internal[i]) {
1763 tn->internal[i] =
1764 yaffs_prune_worker(dev,
1765 tn->internal[i],
1766 level - 1,
1767 (i ==
1768 0) ? del0 : 1);
1769 }
1770
1771 if (tn->internal[i])
1772 has_data++;
1773 }
1774 } else {
1775 int tnode_size_u32 = dev->tnode_size / sizeof(u32);
1776 u32 *map = (u32 *) tn;
1777
1778 for (i = 0; !has_data && i < tnode_size_u32; i++) {
1779 if (map[i])
1780 has_data++;
1781 }
1782 }
1783
1784 if (has_data == 0 && del0) {
1785 /* Free and return NULL */
1786
1787 yaffs_free_tnode(dev, tn);
1788 tn = NULL;
1789 }
1790
1791 }
1792
1793 return tn;
1794
1795}
1796
1797static int yaffs_prune_tree(struct yaffs_dev *dev,
1798 struct yaffs_file_var *file_struct)
1799{
1800 int i;
1801 int has_data;
1802 int done = 0;
1803 struct yaffs_tnode *tn;
1804
1805 if (file_struct->top_level > 0) {
1806 file_struct->top =
1807 yaffs_prune_worker(dev, file_struct->top,
1808 file_struct->top_level, 0);
1809
1810 /* Now we have a tree with all the non-zero branches NULL but the height
1811 * is the same as it was.
1812 * Let's see if we can trim internal tnodes to shorten the tree.
1813 * We can do this if only the 0th element in the tnode is in use
1814 * (ie all the non-zero are NULL)
1815 */
1816
1817 while (file_struct->top_level && !done) {
1818 tn = file_struct->top;
1819
1820 has_data = 0;
1821 for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
1822 if (tn->internal[i])
1823 has_data++;
1824 }
1825
1826 if (!has_data) {
1827 file_struct->top = tn->internal[0];
1828 file_struct->top_level--;
1829 yaffs_free_tnode(dev, tn);
1830 } else {
1831 done = 1;
1832 }
1833 }
1834 }
1835
1836 return YAFFS_OK;
1837}
1838
1839/*-------------------- End of File Structure functions.-------------------*/
1840
1841/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
1842static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
1843{
1844 struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
1845
1846 if (obj) {
1847 dev->n_obj++;
1848
1849 /* Now sweeten it up... */
1850
1851 memset(obj, 0, sizeof(struct yaffs_obj));
1852 obj->being_created = 1;
1853
1854 obj->my_dev = dev;
1855 obj->hdr_chunk = 0;
1856 obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
1857 INIT_LIST_HEAD(&(obj->hard_links));
1858 INIT_LIST_HEAD(&(obj->hash_link));
1859 INIT_LIST_HEAD(&obj->siblings);
1860
1861 /* Now make the directory sane */
1862 if (dev->root_dir) {
1863 obj->parent = dev->root_dir;
1864 list_add(&(obj->siblings),
1865 &dev->root_dir->variant.dir_variant.children);
1866 }
1867
1868 /* Add it to the lost and found directory.
1869 * NB Can't put root or lost-n-found in lost-n-found so
1870 * check if lost-n-found exists first
1871 */
1872 if (dev->lost_n_found)
1873 yaffs_add_obj_to_dir(dev->lost_n_found, obj);
1874
1875 obj->being_created = 0;
1876 }
1877
1878 dev->checkpoint_blocks_required = 0; /* force recalculation */
1879
1880 return obj;
1881}
1882
1883static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
1884{
1885 int i;
1886 int l = 999;
1887 int lowest = 999999;
1888
1889 /* Search for the shortest list or one that
1890 * isn't too long.
1891 */
1892
1893 for (i = 0; i < 10 && lowest > 4; i++) {
1894 dev->bucket_finder++;
1895 dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
1896 if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
1897 lowest = dev->obj_bucket[dev->bucket_finder].count;
1898 l = dev->bucket_finder;
1899 }
1900
1901 }
1902
1903 return l;
1904}
1905
1906static int yaffs_new_obj_id(struct yaffs_dev *dev)
1907{
1908 int bucket = yaffs_find_nice_bucket(dev);
1909
1910 /* Now find an object value that has not already been taken
1911 * by scanning the list.
1912 */
1913
1914 int found = 0;
1915 struct list_head *i;
1916
1917 u32 n = (u32) bucket;
1918
1919 /* yaffs_check_obj_hash_sane(); */
1920
1921 while (!found) {
1922 found = 1;
1923 n += YAFFS_NOBJECT_BUCKETS;
1924 if (1 || dev->obj_bucket[bucket].count > 0) {
1925 list_for_each(i, &dev->obj_bucket[bucket].list) {
1926 /* If there is already one in the list */
1927 if (i && list_entry(i, struct yaffs_obj,
1928 hash_link)->obj_id == n) {
1929 found = 0;
1930 }
1931 }
1932 }
1933 }
1934
1935 return n;
1936}
1937
1938static void yaffs_hash_obj(struct yaffs_obj *in)
1939{
1940 int bucket = yaffs_hash_fn(in->obj_id);
1941 struct yaffs_dev *dev = in->my_dev;
1942
1943 list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
1944 dev->obj_bucket[bucket].count++;
1945}
1946
1947struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
1948{
1949 int bucket = yaffs_hash_fn(number);
1950 struct list_head *i;
1951 struct yaffs_obj *in;
1952
1953 list_for_each(i, &dev->obj_bucket[bucket].list) {
1954 /* Look if it is in the list */
1955 if (i) {
1956 in = list_entry(i, struct yaffs_obj, hash_link);
1957 if (in->obj_id == number) {
1958
1959 /* Don't tell the VFS about this one if it is defered free */
1960 if (in->defered_free)
1961 return NULL;
1962
1963 return in;
1964 }
1965 }
1966 }
1967
1968 return NULL;
1969}
1970
1971struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
1972 enum yaffs_obj_type type)
1973{
1974 struct yaffs_obj *the_obj = NULL;
1975 struct yaffs_tnode *tn = NULL;
1976
1977 if (number < 0)
1978 number = yaffs_new_obj_id(dev);
1979
1980 if (type == YAFFS_OBJECT_TYPE_FILE) {
1981 tn = yaffs_get_tnode(dev);
1982 if (!tn)
1983 return NULL;
1984 }
1985
1986 the_obj = yaffs_alloc_empty_obj(dev);
1987 if (!the_obj) {
1988 if (tn)
1989 yaffs_free_tnode(dev, tn);
1990 return NULL;
1991 }
1992
1993 if (the_obj) {
1994 the_obj->fake = 0;
1995 the_obj->rename_allowed = 1;
1996 the_obj->unlink_allowed = 1;
1997 the_obj->obj_id = number;
1998 yaffs_hash_obj(the_obj);
1999 the_obj->variant_type = type;
2000 yaffs_load_current_time(the_obj, 1, 1);
2001
2002 switch (type) {
2003 case YAFFS_OBJECT_TYPE_FILE:
2004 the_obj->variant.file_variant.file_size = 0;
2005 the_obj->variant.file_variant.scanned_size = 0;
2006 the_obj->variant.file_variant.shrink_size = ~0; /* max */
2007 the_obj->variant.file_variant.top_level = 0;
2008 the_obj->variant.file_variant.top = tn;
2009 break;
2010 case YAFFS_OBJECT_TYPE_DIRECTORY:
2011 INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
2012 INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
2013 break;
2014 case YAFFS_OBJECT_TYPE_SYMLINK:
2015 case YAFFS_OBJECT_TYPE_HARDLINK:
2016 case YAFFS_OBJECT_TYPE_SPECIAL:
2017 /* No action required */
2018 break;
2019 case YAFFS_OBJECT_TYPE_UNKNOWN:
2020 /* todo this should not happen */
2021 break;
2022 }
2023 }
2024
2025 return the_obj;
2026}
2027
2028static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
2029 int number, u32 mode)
2030{
2031
2032 struct yaffs_obj *obj =
2033 yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
2034 if (obj) {
2035 obj->fake = 1; /* it is fake so it might have no NAND presence... */
2036 obj->rename_allowed = 0; /* ... and we're not allowed to rename it... */
2037 obj->unlink_allowed = 0; /* ... or unlink it */
2038 obj->deleted = 0;
2039 obj->unlinked = 0;
2040 obj->yst_mode = mode;
2041 obj->my_dev = dev;
2042 obj->hdr_chunk = 0; /* Not a valid chunk. */
2043 }
2044
2045 return obj;
2046
2047}
2048
2049
2050static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
2051{
2052 int i;
2053
2054 dev->n_obj = 0;
2055 dev->n_tnodes = 0;
2056
2057 yaffs_init_raw_tnodes_and_objs(dev);
2058
2059 for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
2060 INIT_LIST_HEAD(&dev->obj_bucket[i].list);
2061 dev->obj_bucket[i].count = 0;
2062 }
2063}
2064
2065struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
2066 int number,
2067 enum yaffs_obj_type type)
2068{
2069 struct yaffs_obj *the_obj = NULL;
2070
2071 if (number > 0)
2072 the_obj = yaffs_find_by_number(dev, number);
2073
2074 if (!the_obj)
2075 the_obj = yaffs_new_obj(dev, number, type);
2076
2077 return the_obj;
2078
2079}
2080
2081YCHAR *yaffs_clone_str(const YCHAR * str)
2082{
2083 YCHAR *new_str = NULL;
2084 int len;
2085
2086 if (!str)
2087 str = _Y("");
2088
2089 len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
2090 new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
2091 if (new_str) {
2092 strncpy(new_str, str, len);
2093 new_str[len] = 0;
2094 }
2095 return new_str;
2096
2097}
2098/*
2099 *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
2100 * link (ie. name) is created or deleted in the directory.
2101 *
2102 * ie.
2103 * create dir/a : update dir's mtime/ctime
2104 * rm dir/a: update dir's mtime/ctime
2105 * modify dir/a: don't update dir's mtimme/ctime
2106 *
2107 * This can be handled immediately or defered. Defering helps reduce the number
2108 * of updates when many files in a directory are changed within a brief period.
2109 *
2110 * If the directory updating is defered then yaffs_update_dirty_dirs must be
2111 * called periodically.
2112 */
2113
2114static void yaffs_update_parent(struct yaffs_obj *obj)
2115{
2116 struct yaffs_dev *dev;
2117 if (!obj)
2118 return;
2119 dev = obj->my_dev;
2120 obj->dirty = 1;
2121 yaffs_load_current_time(obj, 0, 1);
2122 if (dev->param.defered_dir_update) {
2123 struct list_head *link = &obj->variant.dir_variant.dirty;
2124
2125 if (list_empty(link)) {
2126 list_add(link, &dev->dirty_dirs);
2127 yaffs_trace(YAFFS_TRACE_BACKGROUND,
2128 "Added object %d to dirty directories",
2129 obj->obj_id);
2130 }
2131
2132 } else {
2133 yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
2134 }
2135}
2136
2137void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
2138{
2139 struct list_head *link;
2140 struct yaffs_obj *obj;
2141 struct yaffs_dir_var *d_s;
2142 union yaffs_obj_var *o_v;
2143
2144 yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
2145
2146 while (!list_empty(&dev->dirty_dirs)) {
2147 link = dev->dirty_dirs.next;
2148 list_del_init(link);
2149
2150 d_s = list_entry(link, struct yaffs_dir_var, dirty);
2151 o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
2152 obj = list_entry(o_v, struct yaffs_obj, variant);
2153
2154 yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
2155 obj->obj_id);
2156
2157 if (obj->dirty)
2158 yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
2159 }
2160}
2161
2162/*
2163 * Mknod (create) a new object.
2164 * equiv_obj only has meaning for a hard link;
2165 * alias_str only has meaning for a symlink.
2166 * rdev only has meaning for devices (a subset of special objects)
2167 */
2168
2169static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
2170 struct yaffs_obj *parent,
2171 const YCHAR * name,
2172 u32 mode,
2173 u32 uid,
2174 u32 gid,
2175 struct yaffs_obj *equiv_obj,
2176 const YCHAR * alias_str, u32 rdev)
2177{
2178 struct yaffs_obj *in;
2179 YCHAR *str = NULL;
2180
2181 struct yaffs_dev *dev = parent->my_dev;
2182
2183 /* Check if the entry exists. If it does then fail the call since we don't want a dup. */
2184 if (yaffs_find_by_name(parent, name))
2185 return NULL;
2186
2187 if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
2188 str = yaffs_clone_str(alias_str);
2189 if (!str)
2190 return NULL;
2191 }
2192
2193 in = yaffs_new_obj(dev, -1, type);
2194
2195 if (!in) {
2196 if (str)
2197 kfree(str);
2198 return NULL;
2199 }
2200
2201 if (in) {
2202 in->hdr_chunk = 0;
2203 in->valid = 1;
2204 in->variant_type = type;
2205
2206 in->yst_mode = mode;
2207
2208 yaffs_attribs_init(in, gid, uid, rdev);
2209
2210 in->n_data_chunks = 0;
2211
2212 yaffs_set_obj_name(in, name);
2213 in->dirty = 1;
2214
2215 yaffs_add_obj_to_dir(parent, in);
2216
2217 in->my_dev = parent->my_dev;
2218
2219 switch (type) {
2220 case YAFFS_OBJECT_TYPE_SYMLINK:
2221 in->variant.symlink_variant.alias = str;
2222 break;
2223 case YAFFS_OBJECT_TYPE_HARDLINK:
2224 in->variant.hardlink_variant.equiv_obj = equiv_obj;
2225 in->variant.hardlink_variant.equiv_id =
2226 equiv_obj->obj_id;
2227 list_add(&in->hard_links, &equiv_obj->hard_links);
2228 break;
2229 case YAFFS_OBJECT_TYPE_FILE:
2230 case YAFFS_OBJECT_TYPE_DIRECTORY:
2231 case YAFFS_OBJECT_TYPE_SPECIAL:
2232 case YAFFS_OBJECT_TYPE_UNKNOWN:
2233 /* do nothing */
2234 break;
2235 }
2236
2237 if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
2238 /* Could not create the object header, fail the creation */
2239 yaffs_del_obj(in);
2240 in = NULL;
2241 }
2242
2243 yaffs_update_parent(parent);
2244 }
2245
2246 return in;
2247}
2248
2249struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
2250 const YCHAR * name, u32 mode, u32 uid,
2251 u32 gid)
2252{
2253 return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
2254 uid, gid, NULL, NULL, 0);
2255}
2256
2257struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR * name,
2258 u32 mode, u32 uid, u32 gid)
2259{
2260 return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
2261 mode, uid, gid, NULL, NULL, 0);
2262}
2263
2264struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
2265 const YCHAR * name, u32 mode, u32 uid,
2266 u32 gid, u32 rdev)
2267{
2268 return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
2269 uid, gid, NULL, NULL, rdev);
2270}
2271
2272struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
2273 const YCHAR * name, u32 mode, u32 uid,
2274 u32 gid, const YCHAR * alias)
2275{
2276 return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
2277 uid, gid, NULL, alias, 0);
2278}
2279
2280/* yaffs_link_obj returns the object id of the equivalent object.*/
2281struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
2282 struct yaffs_obj *equiv_obj)
2283{
2284 /* Get the real object in case we were fed a hard link as an equivalent object */
2285 equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
2286
2287 if (yaffs_create_obj
2288 (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
2289 equiv_obj, NULL, 0)) {
2290 return equiv_obj;
2291 } else {
2292 return NULL;
2293 }
2294
2295}
2296
2297
2298
2299/*------------------------- Block Management and Page Allocation ----------------*/
2300
2301static int yaffs_init_blocks(struct yaffs_dev *dev)
2302{
2303 int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
2304
2305 dev->block_info = NULL;
2306 dev->chunk_bits = NULL;
2307
2308 dev->alloc_block = -1; /* force it to get a new one */
2309
2310 /* If the first allocation strategy fails, thry the alternate one */
2311 dev->block_info =
2312 kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
2313 if (!dev->block_info) {
2314 dev->block_info =
2315 vmalloc(n_blocks * sizeof(struct yaffs_block_info));
2316 dev->block_info_alt = 1;
2317 } else {
2318 dev->block_info_alt = 0;
2319 }
2320
2321 if (dev->block_info) {
2322 /* Set up dynamic blockinfo stuff. Round up bytes. */
2323 dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
2324 dev->chunk_bits =
2325 kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
2326 if (!dev->chunk_bits) {
2327 dev->chunk_bits =
2328 vmalloc(dev->chunk_bit_stride * n_blocks);
2329 dev->chunk_bits_alt = 1;
2330 } else {
2331 dev->chunk_bits_alt = 0;
2332 }
2333 }
2334
2335 if (dev->block_info && dev->chunk_bits) {
2336 memset(dev->block_info, 0,
2337 n_blocks * sizeof(struct yaffs_block_info));
2338 memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
2339 return YAFFS_OK;
2340 }
2341
2342 return YAFFS_FAIL;
2343}
2344
2345static void yaffs_deinit_blocks(struct yaffs_dev *dev)
2346{
2347 if (dev->block_info_alt && dev->block_info)
2348 vfree(dev->block_info);
2349 else if (dev->block_info)
2350 kfree(dev->block_info);
2351
2352 dev->block_info_alt = 0;
2353
2354 dev->block_info = NULL;
2355
2356 if (dev->chunk_bits_alt && dev->chunk_bits)
2357 vfree(dev->chunk_bits);
2358 else if (dev->chunk_bits)
2359 kfree(dev->chunk_bits);
2360 dev->chunk_bits_alt = 0;
2361 dev->chunk_bits = NULL;
2362}
2363
2364void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
2365{
2366 struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
2367
2368 int erased_ok = 0;
2369
2370 /* If the block is still healthy erase it and mark as clean.
2371 * If the block has had a data failure, then retire it.
2372 */
2373
2374 yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
2375 "yaffs_block_became_dirty block %d state %d %s",
2376 block_no, bi->block_state,
2377 (bi->needs_retiring) ? "needs retiring" : "");
2378
2379 yaffs2_clear_oldest_dirty_seq(dev, bi);
2380
2381 bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
2382
2383 /* If this is the block being garbage collected then stop gc'ing this block */
2384 if (block_no == dev->gc_block)
2385 dev->gc_block = 0;
2386
2387 /* If this block is currently the best candidate for gc then drop as a candidate */
2388 if (block_no == dev->gc_dirtiest) {
2389 dev->gc_dirtiest = 0;
2390 dev->gc_pages_in_use = 0;
2391 }
2392
2393 if (!bi->needs_retiring) {
2394 yaffs2_checkpt_invalidate(dev);
2395 erased_ok = yaffs_erase_block(dev, block_no);
2396 if (!erased_ok) {
2397 dev->n_erase_failures++;
2398 yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
2399 "**>> Erasure failed %d", block_no);
2400 }
2401 }
2402
2403 if (erased_ok &&
2404 ((yaffs_trace_mask & YAFFS_TRACE_ERASE)
2405 || !yaffs_skip_verification(dev))) {
2406 int i;
2407 for (i = 0; i < dev->param.chunks_per_block; i++) {
2408 if (!yaffs_check_chunk_erased
2409 (dev, block_no * dev->param.chunks_per_block + i)) {
2410 yaffs_trace(YAFFS_TRACE_ERROR,
2411 ">>Block %d erasure supposedly OK, but chunk %d not erased",
2412 block_no, i);
2413 }
2414 }
2415 }
2416
2417 if (erased_ok) {
2418 /* Clean it up... */
2419 bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
2420 bi->seq_number = 0;
2421 dev->n_erased_blocks++;
2422 bi->pages_in_use = 0;
2423 bi->soft_del_pages = 0;
2424 bi->has_shrink_hdr = 0;
2425 bi->skip_erased_check = 1; /* Clean, so no need to check */
2426 bi->gc_prioritise = 0;
2427 yaffs_clear_chunk_bits(dev, block_no);
2428
2429 yaffs_trace(YAFFS_TRACE_ERASE,
2430 "Erased block %d", block_no);
2431 } else {
2432 /* We lost a block of free space */
2433 dev->n_free_chunks -= dev->param.chunks_per_block;
2434 yaffs_retire_block(dev, block_no);
2435 yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
2436 "**>> Block %d retired", block_no);
2437 }
2438}
2439
2440
2441
2442static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
2443{
2444 int old_chunk;
2445 int new_chunk;
2446 int mark_flash;
2447 int ret_val = YAFFS_OK;
2448 int i;
2449 int is_checkpt_block;
2450 int matching_chunk;
2451 int max_copies;
2452
2453 int chunks_before = yaffs_get_erased_chunks(dev);
2454 int chunks_after;
2455
2456 struct yaffs_ext_tags tags;
2457
2458 struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
2459
2460 struct yaffs_obj *object;
2461
2462 is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
2463
2464 yaffs_trace(YAFFS_TRACE_TRACING,
2465 "Collecting block %d, in use %d, shrink %d, whole_block %d",
2466 block, bi->pages_in_use, bi->has_shrink_hdr,
2467 whole_block);
2468
2469 /*yaffs_verify_free_chunks(dev); */
2470
2471 if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
2472 bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
2473
2474 bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
2475
2476 dev->gc_disable = 1;
2477
2478 if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
2479 yaffs_trace(YAFFS_TRACE_TRACING,
2480 "Collecting block %d that has no chunks in use",
2481 block);
2482 yaffs_block_became_dirty(dev, block);
2483 } else {
2484
2485 u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
2486
2487 yaffs_verify_blk(dev, bi, block);
2488
2489 max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
2490 old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
2491
2492 for ( /* init already done */ ;
2493 ret_val == YAFFS_OK &&
2494 dev->gc_chunk < dev->param.chunks_per_block &&
2495 (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
2496 max_copies > 0; dev->gc_chunk++, old_chunk++) {
2497 if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
2498
2499 /* This page is in use and might need to be copied off */
2500
2501 max_copies--;
2502
2503 mark_flash = 1;
2504
2505 yaffs_init_tags(&tags);
2506
2507 yaffs_rd_chunk_tags_nand(dev, old_chunk,
2508 buffer, &tags);
2509
2510 object = yaffs_find_by_number(dev, tags.obj_id);
2511
2512 yaffs_trace(YAFFS_TRACE_GC_DETAIL,
2513 "Collecting chunk in block %d, %d %d %d ",
2514 dev->gc_chunk, tags.obj_id,
2515 tags.chunk_id, tags.n_bytes);
2516
2517 if (object && !yaffs_skip_verification(dev)) {
2518 if (tags.chunk_id == 0)
2519 matching_chunk =
2520 object->hdr_chunk;
2521 else if (object->soft_del)
2522 matching_chunk = old_chunk; /* Defeat the test */
2523 else
2524 matching_chunk =
2525 yaffs_find_chunk_in_file
2526 (object, tags.chunk_id,
2527 NULL);
2528
2529 if (old_chunk != matching_chunk)
2530 yaffs_trace(YAFFS_TRACE_ERROR,
2531 "gc: page in gc mismatch: %d %d %d %d",
2532 old_chunk,
2533 matching_chunk,
2534 tags.obj_id,
2535 tags.chunk_id);
2536
2537 }
2538
2539 if (!object) {
2540 yaffs_trace(YAFFS_TRACE_ERROR,
2541 "page %d in gc has no object: %d %d %d ",
2542 old_chunk,
2543 tags.obj_id, tags.chunk_id,
2544 tags.n_bytes);
2545 }
2546
2547 if (object &&
2548 object->deleted &&
2549 object->soft_del && tags.chunk_id != 0) {
2550 /* Data chunk in a soft deleted file, throw it away
2551 * It's a soft deleted data chunk,
2552 * No need to copy this, just forget about it and
2553 * fix up the object.
2554 */
2555
2556 /* Free chunks already includes softdeleted chunks.
2557 * How ever this chunk is going to soon be really deleted
2558 * which will increment free chunks.
2559 * We have to decrement free chunks so this works out properly.
2560 */
2561 dev->n_free_chunks--;
2562 bi->soft_del_pages--;
2563
2564 object->n_data_chunks--;
2565
2566 if (object->n_data_chunks <= 0) {
2567 /* remeber to clean up the object */
2568 dev->gc_cleanup_list[dev->
2569 n_clean_ups]
2570 = tags.obj_id;
2571 dev->n_clean_ups++;
2572 }
2573 mark_flash = 0;
2574 } else if (0) {
2575 /* Todo object && object->deleted && object->n_data_chunks == 0 */
2576 /* Deleted object header with no data chunks.
2577 * Can be discarded and the file deleted.
2578 */
2579 object->hdr_chunk = 0;
2580 yaffs_free_tnode(object->my_dev,
2581 object->
2582 variant.file_variant.
2583 top);
2584 object->variant.file_variant.top = NULL;
2585 yaffs_generic_obj_del(object);
2586
2587 } else if (object) {
2588 /* It's either a data chunk in a live file or
2589 * an ObjectHeader, so we're interested in it.
2590 * NB Need to keep the ObjectHeaders of deleted files
2591 * until the whole file has been deleted off
2592 */
2593 tags.serial_number++;
2594
2595 dev->n_gc_copies++;
2596
2597 if (tags.chunk_id == 0) {
2598 /* It is an object Id,
2599 * We need to nuke the shrinkheader flags first
2600 * Also need to clean up shadowing.
2601 * We no longer want the shrink_header flag since its work is done
2602 * and if it is left in place it will mess up scanning.
2603 */
2604
2605 struct yaffs_obj_hdr *oh;
2606 oh = (struct yaffs_obj_hdr *)
2607 buffer;
2608
2609 oh->is_shrink = 0;
2610 tags.extra_is_shrink = 0;
2611
2612 oh->shadows_obj = 0;
2613 oh->inband_shadowed_obj_id = 0;
2614 tags.extra_shadows = 0;
2615
2616 /* Update file size */
2617 if (object->variant_type ==
2618 YAFFS_OBJECT_TYPE_FILE) {
2619 oh->file_size =
2620 object->variant.
2621 file_variant.
2622 file_size;
2623 tags.extra_length =
2624 oh->file_size;
2625 }
2626
2627 yaffs_verify_oh(object, oh,
2628 &tags, 1);
2629 new_chunk =
2630 yaffs_write_new_chunk(dev,
2631 (u8 *)
2632 oh,
2633 &tags,
2634 1);
2635 } else {
2636 new_chunk =
2637 yaffs_write_new_chunk(dev,
2638 buffer,
2639 &tags,
2640 1);
2641 }
2642
2643 if (new_chunk < 0) {
2644 ret_val = YAFFS_FAIL;
2645 } else {
2646
2647 /* Ok, now fix up the Tnodes etc. */
2648
2649 if (tags.chunk_id == 0) {
2650 /* It's a header */
2651 object->hdr_chunk =
2652 new_chunk;
2653 object->serial =
2654 tags.serial_number;
2655 } else {
2656 /* It's a data chunk */
2657 int ok;
2658 ok = yaffs_put_chunk_in_file(object, tags.chunk_id, new_chunk, 0);
2659 }
2660 }
2661 }
2662
2663 if (ret_val == YAFFS_OK)
2664 yaffs_chunk_del(dev, old_chunk,
2665 mark_flash, __LINE__);
2666
2667 }
2668 }
2669
2670 yaffs_release_temp_buffer(dev, buffer, __LINE__);
2671
2672 }
2673
2674 yaffs_verify_collected_blk(dev, bi, block);
2675
2676 if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
2677 /*
2678 * The gc did not complete. Set block state back to FULL
2679 * because checkpointing does not restore gc.
2680 */
2681 bi->block_state = YAFFS_BLOCK_STATE_FULL;
2682 } else {
2683 /* The gc completed. */
2684 /* Do any required cleanups */
2685 for (i = 0; i < dev->n_clean_ups; i++) {
2686 /* Time to delete the file too */
2687 object =
2688 yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
2689 if (object) {
2690 yaffs_free_tnode(dev,
2691 object->variant.
2692 file_variant.top);
2693 object->variant.file_variant.top = NULL;
2694 yaffs_trace(YAFFS_TRACE_GC,
2695 "yaffs: About to finally delete object %d",
2696 object->obj_id);
2697 yaffs_generic_obj_del(object);
2698 object->my_dev->n_deleted_files--;
2699 }
2700
2701 }
2702
2703 chunks_after = yaffs_get_erased_chunks(dev);
2704 if (chunks_before >= chunks_after)
2705 yaffs_trace(YAFFS_TRACE_GC,
2706 "gc did not increase free chunks before %d after %d",
2707 chunks_before, chunks_after);
2708 dev->gc_block = 0;
2709 dev->gc_chunk = 0;
2710 dev->n_clean_ups = 0;
2711 }
2712
2713 dev->gc_disable = 0;
2714
2715 return ret_val;
2716}
2717
2718/*
2719 * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
2720 * for garbage collection.
2721 */
2722
2723static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
2724 int aggressive, int background)
2725{
2726 int i;
2727 int iterations;
2728 unsigned selected = 0;
2729 int prioritised = 0;
2730 int prioritised_exist = 0;
2731 struct yaffs_block_info *bi;
2732 int threshold;
2733
2734 /* First let's see if we need to grab a prioritised block */
2735 if (dev->has_pending_prioritised_gc && !aggressive) {
2736 dev->gc_dirtiest = 0;
2737 bi = dev->block_info;
2738 for (i = dev->internal_start_block;
2739 i <= dev->internal_end_block && !selected; i++) {
2740
2741 if (bi->gc_prioritise) {
2742 prioritised_exist = 1;
2743 if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
2744 yaffs_block_ok_for_gc(dev, bi)) {
2745 selected = i;
2746 prioritised = 1;
2747 }
2748 }
2749 bi++;
2750 }
2751
2752 /*
2753 * If there is a prioritised block and none was selected then
2754 * this happened because there is at least one old dirty block gumming
2755 * up the works. Let's gc the oldest dirty block.
2756 */
2757
2758 if (prioritised_exist &&
2759 !selected && dev->oldest_dirty_block > 0)
2760 selected = dev->oldest_dirty_block;
2761
2762 if (!prioritised_exist) /* None found, so we can clear this */
2763 dev->has_pending_prioritised_gc = 0;
2764 }
2765
2766 /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
2767 * search harder.
2768 * else (we're doing a leasurely gc), then we only bother to do this if the
2769 * block has only a few pages in use.
2770 */
2771
2772 if (!selected) {
2773 int pages_used;
2774 int n_blocks =
2775 dev->internal_end_block - dev->internal_start_block + 1;
2776 if (aggressive) {
2777 threshold = dev->param.chunks_per_block;
2778 iterations = n_blocks;
2779 } else {
2780 int max_threshold;
2781
2782 if (background)
2783 max_threshold = dev->param.chunks_per_block / 2;
2784 else
2785 max_threshold = dev->param.chunks_per_block / 8;
2786
2787 if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
2788 max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
2789
2790 threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
2791 if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
2792 threshold = YAFFS_GC_PASSIVE_THRESHOLD;
2793 if (threshold > max_threshold)
2794 threshold = max_threshold;
2795
2796 iterations = n_blocks / 16 + 1;
2797 if (iterations > 100)
2798 iterations = 100;
2799 }
2800
2801 for (i = 0;
2802 i < iterations &&
2803 (dev->gc_dirtiest < 1 ||
2804 dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH); i++) {
2805 dev->gc_block_finder++;
2806 if (dev->gc_block_finder < dev->internal_start_block ||
2807 dev->gc_block_finder > dev->internal_end_block)
2808 dev->gc_block_finder =
2809 dev->internal_start_block;
2810
2811 bi = yaffs_get_block_info(dev, dev->gc_block_finder);
2812
2813 pages_used = bi->pages_in_use - bi->soft_del_pages;
2814
2815 if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
2816 pages_used < dev->param.chunks_per_block &&
2817 (dev->gc_dirtiest < 1
2818 || pages_used < dev->gc_pages_in_use)
2819 && yaffs_block_ok_for_gc(dev, bi)) {
2820 dev->gc_dirtiest = dev->gc_block_finder;
2821 dev->gc_pages_in_use = pages_used;
2822 }
2823 }
2824
2825 if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
2826 selected = dev->gc_dirtiest;
2827 }
2828
2829 /*
2830 * If nothing has been selected for a while, try selecting the oldest dirty
2831 * because that's gumming up the works.
2832 */
2833
2834 if (!selected && dev->param.is_yaffs2 &&
2835 dev->gc_not_done >= (background ? 10 : 20)) {
2836 yaffs2_find_oldest_dirty_seq(dev);
2837 if (dev->oldest_dirty_block > 0) {
2838 selected = dev->oldest_dirty_block;
2839 dev->gc_dirtiest = selected;
2840 dev->oldest_dirty_gc_count++;
2841 bi = yaffs_get_block_info(dev, selected);
2842 dev->gc_pages_in_use =
2843 bi->pages_in_use - bi->soft_del_pages;
2844 } else {
2845 dev->gc_not_done = 0;
2846 }
2847 }
2848
2849 if (selected) {
2850 yaffs_trace(YAFFS_TRACE_GC,
2851 "GC Selected block %d with %d free, prioritised:%d",
2852 selected,
2853 dev->param.chunks_per_block - dev->gc_pages_in_use,
2854 prioritised);
2855
2856 dev->n_gc_blocks++;
2857 if (background)
2858 dev->bg_gcs++;
2859
2860 dev->gc_dirtiest = 0;
2861 dev->gc_pages_in_use = 0;
2862 dev->gc_not_done = 0;
2863 if (dev->refresh_skip > 0)
2864 dev->refresh_skip--;
2865 } else {
2866 dev->gc_not_done++;
2867 yaffs_trace(YAFFS_TRACE_GC,
2868 "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
2869 dev->gc_block_finder, dev->gc_not_done, threshold,
2870 dev->gc_dirtiest, dev->gc_pages_in_use,
2871 dev->oldest_dirty_block, background ? " bg" : "");
2872 }
2873
2874 return selected;
2875}
2876
2877/* New garbage collector
2878 * If we're very low on erased blocks then we do aggressive garbage collection
2879 * otherwise we do "leasurely" garbage collection.
2880 * Aggressive gc looks further (whole array) and will accept less dirty blocks.
2881 * Passive gc only inspects smaller areas and will only accept more dirty blocks.
2882 *
2883 * The idea is to help clear out space in a more spread-out manner.
2884 * Dunno if it really does anything useful.
2885 */
2886static int yaffs_check_gc(struct yaffs_dev *dev, int background)
2887{
2888 int aggressive = 0;
2889 int gc_ok = YAFFS_OK;
2890 int max_tries = 0;
2891 int min_erased;
2892 int erased_chunks;
2893 int checkpt_block_adjust;
2894
2895 if (dev->param.gc_control && (dev->param.gc_control(dev) & 1) == 0)
2896 return YAFFS_OK;
2897
2898 if (dev->gc_disable) {
2899 /* Bail out so we don't get recursive gc */
2900 return YAFFS_OK;
2901 }
2902
2903 /* This loop should pass the first time.
2904 * We'll only see looping here if the collection does not increase space.
2905 */
2906
2907 do {
2908 max_tries++;
2909
2910 checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
2911
2912 min_erased =
2913 dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
2914 erased_chunks =
2915 dev->n_erased_blocks * dev->param.chunks_per_block;
2916
2917 /* If we need a block soon then do aggressive gc. */
2918 if (dev->n_erased_blocks < min_erased)
2919 aggressive = 1;
2920 else {
2921 if (!background
2922 && erased_chunks > (dev->n_free_chunks / 4))
2923 break;
2924
2925 if (dev->gc_skip > 20)
2926 dev->gc_skip = 20;
2927 if (erased_chunks < dev->n_free_chunks / 2 ||
2928 dev->gc_skip < 1 || background)
2929 aggressive = 0;
2930 else {
2931 dev->gc_skip--;
2932 break;
2933 }
2934 }
2935
2936 dev->gc_skip = 5;
2937
2938 /* If we don't already have a block being gc'd then see if we should start another */
2939
2940 if (dev->gc_block < 1 && !aggressive) {
2941 dev->gc_block = yaffs2_find_refresh_block(dev);
2942 dev->gc_chunk = 0;
2943 dev->n_clean_ups = 0;
2944 }
2945 if (dev->gc_block < 1) {
2946 dev->gc_block =
2947 yaffs_find_gc_block(dev, aggressive, background);
2948 dev->gc_chunk = 0;
2949 dev->n_clean_ups = 0;
2950 }
2951
2952 if (dev->gc_block > 0) {
2953 dev->all_gcs++;
2954 if (!aggressive)
2955 dev->passive_gc_count++;
2956
2957 yaffs_trace(YAFFS_TRACE_GC,
2958 "yaffs: GC n_erased_blocks %d aggressive %d",
2959 dev->n_erased_blocks, aggressive);
2960
2961 gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
2962 }
2963
2964 if (dev->n_erased_blocks < (dev->param.n_reserved_blocks)
2965 && dev->gc_block > 0) {
2966 yaffs_trace(YAFFS_TRACE_GC,
2967 "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
2968 dev->n_erased_blocks, max_tries,
2969 dev->gc_block);
2970 }
2971 } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
2972 (dev->gc_block > 0) && (max_tries < 2));
2973
2974 return aggressive ? gc_ok : YAFFS_OK;
2975}
2976
2977/*
2978 * yaffs_bg_gc()
2979 * Garbage collects. Intended to be called from a background thread.
2980 * Returns non-zero if at least half the free chunks are erased.
2981 */
2982int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
2983{
2984 int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
2985
2986 yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
2987
2988 yaffs_check_gc(dev, 1);
2989 return erased_chunks > dev->n_free_chunks / 2;
2990}
2991
2992/*-------------------- Data file manipulation -----------------*/
2993
2994static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
2995{
2996 int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
2997
2998 if (nand_chunk >= 0)
2999 return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
3000 buffer, NULL);
3001 else {
3002 yaffs_trace(YAFFS_TRACE_NANDACCESS,
3003 "Chunk %d not found zero instead",
3004 nand_chunk);
3005 /* get sane (zero) data if you read a hole */
3006 memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
3007 return 0;
3008 }
3009
3010}
3011
3012void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
3013 int lyn)
3014{
3015 int block;
3016 int page;
3017 struct yaffs_ext_tags tags;
3018 struct yaffs_block_info *bi;
3019
3020 if (chunk_id <= 0)
3021 return;
3022
3023 dev->n_deletions++;
3024 block = chunk_id / dev->param.chunks_per_block;
3025 page = chunk_id % dev->param.chunks_per_block;
3026
3027 if (!yaffs_check_chunk_bit(dev, block, page))
3028 yaffs_trace(YAFFS_TRACE_VERIFY,
3029 "Deleting invalid chunk %d", chunk_id);
3030
3031 bi = yaffs_get_block_info(dev, block);
3032
3033 yaffs2_update_oldest_dirty_seq(dev, block, bi);
3034
3035 yaffs_trace(YAFFS_TRACE_DELETION,
3036 "line %d delete of chunk %d",
3037 lyn, chunk_id);
3038
3039 if (!dev->param.is_yaffs2 && mark_flash &&
3040 bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
3041
3042 yaffs_init_tags(&tags);
3043
3044 tags.is_deleted = 1;
3045
3046 yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
3047 yaffs_handle_chunk_update(dev, chunk_id, &tags);
3048 } else {
3049 dev->n_unmarked_deletions++;
3050 }
3051
3052 /* Pull out of the management area.
3053 * If the whole block became dirty, this will kick off an erasure.
3054 */
3055 if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
3056 bi->block_state == YAFFS_BLOCK_STATE_FULL ||
3057 bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
3058 bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
3059 dev->n_free_chunks++;
3060
3061 yaffs_clear_chunk_bit(dev, block, page);
3062
3063 bi->pages_in_use--;
3064
3065 if (bi->pages_in_use == 0 &&
3066 !bi->has_shrink_hdr &&
3067 bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
3068 bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
3069 yaffs_block_became_dirty(dev, block);
3070 }
3071
3072 }
3073
3074}
3075
3076static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
3077 const u8 * buffer, int n_bytes, int use_reserve)
3078{
3079 /* Find old chunk Need to do this to get serial number
3080 * Write new one and patch into tree.
3081 * Invalidate old tags.
3082 */
3083
3084 int prev_chunk_id;
3085 struct yaffs_ext_tags prev_tags;
3086
3087 int new_chunk_id;
3088 struct yaffs_ext_tags new_tags;
3089
3090 struct yaffs_dev *dev = in->my_dev;
3091
3092 yaffs_check_gc(dev, 0);
3093
3094 /* Get the previous chunk at this location in the file if it exists.
3095 * If it does not exist then put a zero into the tree. This creates
3096 * the tnode now, rather than later when it is harder to clean up.
3097 */
3098 prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
3099 if (prev_chunk_id < 1 &&
3100 !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
3101 return 0;
3102
3103 /* Set up new tags */
3104 yaffs_init_tags(&new_tags);
3105
3106 new_tags.chunk_id = inode_chunk;
3107 new_tags.obj_id = in->obj_id;
3108 new_tags.serial_number =
3109 (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
3110 new_tags.n_bytes = n_bytes;
3111
3112 if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
3113 yaffs_trace(YAFFS_TRACE_ERROR,
3114 "Writing %d bytes to chunk!!!!!!!!!",
3115 n_bytes);
3116 YBUG();
3117 }
3118
3119 new_chunk_id =
3120 yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
3121
3122 if (new_chunk_id > 0) {
3123 yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
3124
3125 if (prev_chunk_id > 0)
3126 yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
3127
3128 yaffs_verify_file_sane(in);
3129 }
3130 return new_chunk_id;
3131
3132}
3133
3134
3135
3136static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
3137 const YCHAR * name, const void *value, int size,
3138 int flags)
3139{
3140 struct yaffs_xattr_mod xmod;
3141
3142 int result;
3143
3144 xmod.set = set;
3145 xmod.name = name;
3146 xmod.data = value;
3147 xmod.size = size;
3148 xmod.flags = flags;
3149 xmod.result = -ENOSPC;
3150
3151 result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
3152
3153 if (result > 0)
3154 return xmod.result;
3155 else
3156 return -ENOSPC;
3157}
3158
3159static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
3160 struct yaffs_xattr_mod *xmod)
3161{
3162 int retval = 0;
3163 int x_offs = sizeof(struct yaffs_obj_hdr);
3164 struct yaffs_dev *dev = obj->my_dev;
3165 int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
3166
3167 char *x_buffer = buffer + x_offs;
3168
3169 if (xmod->set)
3170 retval =
3171 nval_set(x_buffer, x_size, xmod->name, xmod->data,
3172 xmod->size, xmod->flags);
3173 else
3174 retval = nval_del(x_buffer, x_size, xmod->name);
3175
3176 obj->has_xattr = nval_hasvalues(x_buffer, x_size);
3177 obj->xattr_known = 1;
3178
3179 xmod->result = retval;
3180
3181 return retval;
3182}
3183
3184static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR * name,
3185 void *value, int size)
3186{
3187 char *buffer = NULL;
3188 int result;
3189 struct yaffs_ext_tags tags;
3190 struct yaffs_dev *dev = obj->my_dev;
3191 int x_offs = sizeof(struct yaffs_obj_hdr);
3192 int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
3193
3194 char *x_buffer;
3195
3196 int retval = 0;
3197
3198 if (obj->hdr_chunk < 1)
3199 return -ENODATA;
3200
3201 /* If we know that the object has no xattribs then don't do all the
3202 * reading and parsing.
3203 */
3204 if (obj->xattr_known && !obj->has_xattr) {
3205 if (name)
3206 return -ENODATA;
3207 else
3208 return 0;
3209 }
3210
3211 buffer = (char *)yaffs_get_temp_buffer(dev, __LINE__);
3212 if (!buffer)
3213 return -ENOMEM;
3214
3215 result =
3216 yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
3217
3218 if (result != YAFFS_OK)
3219 retval = -ENOENT;
3220 else {
3221 x_buffer = buffer + x_offs;
3222
3223 if (!obj->xattr_known) {
3224 obj->has_xattr = nval_hasvalues(x_buffer, x_size);
3225 obj->xattr_known = 1;
3226 }
3227
3228 if (name)
3229 retval = nval_get(x_buffer, x_size, name, value, size);
3230 else
3231 retval = nval_list(x_buffer, x_size, value, size);
3232 }
3233 yaffs_release_temp_buffer(dev, (u8 *) buffer, __LINE__);
3234 return retval;
3235}
3236
3237int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
3238 const void *value, int size, int flags)
3239{
3240 return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
3241}
3242
3243int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
3244{
3245 return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
3246}
3247
3248int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
3249 int size)
3250{
3251 return yaffs_do_xattrib_fetch(obj, name, value, size);
3252}
3253
3254int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
3255{
3256 return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
3257}
3258
3259static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
3260{
3261 u8 *chunk_data;
3262 struct yaffs_obj_hdr *oh;
3263 struct yaffs_dev *dev;
3264 struct yaffs_ext_tags tags;
3265 int result;
3266 int alloc_failed = 0;
3267
3268 if (!in)
3269 return;
3270
3271 dev = in->my_dev;
3272
3273 if (in->lazy_loaded && in->hdr_chunk > 0) {
3274 in->lazy_loaded = 0;
3275 chunk_data = yaffs_get_temp_buffer(dev, __LINE__);
3276
3277 result =
3278 yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, chunk_data,
3279 &tags);
3280 oh = (struct yaffs_obj_hdr *)chunk_data;
3281
3282 in->yst_mode = oh->yst_mode;
3283 yaffs_load_attribs(in, oh);
3284 yaffs_set_obj_name_from_oh(in, oh);
3285
3286 if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
3287 in->variant.symlink_variant.alias =
3288 yaffs_clone_str(oh->alias);
3289 if (!in->variant.symlink_variant.alias)
3290 alloc_failed = 1; /* Not returned to caller */
3291 }
3292
3293 yaffs_release_temp_buffer(dev, chunk_data, __LINE__);
3294 }
3295}
3296
3297static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR * name,
3298 const YCHAR * oh_name, int buff_size)
3299{
3300#ifdef CONFIG_YAFFS_AUTO_UNICODE
3301 if (dev->param.auto_unicode) {
3302 if (*oh_name) {
3303 /* It is an ASCII name, do an ASCII to
3304 * unicode conversion */
3305 const char *ascii_oh_name = (const char *)oh_name;
3306 int n = buff_size - 1;
3307 while (n > 0 && *ascii_oh_name) {
3308 *name = *ascii_oh_name;
3309 name++;
3310 ascii_oh_name++;
3311 n--;
3312 }
3313 } else {
3314 strncpy(name, oh_name + 1, buff_size - 1);
3315 }
3316 } else {
3317#else
3318 {
3319#endif
3320 strncpy(name, oh_name, buff_size - 1);
3321 }
3322}
3323
3324static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR * oh_name,
3325 const YCHAR * name)
3326{
3327#ifdef CONFIG_YAFFS_AUTO_UNICODE
3328
3329 int is_ascii;
3330 YCHAR *w;
3331
3332 if (dev->param.auto_unicode) {
3333
3334 is_ascii = 1;
3335 w = name;
3336
3337 /* Figure out if the name will fit in ascii character set */
3338 while (is_ascii && *w) {
3339 if ((*w) & 0xff00)
3340 is_ascii = 0;
3341 w++;
3342 }
3343
3344 if (is_ascii) {
3345 /* It is an ASCII name, so do a unicode to ascii conversion */
3346 char *ascii_oh_name = (char *)oh_name;
3347 int n = YAFFS_MAX_NAME_LENGTH - 1;
3348 while (n > 0 && *name) {
3349 *ascii_oh_name = *name;
3350 name++;
3351 ascii_oh_name++;
3352 n--;
3353 }
3354 } else {
3355 /* It is a unicode name, so save starting at the second YCHAR */
3356 *oh_name = 0;
3357 strncpy(oh_name + 1, name,
3358 YAFFS_MAX_NAME_LENGTH - 2);
3359 }
3360 } else {
3361#else
3362 {
3363#endif
3364 strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
3365 }
3366
3367}
3368
3369/* UpdateObjectHeader updates the header on NAND for an object.
3370 * If name is not NULL, then that new name is used.
3371 */
3372int yaffs_update_oh(struct yaffs_obj *in, const YCHAR * name, int force,
3373 int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
3374{
3375
3376 struct yaffs_block_info *bi;
3377
3378 struct yaffs_dev *dev = in->my_dev;
3379
3380 int prev_chunk_id;
3381 int ret_val = 0;
3382 int result = 0;
3383
3384 int new_chunk_id;
3385 struct yaffs_ext_tags new_tags;
3386 struct yaffs_ext_tags old_tags;
3387 const YCHAR *alias = NULL;
3388
3389 u8 *buffer = NULL;
3390 YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
3391
3392 struct yaffs_obj_hdr *oh = NULL;
3393
3394 strcpy(old_name, _Y("silly old name"));
3395
3396 if (!in->fake || in == dev->root_dir ||
3397 force || xmod) {
3398
3399 yaffs_check_gc(dev, 0);
3400 yaffs_check_obj_details_loaded(in);
3401
3402 buffer = yaffs_get_temp_buffer(in->my_dev, __LINE__);
3403 oh = (struct yaffs_obj_hdr *)buffer;
3404
3405 prev_chunk_id = in->hdr_chunk;
3406
3407 if (prev_chunk_id > 0) {
3408 result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
3409 buffer, &old_tags);
3410
3411 yaffs_verify_oh(in, oh, &old_tags, 0);
3412
3413 memcpy(old_name, oh->name, sizeof(oh->name));
3414 memset(buffer, 0xFF, sizeof(struct yaffs_obj_hdr));
3415 } else {
3416 memset(buffer, 0xFF, dev->data_bytes_per_chunk);
3417 }
3418
3419 oh->type = in->variant_type;
3420 oh->yst_mode = in->yst_mode;
3421 oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
3422
3423 yaffs_load_attribs_oh(oh, in);
3424
3425 if (in->parent)
3426 oh->parent_obj_id = in->parent->obj_id;
3427 else
3428 oh->parent_obj_id = 0;
3429
3430 if (name && *name) {
3431 memset(oh->name, 0, sizeof(oh->name));
3432 yaffs_load_oh_from_name(dev, oh->name, name);
3433 } else if (prev_chunk_id > 0) {
3434 memcpy(oh->name, old_name, sizeof(oh->name));
3435 } else {
3436 memset(oh->name, 0, sizeof(oh->name));
3437 }
3438
3439 oh->is_shrink = is_shrink;
3440
3441 switch (in->variant_type) {
3442 case YAFFS_OBJECT_TYPE_UNKNOWN:
3443 /* Should not happen */
3444 break;
3445 case YAFFS_OBJECT_TYPE_FILE:
3446 oh->file_size =
3447 (oh->parent_obj_id == YAFFS_OBJECTID_DELETED
3448 || oh->parent_obj_id ==
3449 YAFFS_OBJECTID_UNLINKED) ? 0 : in->
3450 variant.file_variant.file_size;
3451 break;
3452 case YAFFS_OBJECT_TYPE_HARDLINK:
3453 oh->equiv_id = in->variant.hardlink_variant.equiv_id;
3454 break;
3455 case YAFFS_OBJECT_TYPE_SPECIAL:
3456 /* Do nothing */
3457 break;
3458 case YAFFS_OBJECT_TYPE_DIRECTORY:
3459 /* Do nothing */
3460 break;
3461 case YAFFS_OBJECT_TYPE_SYMLINK:
3462 alias = in->variant.symlink_variant.alias;
3463 if (!alias)
3464 alias = _Y("no alias");
3465 strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
3466 oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
3467 break;
3468 }
3469
3470 /* process any xattrib modifications */
3471 if (xmod)
3472 yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
3473
3474 /* Tags */
3475 yaffs_init_tags(&new_tags);
3476 in->serial++;
3477 new_tags.chunk_id = 0;
3478 new_tags.obj_id = in->obj_id;
3479 new_tags.serial_number = in->serial;
3480
3481 /* Add extra info for file header */
3482
3483 new_tags.extra_available = 1;
3484 new_tags.extra_parent_id = oh->parent_obj_id;
3485 new_tags.extra_length = oh->file_size;
3486 new_tags.extra_is_shrink = oh->is_shrink;
3487 new_tags.extra_equiv_id = oh->equiv_id;
3488 new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
3489 new_tags.extra_obj_type = in->variant_type;
3490
3491 yaffs_verify_oh(in, oh, &new_tags, 1);
3492
3493 /* Create new chunk in NAND */
3494 new_chunk_id =
3495 yaffs_write_new_chunk(dev, buffer, &new_tags,
3496 (prev_chunk_id > 0) ? 1 : 0);
3497
3498 if (new_chunk_id >= 0) {
3499
3500 in->hdr_chunk = new_chunk_id;
3501
3502 if (prev_chunk_id > 0) {
3503 yaffs_chunk_del(dev, prev_chunk_id, 1,
3504 __LINE__);
3505 }
3506
3507 if (!yaffs_obj_cache_dirty(in))
3508 in->dirty = 0;
3509
3510 /* If this was a shrink, then mark the block that the chunk lives on */
3511 if (is_shrink) {
3512 bi = yaffs_get_block_info(in->my_dev,
3513 new_chunk_id /
3514 in->my_dev->param.
3515 chunks_per_block);
3516 bi->has_shrink_hdr = 1;
3517 }
3518
3519 }
3520
3521 ret_val = new_chunk_id;
3522
3523 }
3524
3525 if (buffer)
3526 yaffs_release_temp_buffer(dev, buffer, __LINE__);
3527
3528 return ret_val;
3529}
3530
3531/*--------------------- File read/write ------------------------
3532 * Read and write have very similar structures.
3533 * In general the read/write has three parts to it
3534 * An incomplete chunk to start with (if the read/write is not chunk-aligned)
3535 * Some complete chunks
3536 * An incomplete chunk to end off with
3537 *
3538 * Curve-balls: the first chunk might also be the last chunk.
3539 */
3540
3541int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
3542{
3543
3544 int chunk;
3545 u32 start;
3546 int n_copy;
3547 int n = n_bytes;
3548 int n_done = 0;
3549 struct yaffs_cache *cache;
3550
3551 struct yaffs_dev *dev;
3552
3553 dev = in->my_dev;
3554
3555 while (n > 0) {
3556 /* chunk = offset / dev->data_bytes_per_chunk + 1; */
3557 /* start = offset % dev->data_bytes_per_chunk; */
3558 yaffs_addr_to_chunk(dev, offset, &chunk, &start);
3559 chunk++;
3560
3561 /* OK now check for the curveball where the start and end are in
3562 * the same chunk.
3563 */
3564 if ((start + n) < dev->data_bytes_per_chunk)
3565 n_copy = n;
3566 else
3567 n_copy = dev->data_bytes_per_chunk - start;
3568
3569 cache = yaffs_find_chunk_cache(in, chunk);
3570
3571 /* If the chunk is already in the cache or it is less than a whole chunk
3572 * or we're using inband tags then use the cache (if there is caching)
3573 * else bypass the cache.
3574 */
3575 if (cache || n_copy != dev->data_bytes_per_chunk
3576 || dev->param.inband_tags) {
3577 if (dev->param.n_caches > 0) {
3578
3579 /* If we can't find the data in the cache, then load it up. */
3580
3581 if (!cache) {
3582 cache =
3583 yaffs_grab_chunk_cache(in->my_dev);
3584 cache->object = in;
3585 cache->chunk_id = chunk;
3586 cache->dirty = 0;
3587 cache->locked = 0;
3588 yaffs_rd_data_obj(in, chunk,
3589 cache->data);
3590 cache->n_bytes = 0;
3591 }
3592
3593 yaffs_use_cache(dev, cache, 0);
3594
3595 cache->locked = 1;
3596
3597 memcpy(buffer, &cache->data[start], n_copy);
3598
3599 cache->locked = 0;
3600 } else {
3601 /* Read into the local buffer then copy.. */
3602
3603 u8 *local_buffer =
3604 yaffs_get_temp_buffer(dev, __LINE__);
3605 yaffs_rd_data_obj(in, chunk, local_buffer);
3606
3607 memcpy(buffer, &local_buffer[start], n_copy);
3608
3609 yaffs_release_temp_buffer(dev, local_buffer,
3610 __LINE__);
3611 }
3612
3613 } else {
3614
3615 /* A full chunk. Read directly into the supplied buffer. */
3616 yaffs_rd_data_obj(in, chunk, buffer);
3617
3618 }
3619
3620 n -= n_copy;
3621 offset += n_copy;
3622 buffer += n_copy;
3623 n_done += n_copy;
3624
3625 }
3626
3627 return n_done;
3628}
3629
3630int yaffs_do_file_wr(struct yaffs_obj *in, const u8 * buffer, loff_t offset,
3631 int n_bytes, int write_trhrough)
3632{
3633
3634 int chunk;
3635 u32 start;
3636 int n_copy;
3637 int n = n_bytes;
3638 int n_done = 0;
3639 int n_writeback;
3640 int start_write = offset;
3641 int chunk_written = 0;
3642 u32 n_bytes_read;
3643 u32 chunk_start;
3644
3645 struct yaffs_dev *dev;
3646
3647 dev = in->my_dev;
3648
3649 while (n > 0 && chunk_written >= 0) {
3650 yaffs_addr_to_chunk(dev, offset, &chunk, &start);
3651
3652 if (chunk * dev->data_bytes_per_chunk + start != offset ||
3653 start >= dev->data_bytes_per_chunk) {
3654 yaffs_trace(YAFFS_TRACE_ERROR,
3655 "AddrToChunk of offset %d gives chunk %d start %d",
3656 (int)offset, chunk, start);
3657 }
3658 chunk++; /* File pos to chunk in file offset */
3659
3660 /* OK now check for the curveball where the start and end are in
3661 * the same chunk.
3662 */
3663
3664 if ((start + n) < dev->data_bytes_per_chunk) {
3665 n_copy = n;
3666
3667 /* Now folks, to calculate how many bytes to write back....
3668 * If we're overwriting and not writing to then end of file then
3669 * we need to write back as much as was there before.
3670 */
3671
3672 chunk_start = ((chunk - 1) * dev->data_bytes_per_chunk);
3673
3674 if (chunk_start > in->variant.file_variant.file_size)
3675 n_bytes_read = 0; /* Past end of file */
3676 else
3677 n_bytes_read =
3678 in->variant.file_variant.file_size -
3679 chunk_start;
3680
3681 if (n_bytes_read > dev->data_bytes_per_chunk)
3682 n_bytes_read = dev->data_bytes_per_chunk;
3683
3684 n_writeback =
3685 (n_bytes_read >
3686 (start + n)) ? n_bytes_read : (start + n);
3687
3688 if (n_writeback < 0
3689 || n_writeback > dev->data_bytes_per_chunk)
3690 YBUG();
3691
3692 } else {
3693 n_copy = dev->data_bytes_per_chunk - start;
3694 n_writeback = dev->data_bytes_per_chunk;
3695 }
3696
3697 if (n_copy != dev->data_bytes_per_chunk
3698 || dev->param.inband_tags) {
3699 /* An incomplete start or end chunk (or maybe both start and end chunk),
3700 * or we're using inband tags, so we want to use the cache buffers.
3701 */
3702 if (dev->param.n_caches > 0) {
3703 struct yaffs_cache *cache;
3704 /* If we can't find the data in the cache, then load the cache */
3705 cache = yaffs_find_chunk_cache(in, chunk);
3706
3707 if (!cache
3708 && yaffs_check_alloc_available(dev, 1)) {
3709 cache = yaffs_grab_chunk_cache(dev);
3710 cache->object = in;
3711 cache->chunk_id = chunk;
3712 cache->dirty = 0;
3713 cache->locked = 0;
3714 yaffs_rd_data_obj(in, chunk,
3715 cache->data);
3716 } else if (cache &&
3717 !cache->dirty &&
3718 !yaffs_check_alloc_available(dev,
3719 1)) {
3720 /* Drop the cache if it was a read cache item and
3721 * no space check has been made for it.
3722 */
3723 cache = NULL;
3724 }
3725
3726 if (cache) {
3727 yaffs_use_cache(dev, cache, 1);
3728 cache->locked = 1;
3729
3730 memcpy(&cache->data[start], buffer,
3731 n_copy);
3732
3733 cache->locked = 0;
3734 cache->n_bytes = n_writeback;
3735
3736 if (write_trhrough) {
3737 chunk_written =
3738 yaffs_wr_data_obj
3739 (cache->object,
3740 cache->chunk_id,
3741 cache->data,
3742 cache->n_bytes, 1);
3743 cache->dirty = 0;
3744 }
3745
3746 } else {
3747 chunk_written = -1; /* fail the write */
3748 }
3749 } else {
3750 /* An incomplete start or end chunk (or maybe both start and end chunk)
3751 * Read into the local buffer then copy, then copy over and write back.
3752 */
3753
3754 u8 *local_buffer =
3755 yaffs_get_temp_buffer(dev, __LINE__);
3756
3757 yaffs_rd_data_obj(in, chunk, local_buffer);
3758
3759 memcpy(&local_buffer[start], buffer, n_copy);
3760
3761 chunk_written =
3762 yaffs_wr_data_obj(in, chunk,
3763 local_buffer,
3764 n_writeback, 0);
3765
3766 yaffs_release_temp_buffer(dev, local_buffer,
3767 __LINE__);
3768
3769 }
3770
3771 } else {
3772 /* A full chunk. Write directly from the supplied buffer. */
3773
3774 chunk_written =
3775 yaffs_wr_data_obj(in, chunk, buffer,
3776 dev->data_bytes_per_chunk, 0);
3777
3778 /* Since we've overwritten the cached data, we better invalidate it. */
3779 yaffs_invalidate_chunk_cache(in, chunk);
3780 }
3781
3782 if (chunk_written >= 0) {
3783 n -= n_copy;
3784 offset += n_copy;
3785 buffer += n_copy;
3786 n_done += n_copy;
3787 }
3788
3789 }
3790
3791 /* Update file object */
3792
3793 if ((start_write + n_done) > in->variant.file_variant.file_size)
3794 in->variant.file_variant.file_size = (start_write + n_done);
3795
3796 in->dirty = 1;
3797
3798 return n_done;
3799}
3800
3801int yaffs_wr_file(struct yaffs_obj *in, const u8 * buffer, loff_t offset,
3802 int n_bytes, int write_trhrough)
3803{
3804 yaffs2_handle_hole(in, offset);
3805 return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_trhrough);
3806}
3807
3808/* ---------------------- File resizing stuff ------------------ */
3809
3810static void yaffs_prune_chunks(struct yaffs_obj *in, int new_size)
3811{
3812
3813 struct yaffs_dev *dev = in->my_dev;
3814 int old_size = in->variant.file_variant.file_size;
3815
3816 int last_del = 1 + (old_size - 1) / dev->data_bytes_per_chunk;
3817
3818 int start_del = 1 + (new_size + dev->data_bytes_per_chunk - 1) /
3819 dev->data_bytes_per_chunk;
3820 int i;
3821 int chunk_id;
3822
3823 /* Delete backwards so that we don't end up with holes if
3824 * power is lost part-way through the operation.
3825 */
3826 for (i = last_del; i >= start_del; i--) {
3827 /* NB this could be optimised somewhat,
3828 * eg. could retrieve the tags and write them without
3829 * using yaffs_chunk_del
3830 */
3831
3832 chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
3833 if (chunk_id > 0) {
3834 if (chunk_id <
3835 (dev->internal_start_block *
3836 dev->param.chunks_per_block)
3837 || chunk_id >=
3838 ((dev->internal_end_block +
3839 1) * dev->param.chunks_per_block)) {
3840 yaffs_trace(YAFFS_TRACE_ALWAYS,
3841 "Found daft chunk_id %d for %d",
3842 chunk_id, i);
3843 } else {
3844 in->n_data_chunks--;
3845 yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
3846 }
3847 }
3848 }
3849
3850}
3851
3852void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
3853{
3854 int new_full;
3855 u32 new_partial;
3856 struct yaffs_dev *dev = obj->my_dev;
3857
3858 yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
3859
3860 yaffs_prune_chunks(obj, new_size);
3861
3862 if (new_partial != 0) {
3863 int last_chunk = 1 + new_full;
3864 u8 *local_buffer = yaffs_get_temp_buffer(dev, __LINE__);
3865
3866 /* Rewrite the last chunk with its new size and zero pad */
3867 yaffs_rd_data_obj(obj, last_chunk, local_buffer);
3868 memset(local_buffer + new_partial, 0,
3869 dev->data_bytes_per_chunk - new_partial);
3870
3871 yaffs_wr_data_obj(obj, last_chunk, local_buffer,
3872 new_partial, 1);
3873
3874 yaffs_release_temp_buffer(dev, local_buffer, __LINE__);
3875 }
3876
3877 obj->variant.file_variant.file_size = new_size;
3878
3879 yaffs_prune_tree(dev, &obj->variant.file_variant);
3880}
3881
3882int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
3883{
3884 struct yaffs_dev *dev = in->my_dev;
3885 int old_size = in->variant.file_variant.file_size;
3886
3887 yaffs_flush_file_cache(in);
3888 yaffs_invalidate_whole_cache(in);
3889
3890 yaffs_check_gc(dev, 0);
3891
3892 if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
3893 return YAFFS_FAIL;
3894
3895 if (new_size == old_size)
3896 return YAFFS_OK;
3897
3898 if (new_size > old_size) {
3899 yaffs2_handle_hole(in, new_size);
3900 in->variant.file_variant.file_size = new_size;
3901 } else {
3902 /* new_size < old_size */
3903 yaffs_resize_file_down(in, new_size);
3904 }
3905
3906 /* Write a new object header to reflect the resize.
3907 * show we've shrunk the file, if need be
3908 * Do this only if the file is not in the deleted directories
3909 * and is not shadowed.
3910 */
3911 if (in->parent &&
3912 !in->is_shadowed &&
3913 in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
3914 in->parent->obj_id != YAFFS_OBJECTID_DELETED)
3915 yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
3916
3917 return YAFFS_OK;
3918}
3919
3920int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
3921{
3922 int ret_val;
3923 if (in->dirty) {
3924 yaffs_flush_file_cache(in);
3925 if (data_sync) /* Only sync data */
3926 ret_val = YAFFS_OK;
3927 else {
3928 if (update_time)
3929 yaffs_load_current_time(in, 0, 0);
3930
3931 ret_val = (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >=
3932 0) ? YAFFS_OK : YAFFS_FAIL;
3933 }
3934 } else {
3935 ret_val = YAFFS_OK;
3936 }
3937
3938 return ret_val;
3939
3940}
3941
3942
3943/* yaffs_del_file deletes the whole file data
3944 * and the inode associated with the file.
3945 * It does not delete the links associated with the file.
3946 */
3947static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
3948{
3949
3950 int ret_val;
3951 int del_now = 0;
3952 struct yaffs_dev *dev = in->my_dev;
3953
3954 if (!in->my_inode)
3955 del_now = 1;
3956
3957 if (del_now) {
3958 ret_val =
3959 yaffs_change_obj_name(in, in->my_dev->del_dir,
3960 _Y("deleted"), 0, 0);
3961 yaffs_trace(YAFFS_TRACE_TRACING,
3962 "yaffs: immediate deletion of file %d",
3963 in->obj_id);
3964 in->deleted = 1;
3965 in->my_dev->n_deleted_files++;
3966 if (dev->param.disable_soft_del || dev->param.is_yaffs2)
3967 yaffs_resize_file(in, 0);
3968 yaffs_soft_del_file(in);
3969 } else {
3970 ret_val =
3971 yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
3972 _Y("unlinked"), 0, 0);
3973 }
3974
3975 return ret_val;
3976}
3977
3978int yaffs_del_file(struct yaffs_obj *in)
3979{
3980 int ret_val = YAFFS_OK;
3981 int deleted; /* Need to cache value on stack if in is freed */
3982 struct yaffs_dev *dev = in->my_dev;
3983
3984 if (dev->param.disable_soft_del || dev->param.is_yaffs2)
3985 yaffs_resize_file(in, 0);
3986
3987 if (in->n_data_chunks > 0) {
3988 /* Use soft deletion if there is data in the file.
3989 * That won't be the case if it has been resized to zero.
3990 */
3991 if (!in->unlinked)
3992 ret_val = yaffs_unlink_file_if_needed(in);
3993
3994 deleted = in->deleted;
3995
3996 if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
3997 in->deleted = 1;
3998 deleted = 1;
3999 in->my_dev->n_deleted_files++;
4000 yaffs_soft_del_file(in);
4001 }
4002 return deleted ? YAFFS_OK : YAFFS_FAIL;
4003 } else {
4004 /* The file has no data chunks so we toss it immediately */
4005 yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
4006 in->variant.file_variant.top = NULL;
4007 yaffs_generic_obj_del(in);
4008
4009 return YAFFS_OK;
4010 }
4011}
4012
4013int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
4014{
4015 return (obj &&
4016 obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
4017 !(list_empty(&obj->variant.dir_variant.children));
4018}
4019
4020static int yaffs_del_dir(struct yaffs_obj *obj)
4021{
4022 /* First check that the directory is empty. */
4023 if (yaffs_is_non_empty_dir(obj))
4024 return YAFFS_FAIL;
4025
4026 return yaffs_generic_obj_del(obj);
4027}
4028
4029static int yaffs_del_symlink(struct yaffs_obj *in)
4030{
4031 if (in->variant.symlink_variant.alias)
4032 kfree(in->variant.symlink_variant.alias);
4033 in->variant.symlink_variant.alias = NULL;
4034
4035 return yaffs_generic_obj_del(in);
4036}
4037
4038static int yaffs_del_link(struct yaffs_obj *in)
4039{
4040 /* remove this hardlink from the list assocaited with the equivalent
4041 * object
4042 */
4043 list_del_init(&in->hard_links);
4044 return yaffs_generic_obj_del(in);
4045}
4046
4047int yaffs_del_obj(struct yaffs_obj *obj)
4048{
4049 int ret_val = -1;
4050 switch (obj->variant_type) {
4051 case YAFFS_OBJECT_TYPE_FILE:
4052 ret_val = yaffs_del_file(obj);
4053 break;
4054 case YAFFS_OBJECT_TYPE_DIRECTORY:
4055 if (!list_empty(&obj->variant.dir_variant.dirty)) {
4056 yaffs_trace(YAFFS_TRACE_BACKGROUND,
4057 "Remove object %d from dirty directories",
4058 obj->obj_id);
4059 list_del_init(&obj->variant.dir_variant.dirty);
4060 }
4061 return yaffs_del_dir(obj);
4062 break;
4063 case YAFFS_OBJECT_TYPE_SYMLINK:
4064 ret_val = yaffs_del_symlink(obj);
4065 break;
4066 case YAFFS_OBJECT_TYPE_HARDLINK:
4067 ret_val = yaffs_del_link(obj);
4068 break;
4069 case YAFFS_OBJECT_TYPE_SPECIAL:
4070 ret_val = yaffs_generic_obj_del(obj);
4071 break;
4072 case YAFFS_OBJECT_TYPE_UNKNOWN:
4073 ret_val = 0;
4074 break; /* should not happen. */
4075 }
4076
4077 return ret_val;
4078}
4079
4080static int yaffs_unlink_worker(struct yaffs_obj *obj)
4081{
4082
4083 int del_now = 0;
4084
4085 if (!obj->my_inode)
4086 del_now = 1;
4087
4088 if (obj)
4089 yaffs_update_parent(obj->parent);
4090
4091 if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
4092 return yaffs_del_link(obj);
4093 } else if (!list_empty(&obj->hard_links)) {
4094 /* Curve ball: We're unlinking an object that has a hardlink.
4095 *
4096 * This problem arises because we are not strictly following
4097 * The Linux link/inode model.
4098 *
4099 * We can't really delete the object.
4100 * Instead, we do the following:
4101 * - Select a hardlink.
4102 * - Unhook it from the hard links
4103 * - Move it from its parent directory (so that the rename can work)
4104 * - Rename the object to the hardlink's name.
4105 * - Delete the hardlink
4106 */
4107
4108 struct yaffs_obj *hl;
4109 struct yaffs_obj *parent;
4110 int ret_val;
4111 YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
4112
4113 hl = list_entry(obj->hard_links.next, struct yaffs_obj,
4114 hard_links);
4115
4116 yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
4117 parent = hl->parent;
4118
4119 list_del_init(&hl->hard_links);
4120
4121 yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
4122
4123 ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
4124
4125 if (ret_val == YAFFS_OK)
4126 ret_val = yaffs_generic_obj_del(hl);
4127
4128 return ret_val;
4129
4130 } else if (del_now) {
4131 switch (obj->variant_type) {
4132 case YAFFS_OBJECT_TYPE_FILE:
4133 return yaffs_del_file(obj);
4134 break;
4135 case YAFFS_OBJECT_TYPE_DIRECTORY:
4136 list_del_init(&obj->variant.dir_variant.dirty);
4137 return yaffs_del_dir(obj);
4138 break;
4139 case YAFFS_OBJECT_TYPE_SYMLINK:
4140 return yaffs_del_symlink(obj);
4141 break;
4142 case YAFFS_OBJECT_TYPE_SPECIAL:
4143 return yaffs_generic_obj_del(obj);
4144 break;
4145 case YAFFS_OBJECT_TYPE_HARDLINK:
4146 case YAFFS_OBJECT_TYPE_UNKNOWN:
4147 default:
4148 return YAFFS_FAIL;
4149 }
4150 } else if (yaffs_is_non_empty_dir(obj)) {
4151 return YAFFS_FAIL;
4152 } else {
4153 return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
4154 _Y("unlinked"), 0, 0);
4155 }
4156}
4157
4158static int yaffs_unlink_obj(struct yaffs_obj *obj)
4159{
4160
4161 if (obj && obj->unlink_allowed)
4162 return yaffs_unlink_worker(obj);
4163
4164 return YAFFS_FAIL;
4165
4166}
4167
4168int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name)
4169{
4170 struct yaffs_obj *obj;
4171
4172 obj = yaffs_find_by_name(dir, name);
4173 return yaffs_unlink_obj(obj);
4174}
4175
4176/* Note:
4177 * If old_name is NULL then we take old_dir as the object to be renamed.
4178 */
4179int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
4180 struct yaffs_obj *new_dir, const YCHAR * new_name)
4181{
4182 struct yaffs_obj *obj = NULL;
4183 struct yaffs_obj *existing_target = NULL;
4184 int force = 0;
4185 int result;
4186 struct yaffs_dev *dev;
4187
4188 if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
4189 YBUG();
4190 if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
4191 YBUG();
4192
4193 dev = old_dir->my_dev;
4194
4195#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
4196 /* Special case for case insemsitive systems.
4197 * While look-up is case insensitive, the name isn't.
4198 * Therefore we might want to change x.txt to X.txt
4199 */
4200 if (old_dir == new_dir &&
4201 old_name && new_name &&
4202 strcmp(old_name, new_name) == 0)
4203 force = 1;
4204#endif
4205
4206 if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
4207 YAFFS_MAX_NAME_LENGTH)
4208 /* ENAMETOOLONG */
4209 return YAFFS_FAIL;
4210
4211 if(old_name)
4212 obj = yaffs_find_by_name(old_dir, old_name);
4213 else{
4214 obj = old_dir;
4215 old_dir = obj->parent;
4216 }
4217
4218
4219 if (obj && obj->rename_allowed) {
4220
4221 /* Now do the handling for an existing target, if there is one */
4222
4223 existing_target = yaffs_find_by_name(new_dir, new_name);
4224 if (yaffs_is_non_empty_dir(existing_target)){
4225 return YAFFS_FAIL; /* ENOTEMPTY */
4226 } else if (existing_target && existing_target != obj) {
4227 /* Nuke the target first, using shadowing,
4228 * but only if it isn't the same object.
4229 *
4230 * Note we must disable gc otherwise it can mess up the shadowing.
4231 *
4232 */
4233 dev->gc_disable = 1;
4234 yaffs_change_obj_name(obj, new_dir, new_name, force,
4235 existing_target->obj_id);
4236 existing_target->is_shadowed = 1;
4237 yaffs_unlink_obj(existing_target);
4238 dev->gc_disable = 0;
4239 }
4240
4241 result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
4242
4243 yaffs_update_parent(old_dir);
4244 if (new_dir != old_dir)
4245 yaffs_update_parent(new_dir);
4246
4247 return result;
4248 }
4249 return YAFFS_FAIL;
4250}
4251
4252/*----------------------- Initialisation Scanning ---------------------- */
4253
4254void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
4255 int backward_scanning)
4256{
4257 struct yaffs_obj *obj;
4258
4259 if (!backward_scanning) {
4260 /* Handle YAFFS1 forward scanning case
4261 * For YAFFS1 we always do the deletion
4262 */
4263
4264 } else {
4265 /* Handle YAFFS2 case (backward scanning)
4266 * If the shadowed object exists then ignore.
4267 */
4268 obj = yaffs_find_by_number(dev, obj_id);
4269 if (obj)
4270 return;
4271 }
4272
4273 /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
4274 * We put it in unlinked dir to be cleaned up after the scanning
4275 */
4276 obj =
4277 yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
4278 if (!obj)
4279 return;
4280 obj->is_shadowed = 1;
4281 yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
4282 obj->variant.file_variant.shrink_size = 0;
4283 obj->valid = 1; /* So that we don't read any other info for this file */
4284
4285}
4286
4287void yaffs_link_fixup(struct yaffs_dev *dev, struct yaffs_obj *hard_list)
4288{
4289 struct yaffs_obj *hl;
4290 struct yaffs_obj *in;
4291
4292 while (hard_list) {
4293 hl = hard_list;
4294 hard_list = (struct yaffs_obj *)(hard_list->hard_links.next);
4295
4296 in = yaffs_find_by_number(dev,
4297 hl->variant.
4298 hardlink_variant.equiv_id);
4299
4300 if (in) {
4301 /* Add the hardlink pointers */
4302 hl->variant.hardlink_variant.equiv_obj = in;
4303 list_add(&hl->hard_links, &in->hard_links);
4304 } else {
4305 /* Todo Need to report/handle this better.
4306 * Got a problem... hardlink to a non-existant object
4307 */
4308 hl->variant.hardlink_variant.equiv_obj = NULL;
4309 INIT_LIST_HEAD(&hl->hard_links);
4310
4311 }
4312 }
4313}
4314
4315static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
4316{
4317 /*
4318 * Sort out state of unlinked and deleted objects after scanning.
4319 */
4320 struct list_head *i;
4321 struct list_head *n;
4322 struct yaffs_obj *l;
4323
4324 if (dev->read_only)
4325 return;
4326
4327 /* Soft delete all the unlinked files */
4328 list_for_each_safe(i, n,
4329 &dev->unlinked_dir->variant.dir_variant.children) {
4330 if (i) {
4331 l = list_entry(i, struct yaffs_obj, siblings);
4332 yaffs_del_obj(l);
4333 }
4334 }
4335
4336 list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
4337 if (i) {
4338 l = list_entry(i, struct yaffs_obj, siblings);
4339 yaffs_del_obj(l);
4340 }
4341 }
4342
4343}
4344
4345/*
4346 * This code iterates through all the objects making sure that they are rooted.
4347 * Any unrooted objects are re-rooted in lost+found.
4348 * An object needs to be in one of:
4349 * - Directly under deleted, unlinked
4350 * - Directly or indirectly under root.
4351 *
4352 * Note:
4353 * This code assumes that we don't ever change the current relationships between
4354 * directories:
4355 * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
4356 * lost-n-found->parent == root_dir
4357 *
4358 * This fixes the problem where directories might have inadvertently been deleted
4359 * leaving the object "hanging" without being rooted in the directory tree.
4360 */
4361
4362static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
4363{
4364 return (obj == dev->del_dir ||
4365 obj == dev->unlinked_dir || obj == dev->root_dir);
4366}
4367
4368static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
4369{
4370 struct yaffs_obj *obj;
4371 struct yaffs_obj *parent;
4372 int i;
4373 struct list_head *lh;
4374 struct list_head *n;
4375 int depth_limit;
4376 int hanging;
4377
4378 if (dev->read_only)
4379 return;
4380
4381 /* Iterate through the objects in each hash entry,
4382 * looking at each object.
4383 * Make sure it is rooted.
4384 */
4385
4386 for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
4387 list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
4388 if (lh) {
4389 obj =
4390 list_entry(lh, struct yaffs_obj, hash_link);
4391 parent = obj->parent;
4392
4393 if (yaffs_has_null_parent(dev, obj)) {
4394 /* These directories are not hanging */
4395 hanging = 0;
4396 } else if (!parent
4397 || parent->variant_type !=
4398 YAFFS_OBJECT_TYPE_DIRECTORY) {
4399 hanging = 1;
4400 } else if (yaffs_has_null_parent(dev, parent)) {
4401 hanging = 0;
4402 } else {
4403 /*
4404 * Need to follow the parent chain to see if it is hanging.
4405 */
4406 hanging = 0;
4407 depth_limit = 100;
4408
4409 while (parent != dev->root_dir &&
4410 parent->parent &&
4411 parent->parent->variant_type ==
4412 YAFFS_OBJECT_TYPE_DIRECTORY
4413 && depth_limit > 0) {
4414 parent = parent->parent;
4415 depth_limit--;
4416 }
4417 if (parent != dev->root_dir)
4418 hanging = 1;
4419 }
4420 if (hanging) {
4421 yaffs_trace(YAFFS_TRACE_SCAN,
4422 "Hanging object %d moved to lost and found",
4423 obj->obj_id);
4424 yaffs_add_obj_to_dir(dev->lost_n_found,
4425 obj);
4426 }
4427 }
4428 }
4429 }
4430}
4431
4432/*
4433 * Delete directory contents for cleaning up lost and found.
4434 */
4435static void yaffs_del_dir_contents(struct yaffs_obj *dir)
4436{
4437 struct yaffs_obj *obj;
4438 struct list_head *lh;
4439 struct list_head *n;
4440
4441 if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
4442 YBUG();
4443
4444 list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
4445 if (lh) {
4446 obj = list_entry(lh, struct yaffs_obj, siblings);
4447 if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
4448 yaffs_del_dir_contents(obj);
4449
4450 yaffs_trace(YAFFS_TRACE_SCAN,
4451 "Deleting lost_found object %d",
4452 obj->obj_id);
4453
4454 /* Need to use UnlinkObject since Delete would not handle
4455 * hardlinked objects correctly.
4456 */
4457 yaffs_unlink_obj(obj);
4458 }
4459 }
4460
4461}
4462
4463static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
4464{
4465 yaffs_del_dir_contents(dev->lost_n_found);
4466}
4467
4468
4469struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
4470 const YCHAR * name)
4471{
4472 int sum;
4473
4474 struct list_head *i;
4475 YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
4476
4477 struct yaffs_obj *l;
4478
4479 if (!name)
4480 return NULL;
4481
4482 if (!directory) {
4483 yaffs_trace(YAFFS_TRACE_ALWAYS,
4484 "tragedy: yaffs_find_by_name: null pointer directory"
4485 );
4486 YBUG();
4487 return NULL;
4488 }
4489 if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
4490 yaffs_trace(YAFFS_TRACE_ALWAYS,
4491 "tragedy: yaffs_find_by_name: non-directory"
4492 );
4493 YBUG();
4494 }
4495
4496 sum = yaffs_calc_name_sum(name);
4497
4498 list_for_each(i, &directory->variant.dir_variant.children) {
4499 if (i) {
4500 l = list_entry(i, struct yaffs_obj, siblings);
4501
4502 if (l->parent != directory)
4503 YBUG();
4504
4505 yaffs_check_obj_details_loaded(l);
4506
4507 /* Special case for lost-n-found */
4508 if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
4509 if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
4510 return l;
4511 } else if (l->sum == sum
4512 || l->hdr_chunk <= 0) {
4513 /* LostnFound chunk called Objxxx
4514 * Do a real check
4515 */
4516 yaffs_get_obj_name(l, buffer,
4517 YAFFS_MAX_NAME_LENGTH + 1);
4518 if (strncmp
4519 (name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
4520 return l;
4521 }
4522 }
4523 }
4524
4525 return NULL;
4526}
4527
4528/* GetEquivalentObject dereferences any hard links to get to the
4529 * actual object.
4530 */
4531
4532struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
4533{
4534 if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
4535 /* We want the object id of the equivalent object, not this one */
4536 obj = obj->variant.hardlink_variant.equiv_obj;
4537 yaffs_check_obj_details_loaded(obj);
4538 }
4539 return obj;
4540}
4541
4542/*
4543 * A note or two on object names.
4544 * * If the object name is missing, we then make one up in the form objnnn
4545 *
4546 * * ASCII names are stored in the object header's name field from byte zero
4547 * * Unicode names are historically stored starting from byte zero.
4548 *
4549 * Then there are automatic Unicode names...
4550 * The purpose of these is to save names in a way that can be read as
4551 * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
4552 * system to share files.
4553 *
4554 * These automatic unicode are stored slightly differently...
4555 * - If the name can fit in the ASCII character space then they are saved as
4556 * ascii names as per above.
4557 * - If the name needs Unicode then the name is saved in Unicode
4558 * starting at oh->name[1].
4559
4560 */
4561static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR * name,
4562 int buffer_size)
4563{
4564 /* Create an object name if we could not find one. */
4565 if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
4566 YCHAR local_name[20];
4567 YCHAR num_string[20];
4568 YCHAR *x = &num_string[19];
4569 unsigned v = obj->obj_id;
4570 num_string[19] = 0;
4571 while (v > 0) {
4572 x--;
4573 *x = '0' + (v % 10);
4574 v /= 10;
4575 }
4576 /* make up a name */
4577 strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
4578 strcat(local_name, x);
4579 strncpy(name, local_name, buffer_size - 1);
4580 }
4581}
4582
4583int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size)
4584{
4585 memset(name, 0, buffer_size * sizeof(YCHAR));
4586
4587 yaffs_check_obj_details_loaded(obj);
4588
4589 if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
4590 strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
4591 }
4592#ifndef CONFIG_YAFFS_NO_SHORT_NAMES
4593 else if (obj->short_name[0]) {
4594 strcpy(name, obj->short_name);
4595 }
4596#endif
4597 else if (obj->hdr_chunk > 0) {
4598 int result;
4599 u8 *buffer = yaffs_get_temp_buffer(obj->my_dev, __LINE__);
4600
4601 struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
4602
4603 memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
4604
4605 if (obj->hdr_chunk > 0) {
4606 result = yaffs_rd_chunk_tags_nand(obj->my_dev,
4607 obj->hdr_chunk,
4608 buffer, NULL);
4609 }
4610 yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
4611 buffer_size);
4612
4613 yaffs_release_temp_buffer(obj->my_dev, buffer, __LINE__);
4614 }
4615
4616 yaffs_fix_null_name(obj, name, buffer_size);
4617
4618 return strnlen(name, YAFFS_MAX_NAME_LENGTH);
4619}
4620
4621int yaffs_get_obj_length(struct yaffs_obj *obj)
4622{
4623 /* Dereference any hard linking */
4624 obj = yaffs_get_equivalent_obj(obj);
4625
4626 if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
4627 return obj->variant.file_variant.file_size;
4628 if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
4629 if (!obj->variant.symlink_variant.alias)
4630 return 0;
4631 return strnlen(obj->variant.symlink_variant.alias,
4632 YAFFS_MAX_ALIAS_LENGTH);
4633 } else {
4634 /* Only a directory should drop through to here */
4635 return obj->my_dev->data_bytes_per_chunk;
4636 }
4637}
4638
4639int yaffs_get_obj_link_count(struct yaffs_obj *obj)
4640{
4641 int count = 0;
4642 struct list_head *i;
4643
4644 if (!obj->unlinked)
4645 count++; /* the object itself */
4646
4647 list_for_each(i, &obj->hard_links)
4648 count++; /* add the hard links; */
4649
4650 return count;
4651}
4652
4653int yaffs_get_obj_inode(struct yaffs_obj *obj)
4654{
4655 obj = yaffs_get_equivalent_obj(obj);
4656
4657 return obj->obj_id;
4658}
4659
4660unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
4661{
4662 obj = yaffs_get_equivalent_obj(obj);
4663
4664 switch (obj->variant_type) {
4665 case YAFFS_OBJECT_TYPE_FILE:
4666 return DT_REG;
4667 break;
4668 case YAFFS_OBJECT_TYPE_DIRECTORY:
4669 return DT_DIR;
4670 break;
4671 case YAFFS_OBJECT_TYPE_SYMLINK:
4672 return DT_LNK;
4673 break;
4674 case YAFFS_OBJECT_TYPE_HARDLINK:
4675 return DT_REG;
4676 break;
4677 case YAFFS_OBJECT_TYPE_SPECIAL:
4678 if (S_ISFIFO(obj->yst_mode))
4679 return DT_FIFO;
4680 if (S_ISCHR(obj->yst_mode))
4681 return DT_CHR;
4682 if (S_ISBLK(obj->yst_mode))
4683 return DT_BLK;
4684 if (S_ISSOCK(obj->yst_mode))
4685 return DT_SOCK;
4686 default:
4687 return DT_REG;
4688 break;
4689 }
4690}
4691
4692YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
4693{
4694 obj = yaffs_get_equivalent_obj(obj);
4695 if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
4696 return yaffs_clone_str(obj->variant.symlink_variant.alias);
4697 else
4698 return yaffs_clone_str(_Y(""));
4699}
4700
4701/*--------------------------- Initialisation code -------------------------- */
4702
4703static int yaffs_check_dev_fns(const struct yaffs_dev *dev)
4704{
4705
4706 /* Common functions, gotta have */
4707 if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
4708 return 0;
4709
4710#ifdef CONFIG_YAFFS_YAFFS2
4711
4712 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
4713 if (dev->param.write_chunk_tags_fn &&
4714 dev->param.read_chunk_tags_fn &&
4715 !dev->param.write_chunk_fn &&
4716 !dev->param.read_chunk_fn &&
4717 dev->param.bad_block_fn && dev->param.query_block_fn)
4718 return 1;
4719#endif
4720
4721 /* Can use the "spare" style interface for yaffs1 */
4722 if (!dev->param.is_yaffs2 &&
4723 !dev->param.write_chunk_tags_fn &&
4724 !dev->param.read_chunk_tags_fn &&
4725 dev->param.write_chunk_fn &&
4726 dev->param.read_chunk_fn &&
4727 !dev->param.bad_block_fn && !dev->param.query_block_fn)
4728 return 1;
4729
4730 return 0; /* bad */
4731}
4732
4733static int yaffs_create_initial_dir(struct yaffs_dev *dev)
4734{
4735 /* Initialise the unlinked, deleted, root and lost and found directories */
4736
4737 dev->lost_n_found = dev->root_dir = NULL;
4738 dev->unlinked_dir = dev->del_dir = NULL;
4739
4740 dev->unlinked_dir =
4741 yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
4742
4743 dev->del_dir =
4744 yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
4745
4746 dev->root_dir =
4747 yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
4748 YAFFS_ROOT_MODE | S_IFDIR);
4749 dev->lost_n_found =
4750 yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
4751 YAFFS_LOSTNFOUND_MODE | S_IFDIR);
4752
4753 if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
4754 && dev->del_dir) {
4755 yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
4756 return YAFFS_OK;
4757 }
4758
4759 return YAFFS_FAIL;
4760}
4761
4762int yaffs_guts_initialise(struct yaffs_dev *dev)
4763{
4764 int init_failed = 0;
4765 unsigned x;
4766 int bits;
4767
4768 yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_guts_initialise()" );
4769
4770 /* Check stuff that must be set */
4771
4772 if (!dev) {
4773 yaffs_trace(YAFFS_TRACE_ALWAYS,
4774 "yaffs: Need a device"
4775 );
4776 return YAFFS_FAIL;
4777 }
4778
4779 dev->internal_start_block = dev->param.start_block;
4780 dev->internal_end_block = dev->param.end_block;
4781 dev->block_offset = 0;
4782 dev->chunk_offset = 0;
4783 dev->n_free_chunks = 0;
4784
4785 dev->gc_block = 0;
4786
4787 if (dev->param.start_block == 0) {
4788 dev->internal_start_block = dev->param.start_block + 1;
4789 dev->internal_end_block = dev->param.end_block + 1;
4790 dev->block_offset = 1;
4791 dev->chunk_offset = dev->param.chunks_per_block;
4792 }
4793
4794 /* Check geometry parameters. */
4795
4796 if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
4797 dev->param.total_bytes_per_chunk < 1024) ||
4798 (!dev->param.is_yaffs2 &&
4799 dev->param.total_bytes_per_chunk < 512) ||
4800 (dev->param.inband_tags && !dev->param.is_yaffs2) ||
4801 dev->param.chunks_per_block < 2 ||
4802 dev->param.n_reserved_blocks < 2 ||
4803 dev->internal_start_block <= 0 ||
4804 dev->internal_end_block <= 0 ||
4805 dev->internal_end_block <=
4806 (dev->internal_start_block + dev->param.n_reserved_blocks + 2)
4807 ) {
4808 /* otherwise it is too small */
4809 yaffs_trace(YAFFS_TRACE_ALWAYS,
4810 "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
4811 dev->param.total_bytes_per_chunk,
4812 dev->param.is_yaffs2 ? "2" : "",
4813 dev->param.inband_tags);
4814 return YAFFS_FAIL;
4815 }
4816
4817 if (yaffs_init_nand(dev) != YAFFS_OK) {
4818 yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
4819 return YAFFS_FAIL;
4820 }
4821
4822 /* Sort out space for inband tags, if required */
4823 if (dev->param.inband_tags)
4824 dev->data_bytes_per_chunk =
4825 dev->param.total_bytes_per_chunk -
4826 sizeof(struct yaffs_packed_tags2_tags_only);
4827 else
4828 dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
4829
4830 /* Got the right mix of functions? */
4831 if (!yaffs_check_dev_fns(dev)) {
4832 /* Function missing */
4833 yaffs_trace(YAFFS_TRACE_ALWAYS,
4834 "device function(s) missing or wrong");
4835
4836 return YAFFS_FAIL;
4837 }
4838
4839 if (dev->is_mounted) {
4840 yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
4841 return YAFFS_FAIL;
4842 }
4843
4844 /* Finished with most checks. One or two more checks happen later on too. */
4845
4846 dev->is_mounted = 1;
4847
4848 /* OK now calculate a few things for the device */
4849
4850 /*
4851 * Calculate all the chunk size manipulation numbers:
4852 */
4853 x = dev->data_bytes_per_chunk;
4854 /* We always use dev->chunk_shift and dev->chunk_div */
4855 dev->chunk_shift = calc_shifts(x);
4856 x >>= dev->chunk_shift;
4857 dev->chunk_div = x;
4858 /* We only use chunk mask if chunk_div is 1 */
4859 dev->chunk_mask = (1 << dev->chunk_shift) - 1;
4860
4861 /*
4862 * Calculate chunk_grp_bits.
4863 * We need to find the next power of 2 > than internal_end_block
4864 */
4865
4866 x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
4867
4868 bits = calc_shifts_ceiling(x);
4869
4870 /* Set up tnode width if wide tnodes are enabled. */
4871 if (!dev->param.wide_tnodes_disabled) {
4872 /* bits must be even so that we end up with 32-bit words */
4873 if (bits & 1)
4874 bits++;
4875 if (bits < 16)
4876 dev->tnode_width = 16;
4877 else
4878 dev->tnode_width = bits;
4879 } else {
4880 dev->tnode_width = 16;
4881 }
4882
4883 dev->tnode_mask = (1 << dev->tnode_width) - 1;
4884
4885 /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
4886 * so if the bitwidth of the
4887 * chunk range we're using is greater than 16 we need
4888 * to figure out chunk shift and chunk_grp_size
4889 */
4890
4891 if (bits <= dev->tnode_width)
4892 dev->chunk_grp_bits = 0;
4893 else
4894 dev->chunk_grp_bits = bits - dev->tnode_width;
4895
4896 dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
4897 if (dev->tnode_size < sizeof(struct yaffs_tnode))
4898 dev->tnode_size = sizeof(struct yaffs_tnode);
4899
4900 dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
4901
4902 if (dev->param.chunks_per_block < dev->chunk_grp_size) {
4903 /* We have a problem because the soft delete won't work if
4904 * the chunk group size > chunks per block.
4905 * This can be remedied by using larger "virtual blocks".
4906 */
4907 yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
4908
4909 return YAFFS_FAIL;
4910 }
4911
4912 /* OK, we've finished verifying the device, lets continue with initialisation */
4913
4914 /* More device initialisation */
4915 dev->all_gcs = 0;
4916 dev->passive_gc_count = 0;
4917 dev->oldest_dirty_gc_count = 0;
4918 dev->bg_gcs = 0;
4919 dev->gc_block_finder = 0;
4920 dev->buffered_block = -1;
4921 dev->doing_buffered_block_rewrite = 0;
4922 dev->n_deleted_files = 0;
4923 dev->n_bg_deletions = 0;
4924 dev->n_unlinked_files = 0;
4925 dev->n_ecc_fixed = 0;
4926 dev->n_ecc_unfixed = 0;
4927 dev->n_tags_ecc_fixed = 0;
4928 dev->n_tags_ecc_unfixed = 0;
4929 dev->n_erase_failures = 0;
4930 dev->n_erased_blocks = 0;
4931 dev->gc_disable = 0;
4932 dev->has_pending_prioritised_gc = 1; /* Assume the worst for now, will get fixed on first GC */
4933 INIT_LIST_HEAD(&dev->dirty_dirs);
4934 dev->oldest_dirty_seq = 0;
4935 dev->oldest_dirty_block = 0;
4936
4937 /* Initialise temporary buffers and caches. */
4938 if (!yaffs_init_tmp_buffers(dev))
4939 init_failed = 1;
4940
4941 dev->cache = NULL;
4942 dev->gc_cleanup_list = NULL;
4943
4944 if (!init_failed && dev->param.n_caches > 0) {
4945 int i;
4946 void *buf;
4947 int cache_bytes =
4948 dev->param.n_caches * sizeof(struct yaffs_cache);
4949
4950 if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
4951 dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
4952
4953 dev->cache = kmalloc(cache_bytes, GFP_NOFS);
4954
4955 buf = (u8 *) dev->cache;
4956
4957 if (dev->cache)
4958 memset(dev->cache, 0, cache_bytes);
4959
4960 for (i = 0; i < dev->param.n_caches && buf; i++) {
4961 dev->cache[i].object = NULL;
4962 dev->cache[i].last_use = 0;
4963 dev->cache[i].dirty = 0;
4964 dev->cache[i].data = buf =
4965 kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
4966 }
4967 if (!buf)
4968 init_failed = 1;
4969
4970 dev->cache_last_use = 0;
4971 }
4972
4973 dev->cache_hits = 0;
4974
4975 if (!init_failed) {
4976 dev->gc_cleanup_list =
4977 kmalloc(dev->param.chunks_per_block * sizeof(u32),
4978 GFP_NOFS);
4979 if (!dev->gc_cleanup_list)
4980 init_failed = 1;
4981 }
4982
4983 if (dev->param.is_yaffs2)
4984 dev->param.use_header_file_size = 1;
4985
4986 if (!init_failed && !yaffs_init_blocks(dev))
4987 init_failed = 1;
4988
4989 yaffs_init_tnodes_and_objs(dev);
4990
4991 if (!init_failed && !yaffs_create_initial_dir(dev))
4992 init_failed = 1;
4993
4994 if (!init_failed) {
4995 /* Now scan the flash. */
4996 if (dev->param.is_yaffs2) {
4997 if (yaffs2_checkpt_restore(dev)) {
4998 yaffs_check_obj_details_loaded(dev->root_dir);
4999 yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
5000 "yaffs: restored from checkpoint"
5001 );
5002 } else {
5003
5004 /* Clean up the mess caused by an aborted checkpoint load
5005 * and scan backwards.
5006 */
5007 yaffs_deinit_blocks(dev);
5008
5009 yaffs_deinit_tnodes_and_objs(dev);
5010
5011 dev->n_erased_blocks = 0;
5012 dev->n_free_chunks = 0;
5013 dev->alloc_block = -1;
5014 dev->alloc_page = -1;
5015 dev->n_deleted_files = 0;
5016 dev->n_unlinked_files = 0;
5017 dev->n_bg_deletions = 0;
5018
5019 if (!init_failed && !yaffs_init_blocks(dev))
5020 init_failed = 1;
5021
5022 yaffs_init_tnodes_and_objs(dev);
5023
5024 if (!init_failed
5025 && !yaffs_create_initial_dir(dev))
5026 init_failed = 1;
5027
5028 if (!init_failed && !yaffs2_scan_backwards(dev))
5029 init_failed = 1;
5030 }
5031 } else if (!yaffs1_scan(dev)) {
5032 init_failed = 1;
5033 }
5034
5035 yaffs_strip_deleted_objs(dev);
5036 yaffs_fix_hanging_objs(dev);
5037 if (dev->param.empty_lost_n_found)
5038 yaffs_empty_l_n_f(dev);
5039 }
5040
5041 if (init_failed) {
5042 /* Clean up the mess */
5043 yaffs_trace(YAFFS_TRACE_TRACING,
5044 "yaffs: yaffs_guts_initialise() aborted.");
5045
5046 yaffs_deinitialise(dev);
5047 return YAFFS_FAIL;
5048 }
5049
5050 /* Zero out stats */
5051 dev->n_page_reads = 0;
5052 dev->n_page_writes = 0;
5053 dev->n_erasures = 0;
5054 dev->n_gc_copies = 0;
5055 dev->n_retired_writes = 0;
5056
5057 dev->n_retired_blocks = 0;
5058
5059 yaffs_verify_free_chunks(dev);
5060 yaffs_verify_blocks(dev);
5061
5062 /* Clean up any aborted checkpoint data */
5063 if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
5064 yaffs2_checkpt_invalidate(dev);
5065
5066 yaffs_trace(YAFFS_TRACE_TRACING,
5067 "yaffs: yaffs_guts_initialise() done.");
5068 return YAFFS_OK;
5069
5070}
5071
5072void yaffs_deinitialise(struct yaffs_dev *dev)
5073{
5074 if (dev->is_mounted) {
5075 int i;
5076
5077 yaffs_deinit_blocks(dev);
5078 yaffs_deinit_tnodes_and_objs(dev);
5079 if (dev->param.n_caches > 0 && dev->cache) {
5080
5081 for (i = 0; i < dev->param.n_caches; i++) {
5082 if (dev->cache[i].data)
5083 kfree(dev->cache[i].data);
5084 dev->cache[i].data = NULL;
5085 }
5086
5087 kfree(dev->cache);
5088 dev->cache = NULL;
5089 }
5090
5091 kfree(dev->gc_cleanup_list);
5092
5093 for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
5094 kfree(dev->temp_buffer[i].buffer);
5095
5096 dev->is_mounted = 0;
5097
5098 if (dev->param.deinitialise_flash_fn)
5099 dev->param.deinitialise_flash_fn(dev);
5100 }
5101}
5102
5103int yaffs_count_free_chunks(struct yaffs_dev *dev)
5104{
5105 int n_free = 0;
5106 int b;
5107
5108 struct yaffs_block_info *blk;
5109
5110 blk = dev->block_info;
5111 for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
5112 switch (blk->block_state) {
5113 case YAFFS_BLOCK_STATE_EMPTY:
5114 case YAFFS_BLOCK_STATE_ALLOCATING:
5115 case YAFFS_BLOCK_STATE_COLLECTING:
5116 case YAFFS_BLOCK_STATE_FULL:
5117 n_free +=
5118 (dev->param.chunks_per_block - blk->pages_in_use +
5119 blk->soft_del_pages);
5120 break;
5121 default:
5122 break;
5123 }
5124 blk++;
5125 }
5126
5127 return n_free;
5128}
5129
5130int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
5131{
5132 /* This is what we report to the outside world */
5133
5134 int n_free;
5135 int n_dirty_caches;
5136 int blocks_for_checkpt;
5137 int i;
5138
5139 n_free = dev->n_free_chunks;
5140 n_free += dev->n_deleted_files;
5141
5142 /* Now count the number of dirty chunks in the cache and subtract those */
5143
5144 for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
5145 if (dev->cache[i].dirty)
5146 n_dirty_caches++;
5147 }
5148
5149 n_free -= n_dirty_caches;
5150
5151 n_free -=
5152 ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
5153
5154 /* Now we figure out how much to reserve for the checkpoint and report that... */
5155 blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
5156
5157 n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
5158
5159 if (n_free < 0)
5160 n_free = 0;
5161
5162 return n_free;
5163
5164}
diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
new file mode 100644
index 00000000000..307eba28676
--- /dev/null
+++ b/fs/yaffs2/yaffs_guts.h
@@ -0,0 +1,915 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_GUTS_H__
17#define __YAFFS_GUTS_H__
18
19#include "yportenv.h"
20
21#define YAFFS_OK 1
22#define YAFFS_FAIL 0
23
24/* Give us a Y=0x59,
25 * Give us an A=0x41,
26 * Give us an FF=0xFF
27 * Give us an S=0x53
28 * And what have we got...
29 */
30#define YAFFS_MAGIC 0x5941FF53
31
32#define YAFFS_NTNODES_LEVEL0 16
33#define YAFFS_TNODES_LEVEL0_BITS 4
34#define YAFFS_TNODES_LEVEL0_MASK 0xf
35
36#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
37#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
38#define YAFFS_TNODES_INTERNAL_MASK 0x7
39#define YAFFS_TNODES_MAX_LEVEL 6
40
41#ifndef CONFIG_YAFFS_NO_YAFFS1
42#define YAFFS_BYTES_PER_SPARE 16
43#define YAFFS_BYTES_PER_CHUNK 512
44#define YAFFS_CHUNK_SIZE_SHIFT 9
45#define YAFFS_CHUNKS_PER_BLOCK 32
46#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
47#endif
48
49#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
50#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
51
52#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
53
54#define YAFFS_ALLOCATION_NOBJECTS 100
55#define YAFFS_ALLOCATION_NTNODES 100
56#define YAFFS_ALLOCATION_NLINKS 100
57
58#define YAFFS_NOBJECT_BUCKETS 256
59
60#define YAFFS_OBJECT_SPACE 0x40000
61#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1)
62
63#define YAFFS_CHECKPOINT_VERSION 4
64
65#ifdef CONFIG_YAFFS_UNICODE
66#define YAFFS_MAX_NAME_LENGTH 127
67#define YAFFS_MAX_ALIAS_LENGTH 79
68#else
69#define YAFFS_MAX_NAME_LENGTH 255
70#define YAFFS_MAX_ALIAS_LENGTH 159
71#endif
72
73#define YAFFS_SHORT_NAME_LENGTH 15
74
75/* Some special object ids for pseudo objects */
76#define YAFFS_OBJECTID_ROOT 1
77#define YAFFS_OBJECTID_LOSTNFOUND 2
78#define YAFFS_OBJECTID_UNLINKED 3
79#define YAFFS_OBJECTID_DELETED 4
80
81/* Pseudo object ids for checkpointing */
82#define YAFFS_OBJECTID_SB_HEADER 0x10
83#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
84#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
85
86#define YAFFS_MAX_SHORT_OP_CACHES 20
87
88#define YAFFS_N_TEMP_BUFFERS 6
89
90/* We limit the number attempts at sucessfully saving a chunk of data.
91 * Small-page devices have 32 pages per block; large-page devices have 64.
92 * Default to something in the order of 5 to 10 blocks worth of chunks.
93 */
94#define YAFFS_WR_ATTEMPTS (5*64)
95
96/* Sequence numbers are used in YAFFS2 to determine block allocation order.
97 * The range is limited slightly to help distinguish bad numbers from good.
98 * This also allows us to perhaps in the future use special numbers for
99 * special purposes.
100 * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
101 * and is a larger number than the lifetime of a 2GB device.
102 */
103#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
104#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
105
106/* Special sequence number for bad block that failed to be marked bad */
107#define YAFFS_SEQUENCE_BAD_BLOCK 0xFFFF0000
108
109/* ChunkCache is used for short read/write operations.*/
110struct yaffs_cache {
111 struct yaffs_obj *object;
112 int chunk_id;
113 int last_use;
114 int dirty;
115 int n_bytes; /* Only valid if the cache is dirty */
116 int locked; /* Can't push out or flush while locked. */
117 u8 *data;
118};
119
120/* Tags structures in RAM
121 * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
122 * the structure size will get blown out.
123 */
124
125#ifndef CONFIG_YAFFS_NO_YAFFS1
126struct yaffs_tags {
127 unsigned chunk_id:20;
128 unsigned serial_number:2;
129 unsigned n_bytes_lsb:10;
130 unsigned obj_id:18;
131 unsigned ecc:12;
132 unsigned n_bytes_msb:2;
133};
134
135union yaffs_tags_union {
136 struct yaffs_tags as_tags;
137 u8 as_bytes[8];
138};
139
140#endif
141
142/* Stuff used for extended tags in YAFFS2 */
143
144enum yaffs_ecc_result {
145 YAFFS_ECC_RESULT_UNKNOWN,
146 YAFFS_ECC_RESULT_NO_ERROR,
147 YAFFS_ECC_RESULT_FIXED,
148 YAFFS_ECC_RESULT_UNFIXED
149};
150
151enum yaffs_obj_type {
152 YAFFS_OBJECT_TYPE_UNKNOWN,
153 YAFFS_OBJECT_TYPE_FILE,
154 YAFFS_OBJECT_TYPE_SYMLINK,
155 YAFFS_OBJECT_TYPE_DIRECTORY,
156 YAFFS_OBJECT_TYPE_HARDLINK,
157 YAFFS_OBJECT_TYPE_SPECIAL
158};
159
160#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
161
162struct yaffs_ext_tags {
163
164 unsigned validity0;
165 unsigned chunk_used; /* Status of the chunk: used or unused */
166 unsigned obj_id; /* If 0 then this is not part of an object (unused) */
167 unsigned chunk_id; /* If 0 then this is a header, else a data chunk */
168 unsigned n_bytes; /* Only valid for data chunks */
169
170 /* The following stuff only has meaning when we read */
171 enum yaffs_ecc_result ecc_result;
172 unsigned block_bad;
173
174 /* YAFFS 1 stuff */
175 unsigned is_deleted; /* The chunk is marked deleted */
176 unsigned serial_number; /* Yaffs1 2-bit serial number */
177
178 /* YAFFS2 stuff */
179 unsigned seq_number; /* The sequence number of this block */
180
181 /* Extra info if this is an object header (YAFFS2 only) */
182
183 unsigned extra_available; /* There is extra info available if this is not zero */
184 unsigned extra_parent_id; /* The parent object */
185 unsigned extra_is_shrink; /* Is it a shrink header? */
186 unsigned extra_shadows; /* Does this shadow another object? */
187
188 enum yaffs_obj_type extra_obj_type; /* What object type? */
189
190 unsigned extra_length; /* Length if it is a file */
191 unsigned extra_equiv_id; /* Equivalent object Id if it is a hard link */
192
193 unsigned validity1;
194
195};
196
197/* Spare structure for YAFFS1 */
198struct yaffs_spare {
199 u8 tb0;
200 u8 tb1;
201 u8 tb2;
202 u8 tb3;
203 u8 page_status; /* set to 0 to delete the chunk */
204 u8 block_status;
205 u8 tb4;
206 u8 tb5;
207 u8 ecc1[3];
208 u8 tb6;
209 u8 tb7;
210 u8 ecc2[3];
211};
212
213/*Special structure for passing through to mtd */
214struct yaffs_nand_spare {
215 struct yaffs_spare spare;
216 int eccres1;
217 int eccres2;
218};
219
220/* Block data in RAM */
221
222enum yaffs_block_state {
223 YAFFS_BLOCK_STATE_UNKNOWN = 0,
224
225 YAFFS_BLOCK_STATE_SCANNING,
226 /* Being scanned */
227
228 YAFFS_BLOCK_STATE_NEEDS_SCANNING,
229 /* The block might have something on it (ie it is allocating or full, perhaps empty)
230 * but it needs to be scanned to determine its true state.
231 * This state is only valid during scanning.
232 * NB We tolerate empty because the pre-scanner might be incapable of deciding
233 * However, if this state is returned on a YAFFS2 device, then we expect a sequence number
234 */
235
236 YAFFS_BLOCK_STATE_EMPTY,
237 /* This block is empty */
238
239 YAFFS_BLOCK_STATE_ALLOCATING,
240 /* This block is partially allocated.
241 * At least one page holds valid data.
242 * This is the one currently being used for page
243 * allocation. Should never be more than one of these.
244 * If a block is only partially allocated at mount it is treated as full.
245 */
246
247 YAFFS_BLOCK_STATE_FULL,
248 /* All the pages in this block have been allocated.
249 * If a block was only partially allocated when mounted we treat
250 * it as fully allocated.
251 */
252
253 YAFFS_BLOCK_STATE_DIRTY,
254 /* The block was full and now all chunks have been deleted.
255 * Erase me, reuse me.
256 */
257
258 YAFFS_BLOCK_STATE_CHECKPOINT,
259 /* This block is assigned to holding checkpoint data. */
260
261 YAFFS_BLOCK_STATE_COLLECTING,
262 /* This block is being garbage collected */
263
264 YAFFS_BLOCK_STATE_DEAD
265 /* This block has failed and is not in use */
266};
267
268#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
269
270struct yaffs_block_info {
271
272 int soft_del_pages:10; /* number of soft deleted pages */
273 int pages_in_use:10; /* number of pages in use */
274 unsigned block_state:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */
275 u32 needs_retiring:1; /* Data has failed on this block, need to get valid data off */
276 /* and retire the block. */
277 u32 skip_erased_check:1; /* If this is set we can skip the erased check on this block */
278 u32 gc_prioritise:1; /* An ECC check or blank check has failed on this block.
279 It should be prioritised for GC */
280 u32 chunk_error_strikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
281
282#ifdef CONFIG_YAFFS_YAFFS2
283 u32 has_shrink_hdr:1; /* This block has at least one shrink object header */
284 u32 seq_number; /* block sequence number for yaffs2 */
285#endif
286
287};
288
289/* -------------------------- Object structure -------------------------------*/
290/* This is the object structure as stored on NAND */
291
292struct yaffs_obj_hdr {
293 enum yaffs_obj_type type;
294
295 /* Apply to everything */
296 int parent_obj_id;
297 u16 sum_no_longer_used; /* checksum of name. No longer used */
298 YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
299
300 /* The following apply to directories, files, symlinks - not hard links */
301 u32 yst_mode; /* protection */
302
303 u32 yst_uid;
304 u32 yst_gid;
305 u32 yst_atime;
306 u32 yst_mtime;
307 u32 yst_ctime;
308
309 /* File size applies to files only */
310 int file_size;
311
312 /* Equivalent object id applies to hard links only. */
313 int equiv_id;
314
315 /* Alias is for symlinks only. */
316 YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
317
318 u32 yst_rdev; /* device stuff for block and char devices (major/min) */
319
320 u32 win_ctime[2];
321 u32 win_atime[2];
322 u32 win_mtime[2];
323
324 u32 inband_shadowed_obj_id;
325 u32 inband_is_shrink;
326
327 u32 reserved[2];
328 int shadows_obj; /* This object header shadows the specified object if > 0 */
329
330 /* is_shrink applies to object headers written when we shrink the file (ie resize) */
331 u32 is_shrink;
332
333};
334
335/*--------------------------- Tnode -------------------------- */
336
337struct yaffs_tnode {
338 struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
339};
340
341/*------------------------ Object -----------------------------*/
342/* An object can be one of:
343 * - a directory (no data, has children links
344 * - a regular file (data.... not prunes :->).
345 * - a symlink [symbolic link] (the alias).
346 * - a hard link
347 */
348
349struct yaffs_file_var {
350 u32 file_size;
351 u32 scanned_size;
352 u32 shrink_size;
353 int top_level;
354 struct yaffs_tnode *top;
355};
356
357struct yaffs_dir_var {
358 struct list_head children; /* list of child links */
359 struct list_head dirty; /* Entry for list of dirty directories */
360};
361
362struct yaffs_symlink_var {
363 YCHAR *alias;
364};
365
366struct yaffs_hardlink_var {
367 struct yaffs_obj *equiv_obj;
368 u32 equiv_id;
369};
370
371union yaffs_obj_var {
372 struct yaffs_file_var file_variant;
373 struct yaffs_dir_var dir_variant;
374 struct yaffs_symlink_var symlink_variant;
375 struct yaffs_hardlink_var hardlink_variant;
376};
377
378struct yaffs_obj {
379 u8 deleted:1; /* This should only apply to unlinked files. */
380 u8 soft_del:1; /* it has also been soft deleted */
381 u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory. */
382 u8 fake:1; /* A fake object has no presence on NAND. */
383 u8 rename_allowed:1; /* Some objects are not allowed to be renamed. */
384 u8 unlink_allowed:1;
385 u8 dirty:1; /* the object needs to be written to flash */
386 u8 valid:1; /* When the file system is being loaded up, this
387 * object might be created before the data
388 * is available (ie. file data records appear before the header).
389 */
390 u8 lazy_loaded:1; /* This object has been lazy loaded and is missing some detail */
391
392 u8 defered_free:1; /* For Linux kernel. Object is removed from NAND, but is
393 * still in the inode cache. Free of object is defered.
394 * until the inode is released.
395 */
396 u8 being_created:1; /* This object is still being created so skip some checks. */
397 u8 is_shadowed:1; /* This object is shadowed on the way to being renamed. */
398
399 u8 xattr_known:1; /* We know if this has object has xattribs or not. */
400 u8 has_xattr:1; /* This object has xattribs. Valid if xattr_known. */
401
402 u8 serial; /* serial number of chunk in NAND. Cached here */
403 u16 sum; /* sum of the name to speed searching */
404
405 struct yaffs_dev *my_dev; /* The device I'm on */
406
407 struct list_head hash_link; /* list of objects in this hash bucket */
408
409 struct list_head hard_links; /* all the equivalent hard linked objects */
410
411 /* directory structure stuff */
412 /* also used for linking up the free list */
413 struct yaffs_obj *parent;
414 struct list_head siblings;
415
416 /* Where's my object header in NAND? */
417 int hdr_chunk;
418
419 int n_data_chunks; /* Number of data chunks attached to the file. */
420
421 u32 obj_id; /* the object id value */
422
423 u32 yst_mode;
424
425#ifndef CONFIG_YAFFS_NO_SHORT_NAMES
426 YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
427#endif
428
429#ifdef CONFIG_YAFFS_WINCE
430 u32 win_ctime[2];
431 u32 win_mtime[2];
432 u32 win_atime[2];
433#else
434 u32 yst_uid;
435 u32 yst_gid;
436 u32 yst_atime;
437 u32 yst_mtime;
438 u32 yst_ctime;
439#endif
440
441 u32 yst_rdev;
442
443 void *my_inode;
444
445 enum yaffs_obj_type variant_type;
446
447 union yaffs_obj_var variant;
448
449};
450
451struct yaffs_obj_bucket {
452 struct list_head list;
453 int count;
454};
455
456/* yaffs_checkpt_obj holds the definition of an object as dumped
457 * by checkpointing.
458 */
459
460struct yaffs_checkpt_obj {
461 int struct_type;
462 u32 obj_id;
463 u32 parent_id;
464 int hdr_chunk;
465 enum yaffs_obj_type variant_type:3;
466 u8 deleted:1;
467 u8 soft_del:1;
468 u8 unlinked:1;
469 u8 fake:1;
470 u8 rename_allowed:1;
471 u8 unlink_allowed:1;
472 u8 serial;
473 int n_data_chunks;
474 u32 size_or_equiv_obj;
475};
476
477/*--------------------- Temporary buffers ----------------
478 *
479 * These are chunk-sized working buffers. Each device has a few
480 */
481
482struct yaffs_buffer {
483 u8 *buffer;
484 int line; /* track from whence this buffer was allocated */
485 int max_line;
486};
487
488/*----------------- Device ---------------------------------*/
489
490struct yaffs_param {
491 const YCHAR *name;
492
493 /*
494 * Entry parameters set up way early. Yaffs sets up the rest.
495 * The structure should be zeroed out before use so that unused
496 * and defualt values are zero.
497 */
498
499 int inband_tags; /* Use unband tags */
500 u32 total_bytes_per_chunk; /* Should be >= 512, does not need to be a power of 2 */
501 int chunks_per_block; /* does not need to be a power of 2 */
502 int spare_bytes_per_chunk; /* spare area size */
503 int start_block; /* Start block we're allowed to use */
504 int end_block; /* End block we're allowed to use */
505 int n_reserved_blocks; /* We want this tuneable so that we can reduce */
506 /* reserved blocks on NOR and RAM. */
507
508 int n_caches; /* If <= 0, then short op caching is disabled, else
509 * the number of short op caches (don't use too many).
510 * 10 to 20 is a good bet.
511 */
512 int use_nand_ecc; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */
513 int no_tags_ecc; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */
514
515 int is_yaffs2; /* Use yaffs2 mode on this device */
516
517 int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
518
519 int refresh_period; /* How often we should check to do a block refresh */
520
521 /* Checkpoint control. Can be set before or after initialisation */
522 u8 skip_checkpt_rd;
523 u8 skip_checkpt_wr;
524
525 int enable_xattr; /* Enable xattribs */
526
527 /* NAND access functions (Must be set before calling YAFFS) */
528
529 int (*write_chunk_fn) (struct yaffs_dev * dev,
530 int nand_chunk, const u8 * data,
531 const struct yaffs_spare * spare);
532 int (*read_chunk_fn) (struct yaffs_dev * dev,
533 int nand_chunk, u8 * data,
534 struct yaffs_spare * spare);
535 int (*erase_fn) (struct yaffs_dev * dev, int flash_block);
536 int (*initialise_flash_fn) (struct yaffs_dev * dev);
537 int (*deinitialise_flash_fn) (struct yaffs_dev * dev);
538
539#ifdef CONFIG_YAFFS_YAFFS2
540 int (*write_chunk_tags_fn) (struct yaffs_dev * dev,
541 int nand_chunk, const u8 * data,
542 const struct yaffs_ext_tags * tags);
543 int (*read_chunk_tags_fn) (struct yaffs_dev * dev,
544 int nand_chunk, u8 * data,
545 struct yaffs_ext_tags * tags);
546 int (*bad_block_fn) (struct yaffs_dev * dev, int block_no);
547 int (*query_block_fn) (struct yaffs_dev * dev, int block_no,
548 enum yaffs_block_state * state,
549 u32 * seq_number);
550#endif
551
552 /* The remove_obj_fn function must be supplied by OS flavours that
553 * need it.
554 * yaffs direct uses it to implement the faster readdir.
555 * Linux uses it to protect the directory during unlocking.
556 */
557 void (*remove_obj_fn) (struct yaffs_obj * obj);
558
559 /* Callback to mark the superblock dirty */
560 void (*sb_dirty_fn) (struct yaffs_dev * dev);
561
562 /* Callback to control garbage collection. */
563 unsigned (*gc_control) (struct yaffs_dev * dev);
564
565 /* Debug control flags. Don't use unless you know what you're doing */
566 int use_header_file_size; /* Flag to determine if we should use file sizes from the header */
567 int disable_lazy_load; /* Disable lazy loading on this device */
568 int wide_tnodes_disabled; /* Set to disable wide tnodes */
569 int disable_soft_del; /* yaffs 1 only: Set to disable the use of softdeletion. */
570
571 int defered_dir_update; /* Set to defer directory updates */
572
573#ifdef CONFIG_YAFFS_AUTO_UNICODE
574 int auto_unicode;
575#endif
576 int always_check_erased; /* Force chunk erased check always on */
577};
578
579struct yaffs_dev {
580 struct yaffs_param param;
581
582 /* Context storage. Holds extra OS specific data for this device */
583
584 void *os_context;
585 void *driver_context;
586
587 struct list_head dev_list;
588
589 /* Runtime parameters. Set up by YAFFS. */
590 int data_bytes_per_chunk;
591
592 /* Non-wide tnode stuff */
593 u16 chunk_grp_bits; /* Number of bits that need to be resolved if
594 * the tnodes are not wide enough.
595 */
596 u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
597
598 /* Stuff to support wide tnodes */
599 u32 tnode_width;
600 u32 tnode_mask;
601 u32 tnode_size;
602
603 /* Stuff for figuring out file offset to chunk conversions */
604 u32 chunk_shift; /* Shift value */
605 u32 chunk_div; /* Divisor after shifting: 1 for power-of-2 sizes */
606 u32 chunk_mask; /* Mask to use for power-of-2 case */
607
608 int is_mounted;
609 int read_only;
610 int is_checkpointed;
611
612 /* Stuff to support block offsetting to support start block zero */
613 int internal_start_block;
614 int internal_end_block;
615 int block_offset;
616 int chunk_offset;
617
618 /* Runtime checkpointing stuff */
619 int checkpt_page_seq; /* running sequence number of checkpoint pages */
620 int checkpt_byte_count;
621 int checkpt_byte_offs;
622 u8 *checkpt_buffer;
623 int checkpt_open_write;
624 int blocks_in_checkpt;
625 int checkpt_cur_chunk;
626 int checkpt_cur_block;
627 int checkpt_next_block;
628 int *checkpt_block_list;
629 int checkpt_max_blocks;
630 u32 checkpt_sum;
631 u32 checkpt_xor;
632
633 int checkpoint_blocks_required; /* Number of blocks needed to store current checkpoint set */
634
635 /* Block Info */
636 struct yaffs_block_info *block_info;
637 u8 *chunk_bits; /* bitmap of chunks in use */
638 unsigned block_info_alt:1; /* was allocated using alternative strategy */
639 unsigned chunk_bits_alt:1; /* was allocated using alternative strategy */
640 int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
641 * Must be consistent with chunks_per_block.
642 */
643
644 int n_erased_blocks;
645 int alloc_block; /* Current block being allocated off */
646 u32 alloc_page;
647 int alloc_block_finder; /* Used to search for next allocation block */
648
649 /* Object and Tnode memory management */
650 void *allocator;
651 int n_obj;
652 int n_tnodes;
653
654 int n_hardlinks;
655
656 struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
657 u32 bucket_finder;
658
659 int n_free_chunks;
660
661 /* Garbage collection control */
662 u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
663 u32 n_clean_ups;
664
665 unsigned has_pending_prioritised_gc; /* We think this device might have pending prioritised gcs */
666 unsigned gc_disable;
667 unsigned gc_block_finder;
668 unsigned gc_dirtiest;
669 unsigned gc_pages_in_use;
670 unsigned gc_not_done;
671 unsigned gc_block;
672 unsigned gc_chunk;
673 unsigned gc_skip;
674
675 /* Special directories */
676 struct yaffs_obj *root_dir;
677 struct yaffs_obj *lost_n_found;
678
679 /* Buffer areas for storing data to recover from write failures TODO
680 * u8 buffered_data[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
681 * struct yaffs_spare buffered_spare[YAFFS_CHUNKS_PER_BLOCK];
682 */
683
684 int buffered_block; /* Which block is buffered here? */
685 int doing_buffered_block_rewrite;
686
687 struct yaffs_cache *cache;
688 int cache_last_use;
689
690 /* Stuff for background deletion and unlinked files. */
691 struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted files live. */
692 struct yaffs_obj *del_dir; /* Directory where deleted objects are sent to disappear. */
693 struct yaffs_obj *unlinked_deletion; /* Current file being background deleted. */
694 int n_deleted_files; /* Count of files awaiting deletion; */
695 int n_unlinked_files; /* Count of unlinked files. */
696 int n_bg_deletions; /* Count of background deletions. */
697
698 /* Temporary buffer management */
699 struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
700 int max_temp;
701 int temp_in_use;
702 int unmanaged_buffer_allocs;
703 int unmanaged_buffer_deallocs;
704
705 /* yaffs2 runtime stuff */
706 unsigned seq_number; /* Sequence number of currently allocating block */
707 unsigned oldest_dirty_seq;
708 unsigned oldest_dirty_block;
709
710 /* Block refreshing */
711 int refresh_skip; /* A skip down counter. Refresh happens when this gets to zero. */
712
713 /* Dirty directory handling */
714 struct list_head dirty_dirs; /* List of dirty directories */
715
716 /* Statistcs */
717 u32 n_page_writes;
718 u32 n_page_reads;
719 u32 n_erasures;
720 u32 n_erase_failures;
721 u32 n_gc_copies;
722 u32 all_gcs;
723 u32 passive_gc_count;
724 u32 oldest_dirty_gc_count;
725 u32 n_gc_blocks;
726 u32 bg_gcs;
727 u32 n_retired_writes;
728 u32 n_retired_blocks;
729 u32 n_ecc_fixed;
730 u32 n_ecc_unfixed;
731 u32 n_tags_ecc_fixed;
732 u32 n_tags_ecc_unfixed;
733 u32 n_deletions;
734 u32 n_unmarked_deletions;
735 u32 refresh_count;
736 u32 cache_hits;
737
738};
739
740/* The CheckpointDevice structure holds the device information that changes at runtime and
741 * must be preserved over unmount/mount cycles.
742 */
743struct yaffs_checkpt_dev {
744 int struct_type;
745 int n_erased_blocks;
746 int alloc_block; /* Current block being allocated off */
747 u32 alloc_page;
748 int n_free_chunks;
749
750 int n_deleted_files; /* Count of files awaiting deletion; */
751 int n_unlinked_files; /* Count of unlinked files. */
752 int n_bg_deletions; /* Count of background deletions. */
753
754 /* yaffs2 runtime stuff */
755 unsigned seq_number; /* Sequence number of currently allocating block */
756
757};
758
759struct yaffs_checkpt_validity {
760 int struct_type;
761 u32 magic;
762 u32 version;
763 u32 head;
764};
765
766struct yaffs_shadow_fixer {
767 int obj_id;
768 int shadowed_id;
769 struct yaffs_shadow_fixer *next;
770};
771
772/* Structure for doing xattr modifications */
773struct yaffs_xattr_mod {
774 int set; /* If 0 then this is a deletion */
775 const YCHAR *name;
776 const void *data;
777 int size;
778 int flags;
779 int result;
780};
781
782/*----------------------- YAFFS Functions -----------------------*/
783
784int yaffs_guts_initialise(struct yaffs_dev *dev);
785void yaffs_deinitialise(struct yaffs_dev *dev);
786
787int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
788
789int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
790 struct yaffs_obj *new_dir, const YCHAR * new_name);
791
792int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
793int yaffs_del_obj(struct yaffs_obj *obj);
794
795int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
796int yaffs_get_obj_length(struct yaffs_obj *obj);
797int yaffs_get_obj_inode(struct yaffs_obj *obj);
798unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
799int yaffs_get_obj_link_count(struct yaffs_obj *obj);
800
801/* File operations */
802int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
803 int n_bytes);
804int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
805 int n_bytes, int write_trhrough);
806int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
807
808struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
809 const YCHAR * name, u32 mode, u32 uid,
810 u32 gid);
811
812int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
813
814/* Flushing and checkpointing */
815void yaffs_flush_whole_cache(struct yaffs_dev *dev);
816
817int yaffs_checkpoint_save(struct yaffs_dev *dev);
818int yaffs_checkpoint_restore(struct yaffs_dev *dev);
819
820/* Directory operations */
821struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR * name,
822 u32 mode, u32 uid, u32 gid);
823struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
824 const YCHAR * name);
825struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
826
827/* Link operations */
828struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
829 struct yaffs_obj *equiv_obj);
830
831struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
832
833/* Symlink operations */
834struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
835 const YCHAR * name, u32 mode, u32 uid,
836 u32 gid, const YCHAR * alias);
837YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
838
839/* Special inodes (fifos, sockets and devices) */
840struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
841 const YCHAR * name, u32 mode, u32 uid,
842 u32 gid, u32 rdev);
843
844int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
845 const void *value, int size, int flags);
846int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
847 int size);
848int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
849int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name);
850
851/* Special directories */
852struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
853struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
854
855void yaffs_handle_defered_free(struct yaffs_obj *obj);
856
857void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
858
859int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
860
861/* Debug dump */
862int yaffs_dump_obj(struct yaffs_obj *obj);
863
864void yaffs_guts_test(struct yaffs_dev *dev);
865
866/* A few useful functions to be used within the core files*/
867void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
868 int lyn);
869int yaffs_check_ff(u8 * buffer, int n_bytes);
870void yaffs_handle_chunk_error(struct yaffs_dev *dev,
871 struct yaffs_block_info *bi);
872
873u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev, int line_no);
874void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 * buffer, int line_no);
875
876struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
877 int number,
878 enum yaffs_obj_type type);
879int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
880 int nand_chunk, int in_scan);
881void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name);
882void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
883 const struct yaffs_obj_hdr *oh);
884void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
885YCHAR *yaffs_clone_str(const YCHAR * str);
886void yaffs_link_fixup(struct yaffs_dev *dev, struct yaffs_obj *hard_list);
887void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
888int yaffs_update_oh(struct yaffs_obj *in, const YCHAR * name,
889 int force, int is_shrink, int shadows,
890 struct yaffs_xattr_mod *xop);
891void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
892 int backward_scanning);
893int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
894struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
895struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
896 struct yaffs_file_var *file_struct,
897 u32 chunk_id,
898 struct yaffs_tnode *passed_tn);
899
900int yaffs_do_file_wr(struct yaffs_obj *in, const u8 * buffer, loff_t offset,
901 int n_bytes, int write_trhrough);
902void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
903void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
904
905int yaffs_count_free_chunks(struct yaffs_dev *dev);
906
907struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
908 struct yaffs_file_var *file_struct,
909 u32 chunk_id);
910
911u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
912 unsigned pos);
913
914int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
915#endif
diff --git a/fs/yaffs2/yaffs_linux.h b/fs/yaffs2/yaffs_linux.h
new file mode 100644
index 00000000000..3b508cbc4e8
--- /dev/null
+++ b/fs/yaffs2/yaffs_linux.h
@@ -0,0 +1,41 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_LINUX_H__
17#define __YAFFS_LINUX_H__
18
19#include "yportenv.h"
20
21struct yaffs_linux_context {
22 struct list_head context_list; /* List of these we have mounted */
23 struct yaffs_dev *dev;
24 struct super_block *super;
25 struct task_struct *bg_thread; /* Background thread for this device */
26 int bg_running;
27 struct mutex gross_lock; /* Gross locking mutex*/
28 u8 *spare_buffer; /* For mtdif2 use. Don't know the size of the buffer
29 * at compile time so we have to allocate it.
30 */
31 struct list_head search_contexts;
32 void (*put_super_fn) (struct super_block * sb);
33
34 struct task_struct *readdir_process;
35 unsigned mount_id;
36};
37
38#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
39#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
40
41#endif
diff --git a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c
new file mode 100644
index 00000000000..7cf53b3d91b
--- /dev/null
+++ b/fs/yaffs2/yaffs_mtdif.c
@@ -0,0 +1,54 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yportenv.h"
15
16#include "yaffs_mtdif.h"
17
18#include "linux/mtd/mtd.h"
19#include "linux/types.h"
20#include "linux/time.h"
21#include "linux/mtd/nand.h"
22
23#include "yaffs_linux.h"
24
25int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
26{
27 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
28 u32 addr =
29 ((loff_t) block_no) * dev->param.total_bytes_per_chunk
30 * dev->param.chunks_per_block;
31 struct erase_info ei;
32
33 int retval = 0;
34
35 ei.mtd = mtd;
36 ei.addr = addr;
37 ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
38 ei.time = 1000;
39 ei.retries = 2;
40 ei.callback = NULL;
41 ei.priv = (u_long) dev;
42
43 retval = mtd->erase(mtd, &ei);
44
45 if (retval == 0)
46 return YAFFS_OK;
47 else
48 return YAFFS_FAIL;
49}
50
51int nandmtd_initialise(struct yaffs_dev *dev)
52{
53 return YAFFS_OK;
54}
diff --git a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h
new file mode 100644
index 00000000000..666507417fe
--- /dev/null
+++ b/fs/yaffs2/yaffs_mtdif.h
@@ -0,0 +1,23 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_MTDIF_H__
17#define __YAFFS_MTDIF_H__
18
19#include "yaffs_guts.h"
20
21int nandmtd_erase_block(struct yaffs_dev *dev, int block_no);
22int nandmtd_initialise(struct yaffs_dev *dev);
23#endif
diff --git a/fs/yaffs2/yaffs_mtdif1.c b/fs/yaffs2/yaffs_mtdif1.c
new file mode 100644
index 00000000000..51083695eb3
--- /dev/null
+++ b/fs/yaffs2/yaffs_mtdif1.c
@@ -0,0 +1,330 @@
1/*
2 * YAFFS: Yet another FFS. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14/*
15 * This module provides the interface between yaffs_nand.c and the
16 * MTD API. This version is used when the MTD interface supports the
17 * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
18 * and we have small-page NAND device.
19 *
20 * These functions are invoked via function pointers in yaffs_nand.c.
21 * This replaces functionality provided by functions in yaffs_mtdif.c
22 * and the yaffs_tags compatability functions in yaffs_tagscompat.c that are
23 * called in yaffs_mtdif.c when the function pointers are NULL.
24 * We assume the MTD layer is performing ECC (use_nand_ecc is true).
25 */
26
27#include "yportenv.h"
28#include "yaffs_trace.h"
29#include "yaffs_guts.h"
30#include "yaffs_packedtags1.h"
31#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */
32#include "yaffs_linux.h"
33
34#include "linux/kernel.h"
35#include "linux/version.h"
36#include "linux/types.h"
37#include "linux/mtd/mtd.h"
38
39#ifndef CONFIG_YAFFS_9BYTE_TAGS
40# define YTAG1_SIZE 8
41#else
42# define YTAG1_SIZE 9
43#endif
44
45/* Write a chunk (page) of data to NAND.
46 *
47 * Caller always provides ExtendedTags data which are converted to a more
48 * compact (packed) form for storage in NAND. A mini-ECC runs over the
49 * contents of the tags meta-data; used to valid the tags when read.
50 *
51 * - Pack ExtendedTags to packed_tags1 form
52 * - Compute mini-ECC for packed_tags1
53 * - Write data and packed tags to NAND.
54 *
55 * Note: Due to the use of the packed_tags1 meta-data which does not include
56 * a full sequence number (as found in the larger packed_tags2 form) it is
57 * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
58 * discarded and dirty. This is not ideal: newer NAND parts are supposed
59 * to be written just once. When Yaffs performs this operation, this
60 * function is called with a NULL data pointer -- calling MTD write_oob
61 * without data is valid usage (2.6.17).
62 *
63 * Any underlying MTD error results in YAFFS_FAIL.
64 * Returns YAFFS_OK or YAFFS_FAIL.
65 */
66int nandmtd1_write_chunk_tags(struct yaffs_dev *dev,
67 int nand_chunk, const u8 * data,
68 const struct yaffs_ext_tags *etags)
69{
70 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
71 int chunk_bytes = dev->data_bytes_per_chunk;
72 loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
73 struct mtd_oob_ops ops;
74 struct yaffs_packed_tags1 pt1;
75 int retval;
76
77 /* we assume that packed_tags1 and struct yaffs_tags are compatible */
78 compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
79 compile_time_assertion(sizeof(struct yaffs_tags) == 8);
80
81 yaffs_pack_tags1(&pt1, etags);
82 yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
83
84 /* When deleting a chunk, the upper layer provides only skeletal
85 * etags, one with is_deleted set. However, we need to update the
86 * tags, not erase them completely. So we use the NAND write property
87 * that only zeroed-bits stick and set tag bytes to all-ones and
88 * zero just the (not) deleted bit.
89 */
90#ifndef CONFIG_YAFFS_9BYTE_TAGS
91 if (etags->is_deleted) {
92 memset(&pt1, 0xff, 8);
93 /* clear delete status bit to indicate deleted */
94 pt1.deleted = 0;
95 }
96#else
97 ((u8 *) & pt1)[8] = 0xff;
98 if (etags->is_deleted) {
99 memset(&pt1, 0xff, 8);
100 /* zero page_status byte to indicate deleted */
101 ((u8 *) & pt1)[8] = 0;
102 }
103#endif
104
105 memset(&ops, 0, sizeof(ops));
106 ops.mode = MTD_OOB_AUTO;
107 ops.len = (data) ? chunk_bytes : 0;
108 ops.ooblen = YTAG1_SIZE;
109 ops.datbuf = (u8 *) data;
110 ops.oobbuf = (u8 *) & pt1;
111
112 retval = mtd->write_oob(mtd, addr, &ops);
113 if (retval) {
114 yaffs_trace(YAFFS_TRACE_MTD,
115 "write_oob failed, chunk %d, mtd error %d",
116 nand_chunk, retval);
117 }
118 return retval ? YAFFS_FAIL : YAFFS_OK;
119}
120
121/* Return with empty ExtendedTags but add ecc_result.
122 */
123static int rettags(struct yaffs_ext_tags *etags, int ecc_result, int retval)
124{
125 if (etags) {
126 memset(etags, 0, sizeof(*etags));
127 etags->ecc_result = ecc_result;
128 }
129 return retval;
130}
131
132/* Read a chunk (page) from NAND.
133 *
134 * Caller expects ExtendedTags data to be usable even on error; that is,
135 * all members except ecc_result and block_bad are zeroed.
136 *
137 * - Check ECC results for data (if applicable)
138 * - Check for blank/erased block (return empty ExtendedTags if blank)
139 * - Check the packed_tags1 mini-ECC (correct if necessary/possible)
140 * - Convert packed_tags1 to ExtendedTags
141 * - Update ecc_result and block_bad members to refect state.
142 *
143 * Returns YAFFS_OK or YAFFS_FAIL.
144 */
145int nandmtd1_read_chunk_tags(struct yaffs_dev *dev,
146 int nand_chunk, u8 * data,
147 struct yaffs_ext_tags *etags)
148{
149 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
150 int chunk_bytes = dev->data_bytes_per_chunk;
151 loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
152 int eccres = YAFFS_ECC_RESULT_NO_ERROR;
153 struct mtd_oob_ops ops;
154 struct yaffs_packed_tags1 pt1;
155 int retval;
156 int deleted;
157
158 memset(&ops, 0, sizeof(ops));
159 ops.mode = MTD_OOB_AUTO;
160 ops.len = (data) ? chunk_bytes : 0;
161 ops.ooblen = YTAG1_SIZE;
162 ops.datbuf = data;
163 ops.oobbuf = (u8 *) & pt1;
164
165 /* Read page and oob using MTD.
166 * Check status and determine ECC result.
167 */
168 retval = mtd->read_oob(mtd, addr, &ops);
169 if (retval) {
170 yaffs_trace(YAFFS_TRACE_MTD,
171 "read_oob failed, chunk %d, mtd error %d",
172 nand_chunk, retval);
173 }
174
175 switch (retval) {
176 case 0:
177 /* no error */
178 break;
179
180 case -EUCLEAN:
181 /* MTD's ECC fixed the data */
182 eccres = YAFFS_ECC_RESULT_FIXED;
183 dev->n_ecc_fixed++;
184 break;
185
186 case -EBADMSG:
187 /* MTD's ECC could not fix the data */
188 dev->n_ecc_unfixed++;
189 /* fall into... */
190 default:
191 rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
192 etags->block_bad = (mtd->block_isbad) (mtd, addr);
193 return YAFFS_FAIL;
194 }
195
196 /* Check for a blank/erased chunk.
197 */
198 if (yaffs_check_ff((u8 *) & pt1, 8)) {
199 /* when blank, upper layers want ecc_result to be <= NO_ERROR */
200 return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
201 }
202#ifndef CONFIG_YAFFS_9BYTE_TAGS
203 /* Read deleted status (bit) then return it to it's non-deleted
204 * state before performing tags mini-ECC check. pt1.deleted is
205 * inverted.
206 */
207 deleted = !pt1.deleted;
208 pt1.deleted = 1;
209#else
210 deleted = (yaffs_count_bits(((u8 *) & pt1)[8]) < 7);
211#endif
212
213 /* Check the packed tags mini-ECC and correct if necessary/possible.
214 */
215 retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
216 switch (retval) {
217 case 0:
218 /* no tags error, use MTD result */
219 break;
220 case 1:
221 /* recovered tags-ECC error */
222 dev->n_tags_ecc_fixed++;
223 if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
224 eccres = YAFFS_ECC_RESULT_FIXED;
225 break;
226 default:
227 /* unrecovered tags-ECC error */
228 dev->n_tags_ecc_unfixed++;
229 return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
230 }
231
232 /* Unpack the tags to extended form and set ECC result.
233 * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
234 */
235 pt1.should_be_ff = 0xFFFFFFFF;
236 yaffs_unpack_tags1(etags, &pt1);
237 etags->ecc_result = eccres;
238
239 /* Set deleted state */
240 etags->is_deleted = deleted;
241 return YAFFS_OK;
242}
243
244/* Mark a block bad.
245 *
246 * This is a persistant state.
247 * Use of this function should be rare.
248 *
249 * Returns YAFFS_OK or YAFFS_FAIL.
250 */
251int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no)
252{
253 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
254 int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
255 int retval;
256
257 yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
258 "marking block %d bad", block_no);
259
260 retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
261 return (retval) ? YAFFS_FAIL : YAFFS_OK;
262}
263
264/* Check any MTD prerequists.
265 *
266 * Returns YAFFS_OK or YAFFS_FAIL.
267 */
268static int nandmtd1_test_prerequists(struct mtd_info *mtd)
269{
270 /* 2.6.18 has mtd->ecclayout->oobavail */
271 /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
272 int oobavail = mtd->ecclayout->oobavail;
273
274 if (oobavail < YTAG1_SIZE) {
275 yaffs_trace(YAFFS_TRACE_ERROR,
276 "mtd device has only %d bytes for tags, need %d",
277 oobavail, YTAG1_SIZE);
278 return YAFFS_FAIL;
279 }
280 return YAFFS_OK;
281}
282
283/* Query for the current state of a specific block.
284 *
285 * Examine the tags of the first chunk of the block and return the state:
286 * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
287 * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
288 * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
289 *
290 * Always returns YAFFS_OK.
291 */
292int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
293 enum yaffs_block_state *state_ptr, u32 * seq_ptr)
294{
295 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
296 int chunk_num = block_no * dev->param.chunks_per_block;
297 loff_t addr = (loff_t) chunk_num * dev->data_bytes_per_chunk;
298 struct yaffs_ext_tags etags;
299 int state = YAFFS_BLOCK_STATE_DEAD;
300 int seqnum = 0;
301 int retval;
302
303 /* We don't yet have a good place to test for MTD config prerequists.
304 * Do it here as we are called during the initial scan.
305 */
306 if (nandmtd1_test_prerequists(mtd) != YAFFS_OK)
307 return YAFFS_FAIL;
308
309 retval = nandmtd1_read_chunk_tags(dev, chunk_num, NULL, &etags);
310 etags.block_bad = (mtd->block_isbad) (mtd, addr);
311 if (etags.block_bad) {
312 yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
313 "block %d is marked bad", block_no);
314 state = YAFFS_BLOCK_STATE_DEAD;
315 } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
316 /* bad tags, need to look more closely */
317 state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
318 } else if (etags.chunk_used) {
319 state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
320 seqnum = etags.seq_number;
321 } else {
322 state = YAFFS_BLOCK_STATE_EMPTY;
323 }
324
325 *state_ptr = state;
326 *seq_ptr = seqnum;
327
328 /* query always succeeds */
329 return YAFFS_OK;
330}
diff --git a/fs/yaffs2/yaffs_mtdif1.h b/fs/yaffs2/yaffs_mtdif1.h
new file mode 100644
index 00000000000..07ce4524f0f
--- /dev/null
+++ b/fs/yaffs2/yaffs_mtdif1.h
@@ -0,0 +1,29 @@
1/*
2 * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License version 2.1 as
9 * published by the Free Software Foundation.
10 *
11 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
12 */
13
14#ifndef __YAFFS_MTDIF1_H__
15#define __YAFFS_MTDIF1_H__
16
17int nandmtd1_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
18 const u8 * data,
19 const struct yaffs_ext_tags *tags);
20
21int nandmtd1_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
22 u8 * data, struct yaffs_ext_tags *tags);
23
24int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no);
25
26int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
27 enum yaffs_block_state *state, u32 * seq_number);
28
29#endif
diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c
new file mode 100644
index 00000000000..d1643df2c38
--- /dev/null
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -0,0 +1,225 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14/* mtd interface for YAFFS2 */
15
16#include "yportenv.h"
17#include "yaffs_trace.h"
18
19#include "yaffs_mtdif2.h"
20
21#include "linux/mtd/mtd.h"
22#include "linux/types.h"
23#include "linux/time.h"
24
25#include "yaffs_packedtags2.h"
26
27#include "yaffs_linux.h"
28
29/* NB For use with inband tags....
30 * We assume that the data buffer is of size total_bytes_per_chunk so that we can also
31 * use it to load the tags.
32 */
33int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
34 const u8 * data,
35 const struct yaffs_ext_tags *tags)
36{
37 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
38 struct mtd_oob_ops ops;
39 int retval = 0;
40
41 loff_t addr;
42
43 struct yaffs_packed_tags2 pt;
44
45 int packed_tags_size =
46 dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
47 void *packed_tags_ptr =
48 dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
49
50 yaffs_trace(YAFFS_TRACE_MTD,
51 "nandmtd2_write_chunk_tags chunk %d data %p tags %p",
52 nand_chunk, data, tags);
53
54 addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
55
56 /* For yaffs2 writing there must be both data and tags.
57 * If we're using inband tags, then the tags are stuffed into
58 * the end of the data buffer.
59 */
60 if (!data || !tags)
61 BUG();
62 else if (dev->param.inband_tags) {
63 struct yaffs_packed_tags2_tags_only *pt2tp;
64 pt2tp =
65 (struct yaffs_packed_tags2_tags_only *)(data +
66 dev->
67 data_bytes_per_chunk);
68 yaffs_pack_tags2_tags_only(pt2tp, tags);
69 } else {
70 yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
71 }
72
73 ops.mode = MTD_OOB_AUTO;
74 ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
75 ops.len = dev->param.total_bytes_per_chunk;
76 ops.ooboffs = 0;
77 ops.datbuf = (u8 *) data;
78 ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
79 retval = mtd->write_oob(mtd, addr, &ops);
80
81 if (retval == 0)
82 return YAFFS_OK;
83 else
84 return YAFFS_FAIL;
85}
86
87int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
88 u8 * data, struct yaffs_ext_tags *tags)
89{
90 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
91 struct mtd_oob_ops ops;
92
93 size_t dummy;
94 int retval = 0;
95 int local_data = 0;
96
97 loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
98
99 struct yaffs_packed_tags2 pt;
100
101 int packed_tags_size =
102 dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
103 void *packed_tags_ptr =
104 dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
105
106 yaffs_trace(YAFFS_TRACE_MTD,
107 "nandmtd2_read_chunk_tags chunk %d data %p tags %p",
108 nand_chunk, data, tags);
109
110 if (dev->param.inband_tags) {
111
112 if (!data) {
113 local_data = 1;
114 data = yaffs_get_temp_buffer(dev, __LINE__);
115 }
116
117 }
118
119 if (dev->param.inband_tags || (data && !tags))
120 retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
121 &dummy, data);
122 else if (tags) {
123 ops.mode = MTD_OOB_AUTO;
124 ops.ooblen = packed_tags_size;
125 ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
126 ops.ooboffs = 0;
127 ops.datbuf = data;
128 ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
129 retval = mtd->read_oob(mtd, addr, &ops);
130 }
131
132 if (dev->param.inband_tags) {
133 if (tags) {
134 struct yaffs_packed_tags2_tags_only *pt2tp;
135 pt2tp =
136 (struct yaffs_packed_tags2_tags_only *)&data[dev->
137 data_bytes_per_chunk];
138 yaffs_unpack_tags2_tags_only(tags, pt2tp);
139 }
140 } else {
141 if (tags) {
142 memcpy(packed_tags_ptr,
143 yaffs_dev_to_lc(dev)->spare_buffer,
144 packed_tags_size);
145 yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
146 }
147 }
148
149 if (local_data)
150 yaffs_release_temp_buffer(dev, data, __LINE__);
151
152 if (tags && retval == -EBADMSG
153 && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
154 tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
155 dev->n_ecc_unfixed++;
156 }
157 if (tags && retval == -EUCLEAN
158 && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
159 tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
160 dev->n_ecc_fixed++;
161 }
162 if (retval == 0)
163 return YAFFS_OK;
164 else
165 return YAFFS_FAIL;
166}
167
168int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no)
169{
170 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
171 int retval;
172 yaffs_trace(YAFFS_TRACE_MTD,
173 "nandmtd2_mark_block_bad %d", block_no);
174
175 retval =
176 mtd->block_markbad(mtd,
177 block_no * dev->param.chunks_per_block *
178 dev->param.total_bytes_per_chunk);
179
180 if (retval == 0)
181 return YAFFS_OK;
182 else
183 return YAFFS_FAIL;
184
185}
186
187int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
188 enum yaffs_block_state *state, u32 * seq_number)
189{
190 struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
191 int retval;
192
193 yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_query_block %d", block_no);
194 retval =
195 mtd->block_isbad(mtd,
196 block_no * dev->param.chunks_per_block *
197 dev->param.total_bytes_per_chunk);
198
199 if (retval) {
200 yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
201
202 *state = YAFFS_BLOCK_STATE_DEAD;
203 *seq_number = 0;
204 } else {
205 struct yaffs_ext_tags t;
206 nandmtd2_read_chunk_tags(dev, block_no *
207 dev->param.chunks_per_block, NULL, &t);
208
209 if (t.chunk_used) {
210 *seq_number = t.seq_number;
211 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
212 } else {
213 *seq_number = 0;
214 *state = YAFFS_BLOCK_STATE_EMPTY;
215 }
216 }
217 yaffs_trace(YAFFS_TRACE_MTD,
218 "block is bad seq %d state %d", *seq_number, *state);
219
220 if (retval == 0)
221 return YAFFS_OK;
222 else
223 return YAFFS_FAIL;
224}
225
diff --git a/fs/yaffs2/yaffs_mtdif2.h b/fs/yaffs2/yaffs_mtdif2.h
new file mode 100644
index 00000000000..d82112610d0
--- /dev/null
+++ b/fs/yaffs2/yaffs_mtdif2.h
@@ -0,0 +1,29 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_MTDIF2_H__
17#define __YAFFS_MTDIF2_H__
18
19#include "yaffs_guts.h"
20int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
21 const u8 * data,
22 const struct yaffs_ext_tags *tags);
23int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
24 u8 * data, struct yaffs_ext_tags *tags);
25int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no);
26int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
27 enum yaffs_block_state *state, u32 * seq_number);
28
29#endif
diff --git a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c
new file mode 100644
index 00000000000..daa36f989d3
--- /dev/null
+++ b/fs/yaffs2/yaffs_nameval.c
@@ -0,0 +1,201 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14/*
15 * This simple implementation of a name-value store assumes a small number of values and fits
16 * into a small finite buffer.
17 *
18 * Each attribute is stored as a record:
19 * sizeof(int) bytes record size.
20 * strnlen+1 bytes name null terminated.
21 * nbytes value.
22 * ----------
23 * total size stored in record size
24 *
25 * This code has not been tested with unicode yet.
26 */
27
28#include "yaffs_nameval.h"
29
30#include "yportenv.h"
31
32static int nval_find(const char *xb, int xb_size, const YCHAR * name,
33 int *exist_size)
34{
35 int pos = 0;
36 int size;
37
38 memcpy(&size, xb, sizeof(int));
39 while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
40 if (strncmp
41 ((YCHAR *) (xb + pos + sizeof(int)), name, size) == 0) {
42 if (exist_size)
43 *exist_size = size;
44 return pos;
45 }
46 pos += size;
47 if (pos < xb_size - sizeof(int))
48 memcpy(&size, xb + pos, sizeof(int));
49 else
50 size = 0;
51 }
52 if (exist_size)
53 *exist_size = 0;
54 return -1;
55}
56
57static int nval_used(const char *xb, int xb_size)
58{
59 int pos = 0;
60 int size;
61
62 memcpy(&size, xb + pos, sizeof(int));
63 while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
64 pos += size;
65 if (pos < xb_size - sizeof(int))
66 memcpy(&size, xb + pos, sizeof(int));
67 else
68 size = 0;
69 }
70 return pos;
71}
72
73int nval_del(char *xb, int xb_size, const YCHAR * name)
74{
75 int pos = nval_find(xb, xb_size, name, NULL);
76 int size;
77
78 if (pos >= 0 && pos < xb_size) {
79 /* Find size, shift rest over this record, then zero out the rest of buffer */
80 memcpy(&size, xb + pos, sizeof(int));
81 memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
82 memset(xb + (xb_size - size), 0, size);
83 return 0;
84 } else {
85 return -ENODATA;
86 }
87}
88
89int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
90 int bsize, int flags)
91{
92 int pos;
93 int namelen = strnlen(name, xb_size);
94 int reclen;
95 int size_exist = 0;
96 int space;
97 int start;
98
99 pos = nval_find(xb, xb_size, name, &size_exist);
100
101 if (flags & XATTR_CREATE && pos >= 0)
102 return -EEXIST;
103 if (flags & XATTR_REPLACE && pos < 0)
104 return -ENODATA;
105
106 start = nval_used(xb, xb_size);
107 space = xb_size - start + size_exist;
108
109 reclen = (sizeof(int) + namelen + 1 + bsize);
110
111 if (reclen > space)
112 return -ENOSPC;
113
114 if (pos >= 0) {
115 nval_del(xb, xb_size, name);
116 start = nval_used(xb, xb_size);
117 }
118
119 pos = start;
120
121 memcpy(xb + pos, &reclen, sizeof(int));
122 pos += sizeof(int);
123 strncpy((YCHAR *) (xb + pos), name, reclen);
124 pos += (namelen + 1);
125 memcpy(xb + pos, buf, bsize);
126 return 0;
127}
128
129int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
130 int bsize)
131{
132 int pos = nval_find(xb, xb_size, name, NULL);
133 int size;
134
135 if (pos >= 0 && pos < xb_size) {
136
137 memcpy(&size, xb + pos, sizeof(int));
138 pos += sizeof(int); /* advance past record length */
139 size -= sizeof(int);
140
141 /* Advance over name string */
142 while (xb[pos] && size > 0 && pos < xb_size) {
143 pos++;
144 size--;
145 }
146 /*Advance over NUL */
147 pos++;
148 size--;
149
150 if (size <= bsize) {
151 memcpy(buf, xb + pos, size);
152 return size;
153 }
154
155 }
156 if (pos >= 0)
157 return -ERANGE;
158 else
159 return -ENODATA;
160}
161
162int nval_list(const char *xb, int xb_size, char *buf, int bsize)
163{
164 int pos = 0;
165 int size;
166 int name_len;
167 int ncopied = 0;
168 int filled = 0;
169
170 memcpy(&size, xb + pos, sizeof(int));
171 while (size > sizeof(int) && size <= xb_size && (pos + size) < xb_size
172 && !filled) {
173 pos += sizeof(int);
174 size -= sizeof(int);
175 name_len = strnlen((YCHAR *) (xb + pos), size);
176 if (ncopied + name_len + 1 < bsize) {
177 memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
178 buf += name_len;
179 *buf = '\0';
180 buf++;
181 if (sizeof(YCHAR) > 1) {
182 *buf = '\0';
183 buf++;
184 }
185 ncopied += (name_len + 1);
186 } else {
187 filled = 1;
188 }
189 pos += size;
190 if (pos < xb_size - sizeof(int))
191 memcpy(&size, xb + pos, sizeof(int));
192 else
193 size = 0;
194 }
195 return ncopied;
196}
197
198int nval_hasvalues(const char *xb, int xb_size)
199{
200 return nval_used(xb, xb_size) > 0;
201}
diff --git a/fs/yaffs2/yaffs_nameval.h b/fs/yaffs2/yaffs_nameval.h
new file mode 100644
index 00000000000..2bb02b62762
--- /dev/null
+++ b/fs/yaffs2/yaffs_nameval.h
@@ -0,0 +1,28 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __NAMEVAL_H__
17#define __NAMEVAL_H__
18
19#include "yportenv.h"
20
21int nval_del(char *xb, int xb_size, const YCHAR * name);
22int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
23 int bsize, int flags);
24int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
25 int bsize);
26int nval_list(const char *xb, int xb_size, char *buf, int bsize);
27int nval_hasvalues(const char *xb, int xb_size);
28#endif
diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c
new file mode 100644
index 00000000000..e816cabf43f
--- /dev/null
+++ b/fs/yaffs2/yaffs_nand.c
@@ -0,0 +1,127 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_nand.h"
15#include "yaffs_tagscompat.h"
16#include "yaffs_tagsvalidity.h"
17
18#include "yaffs_getblockinfo.h"
19
20int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
21 u8 * buffer, struct yaffs_ext_tags *tags)
22{
23 int result;
24 struct yaffs_ext_tags local_tags;
25
26 int realigned_chunk = nand_chunk - dev->chunk_offset;
27
28 dev->n_page_reads++;
29
30 /* If there are no tags provided, use local tags to get prioritised gc working */
31 if (!tags)
32 tags = &local_tags;
33
34 if (dev->param.read_chunk_tags_fn)
35 result =
36 dev->param.read_chunk_tags_fn(dev, realigned_chunk, buffer,
37 tags);
38 else
39 result = yaffs_tags_compat_rd(dev,
40 realigned_chunk, buffer, tags);
41 if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
42
43 struct yaffs_block_info *bi;
44 bi = yaffs_get_block_info(dev,
45 nand_chunk /
46 dev->param.chunks_per_block);
47 yaffs_handle_chunk_error(dev, bi);
48 }
49
50 return result;
51}
52
53int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
54 int nand_chunk,
55 const u8 * buffer, struct yaffs_ext_tags *tags)
56{
57
58 dev->n_page_writes++;
59
60 nand_chunk -= dev->chunk_offset;
61
62 if (tags) {
63 tags->seq_number = dev->seq_number;
64 tags->chunk_used = 1;
65 if (!yaffs_validate_tags(tags)) {
66 yaffs_trace(YAFFS_TRACE_ERROR, "Writing uninitialised tags");
67 YBUG();
68 }
69 yaffs_trace(YAFFS_TRACE_WRITE,
70 "Writing chunk %d tags %d %d",
71 nand_chunk, tags->obj_id, tags->chunk_id);
72 } else {
73 yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
74 YBUG();
75 }
76
77 if (dev->param.write_chunk_tags_fn)
78 return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer,
79 tags);
80 else
81 return yaffs_tags_compat_wr(dev, nand_chunk, buffer, tags);
82}
83
84int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
85{
86 block_no -= dev->block_offset;
87
88 if (dev->param.bad_block_fn)
89 return dev->param.bad_block_fn(dev, block_no);
90 else
91 return yaffs_tags_compat_mark_bad(dev, block_no);
92}
93
94int yaffs_query_init_block_state(struct yaffs_dev *dev,
95 int block_no,
96 enum yaffs_block_state *state,
97 u32 * seq_number)
98{
99 block_no -= dev->block_offset;
100
101 if (dev->param.query_block_fn)
102 return dev->param.query_block_fn(dev, block_no, state,
103 seq_number);
104 else
105 return yaffs_tags_compat_query_block(dev, block_no,
106 state, seq_number);
107}
108
109int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
110{
111 int result;
112
113 flash_block -= dev->block_offset;
114
115 dev->n_erasures++;
116
117 result = dev->param.erase_fn(dev, flash_block);
118
119 return result;
120}
121
122int yaffs_init_nand(struct yaffs_dev *dev)
123{
124 if (dev->param.initialise_flash_fn)
125 return dev->param.initialise_flash_fn(dev);
126 return YAFFS_OK;
127}
diff --git a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h
new file mode 100644
index 00000000000..543f1987124
--- /dev/null
+++ b/fs/yaffs2/yaffs_nand.h
@@ -0,0 +1,38 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_NAND_H__
17#define __YAFFS_NAND_H__
18#include "yaffs_guts.h"
19
20int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
21 u8 * buffer, struct yaffs_ext_tags *tags);
22
23int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
24 int nand_chunk,
25 const u8 * buffer, struct yaffs_ext_tags *tags);
26
27int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
28
29int yaffs_query_init_block_state(struct yaffs_dev *dev,
30 int block_no,
31 enum yaffs_block_state *state,
32 unsigned *seq_number);
33
34int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
35
36int yaffs_init_nand(struct yaffs_dev *dev);
37
38#endif
diff --git a/fs/yaffs2/yaffs_packedtags1.c b/fs/yaffs2/yaffs_packedtags1.c
new file mode 100644
index 00000000000..a77f0954fc1
--- /dev/null
+++ b/fs/yaffs2/yaffs_packedtags1.c
@@ -0,0 +1,53 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_packedtags1.h"
15#include "yportenv.h"
16
17void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
18 const struct yaffs_ext_tags *t)
19{
20 pt->chunk_id = t->chunk_id;
21 pt->serial_number = t->serial_number;
22 pt->n_bytes = t->n_bytes;
23 pt->obj_id = t->obj_id;
24 pt->ecc = 0;
25 pt->deleted = (t->is_deleted) ? 0 : 1;
26 pt->unused_stuff = 0;
27 pt->should_be_ff = 0xFFFFFFFF;
28
29}
30
31void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
32 const struct yaffs_packed_tags1 *pt)
33{
34 static const u8 all_ff[] =
35 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
36 0xff
37 };
38
39 if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
40 t->block_bad = 0;
41 if (pt->should_be_ff != 0xFFFFFFFF)
42 t->block_bad = 1;
43 t->chunk_used = 1;
44 t->obj_id = pt->obj_id;
45 t->chunk_id = pt->chunk_id;
46 t->n_bytes = pt->n_bytes;
47 t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
48 t->is_deleted = (pt->deleted) ? 0 : 1;
49 t->serial_number = pt->serial_number;
50 } else {
51 memset(t, 0, sizeof(struct yaffs_ext_tags));
52 }
53}
diff --git a/fs/yaffs2/yaffs_packedtags1.h b/fs/yaffs2/yaffs_packedtags1.h
new file mode 100644
index 00000000000..d6861ff505e
--- /dev/null
+++ b/fs/yaffs2/yaffs_packedtags1.h
@@ -0,0 +1,39 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
17
18#ifndef __YAFFS_PACKEDTAGS1_H__
19#define __YAFFS_PACKEDTAGS1_H__
20
21#include "yaffs_guts.h"
22
23struct yaffs_packed_tags1 {
24 unsigned chunk_id:20;
25 unsigned serial_number:2;
26 unsigned n_bytes:10;
27 unsigned obj_id:18;
28 unsigned ecc:12;
29 unsigned deleted:1;
30 unsigned unused_stuff:1;
31 unsigned should_be_ff;
32
33};
34
35void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
36 const struct yaffs_ext_tags *t);
37void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
38 const struct yaffs_packed_tags1 *pt);
39#endif
diff --git a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c
new file mode 100644
index 00000000000..8e7fea3d286
--- /dev/null
+++ b/fs/yaffs2/yaffs_packedtags2.c
@@ -0,0 +1,196 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_packedtags2.h"
15#include "yportenv.h"
16#include "yaffs_trace.h"
17#include "yaffs_tagsvalidity.h"
18
19/* This code packs a set of extended tags into a binary structure for
20 * NAND storage
21 */
22
23/* Some of the information is "extra" struff which can be packed in to
24 * speed scanning
25 * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
26 */
27
28/* Extra flags applied to chunk_id */
29
30#define EXTRA_HEADER_INFO_FLAG 0x80000000
31#define EXTRA_SHRINK_FLAG 0x40000000
32#define EXTRA_SHADOWS_FLAG 0x20000000
33#define EXTRA_SPARE_FLAGS 0x10000000
34
35#define ALL_EXTRA_FLAGS 0xF0000000
36
37/* Also, the top 4 bits of the object Id are set to the object type. */
38#define EXTRA_OBJECT_TYPE_SHIFT (28)
39#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
40
41static void yaffs_dump_packed_tags2_tags_only(const struct
42 yaffs_packed_tags2_tags_only *ptt)
43{
44 yaffs_trace(YAFFS_TRACE_MTD,
45 "packed tags obj %d chunk %d byte %d seq %d",
46 ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
47}
48
49static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
50{
51 yaffs_dump_packed_tags2_tags_only(&pt->t);
52}
53
54static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
55{
56 yaffs_trace(YAFFS_TRACE_MTD,
57 "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
58 t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
59 t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
60 t->seq_number);
61
62}
63
64void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
65 const struct yaffs_ext_tags *t)
66{
67 ptt->chunk_id = t->chunk_id;
68 ptt->seq_number = t->seq_number;
69 ptt->n_bytes = t->n_bytes;
70 ptt->obj_id = t->obj_id;
71
72 if (t->chunk_id == 0 && t->extra_available) {
73 /* Store the extra header info instead */
74 /* We save the parent object in the chunk_id */
75 ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
76 if (t->extra_is_shrink)
77 ptt->chunk_id |= EXTRA_SHRINK_FLAG;
78 if (t->extra_shadows)
79 ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
80
81 ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
82 ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
83
84 if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
85 ptt->n_bytes = t->extra_equiv_id;
86 else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
87 ptt->n_bytes = t->extra_length;
88 else
89 ptt->n_bytes = 0;
90 }
91
92 yaffs_dump_packed_tags2_tags_only(ptt);
93 yaffs_dump_tags2(t);
94}
95
96void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
97 const struct yaffs_ext_tags *t, int tags_ecc)
98{
99 yaffs_pack_tags2_tags_only(&pt->t, t);
100
101 if (tags_ecc)
102 yaffs_ecc_calc_other((unsigned char *)&pt->t,
103 sizeof(struct
104 yaffs_packed_tags2_tags_only),
105 &pt->ecc);
106}
107
108void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
109 struct yaffs_packed_tags2_tags_only *ptt)
110{
111
112 memset(t, 0, sizeof(struct yaffs_ext_tags));
113
114 yaffs_init_tags(t);
115
116 if (ptt->seq_number != 0xFFFFFFFF) {
117 t->block_bad = 0;
118 t->chunk_used = 1;
119 t->obj_id = ptt->obj_id;
120 t->chunk_id = ptt->chunk_id;
121 t->n_bytes = ptt->n_bytes;
122 t->is_deleted = 0;
123 t->serial_number = 0;
124 t->seq_number = ptt->seq_number;
125
126 /* Do extra header info stuff */
127
128 if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
129 t->chunk_id = 0;
130 t->n_bytes = 0;
131
132 t->extra_available = 1;
133 t->extra_parent_id =
134 ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
135 t->extra_is_shrink =
136 (ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0;
137 t->extra_shadows =
138 (ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0;
139 t->extra_obj_type =
140 ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
141 t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
142
143 if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
144 t->extra_equiv_id = ptt->n_bytes;
145 else
146 t->extra_length = ptt->n_bytes;
147 }
148 }
149
150 yaffs_dump_packed_tags2_tags_only(ptt);
151 yaffs_dump_tags2(t);
152
153}
154
155void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
156 int tags_ecc)
157{
158
159 enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
160
161 if (pt->t.seq_number != 0xFFFFFFFF && tags_ecc) {
162 /* Chunk is in use and we need to do ECC */
163
164 struct yaffs_ecc_other ecc;
165 int result;
166 yaffs_ecc_calc_other((unsigned char *)&pt->t,
167 sizeof(struct
168 yaffs_packed_tags2_tags_only),
169 &ecc);
170 result =
171 yaffs_ecc_correct_other((unsigned char *)&pt->t,
172 sizeof(struct
173 yaffs_packed_tags2_tags_only),
174 &pt->ecc, &ecc);
175 switch (result) {
176 case 0:
177 ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
178 break;
179 case 1:
180 ecc_result = YAFFS_ECC_RESULT_FIXED;
181 break;
182 case -1:
183 ecc_result = YAFFS_ECC_RESULT_UNFIXED;
184 break;
185 default:
186 ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
187 }
188 }
189
190 yaffs_unpack_tags2_tags_only(t, &pt->t);
191
192 t->ecc_result = ecc_result;
193
194 yaffs_dump_packed_tags2(pt);
195 yaffs_dump_tags2(t);
196}
diff --git a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h
new file mode 100644
index 00000000000..f3296697bc0
--- /dev/null
+++ b/fs/yaffs2/yaffs_packedtags2.h
@@ -0,0 +1,47 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
17
18#ifndef __YAFFS_PACKEDTAGS2_H__
19#define __YAFFS_PACKEDTAGS2_H__
20
21#include "yaffs_guts.h"
22#include "yaffs_ecc.h"
23
24struct yaffs_packed_tags2_tags_only {
25 unsigned seq_number;
26 unsigned obj_id;
27 unsigned chunk_id;
28 unsigned n_bytes;
29};
30
31struct yaffs_packed_tags2 {
32 struct yaffs_packed_tags2_tags_only t;
33 struct yaffs_ecc_other ecc;
34};
35
36/* Full packed tags with ECC, used for oob tags */
37void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
38 const struct yaffs_ext_tags *t, int tags_ecc);
39void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
40 int tags_ecc);
41
42/* Only the tags part (no ECC for use with inband tags */
43void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
44 const struct yaffs_ext_tags *t);
45void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
46 struct yaffs_packed_tags2_tags_only *pt);
47#endif
diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c
new file mode 100644
index 00000000000..7578075d9ac
--- /dev/null
+++ b/fs/yaffs2/yaffs_tagscompat.c
@@ -0,0 +1,422 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_guts.h"
15#include "yaffs_tagscompat.h"
16#include "yaffs_ecc.h"
17#include "yaffs_getblockinfo.h"
18#include "yaffs_trace.h"
19
20static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
21
22
23/********** Tags ECC calculations *********/
24
25void yaffs_calc_ecc(const u8 * data, struct yaffs_spare *spare)
26{
27 yaffs_ecc_cacl(data, spare->ecc1);
28 yaffs_ecc_cacl(&data[256], spare->ecc2);
29}
30
31void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
32{
33 /* Calculate an ecc */
34
35 unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
36 unsigned i, j;
37 unsigned ecc = 0;
38 unsigned bit = 0;
39
40 tags->ecc = 0;
41
42 for (i = 0; i < 8; i++) {
43 for (j = 1; j & 0xff; j <<= 1) {
44 bit++;
45 if (b[i] & j)
46 ecc ^= bit;
47 }
48 }
49
50 tags->ecc = ecc;
51
52}
53
54int yaffs_check_tags_ecc(struct yaffs_tags *tags)
55{
56 unsigned ecc = tags->ecc;
57
58 yaffs_calc_tags_ecc(tags);
59
60 ecc ^= tags->ecc;
61
62 if (ecc && ecc <= 64) {
63 /* TODO: Handle the failure better. Retire? */
64 unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
65
66 ecc--;
67
68 b[ecc / 8] ^= (1 << (ecc & 7));
69
70 /* Now recvalc the ecc */
71 yaffs_calc_tags_ecc(tags);
72
73 return 1; /* recovered error */
74 } else if (ecc) {
75 /* Wierd ecc failure value */
76 /* TODO Need to do somethiong here */
77 return -1; /* unrecovered error */
78 }
79
80 return 0;
81}
82
83/********** Tags **********/
84
85static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
86 struct yaffs_tags *tags_ptr)
87{
88 union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
89
90 yaffs_calc_tags_ecc(tags_ptr);
91
92 spare_ptr->tb0 = tu->as_bytes[0];
93 spare_ptr->tb1 = tu->as_bytes[1];
94 spare_ptr->tb2 = tu->as_bytes[2];
95 spare_ptr->tb3 = tu->as_bytes[3];
96 spare_ptr->tb4 = tu->as_bytes[4];
97 spare_ptr->tb5 = tu->as_bytes[5];
98 spare_ptr->tb6 = tu->as_bytes[6];
99 spare_ptr->tb7 = tu->as_bytes[7];
100}
101
102static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
103 struct yaffs_spare *spare_ptr,
104 struct yaffs_tags *tags_ptr)
105{
106 union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
107 int result;
108
109 tu->as_bytes[0] = spare_ptr->tb0;
110 tu->as_bytes[1] = spare_ptr->tb1;
111 tu->as_bytes[2] = spare_ptr->tb2;
112 tu->as_bytes[3] = spare_ptr->tb3;
113 tu->as_bytes[4] = spare_ptr->tb4;
114 tu->as_bytes[5] = spare_ptr->tb5;
115 tu->as_bytes[6] = spare_ptr->tb6;
116 tu->as_bytes[7] = spare_ptr->tb7;
117
118 result = yaffs_check_tags_ecc(tags_ptr);
119 if (result > 0)
120 dev->n_tags_ecc_fixed++;
121 else if (result < 0)
122 dev->n_tags_ecc_unfixed++;
123}
124
125static void yaffs_spare_init(struct yaffs_spare *spare)
126{
127 memset(spare, 0xFF, sizeof(struct yaffs_spare));
128}
129
130static int yaffs_wr_nand(struct yaffs_dev *dev,
131 int nand_chunk, const u8 * data,
132 struct yaffs_spare *spare)
133{
134 if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
135 yaffs_trace(YAFFS_TRACE_ERROR,
136 "**>> yaffs chunk %d is not valid",
137 nand_chunk);
138 return YAFFS_FAIL;
139 }
140
141 return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
142}
143
144static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
145 int nand_chunk,
146 u8 * data,
147 struct yaffs_spare *spare,
148 enum yaffs_ecc_result *ecc_result,
149 int correct_errors)
150{
151 int ret_val;
152 struct yaffs_spare local_spare;
153
154 if (!spare && data) {
155 /* If we don't have a real spare, then we use a local one. */
156 /* Need this for the calculation of the ecc */
157 spare = &local_spare;
158 }
159
160 if (!dev->param.use_nand_ecc) {
161 ret_val =
162 dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
163 if (data && correct_errors) {
164 /* Do ECC correction */
165 /* Todo handle any errors */
166 int ecc_result1, ecc_result2;
167 u8 calc_ecc[3];
168
169 yaffs_ecc_cacl(data, calc_ecc);
170 ecc_result1 =
171 yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
172 yaffs_ecc_cacl(&data[256], calc_ecc);
173 ecc_result2 =
174 yaffs_ecc_correct(&data[256], spare->ecc2,
175 calc_ecc);
176
177 if (ecc_result1 > 0) {
178 yaffs_trace(YAFFS_TRACE_ERROR,
179 "**>>yaffs ecc error fix performed on chunk %d:0",
180 nand_chunk);
181 dev->n_ecc_fixed++;
182 } else if (ecc_result1 < 0) {
183 yaffs_trace(YAFFS_TRACE_ERROR,
184 "**>>yaffs ecc error unfixed on chunk %d:0",
185 nand_chunk);
186 dev->n_ecc_unfixed++;
187 }
188
189 if (ecc_result2 > 0) {
190 yaffs_trace(YAFFS_TRACE_ERROR,
191 "**>>yaffs ecc error fix performed on chunk %d:1",
192 nand_chunk);
193 dev->n_ecc_fixed++;
194 } else if (ecc_result2 < 0) {
195 yaffs_trace(YAFFS_TRACE_ERROR,
196 "**>>yaffs ecc error unfixed on chunk %d:1",
197 nand_chunk);
198 dev->n_ecc_unfixed++;
199 }
200
201 if (ecc_result1 || ecc_result2) {
202 /* We had a data problem on this page */
203 yaffs_handle_rd_data_error(dev, nand_chunk);
204 }
205
206 if (ecc_result1 < 0 || ecc_result2 < 0)
207 *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
208 else if (ecc_result1 > 0 || ecc_result2 > 0)
209 *ecc_result = YAFFS_ECC_RESULT_FIXED;
210 else
211 *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
212 }
213 } else {
214 /* Must allocate enough memory for spare+2*sizeof(int) */
215 /* for ecc results from device. */
216 struct yaffs_nand_spare nspare;
217
218 memset(&nspare, 0, sizeof(nspare));
219
220 ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data,
221 (struct yaffs_spare *)
222 &nspare);
223 memcpy(spare, &nspare, sizeof(struct yaffs_spare));
224 if (data && correct_errors) {
225 if (nspare.eccres1 > 0) {
226 yaffs_trace(YAFFS_TRACE_ERROR,
227 "**>>mtd ecc error fix performed on chunk %d:0",
228 nand_chunk);
229 } else if (nspare.eccres1 < 0) {
230 yaffs_trace(YAFFS_TRACE_ERROR,
231 "**>>mtd ecc error unfixed on chunk %d:0",
232 nand_chunk);
233 }
234
235 if (nspare.eccres2 > 0) {
236 yaffs_trace(YAFFS_TRACE_ERROR,
237 "**>>mtd ecc error fix performed on chunk %d:1",
238 nand_chunk);
239 } else if (nspare.eccres2 < 0) {
240 yaffs_trace(YAFFS_TRACE_ERROR,
241 "**>>mtd ecc error unfixed on chunk %d:1",
242 nand_chunk);
243 }
244
245 if (nspare.eccres1 || nspare.eccres2) {
246 /* We had a data problem on this page */
247 yaffs_handle_rd_data_error(dev, nand_chunk);
248 }
249
250 if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
251 *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
252 else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
253 *ecc_result = YAFFS_ECC_RESULT_FIXED;
254 else
255 *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
256
257 }
258 }
259 return ret_val;
260}
261
262/*
263 * Functions for robustisizing
264 */
265
266static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
267{
268 int flash_block = nand_chunk / dev->param.chunks_per_block;
269
270 /* Mark the block for retirement */
271 yaffs_get_block_info(dev,
272 flash_block + dev->block_offset)->needs_retiring =
273 1;
274 yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
275 "**>>Block %d marked for retirement",
276 flash_block);
277
278 /* TODO:
279 * Just do a garbage collection on the affected block
280 * then retire the block
281 * NB recursion
282 */
283}
284
285int yaffs_tags_compat_wr(struct yaffs_dev *dev,
286 int nand_chunk,
287 const u8 * data, const struct yaffs_ext_tags *ext_tags)
288{
289 struct yaffs_spare spare;
290 struct yaffs_tags tags;
291
292 yaffs_spare_init(&spare);
293
294 if (ext_tags->is_deleted)
295 spare.page_status = 0;
296 else {
297 tags.obj_id = ext_tags->obj_id;
298 tags.chunk_id = ext_tags->chunk_id;
299
300 tags.n_bytes_lsb = ext_tags->n_bytes & 0x3ff;
301
302 if (dev->data_bytes_per_chunk >= 1024)
303 tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
304 else
305 tags.n_bytes_msb = 3;
306
307 tags.serial_number = ext_tags->serial_number;
308
309 if (!dev->param.use_nand_ecc && data)
310 yaffs_calc_ecc(data, &spare);
311
312 yaffs_load_tags_to_spare(&spare, &tags);
313
314 }
315
316 return yaffs_wr_nand(dev, nand_chunk, data, &spare);
317}
318
319int yaffs_tags_compat_rd(struct yaffs_dev *dev,
320 int nand_chunk,
321 u8 * data, struct yaffs_ext_tags *ext_tags)
322{
323
324 struct yaffs_spare spare;
325 struct yaffs_tags tags;
326 enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
327
328 static struct yaffs_spare spare_ff;
329 static int init;
330
331 if (!init) {
332 memset(&spare_ff, 0xFF, sizeof(spare_ff));
333 init = 1;
334 }
335
336 if (yaffs_rd_chunk_nand(dev, nand_chunk, data, &spare, &ecc_result, 1)) {
337 /* ext_tags may be NULL */
338 if (ext_tags) {
339
340 int deleted =
341 (hweight8(spare.page_status) < 7) ? 1 : 0;
342
343 ext_tags->is_deleted = deleted;
344 ext_tags->ecc_result = ecc_result;
345 ext_tags->block_bad = 0; /* We're reading it */
346 /* therefore it is not a bad block */
347 ext_tags->chunk_used =
348 (memcmp(&spare_ff, &spare, sizeof(spare_ff)) !=
349 0) ? 1 : 0;
350
351 if (ext_tags->chunk_used) {
352 yaffs_get_tags_from_spare(dev, &spare, &tags);
353
354 ext_tags->obj_id = tags.obj_id;
355 ext_tags->chunk_id = tags.chunk_id;
356 ext_tags->n_bytes = tags.n_bytes_lsb;
357
358 if (dev->data_bytes_per_chunk >= 1024)
359 ext_tags->n_bytes |=
360 (((unsigned)tags.
361 n_bytes_msb) << 10);
362
363 ext_tags->serial_number = tags.serial_number;
364 }
365 }
366
367 return YAFFS_OK;
368 } else {
369 return YAFFS_FAIL;
370 }
371}
372
373int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
374{
375
376 struct yaffs_spare spare;
377
378 memset(&spare, 0xff, sizeof(struct yaffs_spare));
379
380 spare.block_status = 'Y';
381
382 yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
383 &spare);
384 yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
385 NULL, &spare);
386
387 return YAFFS_OK;
388
389}
390
391int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
392 int block_no,
393 enum yaffs_block_state *state,
394 u32 * seq_number)
395{
396
397 struct yaffs_spare spare0, spare1;
398 static struct yaffs_spare spare_ff;
399 static int init;
400 enum yaffs_ecc_result dummy;
401
402 if (!init) {
403 memset(&spare_ff, 0xFF, sizeof(spare_ff));
404 init = 1;
405 }
406
407 *seq_number = 0;
408
409 yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
410 &spare0, &dummy, 1);
411 yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
412 NULL, &spare1, &dummy, 1);
413
414 if (hweight8(spare0.block_status & spare1.block_status) < 7)
415 *state = YAFFS_BLOCK_STATE_DEAD;
416 else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
417 *state = YAFFS_BLOCK_STATE_EMPTY;
418 else
419 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
420
421 return YAFFS_OK;
422}
diff --git a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h
new file mode 100644
index 00000000000..8cd35dcd3ca
--- /dev/null
+++ b/fs/yaffs2/yaffs_tagscompat.h
@@ -0,0 +1,36 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_TAGSCOMPAT_H__
17#define __YAFFS_TAGSCOMPAT_H__
18
19#include "yaffs_guts.h"
20int yaffs_tags_compat_wr(struct yaffs_dev *dev,
21 int nand_chunk,
22 const u8 * data, const struct yaffs_ext_tags *tags);
23int yaffs_tags_compat_rd(struct yaffs_dev *dev,
24 int nand_chunk,
25 u8 * data, struct yaffs_ext_tags *tags);
26int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
27int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
28 int block_no,
29 enum yaffs_block_state *state,
30 u32 * seq_number);
31
32void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
33int yaffs_check_tags_ecc(struct yaffs_tags *tags);
34int yaffs_count_bits(u8 byte);
35
36#endif
diff --git a/fs/yaffs2/yaffs_tagsvalidity.c b/fs/yaffs2/yaffs_tagsvalidity.c
new file mode 100644
index 00000000000..4358d79d4be
--- /dev/null
+++ b/fs/yaffs2/yaffs_tagsvalidity.c
@@ -0,0 +1,27 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_tagsvalidity.h"
15
16void yaffs_init_tags(struct yaffs_ext_tags *tags)
17{
18 memset(tags, 0, sizeof(struct yaffs_ext_tags));
19 tags->validity0 = 0xAAAAAAAA;
20 tags->validity1 = 0x55555555;
21}
22
23int yaffs_validate_tags(struct yaffs_ext_tags *tags)
24{
25 return (tags->validity0 == 0xAAAAAAAA && tags->validity1 == 0x55555555);
26
27}
diff --git a/fs/yaffs2/yaffs_tagsvalidity.h b/fs/yaffs2/yaffs_tagsvalidity.h
new file mode 100644
index 00000000000..36a021fc8fa
--- /dev/null
+++ b/fs/yaffs2/yaffs_tagsvalidity.h
@@ -0,0 +1,23 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_TAGS_VALIDITY_H__
17#define __YAFFS_TAGS_VALIDITY_H__
18
19#include "yaffs_guts.h"
20
21void yaffs_init_tags(struct yaffs_ext_tags *tags);
22int yaffs_validate_tags(struct yaffs_ext_tags *tags);
23#endif
diff --git a/fs/yaffs2/yaffs_trace.h b/fs/yaffs2/yaffs_trace.h
new file mode 100644
index 00000000000..6273dbf9f63
--- /dev/null
+++ b/fs/yaffs2/yaffs_trace.h
@@ -0,0 +1,57 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YTRACE_H__
17#define __YTRACE_H__
18
19extern unsigned int yaffs_trace_mask;
20extern unsigned int yaffs_wr_attempts;
21
22/*
23 * Tracing flags.
24 * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
25 */
26
27#define YAFFS_TRACE_OS 0x00000002
28#define YAFFS_TRACE_ALLOCATE 0x00000004
29#define YAFFS_TRACE_SCAN 0x00000008
30#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
31#define YAFFS_TRACE_ERASE 0x00000020
32#define YAFFS_TRACE_GC 0x00000040
33#define YAFFS_TRACE_WRITE 0x00000080
34#define YAFFS_TRACE_TRACING 0x00000100
35#define YAFFS_TRACE_DELETION 0x00000200
36#define YAFFS_TRACE_BUFFERS 0x00000400
37#define YAFFS_TRACE_NANDACCESS 0x00000800
38#define YAFFS_TRACE_GC_DETAIL 0x00001000
39#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
40#define YAFFS_TRACE_MTD 0x00004000
41#define YAFFS_TRACE_CHECKPOINT 0x00008000
42
43#define YAFFS_TRACE_VERIFY 0x00010000
44#define YAFFS_TRACE_VERIFY_NAND 0x00020000
45#define YAFFS_TRACE_VERIFY_FULL 0x00040000
46#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
47
48#define YAFFS_TRACE_SYNC 0x00100000
49#define YAFFS_TRACE_BACKGROUND 0x00200000
50#define YAFFS_TRACE_LOCK 0x00400000
51#define YAFFS_TRACE_MOUNT 0x00800000
52
53#define YAFFS_TRACE_ERROR 0x40000000
54#define YAFFS_TRACE_BUG 0x80000000
55#define YAFFS_TRACE_ALWAYS 0xF0000000
56
57#endif
diff --git a/fs/yaffs2/yaffs_verify.c b/fs/yaffs2/yaffs_verify.c
new file mode 100644
index 00000000000..738c7f69a5e
--- /dev/null
+++ b/fs/yaffs2/yaffs_verify.c
@@ -0,0 +1,535 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_verify.h"
15#include "yaffs_trace.h"
16#include "yaffs_bitmap.h"
17#include "yaffs_getblockinfo.h"
18#include "yaffs_nand.h"
19
20int yaffs_skip_verification(struct yaffs_dev *dev)
21{
22 dev = dev;
23 return !(yaffs_trace_mask &
24 (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
25}
26
27static int yaffs_skip_full_verification(struct yaffs_dev *dev)
28{
29 dev = dev;
30 return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
31}
32
33static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
34{
35 dev = dev;
36 return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
37}
38
39static const char *block_state_name[] = {
40 "Unknown",
41 "Needs scanning",
42 "Scanning",
43 "Empty",
44 "Allocating",
45 "Full",
46 "Dirty",
47 "Checkpoint",
48 "Collecting",
49 "Dead"
50};
51
52void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
53{
54 int actually_used;
55 int in_use;
56
57 if (yaffs_skip_verification(dev))
58 return;
59
60 /* Report illegal runtime states */
61 if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
62 yaffs_trace(YAFFS_TRACE_VERIFY,
63 "Block %d has undefined state %d",
64 n, bi->block_state);
65
66 switch (bi->block_state) {
67 case YAFFS_BLOCK_STATE_UNKNOWN:
68 case YAFFS_BLOCK_STATE_SCANNING:
69 case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
70 yaffs_trace(YAFFS_TRACE_VERIFY,
71 "Block %d has bad run-state %s",
72 n, block_state_name[bi->block_state]);
73 }
74
75 /* Check pages in use and soft deletions are legal */
76
77 actually_used = bi->pages_in_use - bi->soft_del_pages;
78
79 if (bi->pages_in_use < 0
80 || bi->pages_in_use > dev->param.chunks_per_block
81 || bi->soft_del_pages < 0
82 || bi->soft_del_pages > dev->param.chunks_per_block
83 || actually_used < 0 || actually_used > dev->param.chunks_per_block)
84 yaffs_trace(YAFFS_TRACE_VERIFY,
85 "Block %d has illegal values pages_in_used %d soft_del_pages %d",
86 n, bi->pages_in_use, bi->soft_del_pages);
87
88 /* Check chunk bitmap legal */
89 in_use = yaffs_count_chunk_bits(dev, n);
90 if (in_use != bi->pages_in_use)
91 yaffs_trace(YAFFS_TRACE_VERIFY,
92 "Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
93 n, bi->pages_in_use, in_use);
94
95}
96
97void yaffs_verify_collected_blk(struct yaffs_dev *dev,
98 struct yaffs_block_info *bi, int n)
99{
100 yaffs_verify_blk(dev, bi, n);
101
102 /* After collection the block should be in the erased state */
103
104 if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
105 bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
106 yaffs_trace(YAFFS_TRACE_ERROR,
107 "Block %d is in state %d after gc, should be erased",
108 n, bi->block_state);
109 }
110}
111
112void yaffs_verify_blocks(struct yaffs_dev *dev)
113{
114 int i;
115 int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
116 int illegal_states = 0;
117
118 if (yaffs_skip_verification(dev))
119 return;
120
121 memset(state_count, 0, sizeof(state_count));
122
123 for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
124 struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
125 yaffs_verify_blk(dev, bi, i);
126
127 if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
128 state_count[bi->block_state]++;
129 else
130 illegal_states++;
131 }
132
133 yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
134
135 yaffs_trace(YAFFS_TRACE_VERIFY,
136 "%d blocks have illegal states",
137 illegal_states);
138 if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
139 yaffs_trace(YAFFS_TRACE_VERIFY,
140 "Too many allocating blocks");
141
142 for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
143 yaffs_trace(YAFFS_TRACE_VERIFY,
144 "%s %d blocks",
145 block_state_name[i], state_count[i]);
146
147 if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
148 yaffs_trace(YAFFS_TRACE_VERIFY,
149 "Checkpoint block count wrong dev %d count %d",
150 dev->blocks_in_checkpt,
151 state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
152
153 if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
154 yaffs_trace(YAFFS_TRACE_VERIFY,
155 "Erased block count wrong dev %d count %d",
156 dev->n_erased_blocks,
157 state_count[YAFFS_BLOCK_STATE_EMPTY]);
158
159 if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
160 yaffs_trace(YAFFS_TRACE_VERIFY,
161 "Too many collecting blocks %d (max is 1)",
162 state_count[YAFFS_BLOCK_STATE_COLLECTING]);
163}
164
165/*
166 * Verify the object header. oh must be valid, but obj and tags may be NULL in which
167 * case those tests will not be performed.
168 */
169void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
170 struct yaffs_ext_tags *tags, int parent_check)
171{
172 if (obj && yaffs_skip_verification(obj->my_dev))
173 return;
174
175 if (!(tags && obj && oh)) {
176 yaffs_trace(YAFFS_TRACE_VERIFY,
177 "Verifying object header tags %p obj %p oh %p",
178 tags, obj, oh);
179 return;
180 }
181
182 if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
183 oh->type > YAFFS_OBJECT_TYPE_MAX)
184 yaffs_trace(YAFFS_TRACE_VERIFY,
185 "Obj %d header type is illegal value 0x%x",
186 tags->obj_id, oh->type);
187
188 if (tags->obj_id != obj->obj_id)
189 yaffs_trace(YAFFS_TRACE_VERIFY,
190 "Obj %d header mismatch obj_id %d",
191 tags->obj_id, obj->obj_id);
192
193 /*
194 * Check that the object's parent ids match if parent_check requested.
195 *
196 * Tests do not apply to the root object.
197 */
198
199 if (parent_check && tags->obj_id > 1 && !obj->parent)
200 yaffs_trace(YAFFS_TRACE_VERIFY,
201 "Obj %d header mismatch parent_id %d obj->parent is NULL",
202 tags->obj_id, oh->parent_obj_id);
203
204 if (parent_check && obj->parent &&
205 oh->parent_obj_id != obj->parent->obj_id &&
206 (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
207 obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
208 yaffs_trace(YAFFS_TRACE_VERIFY,
209 "Obj %d header mismatch parent_id %d parent_obj_id %d",
210 tags->obj_id, oh->parent_obj_id,
211 obj->parent->obj_id);
212
213 if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
214 yaffs_trace(YAFFS_TRACE_VERIFY,
215 "Obj %d header name is NULL",
216 obj->obj_id);
217
218 if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Trashed name */
219 yaffs_trace(YAFFS_TRACE_VERIFY,
220 "Obj %d header name is 0xFF",
221 obj->obj_id);
222}
223
224void yaffs_verify_file(struct yaffs_obj *obj)
225{
226 int required_depth;
227 int actual_depth;
228 u32 last_chunk;
229 u32 x;
230 u32 i;
231 struct yaffs_dev *dev;
232 struct yaffs_ext_tags tags;
233 struct yaffs_tnode *tn;
234 u32 obj_id;
235
236 if (!obj)
237 return;
238
239 if (yaffs_skip_verification(obj->my_dev))
240 return;
241
242 dev = obj->my_dev;
243 obj_id = obj->obj_id;
244
245 /* Check file size is consistent with tnode depth */
246 last_chunk =
247 obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1;
248 x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
249 required_depth = 0;
250 while (x > 0) {
251 x >>= YAFFS_TNODES_INTERNAL_BITS;
252 required_depth++;
253 }
254
255 actual_depth = obj->variant.file_variant.top_level;
256
257 /* Check that the chunks in the tnode tree are all correct.
258 * We do this by scanning through the tnode tree and
259 * checking the tags for every chunk match.
260 */
261
262 if (yaffs_skip_nand_verification(dev))
263 return;
264
265 for (i = 1; i <= last_chunk; i++) {
266 tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
267
268 if (tn) {
269 u32 the_chunk = yaffs_get_group_base(dev, tn, i);
270 if (the_chunk > 0) {
271 yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
272 &tags);
273 if (tags.obj_id != obj_id || tags.chunk_id != i)
274 yaffs_trace(YAFFS_TRACE_VERIFY,
275 "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
276 obj_id, i, the_chunk,
277 tags.obj_id, tags.chunk_id);
278 }
279 }
280 }
281}
282
283void yaffs_verify_link(struct yaffs_obj *obj)
284{
285 if (obj && yaffs_skip_verification(obj->my_dev))
286 return;
287
288 /* Verify sane equivalent object */
289}
290
291void yaffs_verify_symlink(struct yaffs_obj *obj)
292{
293 if (obj && yaffs_skip_verification(obj->my_dev))
294 return;
295
296 /* Verify symlink string */
297}
298
299void yaffs_verify_special(struct yaffs_obj *obj)
300{
301 if (obj && yaffs_skip_verification(obj->my_dev))
302 return;
303}
304
305void yaffs_verify_obj(struct yaffs_obj *obj)
306{
307 struct yaffs_dev *dev;
308
309 u32 chunk_min;
310 u32 chunk_max;
311
312 u32 chunk_id_ok;
313 u32 chunk_in_range;
314 u32 chunk_wrongly_deleted;
315 u32 chunk_valid;
316
317 if (!obj)
318 return;
319
320 if (obj->being_created)
321 return;
322
323 dev = obj->my_dev;
324
325 if (yaffs_skip_verification(dev))
326 return;
327
328 /* Check sane object header chunk */
329
330 chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
331 chunk_max =
332 (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
333
334 chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
335 ((unsigned)(obj->hdr_chunk)) <= chunk_max);
336 chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
337 chunk_valid = chunk_in_range &&
338 yaffs_check_chunk_bit(dev,
339 obj->hdr_chunk / dev->param.chunks_per_block,
340 obj->hdr_chunk % dev->param.chunks_per_block);
341 chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
342
343 if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
344 yaffs_trace(YAFFS_TRACE_VERIFY,
345 "Obj %d has chunk_id %d %s %s",
346 obj->obj_id, obj->hdr_chunk,
347 chunk_id_ok ? "" : ",out of range",
348 chunk_wrongly_deleted ? ",marked as deleted" : "");
349
350 if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
351 struct yaffs_ext_tags tags;
352 struct yaffs_obj_hdr *oh;
353 u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
354
355 oh = (struct yaffs_obj_hdr *)buffer;
356
357 yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
358
359 yaffs_verify_oh(obj, oh, &tags, 1);
360
361 yaffs_release_temp_buffer(dev, buffer, __LINE__);
362 }
363
364 /* Verify it has a parent */
365 if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
366 yaffs_trace(YAFFS_TRACE_VERIFY,
367 "Obj %d has parent pointer %p which does not look like an object",
368 obj->obj_id, obj->parent);
369 }
370
371 /* Verify parent is a directory */
372 if (obj->parent
373 && obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
374 yaffs_trace(YAFFS_TRACE_VERIFY,
375 "Obj %d's parent is not a directory (type %d)",
376 obj->obj_id, obj->parent->variant_type);
377 }
378
379 switch (obj->variant_type) {
380 case YAFFS_OBJECT_TYPE_FILE:
381 yaffs_verify_file(obj);
382 break;
383 case YAFFS_OBJECT_TYPE_SYMLINK:
384 yaffs_verify_symlink(obj);
385 break;
386 case YAFFS_OBJECT_TYPE_DIRECTORY:
387 yaffs_verify_dir(obj);
388 break;
389 case YAFFS_OBJECT_TYPE_HARDLINK:
390 yaffs_verify_link(obj);
391 break;
392 case YAFFS_OBJECT_TYPE_SPECIAL:
393 yaffs_verify_special(obj);
394 break;
395 case YAFFS_OBJECT_TYPE_UNKNOWN:
396 default:
397 yaffs_trace(YAFFS_TRACE_VERIFY,
398 "Obj %d has illegaltype %d",
399 obj->obj_id, obj->variant_type);
400 break;
401 }
402}
403
404void yaffs_verify_objects(struct yaffs_dev *dev)
405{
406 struct yaffs_obj *obj;
407 int i;
408 struct list_head *lh;
409
410 if (yaffs_skip_verification(dev))
411 return;
412
413 /* Iterate through the objects in each hash entry */
414
415 for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
416 list_for_each(lh, &dev->obj_bucket[i].list) {
417 if (lh) {
418 obj =
419 list_entry(lh, struct yaffs_obj, hash_link);
420 yaffs_verify_obj(obj);
421 }
422 }
423 }
424}
425
426void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
427{
428 struct list_head *lh;
429 struct yaffs_obj *list_obj;
430
431 int count = 0;
432
433 if (!obj) {
434 yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
435 YBUG();
436 return;
437 }
438
439 if (yaffs_skip_verification(obj->my_dev))
440 return;
441
442 if (!obj->parent) {
443 yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent" );
444 YBUG();
445 return;
446 }
447
448 if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
449 yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
450 YBUG();
451 }
452
453 /* Iterate through the objects in each hash entry */
454
455 list_for_each(lh, &obj->parent->variant.dir_variant.children) {
456 if (lh) {
457 list_obj = list_entry(lh, struct yaffs_obj, siblings);
458 yaffs_verify_obj(list_obj);
459 if (obj == list_obj)
460 count++;
461 }
462 }
463
464 if (count != 1) {
465 yaffs_trace(YAFFS_TRACE_ALWAYS,
466 "Object in directory %d times",
467 count);
468 YBUG();
469 }
470}
471
472void yaffs_verify_dir(struct yaffs_obj *directory)
473{
474 struct list_head *lh;
475 struct yaffs_obj *list_obj;
476
477 if (!directory) {
478 YBUG();
479 return;
480 }
481
482 if (yaffs_skip_full_verification(directory->my_dev))
483 return;
484
485 if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
486 yaffs_trace(YAFFS_TRACE_ALWAYS,
487 "Directory has wrong type: %d",
488 directory->variant_type);
489 YBUG();
490 }
491
492 /* Iterate through the objects in each hash entry */
493
494 list_for_each(lh, &directory->variant.dir_variant.children) {
495 if (lh) {
496 list_obj = list_entry(lh, struct yaffs_obj, siblings);
497 if (list_obj->parent != directory) {
498 yaffs_trace(YAFFS_TRACE_ALWAYS,
499 "Object in directory list has wrong parent %p",
500 list_obj->parent);
501 YBUG();
502 }
503 yaffs_verify_obj_in_dir(list_obj);
504 }
505 }
506}
507
508static int yaffs_free_verification_failures;
509
510void yaffs_verify_free_chunks(struct yaffs_dev *dev)
511{
512 int counted;
513 int difference;
514
515 if (yaffs_skip_verification(dev))
516 return;
517
518 counted = yaffs_count_free_chunks(dev);
519
520 difference = dev->n_free_chunks - counted;
521
522 if (difference) {
523 yaffs_trace(YAFFS_TRACE_ALWAYS,
524 "Freechunks verification failure %d %d %d",
525 dev->n_free_chunks, counted, difference);
526 yaffs_free_verification_failures++;
527 }
528}
529
530int yaffs_verify_file_sane(struct yaffs_obj *in)
531{
532 in = in;
533 return YAFFS_OK;
534}
535
diff --git a/fs/yaffs2/yaffs_verify.h b/fs/yaffs2/yaffs_verify.h
new file mode 100644
index 00000000000..cc6f8899930
--- /dev/null
+++ b/fs/yaffs2/yaffs_verify.h
@@ -0,0 +1,43 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_VERIFY_H__
17#define __YAFFS_VERIFY_H__
18
19#include "yaffs_guts.h"
20
21void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
22 int n);
23void yaffs_verify_collected_blk(struct yaffs_dev *dev,
24 struct yaffs_block_info *bi, int n);
25void yaffs_verify_blocks(struct yaffs_dev *dev);
26
27void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
28 struct yaffs_ext_tags *tags, int parent_check);
29void yaffs_verify_file(struct yaffs_obj *obj);
30void yaffs_verify_link(struct yaffs_obj *obj);
31void yaffs_verify_symlink(struct yaffs_obj *obj);
32void yaffs_verify_special(struct yaffs_obj *obj);
33void yaffs_verify_obj(struct yaffs_obj *obj);
34void yaffs_verify_objects(struct yaffs_dev *dev);
35void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
36void yaffs_verify_dir(struct yaffs_obj *directory);
37void yaffs_verify_free_chunks(struct yaffs_dev *dev);
38
39int yaffs_verify_file_sane(struct yaffs_obj *obj);
40
41int yaffs_skip_verification(struct yaffs_dev *dev);
42
43#endif
diff --git a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c
new file mode 100644
index 00000000000..d95875fe1e5
--- /dev/null
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -0,0 +1,2790 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 * Acknowledgements:
9 * Luc van OostenRyck for numerous patches.
10 * Nick Bane for numerous patches.
11 * Nick Bane for 2.5/2.6 integration.
12 * Andras Toth for mknod rdev issue.
13 * Michael Fischer for finding the problem with inode inconsistency.
14 * Some code bodily lifted from JFFS
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
19 */
20
21/*
22 *
23 * This is the file system front-end to YAFFS that hooks it up to
24 * the VFS.
25 *
26 * Special notes:
27 * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with
28 * this superblock
29 * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this
30 * superblock
31 * >> inode->u.generic_ip points to the associated struct yaffs_obj.
32 */
33
34/*
35 * NB There are two variants of Linux VFS glue code. This variant supports
36 * a single version and should not include any multi-version code.
37 */
38#include <linux/version.h>
39
40#include <linux/kernel.h>
41#include <linux/module.h>
42#include <linux/slab.h>
43#include <linux/init.h>
44#include <linux/fs.h>
45#include <linux/proc_fs.h>
46#include <linux/pagemap.h>
47#include <linux/mtd/mtd.h>
48#include <linux/interrupt.h>
49#include <linux/string.h>
50#include <linux/ctype.h>
51#include <linux/namei.h>
52#include <linux/exportfs.h>
53#include <linux/kthread.h>
54#include <linux/delay.h>
55#include <linux/freezer.h>
56
57#include <asm/div64.h>
58
59#include <linux/statfs.h>
60
61#define UnlockPage(p) unlock_page(p)
62#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
63
64#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
65
66#define YPROC_ROOT NULL
67
68#define Y_INIT_TIMER(a) init_timer_on_stack(a)
69
70#define WRITE_SIZE_STR "writesize"
71#define WRITE_SIZE(mtd) ((mtd)->writesize)
72
73static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
74{
75 uint64_t result = partition_size;
76 do_div(result, block_size);
77 return (uint32_t) result;
78}
79
80#include <linux/uaccess.h>
81#include <linux/mtd/mtd.h>
82
83#include "yportenv.h"
84#include "yaffs_trace.h"
85#include "yaffs_guts.h"
86#include "yaffs_attribs.h"
87
88#include "yaffs_linux.h"
89
90#include "yaffs_mtdif.h"
91#include "yaffs_mtdif1.h"
92#include "yaffs_mtdif2.h"
93
94unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
95unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
96unsigned int yaffs_auto_checkpoint = 1;
97unsigned int yaffs_gc_control = 1;
98unsigned int yaffs_bg_enable = 1;
99
100/* Module Parameters */
101module_param(yaffs_trace_mask, uint, 0644);
102module_param(yaffs_wr_attempts, uint, 0644);
103module_param(yaffs_auto_checkpoint, uint, 0644);
104module_param(yaffs_gc_control, uint, 0644);
105module_param(yaffs_bg_enable, uint, 0644);
106
107
108#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
109#define yaffs_inode_to_obj(iptr) ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
110#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
111#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info)
112
113#define update_dir_time(dir) do {\
114 (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
115 } while(0)
116
117
118static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
119{
120 return yaffs_gc_control;
121}
122
123static void yaffs_gross_lock(struct yaffs_dev *dev)
124{
125 yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);
126 mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
127 yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);
128}
129
130static void yaffs_gross_unlock(struct yaffs_dev *dev)
131{
132 yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);
133 mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
134}
135
136static void yaffs_fill_inode_from_obj(struct inode *inode,
137 struct yaffs_obj *obj);
138
139static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
140{
141 struct inode *inode;
142 struct yaffs_obj *obj;
143 struct yaffs_dev *dev = yaffs_super_to_dev(sb);
144
145 yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino);
146
147 inode = iget_locked(sb, ino);
148 if (!inode)
149 return ERR_PTR(-ENOMEM);
150 if (!(inode->i_state & I_NEW))
151 return inode;
152
153 /* NB This is called as a side effect of other functions, but
154 * we had to release the lock to prevent deadlocks, so
155 * need to lock again.
156 */
157
158 yaffs_gross_lock(dev);
159
160 obj = yaffs_find_by_number(dev, inode->i_ino);
161
162 yaffs_fill_inode_from_obj(inode, obj);
163
164 yaffs_gross_unlock(dev);
165
166 unlock_new_inode(inode);
167 return inode;
168}
169
170struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
171 struct yaffs_obj *obj)
172{
173 struct inode *inode;
174
175 if (!sb) {
176 yaffs_trace(YAFFS_TRACE_OS,
177 "yaffs_get_inode for NULL super_block!!");
178 return NULL;
179
180 }
181
182 if (!obj) {
183 yaffs_trace(YAFFS_TRACE_OS,
184 "yaffs_get_inode for NULL object!!");
185 return NULL;
186
187 }
188
189 yaffs_trace(YAFFS_TRACE_OS,
190 "yaffs_get_inode for object %d",
191 obj->obj_id);
192
193 inode = yaffs_iget(sb, obj->obj_id);
194 if (IS_ERR(inode))
195 return NULL;
196
197 /* NB Side effect: iget calls back to yaffs_read_inode(). */
198 /* iget also increments the inode's i_count */
199 /* NB You can't be holding gross_lock or deadlock will happen! */
200
201 return inode;
202}
203
204static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
205 dev_t rdev)
206{
207 struct inode *inode;
208
209 struct yaffs_obj *obj = NULL;
210 struct yaffs_dev *dev;
211
212 struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
213
214 int error = -ENOSPC;
215 uid_t uid = current->cred->fsuid;
216 gid_t gid =
217 (dir->i_mode & S_ISGID) ? dir->i_gid : current->cred->fsgid;
218
219 if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
220 mode |= S_ISGID;
221
222 if (parent) {
223 yaffs_trace(YAFFS_TRACE_OS,
224 "yaffs_mknod: parent object %d type %d",
225 parent->obj_id, parent->variant_type);
226 } else {
227 yaffs_trace(YAFFS_TRACE_OS,
228 "yaffs_mknod: could not get parent object");
229 return -EPERM;
230 }
231
232 yaffs_trace(YAFFS_TRACE_OS,
233 "yaffs_mknod: making oject for %s, mode %x dev %x",
234 dentry->d_name.name, mode, rdev);
235
236 dev = parent->my_dev;
237
238 yaffs_gross_lock(dev);
239
240 switch (mode & S_IFMT) {
241 default:
242 /* Special (socket, fifo, device...) */
243 yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");
244 obj =
245 yaffs_create_special(parent, dentry->d_name.name, mode, uid,
246 gid, old_encode_dev(rdev));
247 break;
248 case S_IFREG: /* file */
249 yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");
250 obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
251 gid);
252 break;
253 case S_IFDIR: /* directory */
254 yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");
255 obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
256 uid, gid);
257 break;
258 case S_IFLNK: /* symlink */
259 yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");
260 obj = NULL; /* Do we ever get here? */
261 break;
262 }
263
264 /* Can not call yaffs_get_inode() with gross lock held */
265 yaffs_gross_unlock(dev);
266
267 if (obj) {
268 inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
269 d_instantiate(dentry, inode);
270 update_dir_time(dir);
271 yaffs_trace(YAFFS_TRACE_OS,
272 "yaffs_mknod created object %d count = %d",
273 obj->obj_id, atomic_read(&inode->i_count));
274 error = 0;
275 yaffs_fill_inode_from_obj(dir, parent);
276 } else {
277 yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
278 error = -ENOMEM;
279 }
280
281 return error;
282}
283
284static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
285{
286 return yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
287}
288
289static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
290 struct nameidata *n)
291{
292 return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
293}
294
295static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
296 struct dentry *dentry)
297{
298 struct inode *inode = old_dentry->d_inode;
299 struct yaffs_obj *obj = NULL;
300 struct yaffs_obj *link = NULL;
301 struct yaffs_dev *dev;
302
303 yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");
304
305 obj = yaffs_inode_to_obj(inode);
306 dev = obj->my_dev;
307
308 yaffs_gross_lock(dev);
309
310 if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
311 link =
312 yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
313 obj);
314
315 if (link) {
316 old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj);
317 d_instantiate(dentry, old_dentry->d_inode);
318 atomic_inc(&old_dentry->d_inode->i_count);
319 yaffs_trace(YAFFS_TRACE_OS,
320 "yaffs_link link count %d i_count %d",
321 old_dentry->d_inode->i_nlink,
322 atomic_read(&old_dentry->d_inode->i_count));
323 }
324
325 yaffs_gross_unlock(dev);
326
327 if (link) {
328 update_dir_time(dir);
329 return 0;
330 }
331
332 return -EPERM;
333}
334
335static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
336 const char *symname)
337{
338 struct yaffs_obj *obj;
339 struct yaffs_dev *dev;
340 uid_t uid = current->cred->fsuid;
341 gid_t gid =
342 (dir->i_mode & S_ISGID) ? dir->i_gid : current->cred->fsgid;
343
344 yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
345
346 dev = yaffs_inode_to_obj(dir)->my_dev;
347 yaffs_gross_lock(dev);
348 obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
349 S_IFLNK | S_IRWXUGO, uid, gid, symname);
350 yaffs_gross_unlock(dev);
351
352 if (obj) {
353 struct inode *inode;
354
355 inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
356 d_instantiate(dentry, inode);
357 update_dir_time(dir);
358 yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
359 return 0;
360 } else {
361 yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
362 }
363
364 return -ENOMEM;
365}
366
367static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
368 struct nameidata *n)
369{
370 struct yaffs_obj *obj;
371 struct inode *inode = NULL;
372
373 struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
374
375 if (current != yaffs_dev_to_lc(dev)->readdir_process)
376 yaffs_gross_lock(dev);
377
378 yaffs_trace(YAFFS_TRACE_OS,
379 "yaffs_lookup for %d:%s",
380 yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);
381
382 obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
383
384 obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
385
386 /* Can't hold gross lock when calling yaffs_get_inode() */
387 if (current != yaffs_dev_to_lc(dev)->readdir_process)
388 yaffs_gross_unlock(dev);
389
390 if (obj) {
391 yaffs_trace(YAFFS_TRACE_OS,
392 "yaffs_lookup found %d", obj->obj_id);
393
394 inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
395
396 if (inode) {
397 yaffs_trace(YAFFS_TRACE_OS, "yaffs_loookup dentry");
398 d_add(dentry, inode);
399 /* return dentry; */
400 return NULL;
401 }
402
403 } else {
404 yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");
405
406 }
407
408 d_add(dentry, inode);
409
410 return NULL;
411}
412
413static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
414{
415 int ret_val;
416
417 struct yaffs_dev *dev;
418 struct yaffs_obj *obj;
419
420 yaffs_trace(YAFFS_TRACE_OS,
421 "yaffs_unlink %d:%s",
422 (int)(dir->i_ino), dentry->d_name.name);
423 obj = yaffs_inode_to_obj(dir);
424 dev = obj->my_dev;
425
426 yaffs_gross_lock(dev);
427
428 ret_val = yaffs_unlinker(obj, dentry->d_name.name);
429
430 if (ret_val == YAFFS_OK) {
431 dentry->d_inode->i_nlink--;
432 dir->i_version++;
433 yaffs_gross_unlock(dev);
434 mark_inode_dirty(dentry->d_inode);
435 update_dir_time(dir);
436 return 0;
437 }
438 yaffs_gross_unlock(dev);
439 return -ENOTEMPTY;
440}
441
442static int yaffs_sync_object(struct file *file, int datasync)
443{
444
445 struct yaffs_obj *obj;
446 struct yaffs_dev *dev;
447 struct dentry *dentry = file->f_path.dentry;
448
449 obj = yaffs_dentry_to_obj(dentry);
450
451 dev = obj->my_dev;
452
453 yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, "yaffs_sync_object");
454 yaffs_gross_lock(dev);
455 yaffs_flush_file(obj, 1, datasync);
456 yaffs_gross_unlock(dev);
457 return 0;
458}
459/*
460 * The VFS layer already does all the dentry stuff for rename.
461 *
462 * NB: POSIX says you can rename an object over an old object of the same name
463 */
464static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
465 struct inode *new_dir, struct dentry *new_dentry)
466{
467 struct yaffs_dev *dev;
468 int ret_val = YAFFS_FAIL;
469 struct yaffs_obj *target;
470
471 yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");
472 dev = yaffs_inode_to_obj(old_dir)->my_dev;
473
474 yaffs_gross_lock(dev);
475
476 /* Check if the target is an existing directory that is not empty. */
477 target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
478 new_dentry->d_name.name);
479
480 if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
481 !list_empty(&target->variant.dir_variant.children)) {
482
483 yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");
484
485 ret_val = YAFFS_FAIL;
486 } else {
487 /* Now does unlinking internally using shadowing mechanism */
488 yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");
489
490 ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
491 old_dentry->d_name.name,
492 yaffs_inode_to_obj(new_dir),
493 new_dentry->d_name.name);
494 }
495 yaffs_gross_unlock(dev);
496
497 if (ret_val == YAFFS_OK) {
498 if (target) {
499 new_dentry->d_inode->i_nlink--;
500 mark_inode_dirty(new_dentry->d_inode);
501 }
502
503 update_dir_time(old_dir);
504 if (old_dir != new_dir)
505 update_dir_time(new_dir);
506 return 0;
507 } else {
508 return -ENOTEMPTY;
509 }
510}
511
512static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
513{
514 struct inode *inode = dentry->d_inode;
515 int error = 0;
516 struct yaffs_dev *dev;
517
518 yaffs_trace(YAFFS_TRACE_OS,
519 "yaffs_setattr of object %d",
520 yaffs_inode_to_obj(inode)->obj_id);
521
522 /* Fail if a requested resize >= 2GB */
523 if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
524 error = -EINVAL;
525
526 if (error == 0)
527 error = inode_change_ok(inode, attr);
528 if (error == 0) {
529 int result;
530 if (!error) {
531 setattr_copy(inode, attr);
532 yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
533 if (attr->ia_valid & ATTR_SIZE) {
534 truncate_setsize(inode, attr->ia_size);
535 inode->i_blocks = (inode->i_size + 511) >> 9;
536 }
537 }
538 dev = yaffs_inode_to_obj(inode)->my_dev;
539 if (attr->ia_valid & ATTR_SIZE) {
540 yaffs_trace(YAFFS_TRACE_OS, "resize to %d(%x)",
541 (int)(attr->ia_size),
542 (int)(attr->ia_size));
543 }
544 yaffs_gross_lock(dev);
545 result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
546 if (result == YAFFS_OK) {
547 error = 0;
548 } else {
549 error = -EPERM;
550 }
551 yaffs_gross_unlock(dev);
552
553 }
554
555 yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
556
557 return error;
558}
559
560#ifdef CONFIG_YAFFS_XATTR
561static int yaffs_setxattr(struct dentry *dentry, const char *name,
562 const void *value, size_t size, int flags)
563{
564 struct inode *inode = dentry->d_inode;
565 int error = 0;
566 struct yaffs_dev *dev;
567 struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
568
569 yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
570
571 if (error == 0) {
572 int result;
573 dev = obj->my_dev;
574 yaffs_gross_lock(dev);
575 result = yaffs_set_xattrib(obj, name, value, size, flags);
576 if (result == YAFFS_OK)
577 error = 0;
578 else if (result < 0)
579 error = result;
580 yaffs_gross_unlock(dev);
581
582 }
583 yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
584
585 return error;
586}
587
588static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, void *buff,
589 size_t size)
590{
591 struct inode *inode = dentry->d_inode;
592 int error = 0;
593 struct yaffs_dev *dev;
594 struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
595
596 yaffs_trace(YAFFS_TRACE_OS,
597 "yaffs_getxattr \"%s\" from object %d",
598 name, obj->obj_id);
599
600 if (error == 0) {
601 dev = obj->my_dev;
602 yaffs_gross_lock(dev);
603 error = yaffs_get_xattrib(obj, name, buff, size);
604 yaffs_gross_unlock(dev);
605
606 }
607 yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
608
609 return error;
610}
611
612static int yaffs_removexattr(struct dentry *dentry, const char *name)
613{
614 struct inode *inode = dentry->d_inode;
615 int error = 0;
616 struct yaffs_dev *dev;
617 struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
618
619 yaffs_trace(YAFFS_TRACE_OS,
620 "yaffs_removexattr of object %d", obj->obj_id);
621
622 if (error == 0) {
623 int result;
624 dev = obj->my_dev;
625 yaffs_gross_lock(dev);
626 result = yaffs_remove_xattrib(obj, name);
627 if (result == YAFFS_OK)
628 error = 0;
629 else if (result < 0)
630 error = result;
631 yaffs_gross_unlock(dev);
632
633 }
634 yaffs_trace(YAFFS_TRACE_OS,
635 "yaffs_removexattr done returning %d", error);
636
637 return error;
638}
639
640static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
641{
642 struct inode *inode = dentry->d_inode;
643 int error = 0;
644 struct yaffs_dev *dev;
645 struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
646
647 yaffs_trace(YAFFS_TRACE_OS,
648 "yaffs_listxattr of object %d", obj->obj_id);
649
650 if (error == 0) {
651 dev = obj->my_dev;
652 yaffs_gross_lock(dev);
653 error = yaffs_list_xattrib(obj, buff, size);
654 yaffs_gross_unlock(dev);
655
656 }
657 yaffs_trace(YAFFS_TRACE_OS,
658 "yaffs_listxattr done returning %d", error);
659
660 return error;
661}
662
663#endif
664
665static const struct inode_operations yaffs_dir_inode_operations = {
666 .create = yaffs_create,
667 .lookup = yaffs_lookup,
668 .link = yaffs_link,
669 .unlink = yaffs_unlink,
670 .symlink = yaffs_symlink,
671 .mkdir = yaffs_mkdir,
672 .rmdir = yaffs_unlink,
673 .mknod = yaffs_mknod,
674 .rename = yaffs_rename,
675 .setattr = yaffs_setattr,
676#ifdef CONFIG_YAFFS_XATTR
677 .setxattr = yaffs_setxattr,
678 .getxattr = yaffs_getxattr,
679 .listxattr = yaffs_listxattr,
680 .removexattr = yaffs_removexattr,
681#endif
682};
683/*-----------------------------------------------------------------*/
684/* Directory search context allows us to unlock access to yaffs during
685 * filldir without causing problems with the directory being modified.
686 * This is similar to the tried and tested mechanism used in yaffs direct.
687 *
688 * A search context iterates along a doubly linked list of siblings in the
689 * directory. If the iterating object is deleted then this would corrupt
690 * the list iteration, likely causing a crash. The search context avoids
691 * this by using the remove_obj_fn to move the search context to the
692 * next object before the object is deleted.
693 *
694 * Many readdirs (and thus seach conexts) may be alive simulateously so
695 * each struct yaffs_dev has a list of these.
696 *
697 * A seach context lives for the duration of a readdir.
698 *
699 * All these functions must be called while yaffs is locked.
700 */
701
702struct yaffs_search_context {
703 struct yaffs_dev *dev;
704 struct yaffs_obj *dir_obj;
705 struct yaffs_obj *next_return;
706 struct list_head others;
707};
708
709/*
710 * yaffs_new_search() creates a new search context, initialises it and
711 * adds it to the device's search context list.
712 *
713 * Called at start of readdir.
714 */
715static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
716{
717 struct yaffs_dev *dev = dir->my_dev;
718 struct yaffs_search_context *sc =
719 kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
720 if (sc) {
721 sc->dir_obj = dir;
722 sc->dev = dev;
723 if (list_empty(&sc->dir_obj->variant.dir_variant.children))
724 sc->next_return = NULL;
725 else
726 sc->next_return =
727 list_entry(dir->variant.dir_variant.children.next,
728 struct yaffs_obj, siblings);
729 INIT_LIST_HEAD(&sc->others);
730 list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
731 }
732 return sc;
733}
734
735/*
736 * yaffs_search_end() disposes of a search context and cleans up.
737 */
738static void yaffs_search_end(struct yaffs_search_context *sc)
739{
740 if (sc) {
741 list_del(&sc->others);
742 kfree(sc);
743 }
744}
745
746/*
747 * yaffs_search_advance() moves a search context to the next object.
748 * Called when the search iterates or when an object removal causes
749 * the search context to be moved to the next object.
750 */
751static void yaffs_search_advance(struct yaffs_search_context *sc)
752{
753 if (!sc)
754 return;
755
756 if (sc->next_return == NULL ||
757 list_empty(&sc->dir_obj->variant.dir_variant.children))
758 sc->next_return = NULL;
759 else {
760 struct list_head *next = sc->next_return->siblings.next;
761
762 if (next == &sc->dir_obj->variant.dir_variant.children)
763 sc->next_return = NULL; /* end of list */
764 else
765 sc->next_return =
766 list_entry(next, struct yaffs_obj, siblings);
767 }
768}
769
770/*
771 * yaffs_remove_obj_callback() is called when an object is unlinked.
772 * We check open search contexts and advance any which are currently
773 * on the object being iterated.
774 */
775static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
776{
777
778 struct list_head *i;
779 struct yaffs_search_context *sc;
780 struct list_head *search_contexts =
781 &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
782
783 /* Iterate through the directory search contexts.
784 * If any are currently on the object being removed, then advance
785 * the search context to the next object to prevent a hanging pointer.
786 */
787 list_for_each(i, search_contexts) {
788 if (i) {
789 sc = list_entry(i, struct yaffs_search_context, others);
790 if (sc->next_return == obj)
791 yaffs_search_advance(sc);
792 }
793 }
794
795}
796
797static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
798{
799 struct yaffs_obj *obj;
800 struct yaffs_dev *dev;
801 struct yaffs_search_context *sc;
802 struct inode *inode = f->f_dentry->d_inode;
803 unsigned long offset, curoffs;
804 struct yaffs_obj *l;
805 int ret_val = 0;
806
807 char name[YAFFS_MAX_NAME_LENGTH + 1];
808
809 obj = yaffs_dentry_to_obj(f->f_dentry);
810 dev = obj->my_dev;
811
812 yaffs_gross_lock(dev);
813
814 yaffs_dev_to_lc(dev)->readdir_process = current;
815
816 offset = f->f_pos;
817
818 sc = yaffs_new_search(obj);
819 if (!sc) {
820 ret_val = -ENOMEM;
821 goto out;
822 }
823
824 yaffs_trace(YAFFS_TRACE_OS,
825 "yaffs_readdir: starting at %d", (int)offset);
826
827 if (offset == 0) {
828 yaffs_trace(YAFFS_TRACE_OS,
829 "yaffs_readdir: entry . ino %d",
830 (int)inode->i_ino);
831 yaffs_gross_unlock(dev);
832 if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
833 yaffs_gross_lock(dev);
834 goto out;
835 }
836 yaffs_gross_lock(dev);
837 offset++;
838 f->f_pos++;
839 }
840 if (offset == 1) {
841 yaffs_trace(YAFFS_TRACE_OS,
842 "yaffs_readdir: entry .. ino %d",
843 (int)f->f_dentry->d_parent->d_inode->i_ino);
844 yaffs_gross_unlock(dev);
845 if (filldir(dirent, "..", 2, offset,
846 f->f_dentry->d_parent->d_inode->i_ino,
847 DT_DIR) < 0) {
848 yaffs_gross_lock(dev);
849 goto out;
850 }
851 yaffs_gross_lock(dev);
852 offset++;
853 f->f_pos++;
854 }
855
856 curoffs = 1;
857
858 /* If the directory has changed since the open or last call to
859 readdir, rewind to after the 2 canned entries. */
860 if (f->f_version != inode->i_version) {
861 offset = 2;
862 f->f_pos = offset;
863 f->f_version = inode->i_version;
864 }
865
866 while (sc->next_return) {
867 curoffs++;
868 l = sc->next_return;
869 if (curoffs >= offset) {
870 int this_inode = yaffs_get_obj_inode(l);
871 int this_type = yaffs_get_obj_type(l);
872
873 yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
874 yaffs_trace(YAFFS_TRACE_OS,
875 "yaffs_readdir: %s inode %d",
876 name, yaffs_get_obj_inode(l));
877
878 yaffs_gross_unlock(dev);
879
880 if (filldir(dirent,
881 name,
882 strlen(name),
883 offset, this_inode, this_type) < 0) {
884 yaffs_gross_lock(dev);
885 goto out;
886 }
887
888 yaffs_gross_lock(dev);
889
890 offset++;
891 f->f_pos++;
892 }
893 yaffs_search_advance(sc);
894 }
895
896out:
897 yaffs_search_end(sc);
898 yaffs_dev_to_lc(dev)->readdir_process = NULL;
899 yaffs_gross_unlock(dev);
900
901 return ret_val;
902}
903
904static const struct file_operations yaffs_dir_operations = {
905 .read = generic_read_dir,
906 .readdir = yaffs_readdir,
907 .fsync = yaffs_sync_object,
908 .llseek = generic_file_llseek,
909};
910
911
912
913static int yaffs_file_flush(struct file *file, fl_owner_t id)
914{
915 struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
916
917 struct yaffs_dev *dev = obj->my_dev;
918
919 yaffs_trace(YAFFS_TRACE_OS,
920 "yaffs_file_flush object %d (%s)",
921 obj->obj_id, obj->dirty ? "dirty" : "clean");
922
923 yaffs_gross_lock(dev);
924
925 yaffs_flush_file(obj, 1, 0);
926
927 yaffs_gross_unlock(dev);
928
929 return 0;
930}
931
932static const struct file_operations yaffs_file_operations = {
933 .read = do_sync_read,
934 .write = do_sync_write,
935 .aio_read = generic_file_aio_read,
936 .aio_write = generic_file_aio_write,
937 .mmap = generic_file_mmap,
938 .flush = yaffs_file_flush,
939 .fsync = yaffs_sync_object,
940 .splice_read = generic_file_splice_read,
941 .splice_write = generic_file_splice_write,
942 .llseek = generic_file_llseek,
943};
944
945
946/* ExportFS support */
947static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
948 uint32_t generation)
949{
950 return yaffs_iget(sb, ino);
951}
952
953static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
954 struct fid *fid, int fh_len,
955 int fh_type)
956{
957 return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
958 yaffs2_nfs_get_inode);
959}
960
961static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
962 struct fid *fid, int fh_len,
963 int fh_type)
964{
965 return generic_fh_to_parent(sb, fid, fh_len, fh_type,
966 yaffs2_nfs_get_inode);
967}
968
969struct dentry *yaffs2_get_parent(struct dentry *dentry)
970{
971
972 struct super_block *sb = dentry->d_inode->i_sb;
973 struct dentry *parent = ERR_PTR(-ENOENT);
974 struct inode *inode;
975 unsigned long parent_ino;
976 struct yaffs_obj *d_obj;
977 struct yaffs_obj *parent_obj;
978
979 d_obj = yaffs_inode_to_obj(dentry->d_inode);
980
981 if (d_obj) {
982 parent_obj = d_obj->parent;
983 if (parent_obj) {
984 parent_ino = yaffs_get_obj_inode(parent_obj);
985 inode = yaffs_iget(sb, parent_ino);
986
987 if (IS_ERR(inode)) {
988 parent = ERR_CAST(inode);
989 } else {
990 parent = d_obtain_alias(inode);
991 if (!IS_ERR(parent)) {
992 parent = ERR_PTR(-ENOMEM);
993 iput(inode);
994 }
995 }
996 }
997 }
998
999 return parent;
1000}
1001
1002/* Just declare a zero structure as a NULL value implies
1003 * using the default functions of exportfs.
1004 */
1005
1006static struct export_operations yaffs_export_ops = {
1007 .fh_to_dentry = yaffs2_fh_to_dentry,
1008 .fh_to_parent = yaffs2_fh_to_parent,
1009 .get_parent = yaffs2_get_parent,
1010};
1011
1012
1013/*-----------------------------------------------------------------*/
1014
1015static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
1016 int buflen)
1017{
1018 unsigned char *alias;
1019 int ret;
1020
1021 struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
1022
1023 yaffs_gross_lock(dev);
1024
1025 alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
1026
1027 yaffs_gross_unlock(dev);
1028
1029 if (!alias)
1030 return -ENOMEM;
1031
1032 ret = vfs_readlink(dentry, buffer, buflen, alias);
1033 kfree(alias);
1034 return ret;
1035}
1036
1037static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1038{
1039 unsigned char *alias;
1040 void *ret;
1041 struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
1042
1043 yaffs_gross_lock(dev);
1044
1045 alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
1046 yaffs_gross_unlock(dev);
1047
1048 if (!alias) {
1049 ret = ERR_PTR(-ENOMEM);
1050 goto out;
1051 }
1052
1053 nd_set_link(nd, alias);
1054 ret = (void *)alias;
1055out:
1056 return ret;
1057}
1058
1059void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
1060{
1061 kfree(alias);
1062}
1063
1064
1065static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
1066{
1067 /* Clear the association between the inode and
1068 * the struct yaffs_obj.
1069 */
1070 obj->my_inode = NULL;
1071 yaffs_inode_to_obj_lv(inode) = NULL;
1072
1073 /* If the object freeing was deferred, then the real
1074 * free happens now.
1075 * This should fix the inode inconsistency problem.
1076 */
1077 yaffs_handle_defered_free(obj);
1078}
1079
1080/* yaffs_evict_inode combines into one operation what was previously done in
1081 * yaffs_clear_inode() and yaffs_delete_inode()
1082 *
1083 */
1084static void yaffs_evict_inode(struct inode *inode)
1085{
1086 struct yaffs_obj *obj;
1087 struct yaffs_dev *dev;
1088 int deleteme = 0;
1089
1090 obj = yaffs_inode_to_obj(inode);
1091
1092 yaffs_trace(YAFFS_TRACE_OS,
1093 "yaffs_evict_inode: ino %d, count %d %s",
1094 (int)inode->i_ino,
1095 atomic_read(&inode->i_count),
1096 obj ? "object exists" : "null object");
1097
1098 if (!inode->i_nlink && !is_bad_inode(inode))
1099 deleteme = 1;
1100 truncate_inode_pages(&inode->i_data, 0);
1101 end_writeback(inode);
1102
1103 if (deleteme && obj) {
1104 dev = obj->my_dev;
1105 yaffs_gross_lock(dev);
1106 yaffs_del_obj(obj);
1107 yaffs_gross_unlock(dev);
1108 }
1109 if (obj) {
1110 dev = obj->my_dev;
1111 yaffs_gross_lock(dev);
1112 yaffs_unstitch_obj(inode, obj);
1113 yaffs_gross_unlock(dev);
1114 }
1115
1116}
1117
1118static void yaffs_touch_super(struct yaffs_dev *dev)
1119{
1120 struct super_block *sb = yaffs_dev_to_lc(dev)->super;
1121
1122 yaffs_trace(YAFFS_TRACE_OS, "yaffs_touch_super() sb = %p", sb);
1123 if (sb)
1124 sb->s_dirt = 1;
1125}
1126
1127static int yaffs_readpage_nolock(struct file *f, struct page *pg)
1128{
1129 /* Lifted from jffs2 */
1130
1131 struct yaffs_obj *obj;
1132 unsigned char *pg_buf;
1133 int ret;
1134
1135 struct yaffs_dev *dev;
1136
1137 yaffs_trace(YAFFS_TRACE_OS,
1138 "yaffs_readpage_nolock at %08x, size %08x",
1139 (unsigned)(pg->index << PAGE_CACHE_SHIFT),
1140 (unsigned)PAGE_CACHE_SIZE);
1141
1142 obj = yaffs_dentry_to_obj(f->f_dentry);
1143
1144 dev = obj->my_dev;
1145
1146 BUG_ON(!PageLocked(pg));
1147
1148 pg_buf = kmap(pg);
1149 /* FIXME: Can kmap fail? */
1150
1151 yaffs_gross_lock(dev);
1152
1153 ret = yaffs_file_rd(obj, pg_buf,
1154 pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE);
1155
1156 yaffs_gross_unlock(dev);
1157
1158 if (ret >= 0)
1159 ret = 0;
1160
1161 if (ret) {
1162 ClearPageUptodate(pg);
1163 SetPageError(pg);
1164 } else {
1165 SetPageUptodate(pg);
1166 ClearPageError(pg);
1167 }
1168
1169 flush_dcache_page(pg);
1170 kunmap(pg);
1171
1172 yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");
1173 return ret;
1174}
1175
1176static int yaffs_readpage_unlock(struct file *f, struct page *pg)
1177{
1178 int ret = yaffs_readpage_nolock(f, pg);
1179 UnlockPage(pg);
1180 return ret;
1181}
1182
1183static int yaffs_readpage(struct file *f, struct page *pg)
1184{
1185 int ret;
1186
1187 yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");
1188 ret = yaffs_readpage_unlock(f, pg);
1189 yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");
1190 return ret;
1191}
1192
1193/* writepage inspired by/stolen from smbfs */
1194
1195static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
1196{
1197 struct yaffs_dev *dev;
1198 struct address_space *mapping = page->mapping;
1199 struct inode *inode;
1200 unsigned long end_index;
1201 char *buffer;
1202 struct yaffs_obj *obj;
1203 int n_written = 0;
1204 unsigned n_bytes;
1205 loff_t i_size;
1206
1207 if (!mapping)
1208 BUG();
1209 inode = mapping->host;
1210 if (!inode)
1211 BUG();
1212 i_size = i_size_read(inode);
1213
1214 end_index = i_size >> PAGE_CACHE_SHIFT;
1215
1216 if (page->index < end_index)
1217 n_bytes = PAGE_CACHE_SIZE;
1218 else {
1219 n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
1220
1221 if (page->index > end_index || !n_bytes) {
1222 yaffs_trace(YAFFS_TRACE_OS,
1223 "yaffs_writepage at %08x, inode size = %08x!!!",
1224 (unsigned)(page->index << PAGE_CACHE_SHIFT),
1225 (unsigned)inode->i_size);
1226 yaffs_trace(YAFFS_TRACE_OS,
1227 " -> don't care!!");
1228
1229 zero_user_segment(page, 0, PAGE_CACHE_SIZE);
1230 set_page_writeback(page);
1231 unlock_page(page);
1232 end_page_writeback(page);
1233 return 0;
1234 }
1235 }
1236
1237 if (n_bytes != PAGE_CACHE_SIZE)
1238 zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
1239
1240 get_page(page);
1241
1242 buffer = kmap(page);
1243
1244 obj = yaffs_inode_to_obj(inode);
1245 dev = obj->my_dev;
1246 yaffs_gross_lock(dev);
1247
1248 yaffs_trace(YAFFS_TRACE_OS,
1249 "yaffs_writepage at %08x, size %08x",
1250 (unsigned)(page->index << PAGE_CACHE_SHIFT), n_bytes);
1251 yaffs_trace(YAFFS_TRACE_OS,
1252 "writepag0: obj = %05x, ino = %05x",
1253 (int)obj->variant.file_variant.file_size, (int)inode->i_size);
1254
1255 n_written = yaffs_wr_file(obj, buffer,
1256 page->index << PAGE_CACHE_SHIFT, n_bytes, 0);
1257
1258 yaffs_touch_super(dev);
1259
1260 yaffs_trace(YAFFS_TRACE_OS,
1261 "writepag1: obj = %05x, ino = %05x",
1262 (int)obj->variant.file_variant.file_size, (int)inode->i_size);
1263
1264 yaffs_gross_unlock(dev);
1265
1266 kunmap(page);
1267 set_page_writeback(page);
1268 unlock_page(page);
1269 end_page_writeback(page);
1270 put_page(page);
1271
1272 return (n_written == n_bytes) ? 0 : -ENOSPC;
1273}
1274
1275/* Space holding and freeing is done to ensure we have space available for
1276 * write_begin/end.
1277 * For now we just assume few parallel writes and check against a small
1278 * number.
1279 * Todo: need to do this with a counter to handle parallel reads better.
1280 */
1281
1282static ssize_t yaffs_hold_space(struct file *f)
1283{
1284 struct yaffs_obj *obj;
1285 struct yaffs_dev *dev;
1286
1287 int n_free_chunks;
1288
1289 obj = yaffs_dentry_to_obj(f->f_dentry);
1290
1291 dev = obj->my_dev;
1292
1293 yaffs_gross_lock(dev);
1294
1295 n_free_chunks = yaffs_get_n_free_chunks(dev);
1296
1297 yaffs_gross_unlock(dev);
1298
1299 return (n_free_chunks > 20) ? 1 : 0;
1300}
1301
1302static void yaffs_release_space(struct file *f)
1303{
1304 struct yaffs_obj *obj;
1305 struct yaffs_dev *dev;
1306
1307 obj = yaffs_dentry_to_obj(f->f_dentry);
1308
1309 dev = obj->my_dev;
1310
1311 yaffs_gross_lock(dev);
1312
1313 yaffs_gross_unlock(dev);
1314}
1315
1316static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
1317 loff_t pos, unsigned len, unsigned flags,
1318 struct page **pagep, void **fsdata)
1319{
1320 struct page *pg = NULL;
1321 pgoff_t index = pos >> PAGE_CACHE_SHIFT;
1322
1323 int ret = 0;
1324 int space_held = 0;
1325
1326 /* Get a page */
1327 pg = grab_cache_page_write_begin(mapping, index, flags);
1328
1329 *pagep = pg;
1330 if (!pg) {
1331 ret = -ENOMEM;
1332 goto out;
1333 }
1334 yaffs_trace(YAFFS_TRACE_OS,
1335 "start yaffs_write_begin index %d(%x) uptodate %d",
1336 (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);
1337
1338 /* Get fs space */
1339 space_held = yaffs_hold_space(filp);
1340
1341 if (!space_held) {
1342 ret = -ENOSPC;
1343 goto out;
1344 }
1345
1346 /* Update page if required */
1347
1348 if (!Page_Uptodate(pg))
1349 ret = yaffs_readpage_nolock(filp, pg);
1350
1351 if (ret)
1352 goto out;
1353
1354 /* Happy path return */
1355 yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");
1356
1357 return 0;
1358
1359out:
1360 yaffs_trace(YAFFS_TRACE_OS,
1361 "end yaffs_write_begin fail returning %d", ret);
1362 if (space_held)
1363 yaffs_release_space(filp);
1364 if (pg) {
1365 unlock_page(pg);
1366 page_cache_release(pg);
1367 }
1368 return ret;
1369}
1370
1371static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1372 loff_t * pos)
1373{
1374 struct yaffs_obj *obj;
1375 int n_written, ipos;
1376 struct inode *inode;
1377 struct yaffs_dev *dev;
1378
1379 obj = yaffs_dentry_to_obj(f->f_dentry);
1380
1381 dev = obj->my_dev;
1382
1383 yaffs_gross_lock(dev);
1384
1385 inode = f->f_dentry->d_inode;
1386
1387 if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
1388 ipos = inode->i_size;
1389 else
1390 ipos = *pos;
1391
1392 if (!obj)
1393 yaffs_trace(YAFFS_TRACE_OS,
1394 "yaffs_file_write: hey obj is null!");
1395 else
1396 yaffs_trace(YAFFS_TRACE_OS,
1397 "yaffs_file_write about to write writing %u(%x) bytes to object %d at %d(%x)",
1398 (unsigned)n, (unsigned)n, obj->obj_id, ipos, ipos);
1399
1400 n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
1401
1402 yaffs_touch_super(dev);
1403
1404 yaffs_trace(YAFFS_TRACE_OS,
1405 "yaffs_file_write: %d(%x) bytes written",
1406 (unsigned)n, (unsigned)n);
1407
1408 if (n_written > 0) {
1409 ipos += n_written;
1410 *pos = ipos;
1411 if (ipos > inode->i_size) {
1412 inode->i_size = ipos;
1413 inode->i_blocks = (ipos + 511) >> 9;
1414
1415 yaffs_trace(YAFFS_TRACE_OS,
1416 "yaffs_file_write size updated to %d bytes, %d blocks",
1417 ipos, (int)(inode->i_blocks));
1418 }
1419
1420 }
1421 yaffs_gross_unlock(dev);
1422 return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
1423}
1424
1425static int yaffs_write_end(struct file *filp, struct address_space *mapping,
1426 loff_t pos, unsigned len, unsigned copied,
1427 struct page *pg, void *fsdadata)
1428{
1429 int ret = 0;
1430 void *addr, *kva;
1431 uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
1432
1433 kva = kmap(pg);
1434 addr = kva + offset_into_page;
1435
1436 yaffs_trace(YAFFS_TRACE_OS,
1437 "yaffs_write_end addr %p pos %x n_bytes %d",
1438 addr, (unsigned)pos, copied);
1439
1440 ret = yaffs_file_write(filp, addr, copied, &pos);
1441
1442 if (ret != copied) {
1443 yaffs_trace(YAFFS_TRACE_OS,
1444 "yaffs_write_end not same size ret %d copied %d",
1445 ret, copied);
1446 SetPageError(pg);
1447 }
1448
1449 kunmap(pg);
1450
1451 yaffs_release_space(filp);
1452 unlock_page(pg);
1453 page_cache_release(pg);
1454 return ret;
1455}
1456
1457static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
1458{
1459 struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
1460 struct super_block *sb = dentry->d_sb;
1461
1462 yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");
1463
1464 yaffs_gross_lock(dev);
1465
1466 buf->f_type = YAFFS_MAGIC;
1467 buf->f_bsize = sb->s_blocksize;
1468 buf->f_namelen = 255;
1469
1470 if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
1471 /* Do this if chunk size is not a power of 2 */
1472
1473 uint64_t bytes_in_dev;
1474 uint64_t bytes_free;
1475
1476 bytes_in_dev =
1477 ((uint64_t)
1478 ((dev->param.end_block - dev->param.start_block +
1479 1))) * ((uint64_t) (dev->param.chunks_per_block *
1480 dev->data_bytes_per_chunk));
1481
1482 do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */
1483 buf->f_blocks = bytes_in_dev;
1484
1485 bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
1486 ((uint64_t) (dev->data_bytes_per_chunk));
1487
1488 do_div(bytes_free, sb->s_blocksize);
1489
1490 buf->f_bfree = bytes_free;
1491
1492 } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
1493
1494 buf->f_blocks =
1495 (dev->param.end_block - dev->param.start_block + 1) *
1496 dev->param.chunks_per_block /
1497 (sb->s_blocksize / dev->data_bytes_per_chunk);
1498 buf->f_bfree =
1499 yaffs_get_n_free_chunks(dev) /
1500 (sb->s_blocksize / dev->data_bytes_per_chunk);
1501 } else {
1502 buf->f_blocks =
1503 (dev->param.end_block - dev->param.start_block + 1) *
1504 dev->param.chunks_per_block *
1505 (dev->data_bytes_per_chunk / sb->s_blocksize);
1506
1507 buf->f_bfree =
1508 yaffs_get_n_free_chunks(dev) *
1509 (dev->data_bytes_per_chunk / sb->s_blocksize);
1510 }
1511
1512 buf->f_files = 0;
1513 buf->f_ffree = 0;
1514 buf->f_bavail = buf->f_bfree;
1515
1516 yaffs_gross_unlock(dev);
1517 return 0;
1518}
1519
1520static void yaffs_flush_inodes(struct super_block *sb)
1521{
1522 struct inode *iptr;
1523 struct yaffs_obj *obj;
1524
1525 list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
1526 obj = yaffs_inode_to_obj(iptr);
1527 if (obj) {
1528 yaffs_trace(YAFFS_TRACE_OS,
1529 "flushing obj %d", obj->obj_id);
1530 yaffs_flush_file(obj, 1, 0);
1531 }
1532 }
1533}
1534
1535static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
1536{
1537 struct yaffs_dev *dev = yaffs_super_to_dev(sb);
1538 if (!dev)
1539 return;
1540
1541 yaffs_flush_inodes(sb);
1542 yaffs_update_dirty_dirs(dev);
1543 yaffs_flush_whole_cache(dev);
1544 if (do_checkpoint)
1545 yaffs_checkpoint_save(dev);
1546}
1547
1548static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
1549{
1550 unsigned erased_chunks =
1551 dev->n_erased_blocks * dev->param.chunks_per_block;
1552 struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
1553 unsigned scattered = 0; /* Free chunks not in an erased block */
1554
1555 if (erased_chunks < dev->n_free_chunks)
1556 scattered = (dev->n_free_chunks - erased_chunks);
1557
1558 if (!context->bg_running)
1559 return 0;
1560 else if (scattered < (dev->param.chunks_per_block * 2))
1561 return 0;
1562 else if (erased_chunks > dev->n_free_chunks / 2)
1563 return 0;
1564 else if (erased_chunks > dev->n_free_chunks / 4)
1565 return 1;
1566 else
1567 return 2;
1568}
1569
1570static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
1571{
1572
1573 struct yaffs_dev *dev = yaffs_super_to_dev(sb);
1574 unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
1575 unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
1576 int do_checkpoint;
1577
1578 yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
1579 "yaffs_do_sync_fs: gc-urgency %d %s %s%s",
1580 gc_urgent,
1581 sb->s_dirt ? "dirty" : "clean",
1582 request_checkpoint ? "checkpoint requested" : "no checkpoint",
1583 oneshot_checkpoint ? " one-shot" : "");
1584
1585 yaffs_gross_lock(dev);
1586 do_checkpoint = ((request_checkpoint && !gc_urgent) ||
1587 oneshot_checkpoint) && !dev->is_checkpointed;
1588
1589 if (sb->s_dirt || do_checkpoint) {
1590 yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
1591 sb->s_dirt = 0;
1592 if (oneshot_checkpoint)
1593 yaffs_auto_checkpoint &= ~4;
1594 }
1595 yaffs_gross_unlock(dev);
1596
1597 return 0;
1598}
1599
1600/*
1601 * yaffs background thread functions .
1602 * yaffs_bg_thread_fn() the thread function
1603 * yaffs_bg_start() launches the background thread.
1604 * yaffs_bg_stop() cleans up the background thread.
1605 *
1606 * NB:
1607 * The thread should only run after the yaffs is initialised
1608 * The thread should be stopped before yaffs is unmounted.
1609 * The thread should not do any writing while the fs is in read only.
1610 */
1611
1612void yaffs_background_waker(unsigned long data)
1613{
1614 wake_up_process((struct task_struct *)data);
1615}
1616
1617static int yaffs_bg_thread_fn(void *data)
1618{
1619 struct yaffs_dev *dev = (struct yaffs_dev *)data;
1620 struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
1621 unsigned long now = jiffies;
1622 unsigned long next_dir_update = now;
1623 unsigned long next_gc = now;
1624 unsigned long expires;
1625 unsigned int urgency;
1626
1627 int gc_result;
1628 struct timer_list timer;
1629
1630 yaffs_trace(YAFFS_TRACE_BACKGROUND,
1631 "yaffs_background starting for dev %p", (void *)dev);
1632
1633 set_freezable();
1634 while (context->bg_running) {
1635 yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");
1636
1637 if (kthread_should_stop())
1638 break;
1639
1640 if (try_to_freeze())
1641 continue;
1642
1643 yaffs_gross_lock(dev);
1644
1645 now = jiffies;
1646
1647 if (time_after(now, next_dir_update) && yaffs_bg_enable) {
1648 yaffs_update_dirty_dirs(dev);
1649 next_dir_update = now + HZ;
1650 }
1651
1652 if (time_after(now, next_gc) && yaffs_bg_enable) {
1653 if (!dev->is_checkpointed) {
1654 urgency = yaffs_bg_gc_urgency(dev);
1655 gc_result = yaffs_bg_gc(dev, urgency);
1656 if (urgency > 1)
1657 next_gc = now + HZ / 20 + 1;
1658 else if (urgency > 0)
1659 next_gc = now + HZ / 10 + 1;
1660 else
1661 next_gc = now + HZ * 2;
1662 } else {
1663 /*
1664 * gc not running so set to next_dir_update
1665 * to cut down on wake ups
1666 */
1667 next_gc = next_dir_update;
1668 }
1669 }
1670 yaffs_gross_unlock(dev);
1671 expires = next_dir_update;
1672 if (time_before(next_gc, expires))
1673 expires = next_gc;
1674 if (time_before(expires, now))
1675 expires = now + HZ;
1676
1677 Y_INIT_TIMER(&timer);
1678 timer.expires = expires + 1;
1679 timer.data = (unsigned long)current;
1680 timer.function = yaffs_background_waker;
1681
1682 set_current_state(TASK_INTERRUPTIBLE);
1683 add_timer(&timer);
1684 schedule();
1685 del_timer_sync(&timer);
1686 }
1687
1688 return 0;
1689}
1690
1691static int yaffs_bg_start(struct yaffs_dev *dev)
1692{
1693 int retval = 0;
1694 struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
1695
1696 if (dev->read_only)
1697 return -1;
1698
1699 context->bg_running = 1;
1700
1701 context->bg_thread = kthread_run(yaffs_bg_thread_fn,
1702 (void *)dev, "yaffs-bg-%d",
1703 context->mount_id);
1704
1705 if (IS_ERR(context->bg_thread)) {
1706 retval = PTR_ERR(context->bg_thread);
1707 context->bg_thread = NULL;
1708 context->bg_running = 0;
1709 }
1710 return retval;
1711}
1712
1713static void yaffs_bg_stop(struct yaffs_dev *dev)
1714{
1715 struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
1716
1717 ctxt->bg_running = 0;
1718
1719 if (ctxt->bg_thread) {
1720 kthread_stop(ctxt->bg_thread);
1721 ctxt->bg_thread = NULL;
1722 }
1723}
1724
1725static void yaffs_write_super(struct super_block *sb)
1726{
1727 unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
1728
1729 yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
1730 "yaffs_write_super%s",
1731 request_checkpoint ? " checkpt" : "");
1732
1733 yaffs_do_sync_fs(sb, request_checkpoint);
1734
1735}
1736
1737static int yaffs_sync_fs(struct super_block *sb, int wait)
1738{
1739 unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
1740
1741 yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
1742 "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");
1743
1744 yaffs_do_sync_fs(sb, request_checkpoint);
1745
1746 return 0;
1747}
1748
1749
1750static LIST_HEAD(yaffs_context_list);
1751struct mutex yaffs_context_lock;
1752
1753
1754
1755struct yaffs_options {
1756 int inband_tags;
1757 int skip_checkpoint_read;
1758 int skip_checkpoint_write;
1759 int no_cache;
1760 int tags_ecc_on;
1761 int tags_ecc_overridden;
1762 int lazy_loading_enabled;
1763 int lazy_loading_overridden;
1764 int empty_lost_and_found;
1765 int empty_lost_and_found_overridden;
1766};
1767
1768#define MAX_OPT_LEN 30
1769static int yaffs_parse_options(struct yaffs_options *options,
1770 const char *options_str)
1771{
1772 char cur_opt[MAX_OPT_LEN + 1];
1773 int p;
1774 int error = 0;
1775
1776 /* Parse through the options which is a comma seperated list */
1777
1778 while (options_str && *options_str && !error) {
1779 memset(cur_opt, 0, MAX_OPT_LEN + 1);
1780 p = 0;
1781
1782 while (*options_str == ',')
1783 options_str++;
1784
1785 while (*options_str && *options_str != ',') {
1786 if (p < MAX_OPT_LEN) {
1787 cur_opt[p] = *options_str;
1788 p++;
1789 }
1790 options_str++;
1791 }
1792
1793 if (!strcmp(cur_opt, "inband-tags")) {
1794 options->inband_tags = 1;
1795 } else if (!strcmp(cur_opt, "tags-ecc-off")) {
1796 options->tags_ecc_on = 0;
1797 options->tags_ecc_overridden = 1;
1798 } else if (!strcmp(cur_opt, "tags-ecc-on")) {
1799 options->tags_ecc_on = 1;
1800 options->tags_ecc_overridden = 1;
1801 } else if (!strcmp(cur_opt, "lazy-loading-off")) {
1802 options->lazy_loading_enabled = 0;
1803 options->lazy_loading_overridden = 1;
1804 } else if (!strcmp(cur_opt, "lazy-loading-on")) {
1805 options->lazy_loading_enabled = 1;
1806 options->lazy_loading_overridden = 1;
1807 } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
1808 options->empty_lost_and_found = 0;
1809 options->empty_lost_and_found_overridden = 1;
1810 } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
1811 options->empty_lost_and_found = 1;
1812 options->empty_lost_and_found_overridden = 1;
1813 } else if (!strcmp(cur_opt, "no-cache")) {
1814 options->no_cache = 1;
1815 } else if (!strcmp(cur_opt, "no-checkpoint-read")) {
1816 options->skip_checkpoint_read = 1;
1817 } else if (!strcmp(cur_opt, "no-checkpoint-write")) {
1818 options->skip_checkpoint_write = 1;
1819 } else if (!strcmp(cur_opt, "no-checkpoint")) {
1820 options->skip_checkpoint_read = 1;
1821 options->skip_checkpoint_write = 1;
1822 } else {
1823 printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
1824 cur_opt);
1825 error = 1;
1826 }
1827 }
1828
1829 return error;
1830}
1831
1832static struct address_space_operations yaffs_file_address_operations = {
1833 .readpage = yaffs_readpage,
1834 .writepage = yaffs_writepage,
1835 .write_begin = yaffs_write_begin,
1836 .write_end = yaffs_write_end,
1837};
1838
1839
1840
1841static const struct inode_operations yaffs_file_inode_operations = {
1842 .setattr = yaffs_setattr,
1843#ifdef CONFIG_YAFFS_XATTR
1844 .setxattr = yaffs_setxattr,
1845 .getxattr = yaffs_getxattr,
1846 .listxattr = yaffs_listxattr,
1847 .removexattr = yaffs_removexattr,
1848#endif
1849};
1850
1851static const struct inode_operations yaffs_symlink_inode_operations = {
1852 .readlink = yaffs_readlink,
1853 .follow_link = yaffs_follow_link,
1854 .put_link = yaffs_put_link,
1855 .setattr = yaffs_setattr,
1856#ifdef CONFIG_YAFFS_XATTR
1857 .setxattr = yaffs_setxattr,
1858 .getxattr = yaffs_getxattr,
1859 .listxattr = yaffs_listxattr,
1860 .removexattr = yaffs_removexattr,
1861#endif
1862};
1863
1864static void yaffs_fill_inode_from_obj(struct inode *inode,
1865 struct yaffs_obj *obj)
1866{
1867 if (inode && obj) {
1868
1869 /* Check mode against the variant type and attempt to repair if broken. */
1870 u32 mode = obj->yst_mode;
1871 switch (obj->variant_type) {
1872 case YAFFS_OBJECT_TYPE_FILE:
1873 if (!S_ISREG(mode)) {
1874 obj->yst_mode &= ~S_IFMT;
1875 obj->yst_mode |= S_IFREG;
1876 }
1877
1878 break;
1879 case YAFFS_OBJECT_TYPE_SYMLINK:
1880 if (!S_ISLNK(mode)) {
1881 obj->yst_mode &= ~S_IFMT;
1882 obj->yst_mode |= S_IFLNK;
1883 }
1884
1885 break;
1886 case YAFFS_OBJECT_TYPE_DIRECTORY:
1887 if (!S_ISDIR(mode)) {
1888 obj->yst_mode &= ~S_IFMT;
1889 obj->yst_mode |= S_IFDIR;
1890 }
1891
1892 break;
1893 case YAFFS_OBJECT_TYPE_UNKNOWN:
1894 case YAFFS_OBJECT_TYPE_HARDLINK:
1895 case YAFFS_OBJECT_TYPE_SPECIAL:
1896 default:
1897 /* TODO? */
1898 break;
1899 }
1900
1901 inode->i_flags |= S_NOATIME;
1902
1903 inode->i_ino = obj->obj_id;
1904 inode->i_mode = obj->yst_mode;
1905 inode->i_uid = obj->yst_uid;
1906 inode->i_gid = obj->yst_gid;
1907
1908 inode->i_rdev = old_decode_dev(obj->yst_rdev);
1909
1910 inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
1911 inode->i_atime.tv_nsec = 0;
1912 inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
1913 inode->i_mtime.tv_nsec = 0;
1914 inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
1915 inode->i_ctime.tv_nsec = 0;
1916 inode->i_size = yaffs_get_obj_length(obj);
1917 inode->i_blocks = (inode->i_size + 511) >> 9;
1918
1919 inode->i_nlink = yaffs_get_obj_link_count(obj);
1920
1921 yaffs_trace(YAFFS_TRACE_OS,
1922 "yaffs_fill_inode mode %x uid %d gid %d size %d count %d",
1923 inode->i_mode, inode->i_uid, inode->i_gid,
1924 (int)inode->i_size, atomic_read(&inode->i_count));
1925
1926 switch (obj->yst_mode & S_IFMT) {
1927 default: /* fifo, device or socket */
1928 init_special_inode(inode, obj->yst_mode,
1929 old_decode_dev(obj->yst_rdev));
1930 break;
1931 case S_IFREG: /* file */
1932 inode->i_op = &yaffs_file_inode_operations;
1933 inode->i_fop = &yaffs_file_operations;
1934 inode->i_mapping->a_ops =
1935 &yaffs_file_address_operations;
1936 break;
1937 case S_IFDIR: /* directory */
1938 inode->i_op = &yaffs_dir_inode_operations;
1939 inode->i_fop = &yaffs_dir_operations;
1940 break;
1941 case S_IFLNK: /* symlink */
1942 inode->i_op = &yaffs_symlink_inode_operations;
1943 break;
1944 }
1945
1946 yaffs_inode_to_obj_lv(inode) = obj;
1947
1948 obj->my_inode = inode;
1949
1950 } else {
1951 yaffs_trace(YAFFS_TRACE_OS,
1952 "yaffs_fill_inode invalid parameters");
1953 }
1954}
1955
1956static void yaffs_put_super(struct super_block *sb)
1957{
1958 struct yaffs_dev *dev = yaffs_super_to_dev(sb);
1959
1960 yaffs_trace(YAFFS_TRACE_OS, "yaffs_put_super");
1961
1962 yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
1963 "Shutting down yaffs background thread");
1964 yaffs_bg_stop(dev);
1965 yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
1966 "yaffs background thread shut down");
1967
1968 yaffs_gross_lock(dev);
1969
1970 yaffs_flush_super(sb, 1);
1971
1972 if (yaffs_dev_to_lc(dev)->put_super_fn)
1973 yaffs_dev_to_lc(dev)->put_super_fn(sb);
1974
1975 yaffs_deinitialise(dev);
1976
1977 yaffs_gross_unlock(dev);
1978 mutex_lock(&yaffs_context_lock);
1979 list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
1980 mutex_unlock(&yaffs_context_lock);
1981
1982 if (yaffs_dev_to_lc(dev)->spare_buffer) {
1983 kfree(yaffs_dev_to_lc(dev)->spare_buffer);
1984 yaffs_dev_to_lc(dev)->spare_buffer = NULL;
1985 }
1986
1987 kfree(dev);
1988}
1989
1990static void yaffs_mtd_put_super(struct super_block *sb)
1991{
1992 struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_super_to_dev(sb));
1993
1994 if (mtd->sync)
1995 mtd->sync(mtd);
1996
1997 put_mtd_device(mtd);
1998}
1999
2000static const struct super_operations yaffs_super_ops = {
2001 .statfs = yaffs_statfs,
2002 .put_super = yaffs_put_super,
2003 .evict_inode = yaffs_evict_inode,
2004 .sync_fs = yaffs_sync_fs,
2005 .write_super = yaffs_write_super,
2006};
2007
2008static struct super_block *yaffs_internal_read_super(int yaffs_version,
2009 struct super_block *sb,
2010 void *data, int silent)
2011{
2012 int n_blocks;
2013 struct inode *inode = NULL;
2014 struct dentry *root;
2015 struct yaffs_dev *dev = 0;
2016 char devname_buf[BDEVNAME_SIZE + 1];
2017 struct mtd_info *mtd;
2018 int err;
2019 char *data_str = (char *)data;
2020 struct yaffs_linux_context *context = NULL;
2021 struct yaffs_param *param;
2022
2023 int read_only = 0;
2024
2025 struct yaffs_options options;
2026
2027 unsigned mount_id;
2028 int found;
2029 struct yaffs_linux_context *context_iterator;
2030 struct list_head *l;
2031
2032 sb->s_magic = YAFFS_MAGIC;
2033 sb->s_op = &yaffs_super_ops;
2034 sb->s_flags |= MS_NOATIME;
2035
2036 read_only = ((sb->s_flags & MS_RDONLY) != 0);
2037
2038 sb->s_export_op = &yaffs_export_ops;
2039
2040 if (!sb)
2041 printk(KERN_INFO "yaffs: sb is NULL\n");
2042 else if (!sb->s_dev)
2043 printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
2044 else if (!yaffs_devname(sb, devname_buf))
2045 printk(KERN_INFO "yaffs: devname is NULL\n");
2046 else
2047 printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
2048 sb->s_dev,
2049 yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
2050
2051 if (!data_str)
2052 data_str = "";
2053
2054 printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
2055
2056 memset(&options, 0, sizeof(options));
2057
2058 if (yaffs_parse_options(&options, data_str)) {
2059 /* Option parsing failed */
2060 return NULL;
2061 }
2062
2063 sb->s_blocksize = PAGE_CACHE_SIZE;
2064 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
2065
2066 yaffs_trace(YAFFS_TRACE_OS,
2067 "yaffs_read_super: Using yaffs%d", yaffs_version);
2068 yaffs_trace(YAFFS_TRACE_OS,
2069 "yaffs_read_super: block size %d", (int)(sb->s_blocksize));
2070
2071 yaffs_trace(YAFFS_TRACE_ALWAYS,
2072 "Attempting MTD mount of %u.%u,\"%s\"",
2073 MAJOR(sb->s_dev), MINOR(sb->s_dev),
2074 yaffs_devname(sb, devname_buf));
2075
2076 /* Check it's an mtd device..... */
2077 if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
2078 return NULL; /* This isn't an mtd device */
2079
2080 /* Get the device */
2081 mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
2082 if (!mtd) {
2083 yaffs_trace(YAFFS_TRACE_ALWAYS,
2084 "MTD device #%u doesn't appear to exist",
2085 MINOR(sb->s_dev));
2086 return NULL;
2087 }
2088 /* Check it's NAND */
2089 if (mtd->type != MTD_NANDFLASH) {
2090 yaffs_trace(YAFFS_TRACE_ALWAYS,
2091 "MTD device is not NAND it's type %d",
2092 mtd->type);
2093 return NULL;
2094 }
2095
2096 yaffs_trace(YAFFS_TRACE_OS, " erase %p", mtd->erase);
2097 yaffs_trace(YAFFS_TRACE_OS, " read %p", mtd->read);
2098 yaffs_trace(YAFFS_TRACE_OS, " write %p", mtd->write);
2099 yaffs_trace(YAFFS_TRACE_OS, " readoob %p", mtd->read_oob);
2100 yaffs_trace(YAFFS_TRACE_OS, " writeoob %p", mtd->write_oob);
2101 yaffs_trace(YAFFS_TRACE_OS, " block_isbad %p", mtd->block_isbad);
2102 yaffs_trace(YAFFS_TRACE_OS, " block_markbad %p", mtd->block_markbad);
2103 yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
2104 yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
2105 yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
2106 yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
2107
2108#ifdef CONFIG_YAFFS_AUTO_YAFFS2
2109
2110 if (yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
2111 yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
2112 yaffs_version = 2;
2113 }
2114
2115 /* Added NCB 26/5/2006 for completeness */
2116 if (yaffs_version == 2 && !options.inband_tags
2117 && WRITE_SIZE(mtd) == 512) {
2118 yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
2119 yaffs_version = 1;
2120 }
2121#endif
2122
2123 if (yaffs_version == 2) {
2124 /* Check for version 2 style functions */
2125 if (!mtd->erase ||
2126 !mtd->block_isbad ||
2127 !mtd->block_markbad ||
2128 !mtd->read ||
2129 !mtd->write || !mtd->read_oob || !mtd->write_oob) {
2130 yaffs_trace(YAFFS_TRACE_ALWAYS,
2131 "MTD device does not support required functions");
2132 return NULL;
2133 }
2134
2135 if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
2136 mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
2137 !options.inband_tags) {
2138 yaffs_trace(YAFFS_TRACE_ALWAYS,
2139 "MTD device does not have the right page sizes");
2140 return NULL;
2141 }
2142 } else {
2143 /* Check for V1 style functions */
2144 if (!mtd->erase ||
2145 !mtd->read ||
2146 !mtd->write || !mtd->read_oob || !mtd->write_oob) {
2147 yaffs_trace(YAFFS_TRACE_ALWAYS,
2148 "MTD device does not support required functions");
2149 return NULL;
2150 }
2151
2152 if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
2153 mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
2154 yaffs_trace(YAFFS_TRACE_ALWAYS,
2155 "MTD device does not support have the right page sizes");
2156 return NULL;
2157 }
2158 }
2159
2160 /* OK, so if we got here, we have an MTD that's NAND and looks
2161 * like it has the right capabilities
2162 * Set the struct yaffs_dev up for mtd
2163 */
2164
2165 if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
2166 read_only = 1;
2167 printk(KERN_INFO
2168 "yaffs: mtd is read only, setting superblock read only");
2169 sb->s_flags |= MS_RDONLY;
2170 }
2171
2172 dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
2173 context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
2174
2175 if (!dev || !context) {
2176 if (dev)
2177 kfree(dev);
2178 if (context)
2179 kfree(context);
2180 dev = NULL;
2181 context = NULL;
2182 }
2183
2184 if (!dev) {
2185 /* Deep shit could not allocate device structure */
2186 yaffs_trace(YAFFS_TRACE_ALWAYS,
2187 "yaffs_read_super failed trying to allocate yaffs_dev");
2188 return NULL;
2189 }
2190 memset(dev, 0, sizeof(struct yaffs_dev));
2191 param = &(dev->param);
2192
2193 memset(context, 0, sizeof(struct yaffs_linux_context));
2194 dev->os_context = context;
2195 INIT_LIST_HEAD(&(context->context_list));
2196 context->dev = dev;
2197 context->super = sb;
2198
2199 dev->read_only = read_only;
2200
2201 sb->s_fs_info = dev;
2202
2203 dev->driver_context = mtd;
2204 param->name = mtd->name;
2205
2206 /* Set up the memory size parameters.... */
2207
2208 n_blocks =
2209 YCALCBLOCKS(mtd->size,
2210 (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
2211
2212 param->start_block = 0;
2213 param->end_block = n_blocks - 1;
2214 param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
2215 param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
2216 param->n_reserved_blocks = 5;
2217 param->n_caches = (options.no_cache) ? 0 : 10;
2218 param->inband_tags = options.inband_tags;
2219
2220#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
2221 param->disable_lazy_load = 1;
2222#endif
2223#ifdef CONFIG_YAFFS_XATTR
2224 param->enable_xattr = 1;
2225#endif
2226 if (options.lazy_loading_overridden)
2227 param->disable_lazy_load = !options.lazy_loading_enabled;
2228
2229#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
2230 param->no_tags_ecc = 1;
2231#endif
2232
2233#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
2234#else
2235 param->defered_dir_update = 1;
2236#endif
2237
2238 if (options.tags_ecc_overridden)
2239 param->no_tags_ecc = !options.tags_ecc_on;
2240
2241#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
2242 param->empty_lost_n_found = 1;
2243#endif
2244
2245#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
2246 param->refresh_period = 0;
2247#else
2248 param->refresh_period = 500;
2249#endif
2250
2251#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
2252 param->always_check_erased = 1;
2253#endif
2254
2255 if (options.empty_lost_and_found_overridden)
2256 param->empty_lost_n_found = options.empty_lost_and_found;
2257
2258 /* ... and the functions. */
2259 if (yaffs_version == 2) {
2260 param->write_chunk_tags_fn = nandmtd2_write_chunk_tags;
2261 param->read_chunk_tags_fn = nandmtd2_read_chunk_tags;
2262 param->bad_block_fn = nandmtd2_mark_block_bad;
2263 param->query_block_fn = nandmtd2_query_block;
2264 yaffs_dev_to_lc(dev)->spare_buffer =
2265 kmalloc(mtd->oobsize, GFP_NOFS);
2266 param->is_yaffs2 = 1;
2267 param->total_bytes_per_chunk = mtd->writesize;
2268 param->chunks_per_block = mtd->erasesize / mtd->writesize;
2269 n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
2270
2271 param->start_block = 0;
2272 param->end_block = n_blocks - 1;
2273 } else {
2274 /* use the MTD interface in yaffs_mtdif1.c */
2275 param->write_chunk_tags_fn = nandmtd1_write_chunk_tags;
2276 param->read_chunk_tags_fn = nandmtd1_read_chunk_tags;
2277 param->bad_block_fn = nandmtd1_mark_block_bad;
2278 param->query_block_fn = nandmtd1_query_block;
2279 param->is_yaffs2 = 0;
2280 }
2281 /* ... and common functions */
2282 param->erase_fn = nandmtd_erase_block;
2283 param->initialise_flash_fn = nandmtd_initialise;
2284
2285 yaffs_dev_to_lc(dev)->put_super_fn = yaffs_mtd_put_super;
2286
2287 param->sb_dirty_fn = yaffs_touch_super;
2288 param->gc_control = yaffs_gc_control_callback;
2289
2290 yaffs_dev_to_lc(dev)->super = sb;
2291
2292#ifndef CONFIG_YAFFS_DOES_ECC
2293 param->use_nand_ecc = 1;
2294#endif
2295
2296 param->skip_checkpt_rd = options.skip_checkpoint_read;
2297 param->skip_checkpt_wr = options.skip_checkpoint_write;
2298
2299 mutex_lock(&yaffs_context_lock);
2300 /* Get a mount id */
2301 found = 0;
2302 for (mount_id = 0; !found; mount_id++) {
2303 found = 1;
2304 list_for_each(l, &yaffs_context_list) {
2305 context_iterator =
2306 list_entry(l, struct yaffs_linux_context,
2307 context_list);
2308 if (context_iterator->mount_id == mount_id)
2309 found = 0;
2310 }
2311 }
2312 context->mount_id = mount_id;
2313
2314 list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
2315 &yaffs_context_list);
2316 mutex_unlock(&yaffs_context_lock);
2317
2318 /* Directory search handling... */
2319 INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
2320 param->remove_obj_fn = yaffs_remove_obj_callback;
2321
2322 mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
2323
2324 yaffs_gross_lock(dev);
2325
2326 err = yaffs_guts_initialise(dev);
2327
2328 yaffs_trace(YAFFS_TRACE_OS,
2329 "yaffs_read_super: guts initialised %s",
2330 (err == YAFFS_OK) ? "OK" : "FAILED");
2331
2332 if (err == YAFFS_OK)
2333 yaffs_bg_start(dev);
2334
2335 if (!context->bg_thread)
2336 param->defered_dir_update = 0;
2337
2338 /* Release lock before yaffs_get_inode() */
2339 yaffs_gross_unlock(dev);
2340
2341 /* Create root inode */
2342 if (err == YAFFS_OK)
2343 inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev));
2344
2345 if (!inode)
2346 return NULL;
2347
2348 inode->i_op = &yaffs_dir_inode_operations;
2349 inode->i_fop = &yaffs_dir_operations;
2350
2351 yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");
2352
2353 root = d_alloc_root(inode);
2354
2355 yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: d_alloc_root done");
2356
2357 if (!root) {
2358 iput(inode);
2359 return NULL;
2360 }
2361 sb->s_root = root;
2362 sb->s_dirt = !dev->is_checkpointed;
2363 yaffs_trace(YAFFS_TRACE_ALWAYS,
2364 "yaffs_read_super: is_checkpointed %d",
2365 dev->is_checkpointed);
2366
2367 yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");
2368 return sb;
2369}
2370
2371static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
2372 int silent)
2373{
2374 return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
2375}
2376
2377static struct dentry *yaffs_read_super(struct file_system_type *fs,
2378 int flags, const char *dev_name,
2379 void *data)
2380{
2381
2382 return mount_bdev(fs, flags, dev_name, data,
2383 yaffs_internal_read_super_mtd);
2384}
2385
2386static struct file_system_type yaffs_fs_type = {
2387 .owner = THIS_MODULE,
2388 .name = "yaffs",
2389 .mount = yaffs_read_super,
2390 .kill_sb = kill_block_super,
2391 .fs_flags = FS_REQUIRES_DEV,
2392};
2393
2394#ifdef CONFIG_YAFFS_YAFFS2
2395
2396static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
2397 int silent)
2398{
2399 return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
2400}
2401
2402static struct dentry *yaffs2_read_super(struct file_system_type *fs,
2403 int flags, const char *dev_name, void *data)
2404{
2405 return mount_bdev(fs, flags, dev_name, data,
2406 yaffs2_internal_read_super_mtd);
2407}
2408
2409static struct file_system_type yaffs2_fs_type = {
2410 .owner = THIS_MODULE,
2411 .name = "yaffs2",
2412 .mount = yaffs2_read_super,
2413 .kill_sb = kill_block_super,
2414 .fs_flags = FS_REQUIRES_DEV,
2415};
2416#endif /* CONFIG_YAFFS_YAFFS2 */
2417
2418static struct proc_dir_entry *my_proc_entry;
2419
2420static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
2421{
2422 struct yaffs_param *param = &dev->param;
2423 buf += sprintf(buf, "start_block........... %d\n", param->start_block);
2424 buf += sprintf(buf, "end_block............. %d\n", param->end_block);
2425 buf += sprintf(buf, "total_bytes_per_chunk. %d\n",
2426 param->total_bytes_per_chunk);
2427 buf += sprintf(buf, "use_nand_ecc.......... %d\n",
2428 param->use_nand_ecc);
2429 buf += sprintf(buf, "no_tags_ecc........... %d\n", param->no_tags_ecc);
2430 buf += sprintf(buf, "is_yaffs2............. %d\n", param->is_yaffs2);
2431 buf += sprintf(buf, "inband_tags........... %d\n", param->inband_tags);
2432 buf += sprintf(buf, "empty_lost_n_found.... %d\n",
2433 param->empty_lost_n_found);
2434 buf += sprintf(buf, "disable_lazy_load..... %d\n",
2435 param->disable_lazy_load);
2436 buf += sprintf(buf, "refresh_period........ %d\n",
2437 param->refresh_period);
2438 buf += sprintf(buf, "n_caches.............. %d\n", param->n_caches);
2439 buf += sprintf(buf, "n_reserved_blocks..... %d\n",
2440 param->n_reserved_blocks);
2441 buf += sprintf(buf, "always_check_erased... %d\n",
2442 param->always_check_erased);
2443
2444 return buf;
2445}
2446
2447static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
2448{
2449 buf +=
2450 sprintf(buf, "data_bytes_per_chunk.. %d\n",
2451 dev->data_bytes_per_chunk);
2452 buf += sprintf(buf, "chunk_grp_bits........ %d\n", dev->chunk_grp_bits);
2453 buf += sprintf(buf, "chunk_grp_size........ %d\n", dev->chunk_grp_size);
2454 buf +=
2455 sprintf(buf, "n_erased_blocks....... %d\n", dev->n_erased_blocks);
2456 buf +=
2457 sprintf(buf, "blocks_in_checkpt..... %d\n", dev->blocks_in_checkpt);
2458 buf += sprintf(buf, "\n");
2459 buf += sprintf(buf, "n_tnodes.............. %d\n", dev->n_tnodes);
2460 buf += sprintf(buf, "n_obj................. %d\n", dev->n_obj);
2461 buf += sprintf(buf, "n_free_chunks......... %d\n", dev->n_free_chunks);
2462 buf += sprintf(buf, "\n");
2463 buf += sprintf(buf, "n_page_writes......... %u\n", dev->n_page_writes);
2464 buf += sprintf(buf, "n_page_reads.......... %u\n", dev->n_page_reads);
2465 buf += sprintf(buf, "n_erasures............ %u\n", dev->n_erasures);
2466 buf += sprintf(buf, "n_gc_copies........... %u\n", dev->n_gc_copies);
2467 buf += sprintf(buf, "all_gcs............... %u\n", dev->all_gcs);
2468 buf +=
2469 sprintf(buf, "passive_gc_count...... %u\n", dev->passive_gc_count);
2470 buf +=
2471 sprintf(buf, "oldest_dirty_gc_count. %u\n",
2472 dev->oldest_dirty_gc_count);
2473 buf += sprintf(buf, "n_gc_blocks........... %u\n", dev->n_gc_blocks);
2474 buf += sprintf(buf, "bg_gcs................ %u\n", dev->bg_gcs);
2475 buf +=
2476 sprintf(buf, "n_retired_writes...... %u\n", dev->n_retired_writes);
2477 buf +=
2478 sprintf(buf, "n_retired_blocks...... %u\n", dev->n_retired_blocks);
2479 buf += sprintf(buf, "n_ecc_fixed........... %u\n", dev->n_ecc_fixed);
2480 buf += sprintf(buf, "n_ecc_unfixed......... %u\n", dev->n_ecc_unfixed);
2481 buf +=
2482 sprintf(buf, "n_tags_ecc_fixed...... %u\n", dev->n_tags_ecc_fixed);
2483 buf +=
2484 sprintf(buf, "n_tags_ecc_unfixed.... %u\n",
2485 dev->n_tags_ecc_unfixed);
2486 buf += sprintf(buf, "cache_hits............ %u\n", dev->cache_hits);
2487 buf +=
2488 sprintf(buf, "n_deleted_files....... %u\n", dev->n_deleted_files);
2489 buf +=
2490 sprintf(buf, "n_unlinked_files...... %u\n", dev->n_unlinked_files);
2491 buf += sprintf(buf, "refresh_count......... %u\n", dev->refresh_count);
2492 buf += sprintf(buf, "n_bg_deletions........ %u\n", dev->n_bg_deletions);
2493
2494 return buf;
2495}
2496
2497static int yaffs_proc_read(char *page,
2498 char **start,
2499 off_t offset, int count, int *eof, void *data)
2500{
2501 struct list_head *item;
2502 char *buf = page;
2503 int step = offset;
2504 int n = 0;
2505
2506 /* Get proc_file_read() to step 'offset' by one on each sucessive call.
2507 * We use 'offset' (*ppos) to indicate where we are in dev_list.
2508 * This also assumes the user has posted a read buffer large
2509 * enough to hold the complete output; but that's life in /proc.
2510 */
2511
2512 *(int *)start = 1;
2513
2514 /* Print header first */
2515 if (step == 0)
2516 buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__ "\n");
2517 else if (step == 1)
2518 buf += sprintf(buf, "\n");
2519 else {
2520 step -= 2;
2521
2522 mutex_lock(&yaffs_context_lock);
2523
2524 /* Locate and print the Nth entry. Order N-squared but N is small. */
2525 list_for_each(item, &yaffs_context_list) {
2526 struct yaffs_linux_context *dc =
2527 list_entry(item, struct yaffs_linux_context,
2528 context_list);
2529 struct yaffs_dev *dev = dc->dev;
2530
2531 if (n < (step & ~1)) {
2532 n += 2;
2533 continue;
2534 }
2535 if ((step & 1) == 0) {
2536 buf +=
2537 sprintf(buf, "\nDevice %d \"%s\"\n", n,
2538 dev->param.name);
2539 buf = yaffs_dump_dev_part0(buf, dev);
2540 } else {
2541 buf = yaffs_dump_dev_part1(buf, dev);
2542 }
2543
2544 break;
2545 }
2546 mutex_unlock(&yaffs_context_lock);
2547 }
2548
2549 return buf - page < count ? buf - page : count;
2550}
2551
2552
2553/**
2554 * Set the verbosity of the warnings and error messages.
2555 *
2556 * Note that the names can only be a..z or _ with the current code.
2557 */
2558
2559static struct {
2560 char *mask_name;
2561 unsigned mask_bitfield;
2562} mask_flags[] = {
2563 {"allocate", YAFFS_TRACE_ALLOCATE},
2564 {"always", YAFFS_TRACE_ALWAYS},
2565 {"background", YAFFS_TRACE_BACKGROUND},
2566 {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
2567 {"buffers", YAFFS_TRACE_BUFFERS},
2568 {"bug", YAFFS_TRACE_BUG},
2569 {"checkpt", YAFFS_TRACE_CHECKPOINT},
2570 {"deletion", YAFFS_TRACE_DELETION},
2571 {"erase", YAFFS_TRACE_ERASE},
2572 {"error", YAFFS_TRACE_ERROR},
2573 {"gc_detail", YAFFS_TRACE_GC_DETAIL},
2574 {"gc", YAFFS_TRACE_GC},
2575 {"lock", YAFFS_TRACE_LOCK},
2576 {"mtd", YAFFS_TRACE_MTD},
2577 {"nandaccess", YAFFS_TRACE_NANDACCESS},
2578 {"os", YAFFS_TRACE_OS},
2579 {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
2580 {"scan", YAFFS_TRACE_SCAN},
2581 {"mount", YAFFS_TRACE_MOUNT},
2582 {"tracing", YAFFS_TRACE_TRACING},
2583 {"sync", YAFFS_TRACE_SYNC},
2584 {"write", YAFFS_TRACE_WRITE},
2585 {"verify", YAFFS_TRACE_VERIFY},
2586 {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
2587 {"verify_full", YAFFS_TRACE_VERIFY_FULL},
2588 {"verify_all", YAFFS_TRACE_VERIFY_ALL},
2589 {"all", 0xffffffff},
2590 {"none", 0},
2591 {NULL, 0},
2592};
2593
2594#define MAX_MASK_NAME_LENGTH 40
2595static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
2596 unsigned long count, void *data)
2597{
2598 unsigned rg = 0, mask_bitfield;
2599 char *end;
2600 char *mask_name;
2601 const char *x;
2602 char substring[MAX_MASK_NAME_LENGTH + 1];
2603 int i;
2604 int done = 0;
2605 int add, len = 0;
2606 int pos = 0;
2607
2608 rg = yaffs_trace_mask;
2609
2610 while (!done && (pos < count)) {
2611 done = 1;
2612 while ((pos < count) && isspace(buf[pos]))
2613 pos++;
2614
2615 switch (buf[pos]) {
2616 case '+':
2617 case '-':
2618 case '=':
2619 add = buf[pos];
2620 pos++;
2621 break;
2622
2623 default:
2624 add = ' ';
2625 break;
2626 }
2627 mask_name = NULL;
2628
2629 mask_bitfield = simple_strtoul(buf + pos, &end, 0);
2630
2631 if (end > buf + pos) {
2632 mask_name = "numeral";
2633 len = end - (buf + pos);
2634 pos += len;
2635 done = 0;
2636 } else {
2637 for (x = buf + pos, i = 0;
2638 (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
2639 i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
2640 substring[i] = *x;
2641 substring[i] = '\0';
2642
2643 for (i = 0; mask_flags[i].mask_name != NULL; i++) {
2644 if (strcmp(substring, mask_flags[i].mask_name)
2645 == 0) {
2646 mask_name = mask_flags[i].mask_name;
2647 mask_bitfield =
2648 mask_flags[i].mask_bitfield;
2649 done = 0;
2650 break;
2651 }
2652 }
2653 }
2654
2655 if (mask_name != NULL) {
2656 done = 0;
2657 switch (add) {
2658 case '-':
2659 rg &= ~mask_bitfield;
2660 break;
2661 case '+':
2662 rg |= mask_bitfield;
2663 break;
2664 case '=':
2665 rg = mask_bitfield;
2666 break;
2667 default:
2668 rg |= mask_bitfield;
2669 break;
2670 }
2671 }
2672 }
2673
2674 yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
2675
2676 printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
2677
2678 if (rg & YAFFS_TRACE_ALWAYS) {
2679 for (i = 0; mask_flags[i].mask_name != NULL; i++) {
2680 char flag;
2681 flag = ((rg & mask_flags[i].mask_bitfield) ==
2682 mask_flags[i].mask_bitfield) ? '+' : '-';
2683 printk(KERN_DEBUG "%c%s\n", flag,
2684 mask_flags[i].mask_name);
2685 }
2686 }
2687
2688 return count;
2689}
2690
2691static int yaffs_proc_write(struct file *file, const char *buf,
2692 unsigned long count, void *data)
2693{
2694 return yaffs_proc_write_trace_options(file, buf, count, data);
2695}
2696
2697/* Stuff to handle installation of file systems */
2698struct file_system_to_install {
2699 struct file_system_type *fst;
2700 int installed;
2701};
2702
2703static struct file_system_to_install fs_to_install[] = {
2704 {&yaffs_fs_type, 0},
2705 {&yaffs2_fs_type, 0},
2706 {NULL, 0}
2707};
2708
2709static int __init init_yaffs_fs(void)
2710{
2711 int error = 0;
2712 struct file_system_to_install *fsinst;
2713
2714 yaffs_trace(YAFFS_TRACE_ALWAYS,
2715 "yaffs built " __DATE__ " " __TIME__ " Installing.");
2716
2717#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
2718 yaffs_trace(YAFFS_TRACE_ALWAYS,
2719 "\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n");
2720#endif
2721
2722 mutex_init(&yaffs_context_lock);
2723
2724 /* Install the proc_fs entries */
2725 my_proc_entry = create_proc_entry("yaffs",
2726 S_IRUGO | S_IFREG, YPROC_ROOT);
2727
2728 if (my_proc_entry) {
2729 my_proc_entry->write_proc = yaffs_proc_write;
2730 my_proc_entry->read_proc = yaffs_proc_read;
2731 my_proc_entry->data = NULL;
2732 } else {
2733 return -ENOMEM;
2734 }
2735
2736
2737 /* Now add the file system entries */
2738
2739 fsinst = fs_to_install;
2740
2741 while (fsinst->fst && !error) {
2742 error = register_filesystem(fsinst->fst);
2743 if (!error)
2744 fsinst->installed = 1;
2745 fsinst++;
2746 }
2747
2748 /* Any errors? uninstall */
2749 if (error) {
2750 fsinst = fs_to_install;
2751
2752 while (fsinst->fst) {
2753 if (fsinst->installed) {
2754 unregister_filesystem(fsinst->fst);
2755 fsinst->installed = 0;
2756 }
2757 fsinst++;
2758 }
2759 }
2760
2761 return error;
2762}
2763
2764static void __exit exit_yaffs_fs(void)
2765{
2766
2767 struct file_system_to_install *fsinst;
2768
2769 yaffs_trace(YAFFS_TRACE_ALWAYS,
2770 "yaffs built " __DATE__ " " __TIME__ " removing.");
2771
2772 remove_proc_entry("yaffs", YPROC_ROOT);
2773
2774 fsinst = fs_to_install;
2775
2776 while (fsinst->fst) {
2777 if (fsinst->installed) {
2778 unregister_filesystem(fsinst->fst);
2779 fsinst->installed = 0;
2780 }
2781 fsinst++;
2782 }
2783}
2784
2785module_init(init_yaffs_fs)
2786 module_exit(exit_yaffs_fs)
2787
2788 MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
2789MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
2790MODULE_LICENSE("GPL");
diff --git a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c
new file mode 100644
index 00000000000..9eb60308254
--- /dev/null
+++ b/fs/yaffs2/yaffs_yaffs1.c
@@ -0,0 +1,433 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_yaffs1.h"
15#include "yportenv.h"
16#include "yaffs_trace.h"
17#include "yaffs_bitmap.h"
18#include "yaffs_getblockinfo.h"
19#include "yaffs_nand.h"
20#include "yaffs_attribs.h"
21
22int yaffs1_scan(struct yaffs_dev *dev)
23{
24 struct yaffs_ext_tags tags;
25 int blk;
26 int result;
27
28 int chunk;
29 int c;
30 int deleted;
31 enum yaffs_block_state state;
32 struct yaffs_obj *hard_list = NULL;
33 struct yaffs_block_info *bi;
34 u32 seq_number;
35 struct yaffs_obj_hdr *oh;
36 struct yaffs_obj *in;
37 struct yaffs_obj *parent;
38
39 int alloc_failed = 0;
40
41 struct yaffs_shadow_fixer *shadow_fixers = NULL;
42
43 u8 *chunk_data;
44
45 yaffs_trace(YAFFS_TRACE_SCAN,
46 "yaffs1_scan starts intstartblk %d intendblk %d...",
47 dev->internal_start_block, dev->internal_end_block);
48
49 chunk_data = yaffs_get_temp_buffer(dev, __LINE__);
50
51 dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
52
53 /* Scan all the blocks to determine their state */
54 bi = dev->block_info;
55 for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
56 blk++) {
57 yaffs_clear_chunk_bits(dev, blk);
58 bi->pages_in_use = 0;
59 bi->soft_del_pages = 0;
60
61 yaffs_query_init_block_state(dev, blk, &state, &seq_number);
62
63 bi->block_state = state;
64 bi->seq_number = seq_number;
65
66 if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
67 bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
68
69 yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
70 "Block scanning block %d state %d seq %d",
71 blk, state, seq_number);
72
73 if (state == YAFFS_BLOCK_STATE_DEAD) {
74 yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
75 "block %d is bad", blk);
76 } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
77 yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
78 dev->n_erased_blocks++;
79 dev->n_free_chunks += dev->param.chunks_per_block;
80 }
81 bi++;
82 }
83
84 /* For each block.... */
85 for (blk = dev->internal_start_block;
86 !alloc_failed && blk <= dev->internal_end_block; blk++) {
87
88 cond_resched();
89
90 bi = yaffs_get_block_info(dev, blk);
91 state = bi->block_state;
92
93 deleted = 0;
94
95 /* For each chunk in each block that needs scanning.... */
96 for (c = 0; !alloc_failed && c < dev->param.chunks_per_block &&
97 state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
98 /* Read the tags and decide what to do */
99 chunk = blk * dev->param.chunks_per_block + c;
100
101 result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
102 &tags);
103
104 /* Let's have a good look at this chunk... */
105
106 if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED
107 || tags.is_deleted) {
108 /* YAFFS1 only...
109 * A deleted chunk
110 */
111 deleted++;
112 dev->n_free_chunks++;
113 /*T((" %d %d deleted\n",blk,c)); */
114 } else if (!tags.chunk_used) {
115 /* An unassigned chunk in the block
116 * This means that either the block is empty or
117 * this is the one being allocated from
118 */
119
120 if (c == 0) {
121 /* We're looking at the first chunk in the block so the block is unused */
122 state = YAFFS_BLOCK_STATE_EMPTY;
123 dev->n_erased_blocks++;
124 } else {
125 /* this is the block being allocated from */
126 yaffs_trace(YAFFS_TRACE_SCAN,
127 " Allocating from %d %d",
128 blk, c);
129 state = YAFFS_BLOCK_STATE_ALLOCATING;
130 dev->alloc_block = blk;
131 dev->alloc_page = c;
132 dev->alloc_block_finder = blk;
133 /* Set block finder here to encourage the allocator to go forth from here. */
134
135 }
136
137 dev->n_free_chunks +=
138 (dev->param.chunks_per_block - c);
139 } else if (tags.chunk_id > 0) {
140 /* chunk_id > 0 so it is a data chunk... */
141 unsigned int endpos;
142
143 yaffs_set_chunk_bit(dev, blk, c);
144 bi->pages_in_use++;
145
146 in = yaffs_find_or_create_by_number(dev,
147 tags.obj_id,
148 YAFFS_OBJECT_TYPE_FILE);
149 /* PutChunkIntoFile checks for a clash (two data chunks with
150 * the same chunk_id).
151 */
152
153 if (!in)
154 alloc_failed = 1;
155
156 if (in) {
157 if (!yaffs_put_chunk_in_file
158 (in, tags.chunk_id, chunk, 1))
159 alloc_failed = 1;
160 }
161
162 endpos =
163 (tags.chunk_id -
164 1) * dev->data_bytes_per_chunk +
165 tags.n_bytes;
166 if (in
167 && in->variant_type ==
168 YAFFS_OBJECT_TYPE_FILE
169 && in->variant.file_variant.scanned_size <
170 endpos) {
171 in->variant.file_variant.scanned_size =
172 endpos;
173 if (!dev->param.use_header_file_size) {
174 in->variant.
175 file_variant.file_size =
176 in->variant.
177 file_variant.scanned_size;
178 }
179
180 }
181 /* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */
182 } else {
183 /* chunk_id == 0, so it is an ObjectHeader.
184 * Thus, we read in the object header and make the object
185 */
186 yaffs_set_chunk_bit(dev, blk, c);
187 bi->pages_in_use++;
188
189 result = yaffs_rd_chunk_tags_nand(dev, chunk,
190 chunk_data,
191 NULL);
192
193 oh = (struct yaffs_obj_hdr *)chunk_data;
194
195 in = yaffs_find_by_number(dev, tags.obj_id);
196 if (in && in->variant_type != oh->type) {
197 /* This should not happen, but somehow
198 * Wev'e ended up with an obj_id that has been reused but not yet
199 * deleted, and worse still it has changed type. Delete the old object.
200 */
201
202 yaffs_del_obj(in);
203
204 in = 0;
205 }
206
207 in = yaffs_find_or_create_by_number(dev,
208 tags.obj_id,
209 oh->type);
210
211 if (!in)
212 alloc_failed = 1;
213
214 if (in && oh->shadows_obj > 0) {
215
216 struct yaffs_shadow_fixer *fixer;
217 fixer =
218 kmalloc(sizeof
219 (struct yaffs_shadow_fixer),
220 GFP_NOFS);
221 if (fixer) {
222 fixer->next = shadow_fixers;
223 shadow_fixers = fixer;
224 fixer->obj_id = tags.obj_id;
225 fixer->shadowed_id =
226 oh->shadows_obj;
227 yaffs_trace(YAFFS_TRACE_SCAN,
228 " Shadow fixer: %d shadows %d",
229 fixer->obj_id,
230 fixer->shadowed_id);
231
232 }
233
234 }
235
236 if (in && in->valid) {
237 /* We have already filled this one. We have a duplicate and need to resolve it. */
238
239 unsigned existing_serial = in->serial;
240 unsigned new_serial =
241 tags.serial_number;
242
243 if (((existing_serial + 1) & 3) ==
244 new_serial) {
245 /* Use new one - destroy the exisiting one */
246 yaffs_chunk_del(dev,
247 in->hdr_chunk,
248 1, __LINE__);
249 in->valid = 0;
250 } else {
251 /* Use existing - destroy this one. */
252 yaffs_chunk_del(dev, chunk, 1,
253 __LINE__);
254 }
255 }
256
257 if (in && !in->valid &&
258 (tags.obj_id == YAFFS_OBJECTID_ROOT ||
259 tags.obj_id ==
260 YAFFS_OBJECTID_LOSTNFOUND)) {
261 /* We only load some info, don't fiddle with directory structure */
262 in->valid = 1;
263 in->variant_type = oh->type;
264
265 in->yst_mode = oh->yst_mode;
266 yaffs_load_attribs(in, oh);
267 in->hdr_chunk = chunk;
268 in->serial = tags.serial_number;
269
270 } else if (in && !in->valid) {
271 /* we need to load this info */
272
273 in->valid = 1;
274 in->variant_type = oh->type;
275
276 in->yst_mode = oh->yst_mode;
277 yaffs_load_attribs(in, oh);
278 in->hdr_chunk = chunk;
279 in->serial = tags.serial_number;
280
281 yaffs_set_obj_name_from_oh(in, oh);
282 in->dirty = 0;
283
284 /* directory stuff...
285 * hook up to parent
286 */
287
288 parent =
289 yaffs_find_or_create_by_number
290 (dev, oh->parent_obj_id,
291 YAFFS_OBJECT_TYPE_DIRECTORY);
292 if (!parent)
293 alloc_failed = 1;
294 if (parent && parent->variant_type ==
295 YAFFS_OBJECT_TYPE_UNKNOWN) {
296 /* Set up as a directory */
297 parent->variant_type =
298 YAFFS_OBJECT_TYPE_DIRECTORY;
299 INIT_LIST_HEAD(&parent->
300 variant.dir_variant.children);
301 } else if (!parent
302 || parent->variant_type !=
303 YAFFS_OBJECT_TYPE_DIRECTORY) {
304 /* Hoosterman, another problem....
305 * We're trying to use a non-directory as a directory
306 */
307
308 yaffs_trace(YAFFS_TRACE_ERROR,
309 "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
310 );
311 parent = dev->lost_n_found;
312 }
313
314 yaffs_add_obj_to_dir(parent, in);
315
316 if (0 && (parent == dev->del_dir ||
317 parent ==
318 dev->unlinked_dir)) {
319 in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
320 dev->n_deleted_files++;
321 }
322 /* Note re hardlinks.
323 * Since we might scan a hardlink before its equivalent object is scanned
324 * we put them all in a list.
325 * After scanning is complete, we should have all the objects, so we run through this
326 * list and fix up all the chains.
327 */
328
329 switch (in->variant_type) {
330 case YAFFS_OBJECT_TYPE_UNKNOWN:
331 /* Todo got a problem */
332 break;
333 case YAFFS_OBJECT_TYPE_FILE:
334 if (dev->param.
335 use_header_file_size)
336
337 in->variant.
338 file_variant.file_size
339 = oh->file_size;
340
341 break;
342 case YAFFS_OBJECT_TYPE_HARDLINK:
343 in->variant.
344 hardlink_variant.equiv_id =
345 oh->equiv_id;
346 in->hard_links.next =
347 (struct list_head *)
348 hard_list;
349 hard_list = in;
350 break;
351 case YAFFS_OBJECT_TYPE_DIRECTORY:
352 /* Do nothing */
353 break;
354 case YAFFS_OBJECT_TYPE_SPECIAL:
355 /* Do nothing */
356 break;
357 case YAFFS_OBJECT_TYPE_SYMLINK:
358 in->variant.symlink_variant.
359 alias =
360 yaffs_clone_str(oh->alias);
361 if (!in->variant.
362 symlink_variant.alias)
363 alloc_failed = 1;
364 break;
365 }
366
367 }
368 }
369 }
370
371 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
372 /* If we got this far while scanning, then the block is fully allocated. */
373 state = YAFFS_BLOCK_STATE_FULL;
374 }
375
376 if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
377 /* If the block was partially allocated then treat it as fully allocated. */
378 state = YAFFS_BLOCK_STATE_FULL;
379 dev->alloc_block = -1;
380 }
381
382 bi->block_state = state;
383
384 /* Now let's see if it was dirty */
385 if (bi->pages_in_use == 0 &&
386 !bi->has_shrink_hdr &&
387 bi->block_state == YAFFS_BLOCK_STATE_FULL) {
388 yaffs_block_became_dirty(dev, blk);
389 }
390
391 }
392
393 /* Ok, we've done all the scanning.
394 * Fix up the hard link chains.
395 * We should now have scanned all the objects, now it's time to add these
396 * hardlinks.
397 */
398
399 yaffs_link_fixup(dev, hard_list);
400
401 /* Fix up any shadowed objects */
402 {
403 struct yaffs_shadow_fixer *fixer;
404 struct yaffs_obj *obj;
405
406 while (shadow_fixers) {
407 fixer = shadow_fixers;
408 shadow_fixers = fixer->next;
409 /* Complete the rename transaction by deleting the shadowed object
410 * then setting the object header to unshadowed.
411 */
412 obj = yaffs_find_by_number(dev, fixer->shadowed_id);
413 if (obj)
414 yaffs_del_obj(obj);
415
416 obj = yaffs_find_by_number(dev, fixer->obj_id);
417
418 if (obj)
419 yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
420
421 kfree(fixer);
422 }
423 }
424
425 yaffs_release_temp_buffer(dev, chunk_data, __LINE__);
426
427 if (alloc_failed)
428 return YAFFS_FAIL;
429
430 yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
431
432 return YAFFS_OK;
433}
diff --git a/fs/yaffs2/yaffs_yaffs1.h b/fs/yaffs2/yaffs_yaffs1.h
new file mode 100644
index 00000000000..db23e04973b
--- /dev/null
+++ b/fs/yaffs2/yaffs_yaffs1.h
@@ -0,0 +1,22 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_YAFFS1_H__
17#define __YAFFS_YAFFS1_H__
18
19#include "yaffs_guts.h"
20int yaffs1_scan(struct yaffs_dev *dev);
21
22#endif
diff --git a/fs/yaffs2/yaffs_yaffs2.c b/fs/yaffs2/yaffs_yaffs2.c
new file mode 100644
index 00000000000..33397af7003
--- /dev/null
+++ b/fs/yaffs2/yaffs_yaffs2.c
@@ -0,0 +1,1598 @@
1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include "yaffs_guts.h"
15#include "yaffs_trace.h"
16#include "yaffs_yaffs2.h"
17#include "yaffs_checkptrw.h"
18#include "yaffs_bitmap.h"
19#include "yaffs_nand.h"
20#include "yaffs_getblockinfo.h"
21#include "yaffs_verify.h"
22#include "yaffs_attribs.h"
23
24/*
25 * Checkpoints are really no benefit on very small partitions.
26 *
27 * To save space on small partitions don't bother with checkpoints unless
28 * the partition is at least this big.
29 */
30#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
31
32#define YAFFS_SMALL_HOLE_THRESHOLD 4
33
34/*
35 * Oldest Dirty Sequence Number handling.
36 */
37
38/* yaffs_calc_oldest_dirty_seq()
39 * yaffs2_find_oldest_dirty_seq()
40 * Calculate the oldest dirty sequence number if we don't know it.
41 */
42void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
43{
44 int i;
45 unsigned seq;
46 unsigned block_no = 0;
47 struct yaffs_block_info *b;
48
49 if (!dev->param.is_yaffs2)
50 return;
51
52 /* Find the oldest dirty sequence number. */
53 seq = dev->seq_number + 1;
54 b = dev->block_info;
55 for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
56 if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
57 (b->pages_in_use - b->soft_del_pages) <
58 dev->param.chunks_per_block && b->seq_number < seq) {
59 seq = b->seq_number;
60 block_no = i;
61 }
62 b++;
63 }
64
65 if (block_no) {
66 dev->oldest_dirty_seq = seq;
67 dev->oldest_dirty_block = block_no;
68 }
69
70}
71
72void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
73{
74 if (!dev->param.is_yaffs2)
75 return;
76
77 if (!dev->oldest_dirty_seq)
78 yaffs_calc_oldest_dirty_seq(dev);
79}
80
81/*
82 * yaffs_clear_oldest_dirty_seq()
83 * Called when a block is erased or marked bad. (ie. when its seq_number
84 * becomes invalid). If the value matches the oldest then we clear
85 * dev->oldest_dirty_seq to force its recomputation.
86 */
87void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
88 struct yaffs_block_info *bi)
89{
90
91 if (!dev->param.is_yaffs2)
92 return;
93
94 if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
95 dev->oldest_dirty_seq = 0;
96 dev->oldest_dirty_block = 0;
97 }
98}
99
100/*
101 * yaffs2_update_oldest_dirty_seq()
102 * Update the oldest dirty sequence number whenever we dirty a block.
103 * Only do this if the oldest_dirty_seq is actually being tracked.
104 */
105void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
106 struct yaffs_block_info *bi)
107{
108 if (!dev->param.is_yaffs2)
109 return;
110
111 if (dev->oldest_dirty_seq) {
112 if (dev->oldest_dirty_seq > bi->seq_number) {
113 dev->oldest_dirty_seq = bi->seq_number;
114 dev->oldest_dirty_block = block_no;
115 }
116 }
117}
118
119int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
120{
121
122 if (!dev->param.is_yaffs2)
123 return 1; /* disqualification only applies to yaffs2. */
124
125 if (!bi->has_shrink_hdr)
126 return 1; /* can gc */
127
128 yaffs2_find_oldest_dirty_seq(dev);
129
130 /* Can't do gc of this block if there are any blocks older than this one that have
131 * discarded pages.
132 */
133 return (bi->seq_number <= dev->oldest_dirty_seq);
134}
135
136/*
137 * yaffs2_find_refresh_block()
138 * periodically finds the oldest full block by sequence number for refreshing.
139 * Only for yaffs2.
140 */
141u32 yaffs2_find_refresh_block(struct yaffs_dev * dev)
142{
143 u32 b;
144
145 u32 oldest = 0;
146 u32 oldest_seq = 0;
147
148 struct yaffs_block_info *bi;
149
150 if (!dev->param.is_yaffs2)
151 return oldest;
152
153 /*
154 * If refresh period < 10 then refreshing is disabled.
155 */
156 if (dev->param.refresh_period < 10)
157 return oldest;
158
159 /*
160 * Fix broken values.
161 */
162 if (dev->refresh_skip > dev->param.refresh_period)
163 dev->refresh_skip = dev->param.refresh_period;
164
165 if (dev->refresh_skip > 0)
166 return oldest;
167
168 /*
169 * Refresh skip is now zero.
170 * We'll do a refresh this time around....
171 * Update the refresh skip and find the oldest block.
172 */
173 dev->refresh_skip = dev->param.refresh_period;
174 dev->refresh_count++;
175 bi = dev->block_info;
176 for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
177
178 if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
179
180 if (oldest < 1 || bi->seq_number < oldest_seq) {
181 oldest = b;
182 oldest_seq = bi->seq_number;
183 }
184 }
185 bi++;
186 }
187
188 if (oldest > 0) {
189 yaffs_trace(YAFFS_TRACE_GC,
190 "GC refresh count %d selected block %d with seq_number %d",
191 dev->refresh_count, oldest, oldest_seq);
192 }
193
194 return oldest;
195}
196
197int yaffs2_checkpt_required(struct yaffs_dev *dev)
198{
199 int nblocks;
200
201 if (!dev->param.is_yaffs2)
202 return 0;
203
204 nblocks = dev->internal_end_block - dev->internal_start_block + 1;
205
206 return !dev->param.skip_checkpt_wr &&
207 !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
208}
209
210int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
211{
212 int retval;
213
214 if (!dev->param.is_yaffs2)
215 return 0;
216
217 if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
218 /* Not a valid value so recalculate */
219 int n_bytes = 0;
220 int n_blocks;
221 int dev_blocks =
222 (dev->param.end_block - dev->param.start_block + 1);
223
224 n_bytes += sizeof(struct yaffs_checkpt_validity);
225 n_bytes += sizeof(struct yaffs_checkpt_dev);
226 n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
227 n_bytes += dev_blocks * dev->chunk_bit_stride;
228 n_bytes +=
229 (sizeof(struct yaffs_checkpt_obj) +
230 sizeof(u32)) * (dev->n_obj);
231 n_bytes += (dev->tnode_size + sizeof(u32)) * (dev->n_tnodes);
232 n_bytes += sizeof(struct yaffs_checkpt_validity);
233 n_bytes += sizeof(u32); /* checksum */
234
235 /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
236
237 n_blocks =
238 (n_bytes /
239 (dev->data_bytes_per_chunk *
240 dev->param.chunks_per_block)) + 3;
241
242 dev->checkpoint_blocks_required = n_blocks;
243 }
244
245 retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
246 if (retval < 0)
247 retval = 0;
248 return retval;
249}
250
251/*--------------------- Checkpointing --------------------*/
252
253static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
254{
255 struct yaffs_checkpt_validity cp;
256
257 memset(&cp, 0, sizeof(cp));
258
259 cp.struct_type = sizeof(cp);
260 cp.magic = YAFFS_MAGIC;
261 cp.version = YAFFS_CHECKPOINT_VERSION;
262 cp.head = (head) ? 1 : 0;
263
264 return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
265}
266
267static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
268{
269 struct yaffs_checkpt_validity cp;
270 int ok;
271
272 ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
273
274 if (ok)
275 ok = (cp.struct_type == sizeof(cp)) &&
276 (cp.magic == YAFFS_MAGIC) &&
277 (cp.version == YAFFS_CHECKPOINT_VERSION) &&
278 (cp.head == ((head) ? 1 : 0));
279 return ok ? 1 : 0;
280}
281
282static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
283 struct yaffs_dev *dev)
284{
285 cp->n_erased_blocks = dev->n_erased_blocks;
286 cp->alloc_block = dev->alloc_block;
287 cp->alloc_page = dev->alloc_page;
288 cp->n_free_chunks = dev->n_free_chunks;
289
290 cp->n_deleted_files = dev->n_deleted_files;
291 cp->n_unlinked_files = dev->n_unlinked_files;
292 cp->n_bg_deletions = dev->n_bg_deletions;
293 cp->seq_number = dev->seq_number;
294
295}
296
297static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
298 struct yaffs_checkpt_dev *cp)
299{
300 dev->n_erased_blocks = cp->n_erased_blocks;
301 dev->alloc_block = cp->alloc_block;
302 dev->alloc_page = cp->alloc_page;
303 dev->n_free_chunks = cp->n_free_chunks;
304
305 dev->n_deleted_files = cp->n_deleted_files;
306 dev->n_unlinked_files = cp->n_unlinked_files;
307 dev->n_bg_deletions = cp->n_bg_deletions;
308 dev->seq_number = cp->seq_number;
309}
310
311static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
312{
313 struct yaffs_checkpt_dev cp;
314 u32 n_bytes;
315 u32 n_blocks =
316 (dev->internal_end_block - dev->internal_start_block + 1);
317
318 int ok;
319
320 /* Write device runtime values */
321 yaffs2_dev_to_checkpt_dev(&cp, dev);
322 cp.struct_type = sizeof(cp);
323
324 ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
325
326 /* Write block info */
327 if (ok) {
328 n_bytes = n_blocks * sizeof(struct yaffs_block_info);
329 ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) ==
330 n_bytes);
331 }
332
333 /* Write chunk bits */
334 if (ok) {
335 n_bytes = n_blocks * dev->chunk_bit_stride;
336 ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) ==
337 n_bytes);
338 }
339 return ok ? 1 : 0;
340
341}
342
343static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
344{
345 struct yaffs_checkpt_dev cp;
346 u32 n_bytes;
347 u32 n_blocks =
348 (dev->internal_end_block - dev->internal_start_block + 1);
349
350 int ok;
351
352 ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
353 if (!ok)
354 return 0;
355
356 if (cp.struct_type != sizeof(cp))
357 return 0;
358
359 yaffs_checkpt_dev_to_dev(dev, &cp);
360
361 n_bytes = n_blocks * sizeof(struct yaffs_block_info);
362
363 ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
364
365 if (!ok)
366 return 0;
367 n_bytes = n_blocks * dev->chunk_bit_stride;
368
369 ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
370
371 return ok ? 1 : 0;
372}
373
374static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
375 struct yaffs_obj *obj)
376{
377
378 cp->obj_id = obj->obj_id;
379 cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
380 cp->hdr_chunk = obj->hdr_chunk;
381 cp->variant_type = obj->variant_type;
382 cp->deleted = obj->deleted;
383 cp->soft_del = obj->soft_del;
384 cp->unlinked = obj->unlinked;
385 cp->fake = obj->fake;
386 cp->rename_allowed = obj->rename_allowed;
387 cp->unlink_allowed = obj->unlink_allowed;
388 cp->serial = obj->serial;
389 cp->n_data_chunks = obj->n_data_chunks;
390
391 if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
392 cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
393 else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
394 cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
395}
396
397static int taffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
398 struct yaffs_checkpt_obj *cp)
399{
400
401 struct yaffs_obj *parent;
402
403 if (obj->variant_type != cp->variant_type) {
404 yaffs_trace(YAFFS_TRACE_ERROR,
405 "Checkpoint read object %d type %d chunk %d does not match existing object type %d",
406 cp->obj_id, cp->variant_type, cp->hdr_chunk,
407 obj->variant_type);
408 return 0;
409 }
410
411 obj->obj_id = cp->obj_id;
412
413 if (cp->parent_id)
414 parent = yaffs_find_or_create_by_number(obj->my_dev,
415 cp->parent_id,
416 YAFFS_OBJECT_TYPE_DIRECTORY);
417 else
418 parent = NULL;
419
420 if (parent) {
421 if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
422 yaffs_trace(YAFFS_TRACE_ALWAYS,
423 "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
424 cp->obj_id, cp->parent_id,
425 cp->variant_type, cp->hdr_chunk,
426 parent->variant_type);
427 return 0;
428 }
429 yaffs_add_obj_to_dir(parent, obj);
430 }
431
432 obj->hdr_chunk = cp->hdr_chunk;
433 obj->variant_type = cp->variant_type;
434 obj->deleted = cp->deleted;
435 obj->soft_del = cp->soft_del;
436 obj->unlinked = cp->unlinked;
437 obj->fake = cp->fake;
438 obj->rename_allowed = cp->rename_allowed;
439 obj->unlink_allowed = cp->unlink_allowed;
440 obj->serial = cp->serial;
441 obj->n_data_chunks = cp->n_data_chunks;
442
443 if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
444 obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
445 else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
446 obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
447
448 if (obj->hdr_chunk > 0)
449 obj->lazy_loaded = 1;
450 return 1;
451}
452
453static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
454 struct yaffs_tnode *tn, u32 level,
455 int chunk_offset)
456{
457 int i;
458 struct yaffs_dev *dev = in->my_dev;
459 int ok = 1;
460
461 if (tn) {
462 if (level > 0) {
463
464 for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
465 if (tn->internal[i]) {
466 ok = yaffs2_checkpt_tnode_worker(in,
467 tn->
468 internal
469 [i],
470 level -
471 1,
472 (chunk_offset
473 <<
474 YAFFS_TNODES_INTERNAL_BITS)
475 + i);
476 }
477 }
478 } else if (level == 0) {
479 u32 base_offset =
480 chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
481 ok = (yaffs2_checkpt_wr
482 (dev, &base_offset,
483 sizeof(base_offset)) == sizeof(base_offset));
484 if (ok)
485 ok = (yaffs2_checkpt_wr
486 (dev, tn,
487 dev->tnode_size) == dev->tnode_size);
488 }
489 }
490
491 return ok;
492
493}
494
495static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
496{
497 u32 end_marker = ~0;
498 int ok = 1;
499
500 if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
501 ok = yaffs2_checkpt_tnode_worker(obj,
502 obj->variant.file_variant.top,
503 obj->variant.file_variant.
504 top_level, 0);
505 if (ok)
506 ok = (yaffs2_checkpt_wr
507 (obj->my_dev, &end_marker,
508 sizeof(end_marker)) == sizeof(end_marker));
509 }
510
511 return ok ? 1 : 0;
512}
513
514static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
515{
516 u32 base_chunk;
517 int ok = 1;
518 struct yaffs_dev *dev = obj->my_dev;
519 struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
520 struct yaffs_tnode *tn;
521 int nread = 0;
522
523 ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
524 sizeof(base_chunk));
525
526 while (ok && (~base_chunk)) {
527 nread++;
528 /* Read level 0 tnode */
529
530 tn = yaffs_get_tnode(dev);
531 if (tn) {
532 ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
533 dev->tnode_size);
534 } else {
535 ok = 0;
536 }
537
538 if (tn && ok)
539 ok = yaffs_add_find_tnode_0(dev,
540 file_stuct_ptr,
541 base_chunk, tn) ? 1 : 0;
542
543 if (ok)
544 ok = (yaffs2_checkpt_rd
545 (dev, &base_chunk,
546 sizeof(base_chunk)) == sizeof(base_chunk));
547
548 }
549
550 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
551 "Checkpoint read tnodes %d records, last %d. ok %d",
552 nread, base_chunk, ok);
553
554 return ok ? 1 : 0;
555}
556
557static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
558{
559 struct yaffs_obj *obj;
560 struct yaffs_checkpt_obj cp;
561 int i;
562 int ok = 1;
563 struct list_head *lh;
564
565 /* Iterate through the objects in each hash entry,
566 * dumping them to the checkpointing stream.
567 */
568
569 for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
570 list_for_each(lh, &dev->obj_bucket[i].list) {
571 if (lh) {
572 obj =
573 list_entry(lh, struct yaffs_obj, hash_link);
574 if (!obj->defered_free) {
575 yaffs2_obj_checkpt_obj(&cp, obj);
576 cp.struct_type = sizeof(cp);
577
578 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
579 "Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
580 cp.obj_id, cp.parent_id,
581 cp.variant_type, cp.hdr_chunk, obj);
582
583 ok = (yaffs2_checkpt_wr
584 (dev, &cp,
585 sizeof(cp)) == sizeof(cp));
586
587 if (ok
588 && obj->variant_type ==
589 YAFFS_OBJECT_TYPE_FILE)
590 ok = yaffs2_wr_checkpt_tnodes
591 (obj);
592 }
593 }
594 }
595 }
596
597 /* Dump end of list */
598 memset(&cp, 0xFF, sizeof(struct yaffs_checkpt_obj));
599 cp.struct_type = sizeof(cp);
600
601 if (ok)
602 ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
603
604 return ok ? 1 : 0;
605}
606
607static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
608{
609 struct yaffs_obj *obj;
610 struct yaffs_checkpt_obj cp;
611 int ok = 1;
612 int done = 0;
613 struct yaffs_obj *hard_list = NULL;
614
615 while (ok && !done) {
616 ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
617 if (cp.struct_type != sizeof(cp)) {
618 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
619 "struct size %d instead of %d ok %d",
620 cp.struct_type, (int)sizeof(cp), ok);
621 ok = 0;
622 }
623
624 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
625 "Checkpoint read object %d parent %d type %d chunk %d ",
626 cp.obj_id, cp.parent_id, cp.variant_type,
627 cp.hdr_chunk);
628
629 if (ok && cp.obj_id == ~0) {
630 done = 1;
631 } else if (ok) {
632 obj =
633 yaffs_find_or_create_by_number(dev, cp.obj_id,
634 cp.variant_type);
635 if (obj) {
636 ok = taffs2_checkpt_obj_to_obj(obj, &cp);
637 if (!ok)
638 break;
639 if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
640 ok = yaffs2_rd_checkpt_tnodes(obj);
641 } else if (obj->variant_type ==
642 YAFFS_OBJECT_TYPE_HARDLINK) {
643 obj->hard_links.next =
644 (struct list_head *)hard_list;
645 hard_list = obj;
646 }
647 } else {
648 ok = 0;
649 }
650 }
651 }
652
653 if (ok)
654 yaffs_link_fixup(dev, hard_list);
655
656 return ok ? 1 : 0;
657}
658
659static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
660{
661 u32 checkpt_sum;
662 int ok;
663
664 yaffs2_get_checkpt_sum(dev, &checkpt_sum);
665
666 ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
667 sizeof(checkpt_sum));
668
669 if (!ok)
670 return 0;
671
672 return 1;
673}
674
675static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
676{
677 u32 checkpt_sum0;
678 u32 checkpt_sum1;
679 int ok;
680
681 yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
682
683 ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
684 sizeof(checkpt_sum1));
685
686 if (!ok)
687 return 0;
688
689 if (checkpt_sum0 != checkpt_sum1)
690 return 0;
691
692 return 1;
693}
694
695static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
696{
697 int ok = 1;
698
699 if (!yaffs2_checkpt_required(dev)) {
700 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
701 "skipping checkpoint write");
702 ok = 0;
703 }
704
705 if (ok)
706 ok = yaffs2_checkpt_open(dev, 1);
707
708 if (ok) {
709 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
710 "write checkpoint validity");
711 ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
712 }
713 if (ok) {
714 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
715 "write checkpoint device");
716 ok = yaffs2_wr_checkpt_dev(dev);
717 }
718 if (ok) {
719 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
720 "write checkpoint objects");
721 ok = yaffs2_wr_checkpt_objs(dev);
722 }
723 if (ok) {
724 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
725 "write checkpoint validity");
726 ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
727 }
728
729 if (ok)
730 ok = yaffs2_wr_checkpt_sum(dev);
731
732 if (!yaffs_checkpt_close(dev))
733 ok = 0;
734
735 if (ok)
736 dev->is_checkpointed = 1;
737 else
738 dev->is_checkpointed = 0;
739
740 return dev->is_checkpointed;
741}
742
743static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
744{
745 int ok = 1;
746
747 if (!dev->param.is_yaffs2)
748 ok = 0;
749
750 if (ok && dev->param.skip_checkpt_rd) {
751 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
752 "skipping checkpoint read");
753 ok = 0;
754 }
755
756 if (ok)
757 ok = yaffs2_checkpt_open(dev, 0); /* open for read */
758
759 if (ok) {
760 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
761 "read checkpoint validity");
762 ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
763 }
764 if (ok) {
765 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
766 "read checkpoint device");
767 ok = yaffs2_rd_checkpt_dev(dev);
768 }
769 if (ok) {
770 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
771 "read checkpoint objects");
772 ok = yaffs2_rd_checkpt_objs(dev);
773 }
774 if (ok) {
775 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
776 "read checkpoint validity");
777 ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
778 }
779
780 if (ok) {
781 ok = yaffs2_rd_checkpt_sum(dev);
782 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
783 "read checkpoint checksum %d", ok);
784 }
785
786 if (!yaffs_checkpt_close(dev))
787 ok = 0;
788
789 if (ok)
790 dev->is_checkpointed = 1;
791 else
792 dev->is_checkpointed = 0;
793
794 return ok ? 1 : 0;
795
796}
797
798void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
799{
800 if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
801 dev->is_checkpointed = 0;
802 yaffs2_checkpt_invalidate_stream(dev);
803 }
804 if (dev->param.sb_dirty_fn)
805 dev->param.sb_dirty_fn(dev);
806}
807
808int yaffs_checkpoint_save(struct yaffs_dev *dev)
809{
810
811 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
812 "save entry: is_checkpointed %d",
813 dev->is_checkpointed);
814
815 yaffs_verify_objects(dev);
816 yaffs_verify_blocks(dev);
817 yaffs_verify_free_chunks(dev);
818
819 if (!dev->is_checkpointed) {
820 yaffs2_checkpt_invalidate(dev);
821 yaffs2_wr_checkpt_data(dev);
822 }
823
824 yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
825 "save exit: is_checkpointed %d",
826 dev->is_checkpointed);
827
828 return dev->is_checkpointed;
829}
830
831int yaffs2_checkpt_restore(struct yaffs_dev *dev)
832{
833 int retval;
834 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
835 "restore entry: is_checkpointed %d",
836 dev->is_checkpointed);
837
838 retval = yaffs2_rd_checkpt_data(dev);
839
840 if (dev->is_checkpointed) {
841 yaffs_verify_objects(dev);
842 yaffs_verify_blocks(dev);
843 yaffs_verify_free_chunks(dev);
844 }
845
846 yaffs_trace(YAFFS_TRACE_CHECKPOINT,
847 "restore exit: is_checkpointed %d",
848 dev->is_checkpointed);
849
850 return retval;
851}
852
853int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
854{
855 /* if new_size > old_file_size.
856 * We're going to be writing a hole.
857 * If the hole is small then write zeros otherwise write a start of hole marker.
858 */
859
860 loff_t old_file_size;
861 int increase;
862 int small_hole;
863 int result = YAFFS_OK;
864 struct yaffs_dev *dev = NULL;
865
866 u8 *local_buffer = NULL;
867
868 int small_increase_ok = 0;
869
870 if (!obj)
871 return YAFFS_FAIL;
872
873 if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
874 return YAFFS_FAIL;
875
876 dev = obj->my_dev;
877
878 /* Bail out if not yaffs2 mode */
879 if (!dev->param.is_yaffs2)
880 return YAFFS_OK;
881
882 old_file_size = obj->variant.file_variant.file_size;
883
884 if (new_size <= old_file_size)
885 return YAFFS_OK;
886
887 increase = new_size - old_file_size;
888
889 if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
890 yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
891 small_hole = 1;
892 else
893 small_hole = 0;
894
895 if (small_hole)
896 local_buffer = yaffs_get_temp_buffer(dev, __LINE__);
897
898 if (local_buffer) {
899 /* fill hole with zero bytes */
900 int pos = old_file_size;
901 int this_write;
902 int written;
903 memset(local_buffer, 0, dev->data_bytes_per_chunk);
904 small_increase_ok = 1;
905
906 while (increase > 0 && small_increase_ok) {
907 this_write = increase;
908 if (this_write > dev->data_bytes_per_chunk)
909 this_write = dev->data_bytes_per_chunk;
910 written =
911 yaffs_do_file_wr(obj, local_buffer, pos, this_write,
912 0);
913 if (written == this_write) {
914 pos += this_write;
915 increase -= this_write;
916 } else {
917 small_increase_ok = 0;
918 }
919 }
920
921 yaffs_release_temp_buffer(dev, local_buffer, __LINE__);
922
923 /* If we were out of space then reverse any chunks we've added */
924 if (!small_increase_ok)
925 yaffs_resize_file_down(obj, old_file_size);
926 }
927
928 if (!small_increase_ok &&
929 obj->parent &&
930 obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
931 obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
932 /* Write a hole start header with the old file size */
933 yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
934 }
935
936 return result;
937
938}
939
940struct yaffs_block_index {
941 int seq;
942 int block;
943};
944
945static int yaffs2_ybicmp(const void *a, const void *b)
946{
947 int aseq = ((struct yaffs_block_index *)a)->seq;
948 int bseq = ((struct yaffs_block_index *)b)->seq;
949 int ablock = ((struct yaffs_block_index *)a)->block;
950 int bblock = ((struct yaffs_block_index *)b)->block;
951 if (aseq == bseq)
952 return ablock - bblock;
953 else
954 return aseq - bseq;
955}
956
957int yaffs2_scan_backwards(struct yaffs_dev *dev)
958{
959 struct yaffs_ext_tags tags;
960 int blk;
961 int block_iter;
962 int start_iter;
963 int end_iter;
964 int n_to_scan = 0;
965
966 int chunk;
967 int result;
968 int c;
969 int deleted;
970 enum yaffs_block_state state;
971 struct yaffs_obj *hard_list = NULL;
972 struct yaffs_block_info *bi;
973 u32 seq_number;
974 struct yaffs_obj_hdr *oh;
975 struct yaffs_obj *in;
976 struct yaffs_obj *parent;
977 int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
978 int is_unlinked;
979 u8 *chunk_data;
980
981 int file_size;
982 int is_shrink;
983 int found_chunks;
984 int equiv_id;
985 int alloc_failed = 0;
986
987 struct yaffs_block_index *block_index = NULL;
988 int alt_block_index = 0;
989
990 yaffs_trace(YAFFS_TRACE_SCAN,
991 "yaffs2_scan_backwards starts intstartblk %d intendblk %d...",
992 dev->internal_start_block, dev->internal_end_block);
993
994 dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
995
996 block_index = kmalloc(n_blocks * sizeof(struct yaffs_block_index),
997 GFP_NOFS);
998
999 if (!block_index) {
1000 block_index =
1001 vmalloc(n_blocks * sizeof(struct yaffs_block_index));
1002 alt_block_index = 1;
1003 }
1004
1005 if (!block_index) {
1006 yaffs_trace(YAFFS_TRACE_SCAN,
1007 "yaffs2_scan_backwards() could not allocate block index!"
1008 );
1009 return YAFFS_FAIL;
1010 }
1011
1012 dev->blocks_in_checkpt = 0;
1013
1014 chunk_data = yaffs_get_temp_buffer(dev, __LINE__);
1015
1016 /* Scan all the blocks to determine their state */
1017 bi = dev->block_info;
1018 for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
1019 blk++) {
1020 yaffs_clear_chunk_bits(dev, blk);
1021 bi->pages_in_use = 0;
1022 bi->soft_del_pages = 0;
1023
1024 yaffs_query_init_block_state(dev, blk, &state, &seq_number);
1025
1026 bi->block_state = state;
1027 bi->seq_number = seq_number;
1028
1029 if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
1030 bi->block_state = state = YAFFS_BLOCK_STATE_CHECKPOINT;
1031 if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
1032 bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
1033
1034 yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
1035 "Block scanning block %d state %d seq %d",
1036 blk, state, seq_number);
1037
1038 if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
1039 dev->blocks_in_checkpt++;
1040
1041 } else if (state == YAFFS_BLOCK_STATE_DEAD) {
1042 yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
1043 "block %d is bad", blk);
1044 } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
1045 yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
1046 dev->n_erased_blocks++;
1047 dev->n_free_chunks += dev->param.chunks_per_block;
1048 } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
1049
1050 /* Determine the highest sequence number */
1051 if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
1052 seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
1053
1054 block_index[n_to_scan].seq = seq_number;
1055 block_index[n_to_scan].block = blk;
1056
1057 n_to_scan++;
1058
1059 if (seq_number >= dev->seq_number)
1060 dev->seq_number = seq_number;
1061 } else {
1062 /* TODO: Nasty sequence number! */
1063 yaffs_trace(YAFFS_TRACE_SCAN,
1064 "Block scanning block %d has bad sequence number %d",
1065 blk, seq_number);
1066
1067 }
1068 }
1069 bi++;
1070 }
1071
1072 yaffs_trace(YAFFS_TRACE_SCAN, "%d blocks to be sorted...", n_to_scan);
1073
1074 cond_resched();
1075
1076 /* Sort the blocks by sequence number */
1077 sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
1078 yaffs2_ybicmp, NULL);
1079
1080 cond_resched();
1081
1082 yaffs_trace(YAFFS_TRACE_SCAN, "...done");
1083
1084 /* Now scan the blocks looking at the data. */
1085 start_iter = 0;
1086 end_iter = n_to_scan - 1;
1087 yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
1088
1089 /* For each block.... backwards */
1090 for (block_iter = end_iter; !alloc_failed && block_iter >= start_iter;
1091 block_iter--) {
1092 /* Cooperative multitasking! This loop can run for so
1093 long that watchdog timers expire. */
1094 cond_resched();
1095
1096 /* get the block to scan in the correct order */
1097 blk = block_index[block_iter].block;
1098
1099 bi = yaffs_get_block_info(dev, blk);
1100
1101 state = bi->block_state;
1102
1103 deleted = 0;
1104
1105 /* For each chunk in each block that needs scanning.... */
1106 found_chunks = 0;
1107 for (c = dev->param.chunks_per_block - 1;
1108 !alloc_failed && c >= 0 &&
1109 (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
1110 state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
1111 /* Scan backwards...
1112 * Read the tags and decide what to do
1113 */
1114
1115 chunk = blk * dev->param.chunks_per_block + c;
1116
1117 result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
1118 &tags);
1119
1120 /* Let's have a good look at this chunk... */
1121
1122 if (!tags.chunk_used) {
1123 /* An unassigned chunk in the block.
1124 * If there are used chunks after this one, then
1125 * it is a chunk that was skipped due to failing the erased
1126 * check. Just skip it so that it can be deleted.
1127 * But, more typically, We get here when this is an unallocated
1128 * chunk and his means that either the block is empty or
1129 * this is the one being allocated from
1130 */
1131
1132 if (found_chunks) {
1133 /* This is a chunk that was skipped due to failing the erased check */
1134 } else if (c == 0) {
1135 /* We're looking at the first chunk in the block so the block is unused */
1136 state = YAFFS_BLOCK_STATE_EMPTY;
1137 dev->n_erased_blocks++;
1138 } else {
1139 if (state ==
1140 YAFFS_BLOCK_STATE_NEEDS_SCANNING
1141 || state ==
1142 YAFFS_BLOCK_STATE_ALLOCATING) {
1143 if (dev->seq_number ==
1144 bi->seq_number) {
1145 /* this is the block being allocated from */
1146
1147 yaffs_trace(YAFFS_TRACE_SCAN,
1148 " Allocating from %d %d",
1149 blk, c);
1150
1151 state =
1152 YAFFS_BLOCK_STATE_ALLOCATING;
1153 dev->alloc_block = blk;
1154 dev->alloc_page = c;
1155 dev->
1156 alloc_block_finder =
1157 blk;
1158 } else {
1159 /* This is a partially written block that is not
1160 * the current allocation block.
1161 */
1162
1163 yaffs_trace(YAFFS_TRACE_SCAN,
1164 "Partially written block %d detected",
1165 blk);
1166 }
1167 }
1168 }
1169
1170 dev->n_free_chunks++;
1171
1172 } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
1173 yaffs_trace(YAFFS_TRACE_SCAN,
1174 " Unfixed ECC in chunk(%d:%d), chunk ignored",
1175 blk, c);
1176
1177 dev->n_free_chunks++;
1178
1179 } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
1180 tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
1181 (tags.chunk_id > 0
1182 && tags.n_bytes > dev->data_bytes_per_chunk)
1183 || tags.seq_number != bi->seq_number) {
1184 yaffs_trace(YAFFS_TRACE_SCAN,
1185 "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
1186 blk, c, tags.obj_id,
1187 tags.chunk_id, tags.n_bytes);
1188
1189 dev->n_free_chunks++;
1190
1191 } else if (tags.chunk_id > 0) {
1192 /* chunk_id > 0 so it is a data chunk... */
1193 unsigned int endpos;
1194 u32 chunk_base =
1195 (tags.chunk_id -
1196 1) * dev->data_bytes_per_chunk;
1197
1198 found_chunks = 1;
1199
1200 yaffs_set_chunk_bit(dev, blk, c);
1201 bi->pages_in_use++;
1202
1203 in = yaffs_find_or_create_by_number(dev,
1204 tags.obj_id,
1205 YAFFS_OBJECT_TYPE_FILE);
1206 if (!in) {
1207 /* Out of memory */
1208 alloc_failed = 1;
1209 }
1210
1211 if (in &&
1212 in->variant_type == YAFFS_OBJECT_TYPE_FILE
1213 && chunk_base <
1214 in->variant.file_variant.shrink_size) {
1215 /* This has not been invalidated by a resize */
1216 if (!yaffs_put_chunk_in_file
1217 (in, tags.chunk_id, chunk, -1)) {
1218 alloc_failed = 1;
1219 }
1220
1221 /* File size is calculated by looking at the data chunks if we have not
1222 * seen an object header yet. Stop this practice once we find an object header.
1223 */
1224 endpos = chunk_base + tags.n_bytes;
1225
1226 if (!in->valid && /* have not got an object header yet */
1227 in->variant.file_variant.
1228 scanned_size < endpos) {
1229 in->variant.file_variant.
1230 scanned_size = endpos;
1231 in->variant.file_variant.
1232 file_size = endpos;
1233 }
1234
1235 } else if (in) {
1236 /* This chunk has been invalidated by a resize, or a past file deletion
1237 * so delete the chunk*/
1238 yaffs_chunk_del(dev, chunk, 1,
1239 __LINE__);
1240
1241 }
1242 } else {
1243 /* chunk_id == 0, so it is an ObjectHeader.
1244 * Thus, we read in the object header and make the object
1245 */
1246 found_chunks = 1;
1247
1248 yaffs_set_chunk_bit(dev, blk, c);
1249 bi->pages_in_use++;
1250
1251 oh = NULL;
1252 in = NULL;
1253
1254 if (tags.extra_available) {
1255 in = yaffs_find_or_create_by_number(dev,
1256 tags.
1257 obj_id,
1258 tags.
1259 extra_obj_type);
1260 if (!in)
1261 alloc_failed = 1;
1262 }
1263
1264 if (!in ||
1265 (!in->valid && dev->param.disable_lazy_load)
1266 || tags.extra_shadows || (!in->valid
1267 && (tags.obj_id ==
1268 YAFFS_OBJECTID_ROOT
1269 || tags.
1270 obj_id ==
1271 YAFFS_OBJECTID_LOSTNFOUND)))
1272 {
1273
1274 /* If we don't have valid info then we need to read the chunk
1275 * TODO In future we can probably defer reading the chunk and
1276 * living with invalid data until needed.
1277 */
1278
1279 result = yaffs_rd_chunk_tags_nand(dev,
1280 chunk,
1281 chunk_data,
1282 NULL);
1283
1284 oh = (struct yaffs_obj_hdr *)chunk_data;
1285
1286 if (dev->param.inband_tags) {
1287 /* Fix up the header if they got corrupted by inband tags */
1288 oh->shadows_obj =
1289 oh->inband_shadowed_obj_id;
1290 oh->is_shrink =
1291 oh->inband_is_shrink;
1292 }
1293
1294 if (!in) {
1295 in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type);
1296 if (!in)
1297 alloc_failed = 1;
1298 }
1299
1300 }
1301
1302 if (!in) {
1303 /* TODO Hoosterman we have a problem! */
1304 yaffs_trace(YAFFS_TRACE_ERROR,
1305 "yaffs tragedy: Could not make object for object %d at chunk %d during scan",
1306 tags.obj_id, chunk);
1307 continue;
1308 }
1309
1310 if (in->valid) {
1311 /* We have already filled this one.
1312 * We have a duplicate that will be discarded, but
1313 * we first have to suck out resize info if it is a file.
1314 */
1315
1316 if ((in->variant_type ==
1317 YAFFS_OBJECT_TYPE_FILE) && ((oh
1318 &&
1319 oh->
1320 type
1321 ==
1322 YAFFS_OBJECT_TYPE_FILE)
1323 ||
1324 (tags.
1325 extra_available
1326 &&
1327 tags.
1328 extra_obj_type
1329 ==
1330 YAFFS_OBJECT_TYPE_FILE)))
1331 {
1332 u32 this_size =
1333 (oh) ? oh->
1334 file_size :
1335 tags.extra_length;
1336 u32 parent_obj_id =
1337 (oh) ? oh->parent_obj_id :
1338 tags.extra_parent_id;
1339
1340 is_shrink =
1341 (oh) ? oh->
1342 is_shrink :
1343 tags.extra_is_shrink;
1344
1345 /* If it is deleted (unlinked at start also means deleted)
1346 * we treat the file size as being zeroed at this point.
1347 */
1348 if (parent_obj_id ==
1349 YAFFS_OBJECTID_DELETED
1350 || parent_obj_id ==
1351 YAFFS_OBJECTID_UNLINKED) {
1352 this_size = 0;
1353 is_shrink = 1;
1354 }
1355
1356 if (is_shrink
1357 && in->variant.file_variant.
1358 shrink_size > this_size)
1359 in->variant.
1360 file_variant.
1361 shrink_size =
1362 this_size;
1363
1364 if (is_shrink)
1365 bi->has_shrink_hdr = 1;
1366
1367 }
1368 /* Use existing - destroy this one. */
1369 yaffs_chunk_del(dev, chunk, 1,
1370 __LINE__);
1371
1372 }
1373
1374 if (!in->valid && in->variant_type !=
1375 (oh ? oh->type : tags.extra_obj_type))
1376 yaffs_trace(YAFFS_TRACE_ERROR,
1377 "yaffs tragedy: Bad object type, %d != %d, for object %d at chunk %d during scan",
1378 oh ?
1379 oh->type : tags.extra_obj_type,
1380 in->variant_type, tags.obj_id,
1381 chunk);
1382
1383 if (!in->valid &&
1384 (tags.obj_id == YAFFS_OBJECTID_ROOT ||
1385 tags.obj_id ==
1386 YAFFS_OBJECTID_LOSTNFOUND)) {
1387 /* We only load some info, don't fiddle with directory structure */
1388 in->valid = 1;
1389
1390 if (oh) {
1391
1392 in->yst_mode = oh->yst_mode;
1393 yaffs_load_attribs(in, oh);
1394 in->lazy_loaded = 0;
1395 } else {
1396 in->lazy_loaded = 1;
1397 }
1398 in->hdr_chunk = chunk;
1399
1400 } else if (!in->valid) {
1401 /* we need to load this info */
1402
1403 in->valid = 1;
1404 in->hdr_chunk = chunk;
1405
1406 if (oh) {
1407 in->variant_type = oh->type;
1408
1409 in->yst_mode = oh->yst_mode;
1410 yaffs_load_attribs(in, oh);
1411
1412 if (oh->shadows_obj > 0)
1413 yaffs_handle_shadowed_obj
1414 (dev,
1415 oh->shadows_obj,
1416 1);
1417
1418 yaffs_set_obj_name_from_oh(in,
1419 oh);
1420 parent =
1421 yaffs_find_or_create_by_number
1422 (dev, oh->parent_obj_id,
1423 YAFFS_OBJECT_TYPE_DIRECTORY);
1424
1425 file_size = oh->file_size;
1426 is_shrink = oh->is_shrink;
1427 equiv_id = oh->equiv_id;
1428
1429 } else {
1430 in->variant_type =
1431 tags.extra_obj_type;
1432 parent =
1433 yaffs_find_or_create_by_number
1434 (dev, tags.extra_parent_id,
1435 YAFFS_OBJECT_TYPE_DIRECTORY);
1436 file_size = tags.extra_length;
1437 is_shrink =
1438 tags.extra_is_shrink;
1439 equiv_id = tags.extra_equiv_id;
1440 in->lazy_loaded = 1;
1441
1442 }
1443 in->dirty = 0;
1444
1445 if (!parent)
1446 alloc_failed = 1;
1447
1448 /* directory stuff...
1449 * hook up to parent
1450 */
1451
1452 if (parent && parent->variant_type ==
1453 YAFFS_OBJECT_TYPE_UNKNOWN) {
1454 /* Set up as a directory */
1455 parent->variant_type =
1456 YAFFS_OBJECT_TYPE_DIRECTORY;
1457 INIT_LIST_HEAD(&parent->
1458 variant.dir_variant.children);
1459 } else if (!parent
1460 || parent->variant_type !=
1461 YAFFS_OBJECT_TYPE_DIRECTORY) {
1462 /* Hoosterman, another problem....
1463 * We're trying to use a non-directory as a directory
1464 */
1465
1466 yaffs_trace(YAFFS_TRACE_ERROR,
1467 "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
1468 );
1469 parent = dev->lost_n_found;
1470 }
1471
1472 yaffs_add_obj_to_dir(parent, in);
1473
1474 is_unlinked = (parent == dev->del_dir)
1475 || (parent == dev->unlinked_dir);
1476
1477 if (is_shrink) {
1478 /* Mark the block as having a shrink header */
1479 bi->has_shrink_hdr = 1;
1480 }
1481
1482 /* Note re hardlinks.
1483 * Since we might scan a hardlink before its equivalent object is scanned
1484 * we put them all in a list.
1485 * After scanning is complete, we should have all the objects, so we run
1486 * through this list and fix up all the chains.
1487 */
1488
1489 switch (in->variant_type) {
1490 case YAFFS_OBJECT_TYPE_UNKNOWN:
1491 /* Todo got a problem */
1492 break;
1493 case YAFFS_OBJECT_TYPE_FILE:
1494
1495 if (in->variant.
1496 file_variant.scanned_size <
1497 file_size) {
1498 /* This covers the case where the file size is greater
1499 * than where the data is
1500 * This will happen if the file is resized to be larger
1501 * than its current data extents.
1502 */
1503 in->variant.
1504 file_variant.
1505 file_size =
1506 file_size;
1507 in->variant.
1508 file_variant.
1509 scanned_size =
1510 file_size;
1511 }
1512
1513 if (in->variant.file_variant.
1514 shrink_size > file_size)
1515 in->variant.
1516 file_variant.
1517 shrink_size =
1518 file_size;
1519
1520 break;
1521 case YAFFS_OBJECT_TYPE_HARDLINK:
1522 if (!is_unlinked) {
1523 in->variant.
1524 hardlink_variant.
1525 equiv_id = equiv_id;
1526 in->hard_links.next =
1527 (struct list_head *)
1528 hard_list;
1529 hard_list = in;
1530 }
1531 break;
1532 case YAFFS_OBJECT_TYPE_DIRECTORY:
1533 /* Do nothing */
1534 break;
1535 case YAFFS_OBJECT_TYPE_SPECIAL:
1536 /* Do nothing */
1537 break;
1538 case YAFFS_OBJECT_TYPE_SYMLINK:
1539 if (oh) {
1540 in->variant.
1541 symlink_variant.
1542 alias =
1543 yaffs_clone_str(oh->
1544 alias);
1545 if (!in->variant.
1546 symlink_variant.
1547 alias)
1548 alloc_failed =
1549 1;
1550 }
1551 break;
1552 }
1553
1554 }
1555
1556 }
1557
1558 } /* End of scanning for each chunk */
1559
1560 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
1561 /* If we got this far while scanning, then the block is fully allocated. */
1562 state = YAFFS_BLOCK_STATE_FULL;
1563 }
1564
1565 bi->block_state = state;
1566
1567 /* Now let's see if it was dirty */
1568 if (bi->pages_in_use == 0 &&
1569 !bi->has_shrink_hdr &&
1570 bi->block_state == YAFFS_BLOCK_STATE_FULL) {
1571 yaffs_block_became_dirty(dev, blk);
1572 }
1573
1574 }
1575
1576 yaffs_skip_rest_of_block(dev);
1577
1578 if (alt_block_index)
1579 vfree(block_index);
1580 else
1581 kfree(block_index);
1582
1583 /* Ok, we've done all the scanning.
1584 * Fix up the hard link chains.
1585 * We should now have scanned all the objects, now it's time to add these
1586 * hardlinks.
1587 */
1588 yaffs_link_fixup(dev, hard_list);
1589
1590 yaffs_release_temp_buffer(dev, chunk_data, __LINE__);
1591
1592 if (alloc_failed)
1593 return YAFFS_FAIL;
1594
1595 yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
1596
1597 return YAFFS_OK;
1598}
diff --git a/fs/yaffs2/yaffs_yaffs2.h b/fs/yaffs2/yaffs_yaffs2.h
new file mode 100644
index 00000000000..e1a9287fc50
--- /dev/null
+++ b/fs/yaffs2/yaffs_yaffs2.h
@@ -0,0 +1,39 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YAFFS_YAFFS2_H__
17#define __YAFFS_YAFFS2_H__
18
19#include "yaffs_guts.h"
20
21void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
22void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
23void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
24 struct yaffs_block_info *bi);
25void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
26 struct yaffs_block_info *bi);
27int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
28u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
29int yaffs2_checkpt_required(struct yaffs_dev *dev);
30int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
31
32void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
33int yaffs2_checkpt_save(struct yaffs_dev *dev);
34int yaffs2_checkpt_restore(struct yaffs_dev *dev);
35
36int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
37int yaffs2_scan_backwards(struct yaffs_dev *dev);
38
39#endif
diff --git a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h
new file mode 100644
index 00000000000..8183425448c
--- /dev/null
+++ b/fs/yaffs2/yportenv.h
@@ -0,0 +1,70 @@
1/*
2 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
12 *
13 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14 */
15
16#ifndef __YPORTENV_LINUX_H__
17#define __YPORTENV_LINUX_H__
18
19#include <linux/version.h>
20#include <linux/kernel.h>
21#include <linux/mm.h>
22#include <linux/sched.h>
23#include <linux/string.h>
24#include <linux/slab.h>
25#include <linux/vmalloc.h>
26#include <linux/xattr.h>
27#include <linux/list.h>
28#include <linux/types.h>
29#include <linux/fs.h>
30#include <linux/stat.h>
31#include <linux/sort.h>
32#include <linux/bitops.h>
33
34#define YCHAR char
35#define YUCHAR unsigned char
36#define _Y(x) x
37
38#define YAFFS_LOSTNFOUND_NAME "lost+found"
39#define YAFFS_LOSTNFOUND_PREFIX "obj"
40
41
42#define YAFFS_ROOT_MODE 0755
43#define YAFFS_LOSTNFOUND_MODE 0700
44
45#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
46#define Y_TIME_CONVERT(x) (x).tv_sec
47
48#define compile_time_assertion(assertion) \
49 ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
50
51
52#ifndef Y_DUMP_STACK
53#define Y_DUMP_STACK() dump_stack()
54#endif
55
56#define yaffs_trace(msk, fmt, ...) do { \
57 if(yaffs_trace_mask & (msk)) \
58 printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
59} while(0)
60
61#ifndef YBUG
62#define YBUG() do {\
63 yaffs_trace(YAFFS_TRACE_BUG,\
64 "bug " __FILE__ " %d",\
65 __LINE__);\
66 Y_DUMP_STACK();\
67} while (0)
68#endif
69
70#endif