Merge branch 'master'
[cascardo/linux.git] / fs / gfs2 / ops_vm.c
1 /*
2  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3  * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
4  *
5  * This copyrighted material is made available to anyone wishing to use,
6  * modify, copy, or redistribute it subject to the terms and conditions
7  * of the GNU General Public License v.2.
8  */
9
10 #include <linux/sched.h>
11 #include <linux/slab.h>
12 #include <linux/spinlock.h>
13 #include <linux/completion.h>
14 #include <linux/buffer_head.h>
15 #include <linux/mm.h>
16 #include <linux/pagemap.h>
17 #include <linux/gfs2_ondisk.h>
18 #include <asm/semaphore.h>
19
20 #include "gfs2.h"
21 #include "lm_interface.h"
22 #include "incore.h"
23 #include "bmap.h"
24 #include "glock.h"
25 #include "inode.h"
26 #include "ops_vm.h"
27 #include "page.h"
28 #include "quota.h"
29 #include "rgrp.h"
30 #include "trans.h"
31 #include "util.h"
32
33 static void pfault_be_greedy(struct gfs2_inode *ip)
34 {
35         unsigned int time;
36
37         spin_lock(&ip->i_spin);
38         time = ip->i_greedy;
39         ip->i_last_pfault = jiffies;
40         spin_unlock(&ip->i_spin);
41
42         gfs2_inode_hold(ip);
43         if (gfs2_glock_be_greedy(ip->i_gl, time))
44                 gfs2_inode_put(ip);
45 }
46
47 static struct page *gfs2_private_nopage(struct vm_area_struct *area,
48                                         unsigned long address, int *type)
49 {
50         struct gfs2_inode *ip = area->vm_file->f_mapping->host->u.generic_ip;
51         struct gfs2_holder i_gh;
52         struct page *result;
53         int error;
54
55         error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
56         if (error)
57                 return NULL;
58
59         set_bit(GIF_PAGED, &ip->i_flags);
60
61         result = filemap_nopage(area, address, type);
62
63         if (result && result != NOPAGE_OOM)
64                 pfault_be_greedy(ip);
65
66         gfs2_glock_dq_uninit(&i_gh);
67
68         return result;
69 }
70
71 static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
72 {
73         struct gfs2_sbd *sdp = ip->i_sbd;
74         unsigned long index = page->index;
75         uint64_t lblock = index << (PAGE_CACHE_SHIFT -
76                                     sdp->sd_sb.sb_bsize_shift);
77         unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift;
78         struct gfs2_alloc *al;
79         unsigned int data_blocks, ind_blocks;
80         unsigned int x;
81         int error;
82
83         al = gfs2_alloc_get(ip);
84
85         error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
86         if (error)
87                 goto out;
88
89         error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
90         if (error)
91                 goto out_gunlock_q;
92
93         gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE,
94                               &data_blocks, &ind_blocks);
95
96         al->al_requested = data_blocks + ind_blocks;
97
98         error = gfs2_inplace_reserve(ip);
99         if (error)
100                 goto out_gunlock_q;
101
102         error = gfs2_trans_begin(sdp,
103                                  al->al_rgd->rd_ri.ri_length +
104                                  ind_blocks + RES_DINODE +
105                                  RES_STATFS + RES_QUOTA, 0);
106         if (error)
107                 goto out_ipres;
108
109         if (gfs2_is_stuffed(ip)) {
110                 error = gfs2_unstuff_dinode(ip, gfs2_unstuffer_page, NULL);
111                 if (error)
112                         goto out_trans;
113         }
114
115         for (x = 0; x < blocks; ) {
116                 uint64_t dblock;
117                 unsigned int extlen;
118                 int new = 1;
119
120                 error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen);
121                 if (error)
122                         goto out_trans;
123
124                 lblock += extlen;
125                 x += extlen;
126         }
127
128         gfs2_assert_warn(sdp, al->al_alloced);
129
130  out_trans:
131         gfs2_trans_end(sdp);
132
133  out_ipres:
134         gfs2_inplace_release(ip);
135
136  out_gunlock_q:
137         gfs2_quota_unlock(ip);
138
139  out:
140         gfs2_alloc_put(ip);
141
142         return error;
143 }
144
145 static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area,
146                                            unsigned long address, int *type)
147 {
148         struct gfs2_inode *ip = area->vm_file->f_mapping->host->u.generic_ip;
149         struct gfs2_holder i_gh;
150         struct page *result = NULL;
151         unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) +
152                               area->vm_pgoff;
153         int alloc_required;
154         int error;
155
156         error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
157         if (error)
158                 return NULL;
159
160         set_bit(GIF_PAGED, &ip->i_flags);
161         set_bit(GIF_SW_PAGED, &ip->i_flags);
162
163         error = gfs2_write_alloc_required(ip,
164                                           (uint64_t)index << PAGE_CACHE_SHIFT,
165                                           PAGE_CACHE_SIZE, &alloc_required);
166         if (error)
167                 goto out;
168
169         result = filemap_nopage(area, address, type);
170         if (!result || result == NOPAGE_OOM)
171                 goto out;
172
173         if (alloc_required) {
174                 error = alloc_page_backing(ip, result);
175                 if (error) {
176                         page_cache_release(result);
177                         result = NULL;
178                         goto out;
179                 }
180                 set_page_dirty(result);
181         }
182
183         pfault_be_greedy(ip);
184
185  out:
186         gfs2_glock_dq_uninit(&i_gh);
187
188         return result;
189 }
190
191 struct vm_operations_struct gfs2_vm_ops_private = {
192         .nopage = gfs2_private_nopage,
193 };
194
195 struct vm_operations_struct gfs2_vm_ops_sharewrite = {
196         .nopage = gfs2_sharewrite_nopage,
197 };
198