~ubuntu-branches/ubuntu/maverick/ocfs2-tools/maverick

« back to all changes in this revision

Viewing changes to libocfs2/truncate.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2007-11-19 06:53:59 UTC
  • Revision ID: james.westby@ubuntu.com-20071119065359-7yan1p3eg1d28sgx
Tags: 1.3.9-0ubuntu1

* Update default timeouts in template and translations files.

* debian/rules: fix clean target to not purge upstream patches/ directory.

* debian/control: rework Build-Depends
  - sort them: debian build specific bits first, upstream after in configure
    check order.
  - add pkg-config.
  - add libselinux1-dev and libsepol1-dev.

* add package ocfs2-tools-static-dev to include all development headers and
  static libraries required to build ocfs2-test (and possibly other tools
  that already in development stage.

* stop shipping local copy of mount.ocfs2.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
 
33
33
#include "ocfs2.h"
34
34
 
 
35
struct truncate_ctxt {
 
36
        uint64_t new_size_in_clusters;
 
37
        uint32_t new_i_clusters;
 
38
};
 
39
 
35
40
/*
36
41
 * Delete and free clusters if needed.  This only works with DEPTH_TRAVERSE.
37
42
 */
41
46
                            uint64_t ref_blkno, int ref_recno,
42
47
                            void *priv_data)
43
48
{
44
 
        uint32_t len, new_i_clusters = *(uint32_t *)priv_data;
 
49
        struct truncate_ctxt *ctxt = (struct truncate_ctxt *)priv_data;
 
50
        uint32_t len = 0, new_size_in_clusters = ctxt->new_size_in_clusters;
45
51
        uint64_t start = 0;
46
52
        errcode_t ret;
 
53
        int func_ret = OCFS2_EXTENT_ERROR;
 
54
        char *buf = NULL;
 
55
        struct ocfs2_extent_list *el = NULL;
47
56
 
48
 
        if ((rec->e_cpos + rec->e_clusters) <= new_i_clusters)
 
57
        if ((rec->e_cpos + ocfs2_rec_clusters(tree_depth, rec)) <=
 
58
                                                        new_size_in_clusters)
49
59
                return 0;
50
60
 
51
 
        if (rec->e_cpos >= new_i_clusters) {
 
61
        if (rec->e_cpos >= new_size_in_clusters) {
52
62
                /* the rec is entirely outside the new size, free it */
53
63
                if (!tree_depth) {
54
64
                        start = rec->e_blkno;
55
 
                        len = rec->e_clusters;
 
65
                        len = ocfs2_rec_clusters(tree_depth, rec);
56
66
                } else {
57
67
                        /* here we meet with a full empty extent block, delete
58
68
                         * it. The extent list it contains should already be
63
73
                                goto bail;
64
74
                }
65
75
 
66
 
                rec->e_blkno = 0;
67
 
                rec->e_clusters = 0;
68
 
                rec->e_cpos = 0;
 
76
                memset(rec, 0, sizeof(struct ocfs2_extent_rec));
69
77
        } else {
70
78
                /* we're truncating into the middle of the rec */
71
 
                len = rec->e_cpos + rec->e_clusters;
72
 
                len -= new_i_clusters;
73
 
                rec->e_clusters = new_i_clusters - rec->e_cpos;
74
 
                if (!tree_depth)
 
79
                len = rec->e_cpos +
 
80
                         ocfs2_rec_clusters(tree_depth, rec);
 
81
                len -= new_size_in_clusters;
 
82
                if (!tree_depth) {
 
83
                        ocfs2_set_rec_clusters(tree_depth, rec,
 
84
                                        new_size_in_clusters - rec->e_cpos);
75
85
                        start = rec->e_blkno +
76
 
                                ocfs2_clusters_to_blocks(fs, rec->e_clusters);
 
86
                                ocfs2_clusters_to_blocks(fs,
 
87
                                                ocfs2_rec_clusters(tree_depth,
 
88
                                                                   rec));
 
89
                } else {
 
90
                        ocfs2_set_rec_clusters(tree_depth, rec,
 
91
                                        new_size_in_clusters - rec->e_cpos);
 
92
                        /*
 
93
                         * For a sparse file, we may meet with another
 
94
                         * situation here:
 
95
                         * The start of the left most extent rec is greater
 
96
                         * than the new size we truncate the file to, but the
 
97
                         * start of the extent block is less than that size.
 
98
                         * In this case, actually all the extent records in
 
99
                         * this extent block have been removed. So we have
 
100
                         * to remove the extent block also.
 
101
                         * In this function, we have to reread the extent list
 
102
                         * to see whether the extent block is empty or not.
 
103
                         */
 
104
                        ret = ocfs2_malloc_block(fs->fs_io, &buf);
 
105
                        if (ret)
 
106
                                goto bail;
 
107
 
 
108
                        ret = ocfs2_read_extent_block(fs, rec->e_blkno, buf);
 
109
                        if (ret)
 
110
                                goto bail;
 
111
 
 
112
                        el = &((struct ocfs2_extent_block *)buf)->h_list;
 
113
                        if (el->l_next_free_rec == 0) {
 
114
                                ret = ocfs2_delete_extent_block(fs, rec->e_blkno);
 
115
                                if (ret)
 
116
                                        goto bail;
 
117
                                memset(rec, 0, sizeof(struct ocfs2_extent_rec));
 
118
                        }
 
119
                }
77
120
        }
78
121
 
79
122
        if (start) {
80
123
                ret = ocfs2_free_clusters(fs, len, start);
81
124
                if (ret)
82
125
                        goto bail;
 
126
                ctxt->new_i_clusters -= len;
83
127
        }
84
128
 
85
 
        return OCFS2_EXTENT_CHANGED;
 
129
        func_ret =  OCFS2_EXTENT_CHANGED;
86
130
bail:
87
 
        return OCFS2_EXTENT_ERROR;
 
131
        if (buf)
 
132
                ocfs2_free(&buf);
 
133
        return func_ret;
 
134
}
 
135
 
 
136
/*
 
137
 * Zero the area past i_size but still within an allocated
 
138
 * cluster. This avoids exposing nonzero data on subsequent file
 
139
 * extends.
 
140
 */
 
141
static errcode_t ocfs2_zero_tail_for_truncate(ocfs2_cached_inode *ci,
 
142
                                              uint64_t new_size)
 
143
{
 
144
        errcode_t ret;
 
145
        char *buf = NULL;
 
146
        ocfs2_filesys *fs = ci->ci_fs;
 
147
        uint64_t start_blk, p_blkno, contig_blocks, start_off;
 
148
        int count, byte_counts, bpc = fs->fs_clustersize /fs->fs_blocksize;
 
149
 
 
150
        if (new_size == 0)
 
151
                return 0;
 
152
 
 
153
        start_blk = new_size / fs->fs_blocksize;
 
154
 
 
155
        ret = ocfs2_extent_map_get_blocks(ci, start_blk, 1,
 
156
                                          &p_blkno, &contig_blocks, NULL);
 
157
        if (ret)
 
158
                goto out;
 
159
 
 
160
        /* Tail is a hole. */
 
161
        if (!p_blkno)
 
162
                goto out;
 
163
 
 
164
        /* calculate the total blocks we need to empty. */
 
165
        count = bpc - (p_blkno & (bpc - 1));
 
166
        ret = ocfs2_malloc_blocks(fs->fs_io, count, &buf);
 
167
        if (ret)
 
168
                goto out;
 
169
 
 
170
        ret = io_read_block(fs->fs_io, p_blkno, count, buf);
 
171
        if (ret)
 
172
                goto out;
 
173
 
 
174
        /* empty the content after the new_size and within the same cluster. */
 
175
        start_off = new_size % fs->fs_blocksize;
 
176
        byte_counts = count * fs->fs_blocksize - start_off;
 
177
        memset(buf + start_off, 0, byte_counts);
 
178
 
 
179
        ret = io_write_block(fs->fs_io, p_blkno, count, buf);
 
180
 
 
181
out:
 
182
        if (buf)
 
183
                ocfs2_free(&buf);
 
184
        return ret;
88
185
}
89
186
 
90
187
/* XXX care about zeroing new clusters and final partially truncated 
92
189
errcode_t ocfs2_truncate(ocfs2_filesys *fs, uint64_t ino, uint64_t new_i_size)
93
190
{
94
191
        errcode_t ret;
95
 
        char *buf;
96
 
        struct ocfs2_dinode *di;
97
 
        uint32_t new_i_clusters;
98
 
        uint64_t new_i_blocks;
99
 
 
100
 
        ret = ocfs2_malloc_block(fs->fs_io, &buf);
101
 
        if (ret)
102
 
                return ret;
103
 
 
104
 
        ret = ocfs2_read_inode(fs, ino, buf);
105
 
        if (ret)
106
 
                goto out;
107
 
        di = (struct ocfs2_dinode *)buf;
108
 
 
109
 
        if (di->i_size == new_i_size)
110
 
                goto out;
111
 
 
112
 
        new_i_blocks = ocfs2_blocks_in_bytes(fs, new_i_size);
113
 
        new_i_clusters = ocfs2_clusters_in_blocks(fs, new_i_blocks);
114
 
 
115
 
        if (di->i_clusters < new_i_clusters) {
116
 
                ret = ocfs2_extend_allocation(fs, ino,
117
 
                                        new_i_clusters - di->i_clusters);
118
 
                if (ret)
119
 
                        goto out;
120
 
 
121
 
                /* the information of dinode has been changed, and we need to
122
 
                 * read it again.
123
 
                 */
124
 
                ret = ocfs2_read_inode(fs, ino, buf);
125
 
                if (ret)
126
 
                        goto out;
127
 
        } else {
128
 
                ret = ocfs2_extent_iterate_inode(fs, di,
129
 
                                                 OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE,
130
 
                                                 NULL, truncate_iterate,
131
 
                                                 &new_i_clusters);
132
 
                if (ret)
133
 
                        goto out;
 
192
        uint32_t new_clusters;
 
193
        ocfs2_cached_inode *ci = NULL;
 
194
 
 
195
        ret = ocfs2_read_cached_inode(fs, ino, &ci);
 
196
        if (ret)
 
197
                goto out;
 
198
 
 
199
        if (ci->ci_inode->i_size == new_i_size)
 
200
                goto out;
 
201
 
 
202
        if (ci->ci_inode->i_size < new_i_size)
 
203
                ret = ocfs2_extend_file(fs, ino, new_i_size);
 
204
        else {
 
205
                ret = ocfs2_zero_tail_and_truncate(fs, ci, new_i_size,
 
206
                                                   &new_clusters);
 
207
                if (ret)
 
208
                        goto out;
 
209
 
 
210
                ci->ci_inode->i_clusters = new_clusters;
134
211
 
135
212
                /* now all the clusters and extent blocks are freed.
136
213
                 * only when the file's content is empty, should the tree depth
137
214
                 * change.
138
215
                 */
139
 
                if (new_i_clusters == 0)
140
 
                        di->id2.i_list.l_tree_depth = 0;
 
216
                if (new_clusters == 0)
 
217
                        ci->ci_inode->id2.i_list.l_tree_depth = 0;
141
218
 
 
219
                ci->ci_inode->i_size = new_i_size;
 
220
                ret = ocfs2_write_cached_inode(fs, ci);
142
221
        }
143
 
 
144
 
        di->i_clusters = new_i_clusters;
145
 
        di->i_size = new_i_size;
146
 
        ret = ocfs2_write_inode(fs, ino, buf);
147
 
 
148
 
out:
149
 
        ocfs2_free(&buf);
150
 
 
 
222
out:
 
223
        if (ci)
 
224
                ocfs2_free_cached_inode(fs, ci);
 
225
        return ret;
 
226
}
 
227
 
 
228
/*
 
229
 * This fucntion will truncate the file's cluster which exceeds
 
230
 * the cluster where new_size resides in and empty all the
 
231
 * bytes in the same cluster which exceeds new_size.
 
232
 */
 
233
errcode_t ocfs2_zero_tail_and_truncate(ocfs2_filesys *fs,
 
234
                                       ocfs2_cached_inode *ci,
 
235
                                       uint64_t new_i_size,
 
236
                                       uint32_t *new_clusters)
 
237
{
 
238
        errcode_t ret;
 
239
        uint64_t new_size_in_blocks;
 
240
        struct truncate_ctxt ctxt;
 
241
 
 
242
        new_size_in_blocks = ocfs2_blocks_in_bytes(fs, new_i_size);
 
243
        ctxt.new_i_clusters = ci->ci_inode->i_clusters;
 
244
        ctxt.new_size_in_clusters =
 
245
                        ocfs2_clusters_in_blocks(fs, new_size_in_blocks);
 
246
 
 
247
        ret = ocfs2_extent_iterate_inode(fs, ci->ci_inode,
 
248
                                         OCFS2_EXTENT_FLAG_DEPTH_TRAVERSE,
 
249
                                         NULL, truncate_iterate,
 
250
                                         &ctxt);
 
251
        if (ret)
 
252
                goto out;
 
253
 
 
254
        ret = ocfs2_zero_tail_for_truncate(ci, new_i_size);
 
255
        if (ret)
 
256
                goto out;
 
257
 
 
258
        if (new_clusters)
 
259
                *new_clusters = ctxt.new_i_clusters;
 
260
out:
151
261
        return ret;
152
262
}
153
263