OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [ntfs/] [super.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * super.c
3
 *
4
 * Copyright (C) 1995-1997, 1999 Martin von Löwis
5
 * Copyright (C) 1996-1997 Régis Duchesne
6
 * Copyright (C) 1999 Steve Dodd
7
 * Copyright (C) 2000-2001 Anton Altparmakov (AIA)
8
 */
9
 
10
#include <linux/ntfs_fs.h>
11
#include <linux/errno.h>
12
#include <linux/bitops.h>
13
#include <linux/module.h>
14
#include "ntfstypes.h"
15
#include "struct.h"
16
#include "super.h"
17
#include "macros.h"
18
#include "inode.h"
19
#include "support.h"
20
#include "util.h"
21
#include <linux/smp_lock.h>
22
 
23
/* All important structures in NTFS use 2 consistency checks:
24
 * . a magic structure identifier (FILE, INDX, RSTR, RCRD...)
25
 * . a fixup technique : the last word of each sector (called a fixup) of a
26
 *   structure's record should end with the word at offset <n> of the first
27
 *   sector, and if it is the case, must be replaced with the words following
28
 *   <n>. The value of <n> and the number of fixups is taken from the fields
29
 *   at the offsets 4 and 6. Note that the sector size is defined as
30
 *   NTFS_SECTOR_SIZE and not as the hardware sector size (this is concordant
31
 *   with what the Windows NTFS driver does).
32
 *
33
 * This function performs these 2 checks, and _fails_ if:
34
 * . the input size is invalid
35
 * . the fixup header is invalid
36
 * . the size does not match the number of sectors
37
 * . the magic identifier is wrong
38
 * . a fixup is invalid
39
 */
40
int ntfs_fixup_record(char *record, char *magic, int size)
41
{
42
        int start, count, offset;
43
        ntfs_u16 fixup;
44
 
45
        if (!IS_MAGIC(record, magic))
46
                return 0;
47
        start = NTFS_GETU16(record + 4);
48
        count = NTFS_GETU16(record + 6) - 1;
49
        if (size & (NTFS_SECTOR_SIZE - 1) || start & 1 ||
50
                        start + count * 2 > size || size >> 9 != count) {
51
                if (size <= 0)
52
                        printk(KERN_ERR "NTFS: BUG: ntfs_fixup_record() got "
53
                                        "zero size! Please report this to "
54
                                        "linux-ntfs-dev@lists.sf.net\n");
55
                return 0;
56
        }
57
        fixup = NTFS_GETU16(record + start);
58
        start += 2;
59
        offset = NTFS_SECTOR_SIZE - 2;
60
        while (count--) {
61
                if (NTFS_GETU16(record + offset) != fixup)
62
                        return 0;
63
                NTFS_PUTU16(record + offset, NTFS_GETU16(record + start));
64
                start += 2;
65
                offset += NTFS_SECTOR_SIZE;
66
        }
67
        return 1;
68
}
69
 
70
/*
71
 * Get vital informations about the ntfs partition from the boot sector.
72
 * Return 0 on success or -1 on error.
73
 */
74
int ntfs_init_volume(ntfs_volume *vol, char *boot)
75
{
76
        int sectors_per_cluster_bits;
77
        __s64 ll;
78
        ntfs_cluster_t mft_zone_size, tc;
79
 
80
        /* System defined default values, in case we don't load $AttrDef. */
81
        vol->at_standard_information = 0x10;
82
        vol->at_attribute_list = 0x20;
83
        vol->at_file_name = 0x30;
84
        vol->at_volume_version = 0x40;
85
        vol->at_security_descriptor = 0x50;
86
        vol->at_volume_name = 0x60;
87
        vol->at_volume_information = 0x70;
88
        vol->at_data = 0x80;
89
        vol->at_index_root = 0x90;
90
        vol->at_index_allocation = 0xA0;
91
        vol->at_bitmap = 0xB0;
92
        vol->at_symlink = 0xC0;
93
        /* Sector size. */
94
        vol->sector_size = NTFS_GETU16(boot + 0xB);
95
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->sector_size = 0x%x\n",
96
                                vol->sector_size);
97
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: sectors_per_cluster = "
98
                                "0x%x\n", NTFS_GETU8(boot + 0xD));
99
        sectors_per_cluster_bits = ffs(NTFS_GETU8(boot + 0xD)) - 1;
100
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: sectors_per_cluster_bits "
101
                                "= 0x%x\n", sectors_per_cluster_bits);
102
        vol->mft_clusters_per_record = NTFS_GETS8(boot + 0x40);
103
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_clusters_per_record"
104
                                " = 0x%x\n", vol->mft_clusters_per_record);
105
        vol->index_clusters_per_record = NTFS_GETS8(boot + 0x44);
106
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: "
107
                                "vol->index_clusters_per_record = 0x%x\n",
108
                                vol->index_clusters_per_record);
109
        vol->cluster_size = vol->sector_size << sectors_per_cluster_bits;
110
        vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
111
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->cluster_size = 0x%x\n",
112
                                vol->cluster_size);
113
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->cluster_size_bits = "
114
                                "0x%x\n", vol->cluster_size_bits);
115
        if (vol->mft_clusters_per_record > 0)
116
                vol->mft_record_size = vol->cluster_size <<
117
                                (ffs(vol->mft_clusters_per_record) - 1);
118
        else
119
                /*
120
                 * When mft_record_size < cluster_size, mft_clusters_per_record
121
                 * = -log2(mft_record_size) bytes. mft_record_size normaly is
122
                 * 1024 bytes, which is encoded as 0xF6 (-10 in decimal).
123
                 */
124
                vol->mft_record_size = 1 << -vol->mft_clusters_per_record;
125
        vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
126
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_record_size = 0x%x"
127
                                "\n", vol->mft_record_size);
128
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_record_size_bits = "
129
                                "0x%x\n", vol->mft_record_size_bits);
130
        if (vol->index_clusters_per_record > 0)
131
                vol->index_record_size = vol->cluster_size <<
132
                                (ffs(vol->index_clusters_per_record) - 1);
133
        else
134
                /*
135
                 * When index_record_size < cluster_size,
136
                 * index_clusters_per_record = -log2(index_record_size) bytes.
137
                 * index_record_size normaly equals 4096 bytes, which is
138
                 * encoded as 0xF4 (-12 in decimal).
139
                 */
140
                vol->index_record_size = 1 << -vol->index_clusters_per_record;
141
        vol->index_record_size_bits = ffs(vol->index_record_size) - 1;
142
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->index_record_size = "
143
                                "0x%x\n", vol->index_record_size);
144
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->index_record_size_bits "
145
                                "= 0x%x\n", vol->index_record_size_bits);
146
        /*
147
         * Get the size of the volume in clusters (ofs 0x28 is nr_sectors) and
148
         * check for 64-bit-ness. Windows currently only uses 32 bits to save
149
         * the clusters so we do the same as it is much faster on 32-bit CPUs.
150
         */
151
        ll = NTFS_GETS64(boot + 0x28) >> sectors_per_cluster_bits;
152
        if (ll >= (__s64)1 << 31) {
153
                ntfs_error("Cannot handle 64-bit clusters. Please inform "
154
                                "linux-ntfs-dev@lists.sf.net that you got this "
155
                                "error.\n");
156
                return -1;
157
        }
158
        vol->nr_clusters = (ntfs_cluster_t)ll;
159
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->nr_clusters = 0x%x\n",
160
                        vol->nr_clusters);
161
        vol->mft_lcn = (ntfs_cluster_t)NTFS_GETS64(boot + 0x30);
162
        vol->mft_mirr_lcn = (ntfs_cluster_t)NTFS_GETS64(boot + 0x38);
163
        /* Determine MFT zone size. */
164
        mft_zone_size = vol->nr_clusters;
165
        switch (vol->mft_zone_multiplier) {  /* % of volume size in clusters */
166
        case 4:
167
                mft_zone_size >>= 1;                    /* 50%   */
168
                break;
169
        case 3:
170
                mft_zone_size = mft_zone_size * 3 >> 3; /* 37.5% */
171
                break;
172
        case 2:
173
                mft_zone_size >>= 2;                    /* 25%   */
174
                break;
175
        /* case 1: */
176
        default:
177
                mft_zone_size >>= 3;                    /* 12.5% */
178
                break;
179
        }
180
        /* Setup mft zone. */
181
        vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;
182
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_zone_pos = %x\n",
183
                        vol->mft_zone_pos);
184
        /*
185
         * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs
186
         * source) and if the actual mft_lcn is in the expected place or even
187
         * further to the front of the volume, extend the mft_zone to cover the
188
         * beginning of the volume as well. This is in order to protect the
189
         * area reserved for the mft bitmap as well within the mft_zone itself.
190
         * On non-standard volumes we don't protect it as well as the overhead
191
         * would be higher than the speed increase we would get by doing it.
192
         */
193
        tc = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size;
194
        if (tc * vol->cluster_size < 16 * 1024)
195
                tc = (16 * 1024 + vol->cluster_size - 1) / vol->cluster_size;
196
        if (vol->mft_zone_start <= tc)
197
                vol->mft_zone_start = (ntfs_cluster_t)0;
198
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_zone_start = %x\n",
199
                        vol->mft_zone_start);
200
        /*
201
         * Need to cap the mft zone on non-standard volumes so that it does
202
         * not point outside the boundaries of the volume, we do this by
203
         * halving the zone size until we are inside the volume.
204
         */
205
        vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
206
        while (vol->mft_zone_end >= vol->nr_clusters) {
207
                mft_zone_size >>= 1;
208
                vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
209
        }
210
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_zone_end = %x\n",
211
                        vol->mft_zone_end);
212
        /*
213
         * Set the current position within each data zone to the start of the
214
         * respective zone.
215
         */
216
        vol->data1_zone_pos = vol->mft_zone_end;
217
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->data1_zone_pos = %x\n",
218
                        vol->data1_zone_pos);
219
        vol->data2_zone_pos = (ntfs_cluster_t)0;
220
        ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->data2_zone_pos = %x\n",
221
                        vol->data2_zone_pos);
222
        /* Set the mft data allocation position to mft record 24. */
223
        vol->mft_data_pos = 24UL;
224
        /* This will be initialized later. */
225
        vol->upcase = 0;
226
        vol->upcase_length = 0;
227
        vol->mft_ino = 0;
228
        return 0;
229
}
230
 
231
static void ntfs_init_upcase(ntfs_inode *upcase)
232
{
233
        ntfs_io io;
234
#define UPCASE_LENGTH  256
235
        upcase->vol->upcase = ntfs_malloc(UPCASE_LENGTH << 1);
236
        if (!upcase->vol->upcase)
237
                return;
238
        io.fn_put = ntfs_put;
239
        io.fn_get = 0;
240
        io.param = (char*)upcase->vol->upcase;
241
        io.size = UPCASE_LENGTH << 1;
242
        ntfs_read_attr(upcase, upcase->vol->at_data, 0, 0, &io);
243
        upcase->vol->upcase_length = io.size >> 1;
244
}
245
 
246
static int process_attrdef(ntfs_inode* attrdef, ntfs_u8* def)
247
{
248
        int type = NTFS_GETU32(def+0x80);
249
        int check_type = 0;
250
        ntfs_volume *vol = attrdef->vol;
251
        ntfs_u16* name = (ntfs_u16*)def;
252
 
253
        if (!type) {
254
                ntfs_debug(DEBUG_OTHER, "process_atrdef: finished processing "
255
                                                        "and returning 1\n");
256
                return 1;
257
        }
258
        if (ntfs_ua_strncmp(name, "$STANDARD_INFORMATION", 64) == 0) {
259
                vol->at_standard_information = type;
260
                check_type = 0x10;
261
        } else if (ntfs_ua_strncmp(name, "$ATTRIBUTE_LIST", 64) == 0) {
262
                vol->at_attribute_list = type;
263
                check_type = 0x20;
264
        } else if (ntfs_ua_strncmp(name, "$FILE_NAME", 64) == 0) {
265
                vol->at_file_name = type;
266
                check_type = 0x30;
267
        } else if (ntfs_ua_strncmp(name, "$VOLUME_VERSION", 64) == 0) {
268
                vol->at_volume_version = type;
269
                check_type = 0x40;
270
        } else if (ntfs_ua_strncmp(name, "$SECURITY_DESCRIPTOR", 64) == 0) {
271
                vol->at_security_descriptor = type;
272
                check_type = 0x50;
273
        } else if (ntfs_ua_strncmp(name, "$VOLUME_NAME", 64) == 0) {
274
                vol->at_volume_name = type;
275
                check_type = 0x60;
276
        } else if (ntfs_ua_strncmp(name, "$VOLUME_INFORMATION", 64) == 0) {
277
                vol->at_volume_information = type;
278
                check_type = 0x70;
279
        } else if (ntfs_ua_strncmp(name, "$DATA", 64) == 0) {
280
                vol->at_data = type;
281
                check_type = 0x80;
282
        } else if (ntfs_ua_strncmp(name, "$INDEX_ROOT", 64) == 0) {
283
                vol->at_index_root = type;
284
                check_type = 0x90;
285
        } else if (ntfs_ua_strncmp(name, "$INDEX_ALLOCATION", 64) == 0) {
286
                vol->at_index_allocation = type;
287
                check_type = 0xA0;
288
        } else if (ntfs_ua_strncmp(name, "$BITMAP", 64) == 0) {
289
                vol->at_bitmap = type;
290
                check_type = 0xB0;
291
        } else if (ntfs_ua_strncmp(name, "$SYMBOLIC_LINK", 64) == 0 ||
292
                 ntfs_ua_strncmp(name, "$REPARSE_POINT", 64) == 0) {
293
                vol->at_symlink = type;
294
                check_type = 0xC0;
295
        }
296
        if (check_type && check_type != type) {
297
                ntfs_error("process_attrdef: unexpected type 0x%x for 0x%x\n",
298
                                                        type, check_type);
299
                return -EINVAL;
300
        }
301
        ntfs_debug(DEBUG_OTHER, "process_attrdef: found %s attribute of type "
302
                        "0x%x\n", check_type ? "known" : "unknown", type);
303
        return 0;
304
}
305
 
306
int ntfs_init_attrdef(ntfs_inode* attrdef)
307
{
308
        ntfs_u8 *buf;
309
        ntfs_io io;
310
        __s64 offset;
311
        unsigned i;
312
        int error;
313
        ntfs_attribute *data;
314
 
315
        ntfs_debug(DEBUG_BSD, "Entered ntfs_init_attrdef()\n");
316
        buf = ntfs_malloc(4050); /* 90*45 */
317
        if (!buf)
318
                return -ENOMEM;
319
        io.fn_put = ntfs_put;
320
        io.fn_get = ntfs_get;
321
        io.do_read = 1;
322
        offset = 0;
323
        data = ntfs_find_attr(attrdef, attrdef->vol->at_data, 0);
324
        ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after call to "
325
                        "ntfs_find_attr.\n");
326
        if (!data) {
327
                ntfs_free(buf);
328
                return -EINVAL;
329
        }
330
        do {
331
                io.param = buf;
332
                io.size = 4050;
333
                ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() going to call "
334
                                "ntfs_readwrite_attr.\n");
335
                error = ntfs_readwrite_attr(attrdef, data, offset, &io);
336
                ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after call to "
337
                                "ntfs_readwrite_attr.\n");
338
                for (i = 0; !error && i <= io.size - 0xA0; i += 0xA0) {
339
                        ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() going "
340
                                        "to call process_attrdef.\n");
341
                        error = process_attrdef(attrdef, buf + i);
342
                        ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after "
343
                                        "call to process_attrdef.\n");
344
                }
345
                offset += 4096;
346
        } while (!error && io.size);
347
        ntfs_debug(DEBUG_BSD, "Exiting ntfs_init_attrdef()\n");
348
        ntfs_free(buf);
349
        return error == 1 ? 0 : error;
350
}
351
 
352
/* ntfs_get_version will determine the NTFS version of the volume and will
353
 * return the version in a BCD format, with the MSB being the major version
354
 * number and the LSB the minor one. Otherwise return <0 on error.
355
 * Example: version 3.1 will be returned as 0x0301. This has the obvious
356
 * limitation of not coping with version numbers above 0x80 but that shouldn't
357
 * be a problem... */
358
int ntfs_get_version(ntfs_inode* volume)
359
{
360
        ntfs_attribute *volinfo;
361
 
362
        volinfo = ntfs_find_attr(volume, volume->vol->at_volume_information, 0);
363
        if (!volinfo)
364
                return -EINVAL;
365
        if (!volinfo->resident) {
366
                ntfs_error("Volume information attribute is not resident!\n");
367
                return -EINVAL;
368
        }
369
        return ((ntfs_u8*)volinfo->d.data)[8] << 8 |
370
               ((ntfs_u8*)volinfo->d.data)[9];
371
}
372
 
373
int ntfs_load_special_files(ntfs_volume *vol)
374
{
375
        int error;
376
        ntfs_inode upcase, attrdef, volume;
377
 
378
        vol->mft_ino = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode));
379
        vol->mftmirr = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode));
380
        vol->bitmap = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode));
381
        vol->ino_flags = 4 | 2 | 1;
382
        error = -ENOMEM;
383
        ntfs_debug(DEBUG_BSD, "Going to load MFT\n");
384
        if (!vol->mft_ino || (error = ntfs_init_inode(vol->mft_ino, vol,
385
                        FILE_Mft))) {
386
                ntfs_error("Problem loading MFT\n");
387
                return error;
388
        }
389
        ntfs_debug(DEBUG_BSD, "Going to load MIRR\n");
390
        if ((error = ntfs_init_inode(vol->mftmirr, vol, FILE_MftMirr))) {
391
                ntfs_error("Problem %d loading MFTMirr\n", error);
392
                return error;
393
        }
394
        ntfs_debug(DEBUG_BSD, "Going to load BITMAP\n");
395
        if ((error = ntfs_init_inode(vol->bitmap, vol, FILE_BitMap))) {
396
                ntfs_error("Problem loading Bitmap\n");
397
                return error;
398
        }
399
        ntfs_debug(DEBUG_BSD, "Going to load UPCASE\n");
400
        error = ntfs_init_inode(&upcase, vol, FILE_UpCase);
401
        if (error)
402
                return error;
403
        ntfs_init_upcase(&upcase);
404
        ntfs_clear_inode(&upcase);
405
        ntfs_debug(DEBUG_BSD, "Going to load ATTRDEF\n");
406
        error = ntfs_init_inode(&attrdef, vol, FILE_AttrDef);
407
        if (error)
408
                return error;
409
        error = ntfs_init_attrdef(&attrdef);
410
        ntfs_clear_inode(&attrdef);
411
        if (error)
412
                return error;
413
 
414
        /* Check for NTFS version and if Win2k version (ie. 3.0+) do not allow
415
         * write access since the driver write support is broken. */
416
        ntfs_debug(DEBUG_BSD, "Going to load VOLUME\n");
417
        error = ntfs_init_inode(&volume, vol, FILE_Volume);
418
        if (error)
419
                return error;
420
        if ((error = ntfs_get_version(&volume)) >= 0x0300 &&
421
            !(NTFS_SB(vol)->s_flags & MS_RDONLY)) {
422
                NTFS_SB(vol)->s_flags |= MS_RDONLY;
423
                ntfs_error("Warning! NTFS volume version is Win2k+: Mounting "
424
                           "read-only\n");
425
        }
426
        ntfs_clear_inode(&volume);
427
        if (error < 0)
428
                return error;
429
        ntfs_debug(DEBUG_BSD, "NTFS volume is v%d.%d\n", error >> 8,
430
                        error & 0xff);
431
        return 0;
432
}
433
 
434
int ntfs_release_volume(ntfs_volume *vol)
435
{
436
        if (((vol->ino_flags & 1) == 1) && vol->mft_ino) {
437
                ntfs_clear_inode(vol->mft_ino);
438
                ntfs_free(vol->mft_ino);
439
                vol->mft_ino = 0;
440
        }
441
        if (((vol->ino_flags & 2) == 2) && vol->mftmirr) {
442
                ntfs_clear_inode(vol->mftmirr);
443
                ntfs_free(vol->mftmirr);
444
                vol->mftmirr = 0;
445
        }
446
        if (((vol->ino_flags & 4) == 4) && vol->bitmap) {
447
                ntfs_clear_inode(vol->bitmap);
448
                ntfs_free(vol->bitmap);
449
                vol->bitmap = 0;
450
        }
451
        ntfs_free(vol->mft);
452
        ntfs_free(vol->upcase);
453
        return 0;
454
}
455
 
456
/*
457
 * Writes the volume size (units of clusters) into vol_size.
458
 * Returns 0 if successful or error.
459
 */
460
int ntfs_get_volumesize(ntfs_volume *vol, ntfs_s64 *vol_size)
461
{
462
        ntfs_io io;
463
        char *cluster0;
464
 
465
        if (!vol_size)
466
                return -EFAULT;
467
        cluster0 = ntfs_malloc(vol->cluster_size);
468
        if (!cluster0)
469
                return -ENOMEM;
470
        io.fn_put = ntfs_put;
471
        io.fn_get = ntfs_get;
472
        io.param = cluster0;
473
        io.do_read = 1;
474
        io.size = vol->cluster_size;
475
        ntfs_getput_clusters(vol, 0, 0, &io);
476
        *vol_size = NTFS_GETU64(cluster0 + 0x28) >>
477
                                        (ffs(NTFS_GETU8(cluster0 + 0xD)) - 1);
478
        ntfs_free(cluster0);
479
        return 0;
480
}
481
 
482
static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0};
483
 
484
int ntfs_get_free_cluster_count(ntfs_inode *bitmap)
485
{
486
        ntfs_io io;
487
        int offset, error, clusters;
488
        unsigned char *bits = ntfs_malloc(2048);
489
        if (!bits)
490
                return -ENOMEM;
491
        offset = clusters = 0;
492
        io.fn_put = ntfs_put;
493
        io.fn_get = ntfs_get;
494
        while (1) {
495
                register int i;
496
                io.param = bits;
497
                io.size = 2048;
498
                error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, offset,
499
                                                                        &io);
500
                if (error || io.size == 0)
501
                        break;
502
                /* I never thought I would do loop unrolling some day */
503
                for (i = 0; i < io.size - 8; ) {
504
                        clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
505
                        clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
506
                        clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
507
                        clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
508
                        clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
509
                        clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
510
                        clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
511
                        clusters+=nc[bits[i]>>4];clusters+=nc[bits[i++] & 0xF];
512
                }
513
                while (i < io.size) {
514
                        clusters += nc[bits[i] >> 4];
515
                        clusters += nc[bits[i++] & 0xF];
516
                }
517
                offset += io.size;
518
        }
519
        ntfs_free(bits);
520
        return clusters;
521
}
522
 
523
/*
524
 * Insert the fixups for the record. The number and location of the fixes
525
 * is obtained from the record header but we double check with @rec_size and
526
 * use that as the upper boundary, if necessary overwriting the count value in
527
 * the record header.
528
 *
529
 * We return 0 on success or -1 if fixup header indicated the beginning of the
530
 * update sequence array to be beyond the valid limit.
531
 */
532
int ntfs_insert_fixups(unsigned char *rec, int rec_size)
533
{
534
        int first;
535
        int count;
536
        int offset = -2;
537
        ntfs_u16 fix;
538
 
539
        first = NTFS_GETU16(rec + 4);
540
        count = (rec_size >> NTFS_SECTOR_BITS) + 1;
541
        if (first + count * 2 > NTFS_SECTOR_SIZE - 2) {
542
                printk(KERN_CRIT "NTFS: ntfs_insert_fixups() detected corrupt "
543
                                "NTFS record update sequence array position. - "
544
                                "Cannot hotfix.\n");
545
                return -1;
546
        }
547
        if (count != NTFS_GETU16(rec + 6)) {
548
                printk(KERN_ERR "NTFS: ntfs_insert_fixups() detected corrupt "
549
                                "NTFS record update sequence array size. - "
550
                                "Applying hotfix.\n");
551
                NTFS_PUTU16(rec + 6, count);
552
        }
553
        fix = (NTFS_GETU16(rec + first) + 1) & 0xffff;
554
        if (fix == 0xffff || !fix)
555
                fix = 1;
556
        NTFS_PUTU16(rec + first, fix);
557
        count--;
558
        while (count--) {
559
                first += 2;
560
                offset += NTFS_SECTOR_SIZE;
561
                NTFS_PUTU16(rec + first, NTFS_GETU16(rec + offset));
562
                NTFS_PUTU16(rec + offset, fix);
563
        }
564
        return 0;
565
}
566
 
567
/**
568
 * ntfs_allocate_clusters - allocate logical clusters on an ntfs volume
569
 * @vol:        volume on which to allocate clusters
570
 * @location:   preferred location for first allocated cluster
571
 * @count:      number of clusters to allocate
572
 * @rl:         address of pointer in which to return the allocated run list
573
 * @rl_len:     the number of elements returned in @*rl
574
 *
575
 * Allocate @*count clusters (LCNs), preferably beginning at @*location in the
576
 * bitmap of the volume @vol. If @*location is -1, it does not matter where the
577
 * clusters are. @rl is the address of a ntfs_runlist pointer which this
578
 * function will allocate and fill with the runlist of the allocated clusters.
579
 * It is the callers responsibility to ntfs_vfree() @*rl after she is finished
580
 * with it. If the function was not successful, @*rl will be set to NULL.
581
 * @*rl_len will contain the number of ntfs_runlist elements in @*rl or 0 if
582
 * @*rl is NULL.
583
 *
584
 * Return 0 on success, or -errno on error. On success, @*location and @*count
585
 * say what was really allocated. On -ENOSPC, @*location and @*count say what
586
 * could have been allocated. If nothing could be allocated or a different
587
 * error occured, @*location = -1 and @*count = 0.
588
 *
589
 * There are two data zones. First is the area between the end of the mft zone
590
 * and the end of the volume, and second is the area between the start of the
591
 * volume and the start of the mft zone. On unmodified/standard volumes, the
592
 * second mft zone doesn't exist due to the mft zone being expanded to cover
593
 * the start of volume in order to reserve space for the mft bitmap attribute.
594
 *
595
 * This is not the prettiest function but the complexity stems from the need of
596
 * implementing the mft vs data zoned approach and from the fact that we have
597
 * access to the lcn bitmap in portions of PAGE_SIZE bytes at a time, so we
598
 * need to cope with crossing over boundaries of two pages. Further, the fact
599
 * that the allocator allows for caller supplied hints as to the location of
600
 * where allocation should begin and the fact that the allocator keeps track of
601
 * where in the data zones the next natural allocation should occur, contribute
602
 * to the complexity of the function. But it should all be worthwhile, because
603
 * this allocator should: 1) be a full implementation of the MFT zone approach
604
 * used by Windows, 2) cause reduction in fragmentation as much as possible,
605
 * and 3) be speedy in allocations (the code is not optimized for speed, but
606
 * the algorithm is, so further speed improvements are probably possible).
607
 *
608
 * FIXME: Really need finer-grained locking but this will do for the moment. I
609
 * just want to kill all races and have a working allocator. When that is done,
610
 * we can beautify... (AIA)
611
 *
612
 * FIXME: We should be monitoring cluster allocation and increment the MFT zone
613
 * size dynamically but this is something for the future. We will just cause
614
 * heavier fragmentation by not doing it and I am not even sure Windows would
615
 * grow the MFT zone dynamically, so might even be correct not doing this. The
616
 * overhead in doing dynamic MFT zone expansion would be very large and unlikely
617
 * worth the effort. (AIA)
618
 *
619
 * TODO: I have added in double the required zone position pointer wrap around
620
 * logic which can be optimized to having only one of the two logic sets.
621
 * However, having the double logic will work fine, but if we have only one of
622
 * the sets and we get it wrong somewhere, then we get into trouble, so
623
 * removing the duplicate logic requires _very_ careful consideration of _all_
624
 * possible code paths. So at least for now, I am leaving the double logic -
625
 * better safe than sorry... (AIA)
626
 */
627
int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location,
628
                ntfs_cluster_t *count, ntfs_runlist **rl, int *rl_len,
629
                const NTFS_CLUSTER_ALLOCATION_ZONES zone)
630
{
631
        ntfs_runlist *rl2 = NULL, *rlt;
632
        ntfs_attribute *data;
633
        ntfs_cluster_t buf_pos, zone_start, zone_end, mft_zone_size;
634
        ntfs_cluster_t lcn, last_read_pos, prev_lcn = (ntfs_cluster_t)0;
635
        ntfs_cluster_t initial_location, prev_run_len = (ntfs_cluster_t)0;
636
        ntfs_cluster_t clusters = (ntfs_cluster_t)0;
637
        unsigned char *buf, *byte, bit, search_zone, done_zones;
638
        unsigned char pass, need_writeback;
639
        int rlpos = 0, rlsize, buf_size, err = 0;
640
        ntfs_io io;
641
 
642
        ntfs_debug(DEBUG_OTHER, "%s(): Entering with *location = 0x%x, "
643
                        "*count = 0x%x, zone = %s_ZONE.\n", __FUNCTION__,
644
                        *location, *count, zone == DATA_ZONE ? "DATA" : "MFT");
645
        buf = (char*)__get_free_page(GFP_NOFS);
646
        if (!buf) {
647
                ntfs_debug(DEBUG_OTHER, "%s(): Returning -ENOMEM.\n",
648
                                __FUNCTION__);
649
                return -ENOMEM;
650
        }
651
        io.fn_put = ntfs_put;
652
        io.fn_get = ntfs_get;
653
        lock_kernel();
654
        /* Get the $DATA attribute of $Bitmap. */
655
        data = ntfs_find_attr(vol->bitmap, vol->at_data, 0);
656
        if (!data) {
657
                err = -EINVAL;
658
                goto err_ret;
659
        }
660
        /*
661
         * If no specific location was requested, use the current data zone
662
         * position, otherwise use the requested location but make sure it lies
663
         * outside the mft zone. Also set done_zones to 0 (no zones done) and
664
         * pass depending on whether we are starting inside a zone (1) or
665
         * at the beginning of a zone (2). If requesting from the MFT_ZONE, then
666
         * we either start at the current position within the mft zone or at the
667
         * specified position and if the latter is out of bounds then we start
668
         * at the beginning of the MFT_ZONE.
669
         */
670
        done_zones = 0;
671
        pass = 1;
672
        /*
673
         * zone_start and zone_end are the current search range. search_zone
674
         * is 1 for mft zone, 2 for data zone 1 (end of mft zone till end of
675
         * volume) and 4 for data zone 2 (start of volume till start of mft
676
         * zone).
677
         */
678
        zone_start = *location;
679
        if (zone_start < 0) {
680
                if (zone == DATA_ZONE)
681
                        zone_start = vol->data1_zone_pos;
682
                else
683
                        zone_start = vol->mft_zone_pos;
684
                if (!zone_start)
685
                        /*
686
                         * Zone starts at beginning of volume which means a
687
                         * single pass is sufficient.
688
                         */
689
                        pass = 2;
690
        } else if (zone_start >= vol->mft_zone_start && zone_start <
691
                        vol->mft_zone_end && zone == DATA_ZONE) {
692
                zone_start = vol->mft_zone_end;
693
                pass = 2;
694
        } else if ((zone_start < vol->mft_zone_start || zone_start >=
695
                        vol->mft_zone_end) && zone == MFT_ZONE) {
696
                zone_start = vol->mft_lcn;
697
                if (!vol->mft_zone_end)
698
                        zone_start = (ntfs_cluster_t)0;
699
                pass = 2;
700
        }
701
        if (zone == DATA_ZONE) {
702
                /* Skip searching the mft zone. */
703
                done_zones |= 1;
704
                if (zone_start >= vol->mft_zone_end) {
705
                        zone_end = vol->nr_clusters;
706
                        search_zone = 2;
707
                } else {
708
                        zone_end = vol->mft_zone_start;
709
                        search_zone = 4;
710
                }
711
        } else /* if (zone == MFT_ZONE) */ {
712
                zone_end = vol->mft_zone_end;
713
                search_zone = 1;
714
        }
715
        /*
716
         * buf_pos is the current bit position inside the bitmap. We use
717
         * initial_location to determine whether or not to do a zone switch.
718
         */
719
        buf_pos = initial_location = zone_start;
720
        /* Loop until all clusters are allocated, i.e. clusters == 0. */
721
        clusters = *count;
722
        rlpos = rlsize = 0;
723
        if (*count <= 0) {
724
                ntfs_debug(DEBUG_OTHER, "%s(): *count <= 0, "
725
                                "returning -EINVAL.\n", __FUNCTION__);
726
                err = -EINVAL;
727
                goto err_ret;
728
        }
729
        while (1) {
730
                ntfs_debug(DEBUG_OTHER, "%s(): Start of outer while "
731
                                "loop: done_zones = 0x%x, search_zone = %i, "
732
                                "pass = %i, zone_start = 0x%x, zone_end = "
733
                                "0x%x, initial_location = 0x%x, buf_pos = "
734
                                "0x%x, rlpos = %i, rlsize = %i.\n",
735
                                __FUNCTION__, done_zones, search_zone, pass,
736
                                zone_start, zone_end, initial_location, buf_pos,
737
                                rlpos, rlsize);
738
                /* Loop until we run out of free clusters. */
739
                io.param = buf;
740
                io.size = PAGE_SIZE;
741
                io.do_read = 1;
742
                last_read_pos = buf_pos >> 3;
743
                ntfs_debug(DEBUG_OTHER, "%s(): last_read_pos = 0x%x.\n",
744
                                __FUNCTION__, last_read_pos);
745
                err = ntfs_readwrite_attr(vol->bitmap, data, last_read_pos,
746
                                &io);
747
                if (err) {
748
                        ntfs_debug(DEBUG_OTHER, "%s(): ntfs_read_attr failed "
749
                                        "with error code %i, going to "
750
                                        "err_ret.\n", __FUNCTION__, -err);
751
                        goto err_ret;
752
                }
753
                if (!io.size) {
754
                        ntfs_debug(DEBUG_OTHER, "%s(): !io.size, going to "
755
                                        "zone_pass_done.\n", __FUNCTION__);
756
                        goto zone_pass_done;
757
                }
758
                buf_size = io.size << 3;
759
                lcn = buf_pos & 7;
760
                buf_pos &= ~7;
761
                need_writeback = 0;
762
                ntfs_debug(DEBUG_OTHER, "%s(): Before inner while "
763
                                "loop: buf_size = 0x%x, lcn = 0x%x, buf_pos = "
764
                                "0x%x, need_writeback = %i.\n", __FUNCTION__,
765
                                buf_size, lcn, buf_pos, need_writeback);
766
                while (lcn < buf_size && lcn + buf_pos < zone_end) {
767
                        byte = buf + (lcn >> 3);
768
                        ntfs_debug(DEBUG_OTHER, "%s(): In inner while loop: "
769
                                        "buf_size = 0x%x, lcn = 0x%x, buf_pos "
770
                                        "= 0x%x, need_writeback = %i, byte ofs "
771
                                        "= 0x%x, *byte = 0x%x.\n", __FUNCTION__,
772
                                        buf_size, lcn, buf_pos, need_writeback,
773
                                        lcn >> 3, *byte);
774
                        /* Skip full bytes. */
775
                        if (*byte == 0xff) {
776
                                lcn += 8;
777
                                ntfs_debug(DEBUG_OTHER, "%s(): continuing while"
778
                                            " loop 1.\n", __FUNCTION__);
779
                                continue;
780
                        }
781
                        bit = 1 << (lcn & 7);
782
                        ntfs_debug(DEBUG_OTHER, "%s(): bit = %i.\n",
783
                                        __FUNCTION__, bit);
784
                        /* If the bit is already set, go onto the next one. */
785
                        if (*byte & bit) {
786
                                lcn++;
787
                                ntfs_debug(DEBUG_OTHER, "%s(): continuing while"
788
                                            " loop 2.\n", __FUNCTION__);
789
                                continue;
790
                        }
791
                        /* Allocate the bitmap bit. */
792
                        *byte |= bit;
793
                        /* We need to write this bitmap buffer back to disk! */
794
                        need_writeback = 1;
795
                        ntfs_debug(DEBUG_OTHER, "%s(): *byte = 0x%x, "
796
                                        "need_writeback = %i.\n", __FUNCTION__,
797
                                        *byte, need_writeback);
798
                        /* Reallocate memory if necessary. */
799
                        if ((rlpos + 2) * sizeof(ntfs_runlist) >= rlsize) {
800
                                ntfs_debug(DEBUG_OTHER, "%s(): Reallocating "
801
                                                "space.\n", __FUNCTION__);
802
                                /* Setup first free bit return value. */
803
                                if (!rl2) {
804
                                        *location = lcn + buf_pos;
805
                                        ntfs_debug(DEBUG_OTHER, "%s(): "
806
                                                        "*location = 0x%x.\n",
807
                                                        __FUNCTION__,
808
                                                        *location);
809
                                }
810
                                rlsize += PAGE_SIZE;
811
                                rlt = ntfs_vmalloc(rlsize);
812
                                if (!rlt) {
813
                                        err = -ENOMEM;
814
                                        ntfs_debug(DEBUG_OTHER, "%s(): Failed "
815
                                                        "to allocate memory, "
816
                                                        "returning -ENOMEM, "
817
                                                        "going to wb_err_ret.\n",
818
                                                        __FUNCTION__);
819
                                        goto wb_err_ret;
820
                                }
821
                                if (rl2) {
822
                                        ntfs_memcpy(rlt, rl2, rlsize -
823
                                                        PAGE_SIZE);
824
                                        ntfs_vfree(rl2);
825
                                }
826
                                rl2 = rlt;
827
                                ntfs_debug(DEBUG_OTHER, "%s(): Reallocated "
828
                                                "memory, rlsize = 0x%x.\n",
829
                                                __FUNCTION__, rlsize);
830
                        }
831
                        /*
832
                         * Coalesce with previous run if adjacent LCNs.
833
                         * Otherwise, append a new run.
834
                         */
835
                        ntfs_debug(DEBUG_OTHER, "%s(): Adding run (lcn 0x%x, "
836
                                        "len 0x%x), prev_lcn = 0x%x, lcn = "
837
                                        "0x%x, buf_pos = 0x%x, prev_run_len = "
838
                                        "0x%x, rlpos = %i.\n", __FUNCTION__,
839
                                        lcn + buf_pos, 1, prev_lcn, lcn,
840
                                        buf_pos, prev_run_len, rlpos);
841
                        if (prev_lcn == lcn + buf_pos - prev_run_len && rlpos) {
842
                                ntfs_debug(DEBUG_OTHER, "%s(): Coalescing to "
843
                                                "run (lcn 0x%x, len 0x%x).\n",
844
                                                __FUNCTION__,
845
                                                rl2[rlpos - 1].lcn,
846
                                                rl2[rlpos - 1].len);
847
                                rl2[rlpos - 1].len = ++prev_run_len;
848
                                ntfs_debug(DEBUG_OTHER, "%s(): Run now (lcn "
849
                                                "0x%x, len 0x%x), prev_run_len "
850
                                                "= 0x%x.\n", __FUNCTION__,
851
                                                rl2[rlpos - 1].lcn,
852
                                                rl2[rlpos - 1].len,
853
                                                prev_run_len);
854
                        } else {
855
                                if (rlpos)
856
                                        ntfs_debug(DEBUG_OTHER, "%s(): Adding "
857
                                                        "new run, (previous "
858
                                                        "run lcn 0x%x, "
859
                                                        "len 0x%x).\n",
860
                                                        __FUNCTION__,
861
                                                        rl2[rlpos - 1].lcn,
862
                                                        rl2[rlpos - 1].len);
863
                                else
864
                                        ntfs_debug(DEBUG_OTHER, "%s(): Adding "
865
                                                        "new run, is first "
866
                                                        "run.\n", __FUNCTION__);
867
                                rl2[rlpos].lcn = prev_lcn = lcn + buf_pos;
868
                                rl2[rlpos].len = prev_run_len =
869
                                                (ntfs_cluster_t)1;
870
 
871
                                rlpos++;
872
                        }
873
                        /* Done? */
874
                        if (!--clusters) {
875
                                ntfs_cluster_t tc;
876
                                /*
877
                                 * Update the current zone position. Positions
878
                                 * of already scanned zones have been updated
879
                                 * during the respective zone switches.
880
                                 */
881
                                tc = lcn + buf_pos + 1;
882
                                ntfs_debug(DEBUG_OTHER, "%s(): Done. Updating "
883
                                                "current zone position, tc = "
884
                                                "0x%x, search_zone = %i.\n",
885
                                                __FUNCTION__, tc, search_zone);
886
                                switch (search_zone) {
887
                                case 1:
888
                                        ntfs_debug(DEBUG_OTHER,
889
                                                        "%s(): Before checks, "
890
                                                        "vol->mft_zone_pos = "
891
                                                        "0x%x.\n", __FUNCTION__,
892
                                                        vol->mft_zone_pos);
893
                                        if (tc >= vol->mft_zone_end) {
894
                                                vol->mft_zone_pos =
895
                                                                vol->mft_lcn;
896
                                                if (!vol->mft_zone_end)
897
                                                        vol->mft_zone_pos =
898
                                                             (ntfs_cluster_t)0;
899
                                        } else if ((initial_location >=
900
                                                        vol->mft_zone_pos ||
901
                                                        tc > vol->mft_zone_pos)
902
                                                        && tc >= vol->mft_lcn)
903
                                                vol->mft_zone_pos = tc;
904
                                        ntfs_debug(DEBUG_OTHER,
905
                                                        "%s(): After checks, "
906
                                                        "vol->mft_zone_pos = "
907
                                                        "0x%x.\n", __FUNCTION__,
908
                                                        vol->mft_zone_pos);
909
                                        break;
910
                                case 2:
911
                                        ntfs_debug(DEBUG_OTHER,
912
                                                        "%s(): Before checks, "
913
                                                        "vol->data1_zone_pos = "
914
                                                        "0x%x.\n", __FUNCTION__,
915
                                                        vol->data1_zone_pos);
916
                                        if (tc >= vol->nr_clusters)
917
                                                vol->data1_zone_pos =
918
                                                             vol->mft_zone_end;
919
                                        else if ((initial_location >=
920
                                                    vol->data1_zone_pos ||
921
                                                    tc > vol->data1_zone_pos)
922
                                                    && tc >= vol->mft_zone_end)
923
                                                vol->data1_zone_pos = tc;
924
                                        ntfs_debug(DEBUG_OTHER,
925
                                                        "%s(): After checks, "
926
                                                        "vol->data1_zone_pos = "
927
                                                        "0x%x.\n", __FUNCTION__,
928
                                                        vol->data1_zone_pos);
929
                                        break;
930
                                case 4:
931
                                        ntfs_debug(DEBUG_OTHER,
932
                                                        "%s(): Before checks, "
933
                                                        "vol->data2_zone_pos = "
934
                                                        "0x%x.\n", __FUNCTION__,
935
                                                        vol->data2_zone_pos);
936
                                        if (tc >= vol->mft_zone_start)
937
                                                vol->data2_zone_pos =
938
                                                        (ntfs_cluster_t)0;
939
                                        else if (initial_location >=
940
                                                      vol->data2_zone_pos ||
941
                                                      tc > vol->data2_zone_pos)
942
                                                vol->data2_zone_pos = tc;
943
                                        ntfs_debug(DEBUG_OTHER,
944
                                                        "%s(): After checks, "
945
                                                        "vol->data2_zone_pos = "
946
                                                        "0x%x.\n", __FUNCTION__,
947
                                                        vol->data2_zone_pos);
948
                                        break;
949
                                default:
950
                                        BUG();
951
                                }
952
                                ntfs_debug(DEBUG_OTHER, "%s(): Going to "
953
                                                "done_ret.\n", __FUNCTION__);
954
                                goto done_ret;
955
                        }
956
                        lcn++;
957
                }
958
                buf_pos += buf_size;
959
                ntfs_debug(DEBUG_OTHER, "%s(): After inner while "
960
                                "loop: buf_size = 0x%x, lcn = 0x%x, buf_pos = "
961
                                "0x%x, need_writeback = %i.\n", __FUNCTION__,
962
                                buf_size, lcn, buf_pos, need_writeback);
963
                if (need_writeback) {
964
                        ntfs_debug(DEBUG_OTHER, "%s(): Writing back.\n",
965
                                        __FUNCTION__);
966
                        need_writeback = 0;
967
                        io.param = buf;
968
                        io.do_read = 0;
969
                        err = ntfs_readwrite_attr(vol->bitmap, data,
970
                                        last_read_pos, &io);
971
                        if (err) {
972
                                ntfs_error("%s(): Bitmap writeback failed "
973
                                                "in read next buffer code "
974
                                                "path with error code %i.\n",
975
                                                __FUNCTION__, -err);
976
                                goto err_ret;
977
                        }
978
                }
979
                if (buf_pos < zone_end) {
980
                        ntfs_debug(DEBUG_OTHER, "%s(): Continuing "
981
                                        "outer while loop, buf_pos = 0x%x, "
982
                                        "zone_end = 0x%x.\n", __FUNCTION__,
983
                                        buf_pos, zone_end);
984
                        continue;
985
                }
986
zone_pass_done: /* Finished with the current zone pass. */
987
                ntfs_debug(DEBUG_OTHER, "%s(): At zone_pass_done, pass = %i.\n",
988
                                __FUNCTION__, pass);
989
                if (pass == 1) {
990
                        /*
991
                         * Now do pass 2, scanning the first part of the zone
992
                         * we omitted in pass 1.
993
                         */
994
                        pass = 2;
995
                        zone_end = zone_start;
996
                        switch (search_zone) {
997
                        case 1: /* mft_zone */
998
                                zone_start = vol->mft_zone_start;
999
                                break;
1000
                        case 2: /* data1_zone */
1001
                                zone_start = vol->mft_zone_end;
1002
                                break;
1003
                        case 4: /* data2_zone */
1004
                                zone_start = (ntfs_cluster_t)0;
1005
                                break;
1006
                        default:
1007
                                BUG();
1008
                        }
1009
                        /* Sanity check. */
1010
                        if (zone_end < zone_start)
1011
                                zone_end = zone_start;
1012
                        buf_pos = zone_start;
1013
                        ntfs_debug(DEBUG_OTHER, "%s(): Continuing "
1014
                                        "outer while loop, pass = 2, "
1015
                                        "zone_start = 0x%x, zone_end = 0x%x, "
1016
                                        "buf_pos = 0x%x.\n", __FUNCTION__,
1017
                                        zone_start, zone_end, buf_pos);
1018
                        continue;
1019
                } /* pass == 2 */
1020
done_zones_check:
1021
                ntfs_debug(DEBUG_OTHER, "%s(): At done_zones_check, "
1022
                                "search_zone = %i, done_zones before = 0x%x, "
1023
                                "done_zones after = 0x%x.\n", __FUNCTION__,
1024
                                search_zone, done_zones, done_zones |
1025
                                search_zone);
1026
                done_zones |= search_zone;
1027
                if (done_zones < 7) {
1028
                        ntfs_debug(DEBUG_OTHER, "%s(): Switching zone.\n",
1029
                                        __FUNCTION__);
1030
                        /* Now switch to the next zone we haven't done yet. */
1031
                        pass = 1;
1032
                        switch (search_zone) {
1033
                        case 1:
1034
                                ntfs_debug(DEBUG_OTHER, "%s(): Switching from "
1035
                                                "mft zone to data1 zone.\n",
1036
                                                __FUNCTION__);
1037
                                /* Update mft zone position. */
1038
                                if (rlpos) {
1039
                                        ntfs_cluster_t tc;
1040
                                        ntfs_debug(DEBUG_OTHER,
1041
                                                        "%s(): Before checks, "
1042
                                                        "vol->mft_zone_pos = "
1043
                                                        "0x%x.\n", __FUNCTION__,
1044
                                                        vol->mft_zone_pos);
1045
                                        tc = rl2[rlpos - 1].lcn +
1046
                                                        rl2[rlpos - 1].len;
1047
                                        if (tc >= vol->mft_zone_end) {
1048
                                                vol->mft_zone_pos =
1049
                                                                vol->mft_lcn;
1050
                                                if (!vol->mft_zone_end)
1051
                                                        vol->mft_zone_pos =
1052
                                                             (ntfs_cluster_t)0;
1053
                                        } else if ((initial_location >=
1054
                                                        vol->mft_zone_pos ||
1055
                                                        tc > vol->mft_zone_pos)
1056
                                                        && tc >= vol->mft_lcn)
1057
                                                vol->mft_zone_pos = tc;
1058
                                        ntfs_debug(DEBUG_OTHER,
1059
                                                        "%s(): After checks, "
1060
                                                        "vol->mft_zone_pos = "
1061
                                                        "0x%x.\n", __FUNCTION__,
1062
                                                        vol->mft_zone_pos);
1063
                                }
1064
                                /* Switch from mft zone to data1 zone. */
1065
switch_to_data1_zone:           search_zone = 2;
1066
                                zone_start = initial_location =
1067
                                                vol->data1_zone_pos;
1068
                                zone_end = vol->nr_clusters;
1069
                                if (zone_start == vol->mft_zone_end)
1070
                                        pass = 2;
1071
                                if (zone_start >= zone_end) {
1072
                                        vol->data1_zone_pos = zone_start =
1073
                                                        vol->mft_zone_end;
1074
                                        pass = 2;
1075
                                }
1076
                                break;
1077
                        case 2:
1078
                                ntfs_debug(DEBUG_OTHER, "%s(): Switching from "
1079
                                                "data1 zone to data2 zone.\n",
1080
                                                __FUNCTION__);
1081
                                /* Update data1 zone position. */
1082
                                if (rlpos) {
1083
                                        ntfs_cluster_t tc;
1084
                                        ntfs_debug(DEBUG_OTHER,
1085
                                                        "%s(): Before checks, "
1086
                                                        "vol->data1_zone_pos = "
1087
                                                        "0x%x.\n", __FUNCTION__,
1088
                                                        vol->data1_zone_pos);
1089
                                        tc = rl2[rlpos - 1].lcn +
1090
                                                        rl2[rlpos - 1].len;
1091
                                        if (tc >= vol->nr_clusters)
1092
                                                vol->data1_zone_pos =
1093
                                                             vol->mft_zone_end;
1094
                                        else if ((initial_location >=
1095
                                                    vol->data1_zone_pos ||
1096
                                                    tc > vol->data1_zone_pos)
1097
                                                    && tc >= vol->mft_zone_end)
1098
                                                vol->data1_zone_pos = tc;
1099
                                        ntfs_debug(DEBUG_OTHER,
1100
                                                        "%s(): After checks, "
1101
                                                        "vol->data1_zone_pos = "
1102
                                                        "0x%x.\n", __FUNCTION__,
1103
                                                        vol->data1_zone_pos);
1104
                                }
1105
                                /* Switch from data1 zone to data2 zone. */
1106
                                search_zone = 4;
1107
                                zone_start = initial_location =
1108
                                                vol->data2_zone_pos;
1109
                                zone_end = vol->mft_zone_start;
1110
                                if (!zone_start)
1111
                                        pass = 2;
1112
                                if (zone_start >= zone_end) {
1113
                                        vol->data2_zone_pos = zone_start =
1114
                                                        initial_location =
1115
                                                        (ntfs_cluster_t)0;
1116
                                        pass = 2;
1117
                                }
1118
                                break;
1119
                        case 4:
1120
                                ntfs_debug(DEBUG_OTHER, "%s(): Switching from "
1121
                                                "data2 zone to data1 zone.\n",
1122
                                                __FUNCTION__);
1123
                                /* Update data2 zone position. */
1124
                                if (rlpos) {
1125
                                        ntfs_cluster_t tc;
1126
                                        ntfs_debug(DEBUG_OTHER,
1127
                                                        "%s(): Before checks, "
1128
                                                        "vol->data2_zone_pos = "
1129
                                                        "0x%x.\n", __FUNCTION__,
1130
                                                        vol->data2_zone_pos);
1131
                                        tc = rl2[rlpos - 1].lcn +
1132
                                                        rl2[rlpos - 1].len;
1133
                                        if (tc >= vol->mft_zone_start)
1134
                                                vol->data2_zone_pos =
1135
                                                             (ntfs_cluster_t)0;
1136
                                        else if (initial_location >=
1137
                                                      vol->data2_zone_pos ||
1138
                                                      tc > vol->data2_zone_pos)
1139
                                                vol->data2_zone_pos = tc;
1140
                                        ntfs_debug(DEBUG_OTHER,
1141
                                                        "%s(): After checks, "
1142
                                                        "vol->data2_zone_pos = "
1143
                                                        "0x%x.\n", __FUNCTION__,
1144
                                                        vol->data2_zone_pos);
1145
                                }
1146
                                /* Switch from data2 zone to data1 zone. */
1147
                                goto switch_to_data1_zone; /* See above. */
1148
                        default:
1149
                                BUG();
1150
                        }
1151
                        ntfs_debug(DEBUG_OTHER, "%s(): After zone switch, "
1152
                                        "search_zone = %i, pass = %i, "
1153
                                        "initial_location = 0x%x, zone_start "
1154
                                        "= 0x%x, zone_end = 0x%x.\n",
1155
                                        __FUNCTION__, search_zone, pass,
1156
                                        initial_location, zone_start, zone_end);
1157
                        buf_pos = zone_start;
1158
                        if (zone_start == zone_end) {
1159
                                ntfs_debug(DEBUG_OTHER, "%s(): Empty zone, "
1160
                                                "going to done_zones_check.\n",
1161
                                                __FUNCTION__);
1162
                                /* Empty zone. Don't bother searching it. */
1163
                                goto done_zones_check;
1164
                        }
1165
                        ntfs_debug(DEBUG_OTHER, "%s(): Continuing outer while "
1166
                                        "loop.\n", __FUNCTION__);
1167
                        continue;
1168
                } /* done_zones == 7 */
1169
                ntfs_debug(DEBUG_OTHER, "%s(): All zones are finished.\n",
1170
                                __FUNCTION__);
1171
                /*
1172
                 * All zones are finished! If DATA_ZONE, shrink mft zone. If
1173
                 * MFT_ZONE, we have really run out of space.
1174
                 */
1175
                mft_zone_size = vol->mft_zone_end - vol->mft_zone_start;
1176
                ntfs_debug(DEBUG_OTHER, "%s(): vol->mft_zone_start = 0x%x, "
1177
                                "vol->mft_zone_end = 0x%x, mft_zone_size = "
1178
                                "0x%x.\n", __FUNCTION__, vol->mft_zone_start,
1179
                                vol->mft_zone_end, mft_zone_size);
1180
                if (zone == MFT_ZONE || mft_zone_size <= (ntfs_cluster_t)0) {
1181
                        ntfs_debug(DEBUG_OTHER, "%s(): No free clusters left, "
1182
                                        "returning -ENOSPC, going to "
1183
                                        "fail_ret.\n", __FUNCTION__);
1184
                        /* Really no more space left on device. */
1185
                        err = -ENOSPC;
1186
                        goto fail_ret;
1187
                } /* zone == DATA_ZONE && mft_zone_size > 0 */
1188
                ntfs_debug(DEBUG_OTHER, "%s(): Shrinking mft zone.\n",
1189
                                __FUNCTION__);
1190
                zone_end = vol->mft_zone_end;
1191
                mft_zone_size >>= 1;
1192
                if (mft_zone_size > (ntfs_cluster_t)0)
1193
                        vol->mft_zone_end = vol->mft_zone_start + mft_zone_size;
1194
                else /* mft zone and data2 zone no longer exist. */
1195
                        vol->data2_zone_pos = vol->mft_zone_start =
1196
                                        vol->mft_zone_end = (ntfs_cluster_t)0;
1197
                if (vol->mft_zone_pos >= vol->mft_zone_end) {
1198
                        vol->mft_zone_pos = vol->mft_lcn;
1199
                        if (!vol->mft_zone_end)
1200
                                vol->mft_zone_pos = (ntfs_cluster_t)0;
1201
                }
1202
                buf_pos = zone_start = initial_location =
1203
                                vol->data1_zone_pos = vol->mft_zone_end;
1204
                search_zone = 2;
1205
                pass = 2;
1206
                done_zones &= ~2;
1207
                ntfs_debug(DEBUG_OTHER, "%s(): After shrinking mft "
1208
                                "zone, mft_zone_size = 0x%x, "
1209
                                "vol->mft_zone_start = 0x%x, vol->mft_zone_end "
1210
                                "= 0x%x, vol->mft_zone_pos = 0x%x, search_zone "
1211
                                "= 2, pass = 2, dones_zones = 0x%x, zone_start "
1212
                                "= 0x%x, zone_end = 0x%x, vol->data1_zone_pos "
1213
                                "= 0x%x, continuing outer while loop.\n",
1214
                                __FUNCTION__, mft_zone_size,
1215
                                vol->mft_zone_start, vol->mft_zone_end,
1216
                                vol->mft_zone_pos, done_zones, zone_start,
1217
                                zone_end, vol->data1_zone_pos);
1218
        }
1219
        ntfs_debug(DEBUG_OTHER, "%s(): After outer while loop.\n",
1220
                        __FUNCTION__);
1221
done_ret:
1222
        ntfs_debug(DEBUG_OTHER, "%s(): At done_ret.\n", __FUNCTION__);
1223
        rl2[rlpos].lcn = (ntfs_cluster_t)-1;
1224
        rl2[rlpos].len = (ntfs_cluster_t)0;
1225
        *rl = rl2;
1226
        *rl_len = rlpos;
1227
        if (need_writeback) {
1228
                ntfs_debug(DEBUG_OTHER, "%s(): Writing back.\n", __FUNCTION__);
1229
                need_writeback = 0;
1230
                io.param = buf;
1231
                io.do_read = 0;
1232
                err = ntfs_readwrite_attr(vol->bitmap, data, last_read_pos,
1233
                                &io);
1234
                if (err) {
1235
                        ntfs_error("%s(): Bitmap writeback failed in done "
1236
                                        "code path with error code %i.\n",
1237
                                        __FUNCTION__, -err);
1238
                        goto err_ret;
1239
                }
1240
                ntfs_debug(DEBUG_OTHER, "%s(): Wrote 0x%Lx bytes.\n",
1241
                                __FUNCTION__, io.size);
1242
        }
1243
done_fail_ret:
1244
        ntfs_debug(DEBUG_OTHER, "%s(): At done_fail_ret (follows done_ret).\n",
1245
                         __FUNCTION__);
1246
        unlock_kernel();
1247
        free_page((unsigned long)buf);
1248
        if (err)
1249
                ntfs_debug(DEBUG_FILE3, "%s(): Failed to allocate "
1250
                                "clusters. Returning with error code %i.\n",
1251
                                __FUNCTION__, -err);
1252
        ntfs_debug(DEBUG_OTHER, "%s(): Syncing $Bitmap inode.\n", __FUNCTION__);
1253
        if (ntfs_update_inode(vol->bitmap))
1254
                ntfs_error("%s(): Failed to sync inode $Bitmap. "
1255
                                "Continuing anyway.\n", __FUNCTION__);
1256
        ntfs_debug(DEBUG_OTHER, "%s(): Returning with code %i.\n", __FUNCTION__,
1257
                        err);
1258
        return err;
1259
fail_ret:
1260
        ntfs_debug(DEBUG_OTHER, "%s(): At fail_ret.\n", __FUNCTION__);
1261
        if (rl2) {
1262
                if (err == -ENOSPC) {
1263
                        /* Return first free lcn and count of free clusters. */
1264
                        *location = rl2[0].lcn;
1265
                        *count -= clusters;
1266
                        ntfs_debug(DEBUG_OTHER, "%s(): err = -ENOSPC, "
1267
                                        "*location = 0x%x, *count = 0x%x.\n",
1268
                                        __FUNCTION__, *location, *count);
1269
                }
1270
                /* Deallocate all allocated clusters. */
1271
                ntfs_debug(DEBUG_OTHER, "%s(): Deallocating allocated "
1272
                                "clusters.\n", __FUNCTION__);
1273
                ntfs_deallocate_clusters(vol, rl2, rlpos);
1274
                /* Free the runlist. */
1275
                ntfs_vfree(rl2);
1276
        } else {
1277
                if (err == -ENOSPC) {
1278
                        /* Nothing free at all. */
1279
                        *location = vol->data1_zone_pos; /* Irrelevant... */
1280
                        *count = 0;
1281
                        ntfs_debug(DEBUG_OTHER, "%s(): No space left at all, "
1282
                                        "err = -ENOSPC, *location = 0x%x, "
1283
                                        "*count = 0.\n",
1284
                                        __FUNCTION__, *location);
1285
                }
1286
        }
1287
        *rl = NULL;
1288
        *rl_len = 0;
1289
        ntfs_debug(DEBUG_OTHER, "%s(): *rl = NULL, *rl_len = 0, "
1290
                        "going to done_fail_ret.\n", __FUNCTION__);
1291
        goto done_fail_ret;
1292
wb_err_ret:
1293
        ntfs_debug(DEBUG_OTHER, "%s(): At wb_err_ret.\n", __FUNCTION__);
1294
        if (need_writeback) {
1295
                int __err;
1296
                ntfs_debug(DEBUG_OTHER, "%s(): Writing back.\n", __FUNCTION__);
1297
                io.param = buf;
1298
                io.do_read = 0;
1299
                __err = ntfs_readwrite_attr(vol->bitmap, data, last_read_pos,
1300
                                &io);
1301
                if (__err)
1302
                        ntfs_error("%s(): Bitmap writeback failed in error "
1303
                                        "code path with error code %i.\n",
1304
                                        __FUNCTION__, -__err);
1305
                need_writeback = 0;
1306
        }
1307
err_ret:
1308
        ntfs_debug(DEBUG_OTHER, "%s(): At err_ret, *location = -1, "
1309
                        "*count = 0, going to fail_ret.\n", __FUNCTION__);
1310
        *location = -1;
1311
        *count = 0;
1312
        goto fail_ret;
1313
}
1314
 
1315
/*
1316
 * IMPORTANT: Caller has to hold big kernel lock or the race monster will come
1317
 * to get you! (-;
1318
 * TODO: Need our own lock for bitmap accesses but BKL is more secure for now,
1319
 * considering we might not have covered all places with a lock yet. In that
1320
 * case the BKL offers a one way exclusion which is better than no exclusion
1321
 * at all... (AIA)
1322
 */
1323
static int ntfs_clear_bitrange(ntfs_inode *bitmap,
1324
                const ntfs_cluster_t start_bit, const ntfs_cluster_t count)
1325
{
1326
        ntfs_cluster_t buf_size, bit, nr_bits = count;
1327
        unsigned char *buf, *byte;
1328
        int err;
1329
        ntfs_io io;
1330
 
1331
        io.fn_put = ntfs_put;
1332
        io.fn_get = ntfs_get;
1333
        /* Calculate the required buffer size in bytes. */
1334
        buf_size = (ntfs_cluster_t)((start_bit & 7) + nr_bits + 7) >> 3;
1335
        if (buf_size <= (ntfs_cluster_t)(64 * 1024))
1336
                buf = ntfs_malloc(buf_size);
1337
        else
1338
                buf = ntfs_vmalloc(buf_size);
1339
        if (!buf)
1340
                return -ENOMEM;
1341
        /* Read the bitmap from the data attribute. */
1342
        io.param = byte = buf;
1343
        io.size = buf_size;
1344
        err = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, start_bit >> 3,
1345
                        &io);
1346
        if (err || io.size != buf_size)
1347
                goto err_out;
1348
        /* Now clear the bits in the read bitmap. */
1349
        bit = start_bit & 7;
1350
        while (bit && nr_bits) { /* Process first partial byte, if present. */
1351
                *byte &= ~(1 << bit++);
1352
                nr_bits--;
1353
                bit &= 7;
1354
                if (!bit)
1355
                        byte++;
1356
        }
1357
        while (nr_bits >= 8) { /* Process full bytes. */
1358
                *byte = 0;
1359
                nr_bits -= 8;
1360
                byte++;
1361
        }
1362
        bit = 0;
1363
        while (nr_bits) { /* Process last partial byte, if present. */
1364
                *byte &= ~(1 << bit);
1365
                nr_bits--;
1366
                bit++;
1367
        }
1368
        /* Write the modified bitmap back to disk. */
1369
        io.param = buf;
1370
        io.size = buf_size;
1371
        err = ntfs_write_attr(bitmap, bitmap->vol->at_data, 0, start_bit >> 3,
1372
                        &io);
1373
err_out:
1374
        if (buf_size <= (ntfs_cluster_t)(64 * 1024))
1375
                ntfs_free(buf);
1376
        else
1377
                ntfs_vfree(buf);
1378
        if (!err && io.size != buf_size)
1379
                err = -EIO;
1380
        return err;
1381
}
1382
 
1383
/*
1384
 * See comments for lack of zone adjustments below in the description of the
1385
 * function ntfs_deallocate_clusters().
1386
 */
1387
int ntfs_deallocate_cluster_run(const ntfs_volume *vol,
1388
                const ntfs_cluster_t lcn, const ntfs_cluster_t len)
1389
{
1390
        int err;
1391
 
1392
        lock_kernel();
1393
        err = ntfs_clear_bitrange(vol->bitmap, lcn, len);
1394
        unlock_kernel();
1395
        return err;
1396
}
1397
 
1398
/*
1399
 * This is inefficient, but logically trivial, so will do for now. Note, we
1400
 * do not touch the mft nor the data zones here because we want to minimize
1401
 * recycling of clusters to enhance the chances of data being undeleteable.
1402
 * Also we don't want the overhead. Instead we do one additional sweep of the
1403
 * current data zone during cluster allocation to check for freed clusters.
1404
 */
1405
int ntfs_deallocate_clusters(const ntfs_volume *vol, const ntfs_runlist *rl,
1406
                const int rl_len)
1407
{
1408
        int i, err;
1409
 
1410
        lock_kernel();
1411
        for (i = err = 0; i < rl_len && !err; i++)
1412
                err = ntfs_clear_bitrange(vol->bitmap, rl[i].lcn, rl[i].len);
1413
        unlock_kernel();
1414
        return err;
1415
}
1416
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.