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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [ocfs2/] [mmap.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* -*- mode: c; c-basic-offset: 8; -*-
2
 * vim: noexpandtab sw=8 ts=8 sts=0:
3
 *
4
 * mmap.c
5
 *
6
 * Code to deal with the mess that is clustered mmap.
7
 *
8
 * Copyright (C) 2002, 2004 Oracle.  All rights reserved.
9
 *
10
 * This program is free software; you can redistribute it and/or
11
 * modify it under the terms of the GNU General Public
12
 * License as published by the Free Software Foundation; either
13
 * version 2 of the License, or (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 * General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public
21
 * License along with this program; if not, write to the
22
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23
 * Boston, MA 021110-1307, USA.
24
 */
25
 
26
#include <linux/fs.h>
27
#include <linux/types.h>
28
#include <linux/slab.h>
29
#include <linux/highmem.h>
30
#include <linux/pagemap.h>
31
#include <linux/uio.h>
32
#include <linux/signal.h>
33
#include <linux/rbtree.h>
34
 
35
#define MLOG_MASK_PREFIX ML_FILE_IO
36
#include <cluster/masklog.h>
37
 
38
#include "ocfs2.h"
39
 
40
#include "aops.h"
41
#include "dlmglue.h"
42
#include "file.h"
43
#include "inode.h"
44
#include "mmap.h"
45
 
46
static inline int ocfs2_vm_op_block_sigs(sigset_t *blocked, sigset_t *oldset)
47
{
48
        /* The best way to deal with signals in the vm path is
49
         * to block them upfront, rather than allowing the
50
         * locking paths to return -ERESTARTSYS. */
51
        sigfillset(blocked);
52
 
53
        /* We should technically never get a bad return value
54
         * from sigprocmask */
55
        return sigprocmask(SIG_BLOCK, blocked, oldset);
56
}
57
 
58
static inline int ocfs2_vm_op_unblock_sigs(sigset_t *oldset)
59
{
60
        return sigprocmask(SIG_SETMASK, oldset, NULL);
61
}
62
 
63
static int ocfs2_fault(struct vm_area_struct *area, struct vm_fault *vmf)
64
{
65
        sigset_t blocked, oldset;
66
        int error, ret;
67
 
68
        mlog_entry("(area=%p, page offset=%lu)\n", area, vmf->pgoff);
69
 
70
        error = ocfs2_vm_op_block_sigs(&blocked, &oldset);
71
        if (error < 0) {
72
                mlog_errno(error);
73
                ret = VM_FAULT_SIGBUS;
74
                goto out;
75
        }
76
 
77
        ret = filemap_fault(area, vmf);
78
 
79
        error = ocfs2_vm_op_unblock_sigs(&oldset);
80
        if (error < 0)
81
                mlog_errno(error);
82
out:
83
        mlog_exit_ptr(vmf->page);
84
        return ret;
85
}
86
 
87
static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
88
                                struct page *page)
89
{
90
        int ret;
91
        struct address_space *mapping = inode->i_mapping;
92
        loff_t pos = page_offset(page);
93
        unsigned int len = PAGE_CACHE_SIZE;
94
        pgoff_t last_index;
95
        struct page *locked_page = NULL;
96
        void *fsdata;
97
        loff_t size = i_size_read(inode);
98
 
99
        /*
100
         * Another node might have truncated while we were waiting on
101
         * cluster locks.
102
         */
103
        last_index = size >> PAGE_CACHE_SHIFT;
104
        if (page->index > last_index) {
105
                ret = -EINVAL;
106
                goto out;
107
        }
108
 
109
        /*
110
         * The i_size check above doesn't catch the case where nodes
111
         * truncated and then re-extended the file. We'll re-check the
112
         * page mapping after taking the page lock inside of
113
         * ocfs2_write_begin_nolock().
114
         */
115
        if (!PageUptodate(page) || page->mapping != inode->i_mapping) {
116
                ret = -EINVAL;
117
                goto out;
118
        }
119
 
120
        /*
121
         * Call ocfs2_write_begin() and ocfs2_write_end() to take
122
         * advantage of the allocation code there. We pass a write
123
         * length of the whole page (chopped to i_size) to make sure
124
         * the whole thing is allocated.
125
         *
126
         * Since we know the page is up to date, we don't have to
127
         * worry about ocfs2_write_begin() skipping some buffer reads
128
         * because the "write" would invalidate their data.
129
         */
130
        if (page->index == last_index)
131
                len = size & ~PAGE_CACHE_MASK;
132
 
133
        ret = ocfs2_write_begin_nolock(mapping, pos, len, 0, &locked_page,
134
                                       &fsdata, di_bh, page);
135
        if (ret) {
136
                if (ret != -ENOSPC)
137
                        mlog_errno(ret);
138
                goto out;
139
        }
140
 
141
        ret = ocfs2_write_end_nolock(mapping, pos, len, len, locked_page,
142
                                     fsdata);
143
        if (ret < 0) {
144
                mlog_errno(ret);
145
                goto out;
146
        }
147
        BUG_ON(ret != len);
148
        ret = 0;
149
out:
150
        return ret;
151
}
152
 
153
static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
154
{
155
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
156
        struct buffer_head *di_bh = NULL;
157
        sigset_t blocked, oldset;
158
        int ret, ret2;
159
 
160
        ret = ocfs2_vm_op_block_sigs(&blocked, &oldset);
161
        if (ret < 0) {
162
                mlog_errno(ret);
163
                return ret;
164
        }
165
 
166
        /*
167
         * The cluster locks taken will block a truncate from another
168
         * node. Taking the data lock will also ensure that we don't
169
         * attempt page truncation as part of a downconvert.
170
         */
171
        ret = ocfs2_meta_lock(inode, &di_bh, 1);
172
        if (ret < 0) {
173
                mlog_errno(ret);
174
                goto out;
175
        }
176
 
177
        /*
178
         * The alloc sem should be enough to serialize with
179
         * ocfs2_truncate_file() changing i_size as well as any thread
180
         * modifying the inode btree.
181
         */
182
        down_write(&OCFS2_I(inode)->ip_alloc_sem);
183
 
184
        ret = ocfs2_data_lock(inode, 1);
185
        if (ret < 0) {
186
                mlog_errno(ret);
187
                goto out_meta_unlock;
188
        }
189
 
190
        ret = __ocfs2_page_mkwrite(inode, di_bh, page);
191
 
192
        ocfs2_data_unlock(inode, 1);
193
 
194
out_meta_unlock:
195
        up_write(&OCFS2_I(inode)->ip_alloc_sem);
196
 
197
        brelse(di_bh);
198
        ocfs2_meta_unlock(inode, 1);
199
 
200
out:
201
        ret2 = ocfs2_vm_op_unblock_sigs(&oldset);
202
        if (ret2 < 0)
203
                mlog_errno(ret2);
204
 
205
        return ret;
206
}
207
 
208
static struct vm_operations_struct ocfs2_file_vm_ops = {
209
        .fault          = ocfs2_fault,
210
        .page_mkwrite   = ocfs2_page_mkwrite,
211
};
212
 
213
int ocfs2_mmap(struct file *file, struct vm_area_struct *vma)
214
{
215
        int ret = 0, lock_level = 0;
216
 
217
        ret = ocfs2_meta_lock_atime(file->f_dentry->d_inode,
218
                                    file->f_vfsmnt, &lock_level);
219
        if (ret < 0) {
220
                mlog_errno(ret);
221
                goto out;
222
        }
223
        ocfs2_meta_unlock(file->f_dentry->d_inode, lock_level);
224
out:
225
        vma->vm_ops = &ocfs2_file_vm_ops;
226
        vma->vm_flags |= VM_CAN_NONLINEAR;
227
        return 0;
228
}
229
 

powered by: WebSVN 2.1.0

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