Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 only, | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License version 2 for more details (a copy is included | |
14 | * in the LICENSE file that accompanied this code). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see | |
18 | * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf | |
19 | * | |
20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
21 | * CA 95054 USA or visit www.sun.com if you need additional information or | |
22 | * have any questions. | |
23 | * | |
24 | * GPL HEADER END | |
25 | */ | |
26 | /* | |
27 | * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | * | |
30 | * Copyright (c) 2011, 2012, Intel Corporation. | |
31 | */ | |
32 | /* | |
33 | * This file is part of Lustre, http://www.lustre.org/ | |
34 | * Lustre is a trademark of Sun Microsystems, Inc. | |
35 | * | |
36 | * glimpse code shared between vvp and liblustre (and other Lustre clients in | |
37 | * the future). | |
38 | * | |
39 | * Author: Nikita Danilov <nikita.danilov@sun.com> | |
40 | * Author: Oleg Drokin <oleg.drokin@sun.com> | |
41 | */ | |
42 | ||
9fdaf8c0 | 43 | #include "../../include/linux/libcfs/libcfs.h" |
67a235f5 GKH |
44 | #include "../include/obd_class.h" |
45 | #include "../include/obd_support.h" | |
46 | #include "../include/obd.h" | |
d7e09d03 | 47 | |
67a235f5 GKH |
48 | #include "../include/lustre_dlm.h" |
49 | #include "../include/lustre_lite.h" | |
50 | #include "../include/lustre_mdc.h" | |
51 | #include <linux/pagemap.h> | |
52 | #include <linux/file.h> | |
d7e09d03 | 53 | |
67a235f5 GKH |
54 | #include "../include/cl_object.h" |
55 | #include "../include/lclient.h" | |
56 | #include "../llite/llite_internal.h" | |
d7e09d03 PT |
57 | |
58 | static const struct cl_lock_descr whole_file = { | |
59 | .cld_start = 0, | |
60 | .cld_end = CL_PAGE_EOF, | |
61 | .cld_mode = CLM_READ | |
62 | }; | |
63 | ||
64 | /* | |
65 | * Check whether file has possible unwriten pages. | |
66 | * | |
67 | * \retval 1 file is mmap-ed or has dirty pages | |
68 | * 0 otherwise | |
69 | */ | |
70 | blkcnt_t dirty_cnt(struct inode *inode) | |
71 | { | |
72 | blkcnt_t cnt = 0; | |
73 | struct ccc_object *vob = cl_inode2ccc(inode); | |
74 | void *results[1]; | |
75 | ||
03a7fc24 | 76 | if (inode->i_mapping) |
d7e09d03 PT |
77 | cnt += radix_tree_gang_lookup_tag(&inode->i_mapping->page_tree, |
78 | results, 0, 1, | |
79 | PAGECACHE_TAG_DIRTY); | |
80 | if (cnt == 0 && atomic_read(&vob->cob_mmap_cnt) > 0) | |
81 | cnt = 1; | |
82 | ||
83 | return (cnt > 0) ? 1 : 0; | |
84 | } | |
85 | ||
86 | int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io, | |
87 | struct inode *inode, struct cl_object *clob, int agl) | |
88 | { | |
89 | struct cl_lock_descr *descr = &ccc_env_info(env)->cti_descr; | |
90 | struct cl_inode_info *lli = cl_i2info(inode); | |
91 | const struct lu_fid *fid = lu_object_fid(&clob->co_lu); | |
92 | struct ccc_io *cio = ccc_env_io(env); | |
93 | struct cl_lock *lock; | |
94 | int result; | |
95 | ||
d7e09d03 PT |
96 | result = 0; |
97 | if (!(lli->lli_flags & LLIF_MDS_SIZE_LOCK)) { | |
a7d516d6 | 98 | CDEBUG(D_DLMTRACE, "Glimpsing inode " DFID "\n", PFID(fid)); |
d7e09d03 PT |
99 | if (lli->lli_has_smd) { |
100 | /* NOTE: this looks like DLM lock request, but it may | |
101 | * not be one. Due to CEF_ASYNC flag (translated | |
102 | * to LDLM_FL_HAS_INTENT by osc), this is | |
103 | * glimpse request, that won't revoke any | |
104 | * conflicting DLM locks held. Instead, | |
105 | * ll_glimpse_callback() will be called on each | |
106 | * client holding a DLM lock against this file, | |
107 | * and resulting size will be returned for each | |
108 | * stripe. DLM lock on [0, EOF] is acquired only | |
109 | * if there were no conflicting locks. If there | |
110 | * were conflicting locks, enqueuing or waiting | |
111 | * fails with -ENAVAIL, but valid inode | |
ec9a1ac2 OD |
112 | * attributes are returned anyway. |
113 | */ | |
d7e09d03 PT |
114 | *descr = whole_file; |
115 | descr->cld_obj = clob; | |
116 | descr->cld_mode = CLM_PHANTOM; | |
117 | descr->cld_enq_flags = CEF_ASYNC | CEF_MUST; | |
118 | if (agl) | |
119 | descr->cld_enq_flags |= CEF_AGL; | |
120 | cio->cui_glimpse = 1; | |
121 | /* | |
122 | * CEF_ASYNC is used because glimpse sub-locks cannot | |
123 | * deadlock (because they never conflict with other | |
124 | * locks) and, hence, can be enqueued out-of-order. | |
125 | * | |
126 | * CEF_MUST protects glimpse lock from conversion into | |
127 | * a lockless mode. | |
128 | */ | |
129 | lock = cl_lock_request(env, io, descr, "glimpse", | |
130 | current); | |
131 | cio->cui_glimpse = 0; | |
132 | ||
03a7fc24 | 133 | if (!lock) |
0a3bdb00 | 134 | return 0; |
d7e09d03 PT |
135 | |
136 | if (IS_ERR(lock)) | |
0a3bdb00 | 137 | return PTR_ERR(lock); |
d7e09d03 PT |
138 | |
139 | LASSERT(agl == 0); | |
140 | result = cl_wait(env, lock); | |
141 | if (result == 0) { | |
d2995737 | 142 | ll_merge_attr(env, inode); |
d7e09d03 PT |
143 | if (cl_isize_read(inode) > 0 && |
144 | inode->i_blocks == 0) { | |
145 | /* | |
146 | * LU-417: Add dirty pages block count | |
147 | * lest i_blocks reports 0, some "cp" or | |
148 | * "tar" may think it's a completely | |
149 | * sparse file and skip it. | |
150 | */ | |
151 | inode->i_blocks = dirty_cnt(inode); | |
152 | } | |
153 | cl_unuse(env, lock); | |
154 | } | |
155 | cl_lock_release(env, lock, "glimpse", current); | |
156 | } else { | |
157 | CDEBUG(D_DLMTRACE, "No objects for inode\n"); | |
d2995737 | 158 | ll_merge_attr(env, inode); |
d7e09d03 PT |
159 | } |
160 | } | |
161 | ||
0a3bdb00 | 162 | return result; |
d7e09d03 PT |
163 | } |
164 | ||
165 | static int cl_io_get(struct inode *inode, struct lu_env **envout, | |
166 | struct cl_io **ioout, int *refcheck) | |
167 | { | |
168 | struct lu_env *env; | |
169 | struct cl_io *io; | |
170 | struct cl_inode_info *lli = cl_i2info(inode); | |
171 | struct cl_object *clob = lli->lli_clob; | |
172 | int result; | |
173 | ||
174 | if (S_ISREG(cl_inode_mode(inode))) { | |
175 | env = cl_env_get(refcheck); | |
176 | if (!IS_ERR(env)) { | |
177 | io = ccc_env_thread_io(env); | |
178 | io->ci_obj = clob; | |
179 | *envout = env; | |
180 | *ioout = io; | |
df47bd43 | 181 | result = 1; |
a7d516d6 | 182 | } else { |
d7e09d03 | 183 | result = PTR_ERR(env); |
a7d516d6 JH |
184 | } |
185 | } else { | |
d7e09d03 | 186 | result = 0; |
a7d516d6 | 187 | } |
d7e09d03 PT |
188 | return result; |
189 | } | |
190 | ||
191 | int cl_glimpse_size0(struct inode *inode, int agl) | |
192 | { | |
193 | /* | |
194 | * We don't need ast_flags argument to cl_glimpse_size(), because | |
195 | * osc_lock_enqueue() takes care of the possible deadlock that said | |
196 | * argument was introduced to avoid. | |
197 | */ | |
198 | /* | |
199 | * XXX but note that ll_file_seek() passes LDLM_FL_BLOCK_NOWAIT to | |
200 | * cl_glimpse_size(), which doesn't make sense: glimpse locks are not | |
201 | * blocking anyway. | |
202 | */ | |
203 | struct lu_env *env = NULL; | |
204 | struct cl_io *io = NULL; | |
205 | int result; | |
206 | int refcheck; | |
207 | ||
d7e09d03 PT |
208 | result = cl_io_get(inode, &env, &io, &refcheck); |
209 | if (result > 0) { | |
641cff77 | 210 | again: |
d7e09d03 PT |
211 | io->ci_verify_layout = 1; |
212 | result = cl_io_init(env, io, CIT_MISC, io->ci_obj); | |
213 | if (result > 0) | |
214 | /* | |
215 | * nothing to do for this io. This currently happens | |
216 | * when stripe sub-object's are not yet created. | |
217 | */ | |
218 | result = io->ci_result; | |
219 | else if (result == 0) | |
220 | result = cl_glimpse_lock(env, io, inode, io->ci_obj, | |
221 | agl); | |
222 | ||
223 | OBD_FAIL_TIMEOUT(OBD_FAIL_GLIMPSE_DELAY, 2); | |
224 | cl_io_fini(env, io); | |
225 | if (unlikely(io->ci_need_restart)) | |
226 | goto again; | |
227 | cl_env_put(env, &refcheck); | |
228 | } | |
0a3bdb00 | 229 | return result; |
d7e09d03 PT |
230 | } |
231 | ||
232 | int cl_local_size(struct inode *inode) | |
233 | { | |
234 | struct lu_env *env = NULL; | |
235 | struct cl_io *io = NULL; | |
236 | struct ccc_thread_info *cti; | |
237 | struct cl_object *clob; | |
238 | struct cl_lock_descr *descr; | |
239 | struct cl_lock *lock; | |
240 | int result; | |
241 | int refcheck; | |
242 | ||
d7e09d03 | 243 | if (!cl_i2info(inode)->lli_has_smd) |
0a3bdb00 | 244 | return 0; |
d7e09d03 PT |
245 | |
246 | result = cl_io_get(inode, &env, &io, &refcheck); | |
247 | if (result <= 0) | |
0a3bdb00 | 248 | return result; |
d7e09d03 PT |
249 | |
250 | clob = io->ci_obj; | |
251 | result = cl_io_init(env, io, CIT_MISC, clob); | |
a7d516d6 | 252 | if (result > 0) { |
d7e09d03 | 253 | result = io->ci_result; |
a7d516d6 | 254 | } else if (result == 0) { |
d7e09d03 PT |
255 | cti = ccc_env_info(env); |
256 | descr = &cti->cti_descr; | |
257 | ||
258 | *descr = whole_file; | |
259 | descr->cld_obj = clob; | |
260 | lock = cl_lock_peek(env, io, descr, "localsize", current); | |
03a7fc24 | 261 | if (lock) { |
d2995737 | 262 | ll_merge_attr(env, inode); |
d7e09d03 PT |
263 | cl_unuse(env, lock); |
264 | cl_lock_release(env, lock, "localsize", current); | |
265 | result = 0; | |
a7d516d6 | 266 | } else { |
d7e09d03 | 267 | result = -ENODATA; |
a7d516d6 | 268 | } |
d7e09d03 PT |
269 | } |
270 | cl_io_fini(env, io); | |
271 | cl_env_put(env, &refcheck); | |
0a3bdb00 | 272 | return result; |
d7e09d03 | 273 | } |