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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [xfs/] [xfs_iomap.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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_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_dir2.h"
27
#include "xfs_alloc.h"
28
#include "xfs_dmapi.h"
29
#include "xfs_quota.h"
30
#include "xfs_mount.h"
31
#include "xfs_bmap_btree.h"
32
#include "xfs_alloc_btree.h"
33
#include "xfs_ialloc_btree.h"
34
#include "xfs_dir2_sf.h"
35
#include "xfs_attr_sf.h"
36
#include "xfs_dinode.h"
37
#include "xfs_inode.h"
38
#include "xfs_ialloc.h"
39
#include "xfs_btree.h"
40
#include "xfs_bmap.h"
41
#include "xfs_rtalloc.h"
42
#include "xfs_error.h"
43
#include "xfs_itable.h"
44
#include "xfs_rw.h"
45
#include "xfs_acl.h"
46
#include "xfs_attr.h"
47
#include "xfs_buf_item.h"
48
#include "xfs_trans_space.h"
49
#include "xfs_utils.h"
50
#include "xfs_iomap.h"
51
 
52
#if defined(XFS_RW_TRACE)
53
void
54
xfs_iomap_enter_trace(
55
        int             tag,
56
        xfs_iocore_t    *io,
57
        xfs_off_t       offset,
58
        ssize_t         count)
59
{
60
        xfs_inode_t     *ip = XFS_IO_INODE(io);
61
 
62
        if (!ip->i_rwtrace)
63
                return;
64
 
65
        ktrace_enter(ip->i_rwtrace,
66
                (void *)((unsigned long)tag),
67
                (void *)ip,
68
                (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),
69
                (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),
70
                (void *)((unsigned long)((offset >> 32) & 0xffffffff)),
71
                (void *)((unsigned long)(offset & 0xffffffff)),
72
                (void *)((unsigned long)count),
73
                (void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)),
74
                (void *)((unsigned long)(io->io_new_size & 0xffffffff)),
75
                (void *)((unsigned long)current_pid()),
76
                (void *)NULL,
77
                (void *)NULL,
78
                (void *)NULL,
79
                (void *)NULL,
80
                (void *)NULL,
81
                (void *)NULL);
82
}
83
 
84
void
85
xfs_iomap_map_trace(
86
        int             tag,
87
        xfs_iocore_t    *io,
88
        xfs_off_t       offset,
89
        ssize_t         count,
90
        xfs_iomap_t     *iomapp,
91
        xfs_bmbt_irec_t *imapp,
92
        int             flags)
93
{
94
        xfs_inode_t     *ip = XFS_IO_INODE(io);
95
 
96
        if (!ip->i_rwtrace)
97
                return;
98
 
99
        ktrace_enter(ip->i_rwtrace,
100
                (void *)((unsigned long)tag),
101
                (void *)ip,
102
                (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),
103
                (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),
104
                (void *)((unsigned long)((offset >> 32) & 0xffffffff)),
105
                (void *)((unsigned long)(offset & 0xffffffff)),
106
                (void *)((unsigned long)count),
107
                (void *)((unsigned long)flags),
108
                (void *)((unsigned long)((iomapp->iomap_offset >> 32) & 0xffffffff)),
109
                (void *)((unsigned long)(iomapp->iomap_offset & 0xffffffff)),
110
                (void *)((unsigned long)(iomapp->iomap_delta)),
111
                (void *)((unsigned long)(iomapp->iomap_bsize)),
112
                (void *)((unsigned long)(iomapp->iomap_bn)),
113
                (void *)(__psint_t)(imapp->br_startoff),
114
                (void *)((unsigned long)(imapp->br_blockcount)),
115
                (void *)(__psint_t)(imapp->br_startblock));
116
}
117
#else
118
#define xfs_iomap_enter_trace(tag, io, offset, count)
119
#define xfs_iomap_map_trace(tag, io, offset, count, iomapp, imapp, flags)
120
#endif
121
 
122
#define XFS_WRITEIO_ALIGN(mp,off)       (((off) >> mp->m_writeio_log) \
123
                                                << mp->m_writeio_log)
124
#define XFS_STRAT_WRITE_IMAPS   2
125
#define XFS_WRITE_IMAPS         XFS_BMAP_MAX_NMAP
126
 
127
STATIC int
128
xfs_imap_to_bmap(
129
        xfs_iocore_t    *io,
130
        xfs_off_t       offset,
131
        xfs_bmbt_irec_t *imap,
132
        xfs_iomap_t     *iomapp,
133
        int             imaps,                  /* Number of imap entries */
134
        int             iomaps,                 /* Number of iomap entries */
135
        int             flags)
136
{
137
        xfs_mount_t     *mp;
138
        int             pbm;
139
        xfs_fsblock_t   start_block;
140
 
141
        mp = io->io_mount;
142
 
143
        for (pbm = 0; imaps && pbm < iomaps; imaps--, iomapp++, imap++, pbm++) {
144
                iomapp->iomap_offset = XFS_FSB_TO_B(mp, imap->br_startoff);
145
                iomapp->iomap_delta = offset - iomapp->iomap_offset;
146
                iomapp->iomap_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount);
147
                iomapp->iomap_flags = flags;
148
 
149
                if (io->io_flags & XFS_IOCORE_RT) {
150
                        iomapp->iomap_flags |= IOMAP_REALTIME;
151
                        iomapp->iomap_target = mp->m_rtdev_targp;
152
                } else {
153
                        iomapp->iomap_target = mp->m_ddev_targp;
154
                }
155
                start_block = imap->br_startblock;
156
                if (start_block == HOLESTARTBLOCK) {
157
                        iomapp->iomap_bn = IOMAP_DADDR_NULL;
158
                        iomapp->iomap_flags |= IOMAP_HOLE;
159
                } else if (start_block == DELAYSTARTBLOCK) {
160
                        iomapp->iomap_bn = IOMAP_DADDR_NULL;
161
                        iomapp->iomap_flags |= IOMAP_DELAY;
162
                } else {
163
                        iomapp->iomap_bn = XFS_FSB_TO_DB_IO(io, start_block);
164
                        if (ISUNWRITTEN(imap))
165
                                iomapp->iomap_flags |= IOMAP_UNWRITTEN;
166
                }
167
 
168
                offset += iomapp->iomap_bsize - iomapp->iomap_delta;
169
        }
170
        return pbm;     /* Return the number filled */
171
}
172
 
173
int
174
xfs_iomap(
175
        xfs_iocore_t    *io,
176
        xfs_off_t       offset,
177
        ssize_t         count,
178
        int             flags,
179
        xfs_iomap_t     *iomapp,
180
        int             *niomaps)
181
{
182
        xfs_mount_t     *mp = io->io_mount;
183
        xfs_fileoff_t   offset_fsb, end_fsb;
184
        int             error = 0;
185
        int             lockmode = 0;
186
        xfs_bmbt_irec_t imap;
187
        int             nimaps = 1;
188
        int             bmapi_flags = 0;
189
        int             iomap_flags = 0;
190
 
191
        if (XFS_FORCED_SHUTDOWN(mp))
192
                return XFS_ERROR(EIO);
193
 
194
        switch (flags &
195
                (BMAPI_READ | BMAPI_WRITE | BMAPI_ALLOCATE |
196
                 BMAPI_UNWRITTEN | BMAPI_DEVICE)) {
197
        case BMAPI_READ:
198
                xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count);
199
                lockmode = XFS_LCK_MAP_SHARED(mp, io);
200
                bmapi_flags = XFS_BMAPI_ENTIRE;
201
                break;
202
        case BMAPI_WRITE:
203
                xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count);
204
                lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR;
205
                if (flags & BMAPI_IGNSTATE)
206
                        bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE;
207
                XFS_ILOCK(mp, io, lockmode);
208
                break;
209
        case BMAPI_ALLOCATE:
210
                xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, io, offset, count);
211
                lockmode = XFS_ILOCK_SHARED|XFS_EXTSIZE_RD;
212
                bmapi_flags = XFS_BMAPI_ENTIRE;
213
                /* Attempt non-blocking lock */
214
                if (flags & BMAPI_TRYLOCK) {
215
                        if (!XFS_ILOCK_NOWAIT(mp, io, lockmode))
216
                                return XFS_ERROR(EAGAIN);
217
                } else {
218
                        XFS_ILOCK(mp, io, lockmode);
219
                }
220
                break;
221
        case BMAPI_UNWRITTEN:
222
                goto phase2;
223
        case BMAPI_DEVICE:
224
                lockmode = XFS_LCK_MAP_SHARED(mp, io);
225
                iomapp->iomap_target = io->io_flags & XFS_IOCORE_RT ?
226
                        mp->m_rtdev_targp : mp->m_ddev_targp;
227
                error = 0;
228
                *niomaps = 1;
229
                goto out;
230
        default:
231
                BUG();
232
        }
233
 
234
        ASSERT(offset <= mp->m_maxioffset);
235
        if ((xfs_fsize_t)offset + count > mp->m_maxioffset)
236
                count = mp->m_maxioffset - offset;
237
        end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
238
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
239
 
240
        error = XFS_BMAPI(mp, NULL, io, offset_fsb,
241
                        (xfs_filblks_t)(end_fsb - offset_fsb),
242
                        bmapi_flags,  NULL, 0, &imap,
243
                        &nimaps, NULL, NULL);
244
 
245
        if (error)
246
                goto out;
247
 
248
phase2:
249
        switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE|BMAPI_UNWRITTEN)) {
250
        case BMAPI_WRITE:
251
                /* If we found an extent, return it */
252
                if (nimaps &&
253
                    (imap.br_startblock != HOLESTARTBLOCK) &&
254
                    (imap.br_startblock != DELAYSTARTBLOCK)) {
255
                        xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io,
256
                                        offset, count, iomapp, &imap, flags);
257
                        break;
258
                }
259
 
260
                if (flags & (BMAPI_DIRECT|BMAPI_MMAP)) {
261
                        error = XFS_IOMAP_WRITE_DIRECT(mp, io, offset,
262
                                        count, flags, &imap, &nimaps, nimaps);
263
                } else {
264
                        error = XFS_IOMAP_WRITE_DELAY(mp, io, offset, count,
265
                                        flags, &imap, &nimaps);
266
                }
267
                if (!error) {
268
                        xfs_iomap_map_trace(XFS_IOMAP_ALLOC_MAP, io,
269
                                        offset, count, iomapp, &imap, flags);
270
                }
271
                iomap_flags = IOMAP_NEW;
272
                break;
273
        case BMAPI_ALLOCATE:
274
                /* If we found an extent, return it */
275
                XFS_IUNLOCK(mp, io, lockmode);
276
                lockmode = 0;
277
 
278
                if (nimaps && !ISNULLSTARTBLOCK(imap.br_startblock)) {
279
                        xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io,
280
                                        offset, count, iomapp, &imap, flags);
281
                        break;
282
                }
283
 
284
                error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count,
285
                                                 &imap, &nimaps);
286
                break;
287
        case BMAPI_UNWRITTEN:
288
                lockmode = 0;
289
                error = XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count);
290
                nimaps = 0;
291
                break;
292
        }
293
 
294
        if (nimaps) {
295
                *niomaps = xfs_imap_to_bmap(io, offset, &imap,
296
                                            iomapp, nimaps, *niomaps, iomap_flags);
297
        } else if (niomaps) {
298
                *niomaps = 0;
299
        }
300
 
301
out:
302
        if (lockmode)
303
                XFS_IUNLOCK(mp, io, lockmode);
304
        return XFS_ERROR(error);
305
}
306
 
307
STATIC int
308
xfs_iomap_eof_align_last_fsb(
309
        xfs_mount_t     *mp,
310
        xfs_iocore_t    *io,
311
        xfs_fsize_t     isize,
312
        xfs_extlen_t    extsize,
313
        xfs_fileoff_t   *last_fsb)
314
{
315
        xfs_fileoff_t   new_last_fsb = 0;
316
        xfs_extlen_t    align;
317
        int             eof, error;
318
 
319
        if (io->io_flags & XFS_IOCORE_RT)
320
                ;
321
        /*
322
         * If mounted with the "-o swalloc" option, roundup the allocation
323
         * request to a stripe width boundary if the file size is >=
324
         * stripe width and we are allocating past the allocation eof.
325
         */
326
        else if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC) &&
327
                (isize >= XFS_FSB_TO_B(mp, mp->m_swidth)))
328
                new_last_fsb = roundup_64(*last_fsb, mp->m_swidth);
329
        /*
330
         * Roundup the allocation request to a stripe unit (m_dalign) boundary
331
         * if the file size is >= stripe unit size, and we are allocating past
332
         * the allocation eof.
333
         */
334
        else if (mp->m_dalign && (isize >= XFS_FSB_TO_B(mp, mp->m_dalign)))
335
                new_last_fsb = roundup_64(*last_fsb, mp->m_dalign);
336
 
337
        /*
338
         * Always round up the allocation request to an extent boundary
339
         * (when file on a real-time subvolume or has di_extsize hint).
340
         */
341
        if (extsize) {
342
                if (new_last_fsb)
343
                        align = roundup_64(new_last_fsb, extsize);
344
                else
345
                        align = extsize;
346
                new_last_fsb = roundup_64(*last_fsb, align);
347
        }
348
 
349
        if (new_last_fsb) {
350
                error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof);
351
                if (error)
352
                        return error;
353
                if (eof)
354
                        *last_fsb = new_last_fsb;
355
        }
356
        return 0;
357
}
358
 
359
STATIC int
360
xfs_flush_space(
361
        xfs_inode_t     *ip,
362
        int             *fsynced,
363
        int             *ioflags)
364
{
365
        switch (*fsynced) {
366
        case 0:
367
                if (ip->i_delayed_blks) {
368
                        xfs_iunlock(ip, XFS_ILOCK_EXCL);
369
                        xfs_flush_inode(ip);
370
                        xfs_ilock(ip, XFS_ILOCK_EXCL);
371
                        *fsynced = 1;
372
                } else {
373
                        *ioflags |= BMAPI_SYNC;
374
                        *fsynced = 2;
375
                }
376
                return 0;
377
        case 1:
378
                *fsynced = 2;
379
                *ioflags |= BMAPI_SYNC;
380
                return 0;
381
        case 2:
382
                xfs_iunlock(ip, XFS_ILOCK_EXCL);
383
                xfs_flush_device(ip);
384
                xfs_ilock(ip, XFS_ILOCK_EXCL);
385
                *fsynced = 3;
386
                return 0;
387
        }
388
        return 1;
389
}
390
 
391
STATIC int
392
xfs_cmn_err_fsblock_zero(
393
        xfs_inode_t     *ip,
394
        xfs_bmbt_irec_t *imap)
395
{
396
        xfs_cmn_err(XFS_PTAG_FSBLOCK_ZERO, CE_ALERT, ip->i_mount,
397
                        "Access to block zero in inode %llu "
398
                        "start_block: %llx start_off: %llx "
399
                        "blkcnt: %llx extent-state: %x\n",
400
                (unsigned long long)ip->i_ino,
401
                (unsigned long long)imap->br_startblock,
402
                (unsigned long long)imap->br_startoff,
403
                (unsigned long long)imap->br_blockcount,
404
                imap->br_state);
405
        return EFSCORRUPTED;
406
}
407
 
408
int
409
xfs_iomap_write_direct(
410
        xfs_inode_t     *ip,
411
        xfs_off_t       offset,
412
        size_t          count,
413
        int             flags,
414
        xfs_bmbt_irec_t *ret_imap,
415
        int             *nmaps,
416
        int             found)
417
{
418
        xfs_mount_t     *mp = ip->i_mount;
419
        xfs_iocore_t    *io = &ip->i_iocore;
420
        xfs_fileoff_t   offset_fsb;
421
        xfs_fileoff_t   last_fsb;
422
        xfs_filblks_t   count_fsb, resaligned;
423
        xfs_fsblock_t   firstfsb;
424
        xfs_extlen_t    extsz, temp;
425
        xfs_fsize_t     isize;
426
        int             nimaps;
427
        int             bmapi_flag;
428
        int             quota_flag;
429
        int             rt;
430
        xfs_trans_t     *tp;
431
        xfs_bmbt_irec_t imap;
432
        xfs_bmap_free_t free_list;
433
        uint            qblocks, resblks, resrtextents;
434
        int             committed;
435
        int             error;
436
 
437
        /*
438
         * Make sure that the dquots are there. This doesn't hold
439
         * the ilock across a disk read.
440
         */
441
        error = XFS_QM_DQATTACH(ip->i_mount, ip, XFS_QMOPT_ILOCKED);
442
        if (error)
443
                return XFS_ERROR(error);
444
 
445
        rt = XFS_IS_REALTIME_INODE(ip);
446
        extsz = xfs_get_extsz_hint(ip);
447
 
448
        isize = ip->i_size;
449
        if (io->io_new_size > isize)
450
                isize = io->io_new_size;
451
 
452
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
453
        last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
454
        if ((offset + count) > isize) {
455
                error = xfs_iomap_eof_align_last_fsb(mp, io, isize, extsz,
456
                                                        &last_fsb);
457
                if (error)
458
                        goto error_out;
459
        } else {
460
                if (found && (ret_imap->br_startblock == HOLESTARTBLOCK))
461
                        last_fsb = MIN(last_fsb, (xfs_fileoff_t)
462
                                        ret_imap->br_blockcount +
463
                                        ret_imap->br_startoff);
464
        }
465
        count_fsb = last_fsb - offset_fsb;
466
        ASSERT(count_fsb > 0);
467
 
468
        resaligned = count_fsb;
469
        if (unlikely(extsz)) {
470
                if ((temp = do_mod(offset_fsb, extsz)))
471
                        resaligned += temp;
472
                if ((temp = do_mod(resaligned, extsz)))
473
                        resaligned += extsz - temp;
474
        }
475
 
476
        if (unlikely(rt)) {
477
                resrtextents = qblocks = resaligned;
478
                resrtextents /= mp->m_sb.sb_rextsize;
479
                resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
480
                quota_flag = XFS_QMOPT_RES_RTBLKS;
481
        } else {
482
                resrtextents = 0;
483
                resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
484
                quota_flag = XFS_QMOPT_RES_REGBLKS;
485
        }
486
 
487
        /*
488
         * Allocate and setup the transaction
489
         */
490
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
491
        tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
492
        error = xfs_trans_reserve(tp, resblks,
493
                        XFS_WRITE_LOG_RES(mp), resrtextents,
494
                        XFS_TRANS_PERM_LOG_RES,
495
                        XFS_WRITE_LOG_COUNT);
496
        /*
497
         * Check for running out of space, note: need lock to return
498
         */
499
        if (error)
500
                xfs_trans_cancel(tp, 0);
501
        xfs_ilock(ip, XFS_ILOCK_EXCL);
502
        if (error)
503
                goto error_out;
504
 
505
        error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip,
506
                                              qblocks, 0, quota_flag);
507
        if (error)
508
                goto error1;
509
 
510
        xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
511
        xfs_trans_ihold(tp, ip);
512
 
513
        bmapi_flag = XFS_BMAPI_WRITE;
514
        if ((flags & BMAPI_DIRECT) && (offset < ip->i_size || extsz))
515
                bmapi_flag |= XFS_BMAPI_PREALLOC;
516
 
517
        /*
518
         * Issue the xfs_bmapi() call to allocate the blocks
519
         */
520
        XFS_BMAP_INIT(&free_list, &firstfsb);
521
        nimaps = 1;
522
        error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, bmapi_flag,
523
                &firstfsb, 0, &imap, &nimaps, &free_list, NULL);
524
        if (error)
525
                goto error0;
526
 
527
        /*
528
         * Complete the transaction
529
         */
530
        error = xfs_bmap_finish(&tp, &free_list, &committed);
531
        if (error)
532
                goto error0;
533
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
534
        if (error)
535
                goto error_out;
536
 
537
        /*
538
         * Copy any maps to caller's array and return any error.
539
         */
540
        if (nimaps == 0) {
541
                error = ENOSPC;
542
                goto error_out;
543
        }
544
 
545
        if (unlikely(!imap.br_startblock && !(io->io_flags & XFS_IOCORE_RT))) {
546
                error = xfs_cmn_err_fsblock_zero(ip, &imap);
547
                goto error_out;
548
        }
549
 
550
        *ret_imap = imap;
551
        *nmaps = 1;
552
        return 0;
553
 
554
error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
555
        xfs_bmap_cancel(&free_list);
556
        XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag);
557
 
558
error1: /* Just cancel transaction */
559
        xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
560
        *nmaps = 0;      /* nothing set-up here */
561
 
562
error_out:
563
        return XFS_ERROR(error);
564
}
565
 
566
/*
567
 * If the caller is doing a write at the end of the file,
568
 * then extend the allocation out to the file system's write
569
 * iosize.  We clean up any extra space left over when the
570
 * file is closed in xfs_inactive().
571
 *
572
 * For sync writes, we are flushing delayed allocate space to
573
 * try to make additional space available for allocation near
574
 * the filesystem full boundary - preallocation hurts in that
575
 * situation, of course.
576
 */
577
STATIC int
578
xfs_iomap_eof_want_preallocate(
579
        xfs_mount_t     *mp,
580
        xfs_iocore_t    *io,
581
        xfs_fsize_t     isize,
582
        xfs_off_t       offset,
583
        size_t          count,
584
        int             ioflag,
585
        xfs_bmbt_irec_t *imap,
586
        int             nimaps,
587
        int             *prealloc)
588
{
589
        xfs_fileoff_t   start_fsb;
590
        xfs_filblks_t   count_fsb;
591
        xfs_fsblock_t   firstblock;
592
        int             n, error, imaps;
593
 
594
        *prealloc = 0;
595
        if ((ioflag & BMAPI_SYNC) || (offset + count) <= isize)
596
                return 0;
597
 
598
        /*
599
         * If there are any real blocks past eof, then don't
600
         * do any speculative allocation.
601
         */
602
        start_fsb = XFS_B_TO_FSBT(mp, ((xfs_ufsize_t)(offset + count - 1)));
603
        count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
604
        while (count_fsb > 0) {
605
                imaps = nimaps;
606
                firstblock = NULLFSBLOCK;
607
                error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb, 0,
608
                                  &firstblock, 0, imap, &imaps, NULL, NULL);
609
                if (error)
610
                        return error;
611
                for (n = 0; n < imaps; n++) {
612
                        if ((imap[n].br_startblock != HOLESTARTBLOCK) &&
613
                            (imap[n].br_startblock != DELAYSTARTBLOCK))
614
                                return 0;
615
                        start_fsb += imap[n].br_blockcount;
616
                        count_fsb -= imap[n].br_blockcount;
617
                }
618
        }
619
        *prealloc = 1;
620
        return 0;
621
}
622
 
623
int
624
xfs_iomap_write_delay(
625
        xfs_inode_t     *ip,
626
        xfs_off_t       offset,
627
        size_t          count,
628
        int             ioflag,
629
        xfs_bmbt_irec_t *ret_imap,
630
        int             *nmaps)
631
{
632
        xfs_mount_t     *mp = ip->i_mount;
633
        xfs_iocore_t    *io = &ip->i_iocore;
634
        xfs_fileoff_t   offset_fsb;
635
        xfs_fileoff_t   last_fsb;
636
        xfs_off_t       aligned_offset;
637
        xfs_fileoff_t   ioalign;
638
        xfs_fsblock_t   firstblock;
639
        xfs_extlen_t    extsz;
640
        xfs_fsize_t     isize;
641
        int             nimaps;
642
        xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS];
643
        int             prealloc, fsynced = 0;
644
        int             error;
645
 
646
        ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0);
647
 
648
        /*
649
         * Make sure that the dquots are there. This doesn't hold
650
         * the ilock across a disk read.
651
         */
652
        error = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
653
        if (error)
654
                return XFS_ERROR(error);
655
 
656
        extsz = xfs_get_extsz_hint(ip);
657
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
658
 
659
retry:
660
        isize = ip->i_size;
661
        if (io->io_new_size > isize)
662
                isize = io->io_new_size;
663
 
664
        error = xfs_iomap_eof_want_preallocate(mp, io, isize, offset, count,
665
                                ioflag, imap, XFS_WRITE_IMAPS, &prealloc);
666
        if (error)
667
                return error;
668
 
669
        if (prealloc) {
670
                aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1));
671
                ioalign = XFS_B_TO_FSBT(mp, aligned_offset);
672
                last_fsb = ioalign + mp->m_writeio_blocks;
673
        } else {
674
                last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
675
        }
676
 
677
        if (prealloc || extsz) {
678
                error = xfs_iomap_eof_align_last_fsb(mp, io, isize, extsz,
679
                                                        &last_fsb);
680
                if (error)
681
                        return error;
682
        }
683
 
684
        nimaps = XFS_WRITE_IMAPS;
685
        firstblock = NULLFSBLOCK;
686
        error = XFS_BMAPI(mp, NULL, io, offset_fsb,
687
                          (xfs_filblks_t)(last_fsb - offset_fsb),
688
                          XFS_BMAPI_DELAY | XFS_BMAPI_WRITE |
689
                          XFS_BMAPI_ENTIRE, &firstblock, 1, imap,
690
                          &nimaps, NULL, NULL);
691
        if (error && (error != ENOSPC))
692
                return XFS_ERROR(error);
693
 
694
        /*
695
         * If bmapi returned us nothing, and if we didn't get back EDQUOT,
696
         * then we must have run out of space - flush delalloc, and retry..
697
         */
698
        if (nimaps == 0) {
699
                xfs_iomap_enter_trace(XFS_IOMAP_WRITE_NOSPACE,
700
                                        io, offset, count);
701
                if (xfs_flush_space(ip, &fsynced, &ioflag))
702
                        return XFS_ERROR(ENOSPC);
703
 
704
                error = 0;
705
                goto retry;
706
        }
707
 
708
        if (unlikely(!imap[0].br_startblock && !(io->io_flags & XFS_IOCORE_RT)))
709
                return xfs_cmn_err_fsblock_zero(ip, &imap[0]);
710
 
711
        *ret_imap = imap[0];
712
        *nmaps = 1;
713
 
714
        return 0;
715
}
716
 
717
/*
718
 * Pass in a delayed allocate extent, convert it to real extents;
719
 * return to the caller the extent we create which maps on top of
720
 * the originating callers request.
721
 *
722
 * Called without a lock on the inode.
723
 */
724
int
725
xfs_iomap_write_allocate(
726
        xfs_inode_t     *ip,
727
        xfs_off_t       offset,
728
        size_t          count,
729
        xfs_bmbt_irec_t *map,
730
        int             *retmap)
731
{
732
        xfs_mount_t     *mp = ip->i_mount;
733
        xfs_iocore_t    *io = &ip->i_iocore;
734
        xfs_fileoff_t   offset_fsb, last_block;
735
        xfs_fileoff_t   end_fsb, map_start_fsb;
736
        xfs_fsblock_t   first_block;
737
        xfs_bmap_free_t free_list;
738
        xfs_filblks_t   count_fsb;
739
        xfs_bmbt_irec_t imap[XFS_STRAT_WRITE_IMAPS];
740
        xfs_trans_t     *tp;
741
        int             i, nimaps, committed;
742
        int             error = 0;
743
        int             nres;
744
 
745
        *retmap = 0;
746
 
747
        /*
748
         * Make sure that the dquots are there.
749
         */
750
        if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
751
                return XFS_ERROR(error);
752
 
753
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
754
        count_fsb = map->br_blockcount;
755
        map_start_fsb = map->br_startoff;
756
 
757
        XFS_STATS_ADD(xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb));
758
 
759
        while (count_fsb != 0) {
760
                /*
761
                 * Set up a transaction with which to allocate the
762
                 * backing store for the file.  Do allocations in a
763
                 * loop until we get some space in the range we are
764
                 * interested in.  The other space that might be allocated
765
                 * is in the delayed allocation extent on which we sit
766
                 * but before our buffer starts.
767
                 */
768
 
769
                nimaps = 0;
770
                while (nimaps == 0) {
771
                        tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
772
                        tp->t_flags |= XFS_TRANS_RESERVE;
773
                        nres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
774
                        error = xfs_trans_reserve(tp, nres,
775
                                        XFS_WRITE_LOG_RES(mp),
776
                                        0, XFS_TRANS_PERM_LOG_RES,
777
                                        XFS_WRITE_LOG_COUNT);
778
                        if (error) {
779
                                xfs_trans_cancel(tp, 0);
780
                                return XFS_ERROR(error);
781
                        }
782
                        xfs_ilock(ip, XFS_ILOCK_EXCL);
783
                        xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
784
                        xfs_trans_ihold(tp, ip);
785
 
786
                        XFS_BMAP_INIT(&free_list, &first_block);
787
 
788
                        nimaps = XFS_STRAT_WRITE_IMAPS;
789
                        /*
790
                         * Ensure we don't go beyond eof - it is possible
791
                         * the extents changed since we did the read call,
792
                         * we dropped the ilock in the interim.
793
                         */
794
 
795
                        end_fsb = XFS_B_TO_FSB(mp, ip->i_size);
796
                        xfs_bmap_last_offset(NULL, ip, &last_block,
797
                                XFS_DATA_FORK);
798
                        last_block = XFS_FILEOFF_MAX(last_block, end_fsb);
799
                        if ((map_start_fsb + count_fsb) > last_block) {
800
                                count_fsb = last_block - map_start_fsb;
801
                                if (count_fsb == 0) {
802
                                        error = EAGAIN;
803
                                        goto trans_cancel;
804
                                }
805
                        }
806
 
807
                        /* Go get the actual blocks */
808
                        error = XFS_BMAPI(mp, tp, io, map_start_fsb, count_fsb,
809
                                        XFS_BMAPI_WRITE, &first_block, 1,
810
                                        imap, &nimaps, &free_list, NULL);
811
                        if (error)
812
                                goto trans_cancel;
813
 
814
                        error = xfs_bmap_finish(&tp, &free_list, &committed);
815
                        if (error)
816
                                goto trans_cancel;
817
 
818
                        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
819
                        if (error)
820
                                goto error0;
821
 
822
                        xfs_iunlock(ip, XFS_ILOCK_EXCL);
823
                }
824
 
825
                /*
826
                 * See if we were able to allocate an extent that
827
                 * covers at least part of the callers request
828
                 */
829
                for (i = 0; i < nimaps; i++) {
830
                        if (unlikely(!imap[i].br_startblock &&
831
                                     !(io->io_flags & XFS_IOCORE_RT)))
832
                                return xfs_cmn_err_fsblock_zero(ip, &imap[i]);
833
                        if ((offset_fsb >= imap[i].br_startoff) &&
834
                            (offset_fsb < (imap[i].br_startoff +
835
                                           imap[i].br_blockcount))) {
836
                                *map = imap[i];
837
                                *retmap = 1;
838
                                XFS_STATS_INC(xs_xstrat_quick);
839
                                return 0;
840
                        }
841
                        count_fsb -= imap[i].br_blockcount;
842
                }
843
 
844
                /* So far we have not mapped the requested part of the
845
                 * file, just surrounding data, try again.
846
                 */
847
                nimaps--;
848
                map_start_fsb = imap[nimaps].br_startoff +
849
                                imap[nimaps].br_blockcount;
850
        }
851
 
852
trans_cancel:
853
        xfs_bmap_cancel(&free_list);
854
        xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
855
error0:
856
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
857
        return XFS_ERROR(error);
858
}
859
 
860
int
861
xfs_iomap_write_unwritten(
862
        xfs_inode_t     *ip,
863
        xfs_off_t       offset,
864
        size_t          count)
865
{
866
        xfs_mount_t     *mp = ip->i_mount;
867
        xfs_iocore_t    *io = &ip->i_iocore;
868
        xfs_fileoff_t   offset_fsb;
869
        xfs_filblks_t   count_fsb;
870
        xfs_filblks_t   numblks_fsb;
871
        xfs_fsblock_t   firstfsb;
872
        int             nimaps;
873
        xfs_trans_t     *tp;
874
        xfs_bmbt_irec_t imap;
875
        xfs_bmap_free_t free_list;
876
        uint            resblks;
877
        int             committed;
878
        int             error;
879
 
880
        xfs_iomap_enter_trace(XFS_IOMAP_UNWRITTEN,
881
                                &ip->i_iocore, offset, count);
882
 
883
        offset_fsb = XFS_B_TO_FSBT(mp, offset);
884
        count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
885
        count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb);
886
 
887
        resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1;
888
 
889
        do {
890
                /*
891
                 * set up a transaction to convert the range of extents
892
                 * from unwritten to real. Do allocations in a loop until
893
                 * we have covered the range passed in.
894
                 */
895
                tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
896
                tp->t_flags |= XFS_TRANS_RESERVE;
897
                error = xfs_trans_reserve(tp, resblks,
898
                                XFS_WRITE_LOG_RES(mp), 0,
899
                                XFS_TRANS_PERM_LOG_RES,
900
                                XFS_WRITE_LOG_COUNT);
901
                if (error) {
902
                        xfs_trans_cancel(tp, 0);
903
                        return XFS_ERROR(error);
904
                }
905
 
906
                xfs_ilock(ip, XFS_ILOCK_EXCL);
907
                xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
908
                xfs_trans_ihold(tp, ip);
909
 
910
                /*
911
                 * Modify the unwritten extent state of the buffer.
912
                 */
913
                XFS_BMAP_INIT(&free_list, &firstfsb);
914
                nimaps = 1;
915
                error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb,
916
                                  XFS_BMAPI_WRITE|XFS_BMAPI_CONVERT, &firstfsb,
917
                                  1, &imap, &nimaps, &free_list, NULL);
918
                if (error)
919
                        goto error_on_bmapi_transaction;
920
 
921
                error = xfs_bmap_finish(&(tp), &(free_list), &committed);
922
                if (error)
923
                        goto error_on_bmapi_transaction;
924
 
925
                error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
926
                xfs_iunlock(ip, XFS_ILOCK_EXCL);
927
                if (error)
928
                        return XFS_ERROR(error);
929
 
930
                if (unlikely(!imap.br_startblock &&
931
                             !(io->io_flags & XFS_IOCORE_RT)))
932
                        return xfs_cmn_err_fsblock_zero(ip, &imap);
933
 
934
                if ((numblks_fsb = imap.br_blockcount) == 0) {
935
                        /*
936
                         * The numblks_fsb value should always get
937
                         * smaller, otherwise the loop is stuck.
938
                         */
939
                        ASSERT(imap.br_blockcount);
940
                        break;
941
                }
942
                offset_fsb += numblks_fsb;
943
                count_fsb -= numblks_fsb;
944
        } while (count_fsb > 0);
945
 
946
        return 0;
947
 
948
error_on_bmapi_transaction:
949
        xfs_bmap_cancel(&free_list);
950
        xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT));
951
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
952
        return XFS_ERROR(error);
953
}

powered by: WebSVN 2.1.0

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