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 | 54 | #include "../include/cl_object.h" |
67a235f5 | 55 | #include "../llite/llite_internal.h" |
d7e09d03 PT |
56 | |
57 | static const struct cl_lock_descr whole_file = { | |
58 | .cld_start = 0, | |
59 | .cld_end = CL_PAGE_EOF, | |
60 | .cld_mode = CLM_READ | |
61 | }; | |
62 | ||
63 | /* | |
64 | * Check whether file has possible unwriten pages. | |
65 | * | |
66 | * \retval 1 file is mmap-ed or has dirty pages | |
67 | * 0 otherwise | |
68 | */ | |
69 | blkcnt_t dirty_cnt(struct inode *inode) | |
70 | { | |
71 | blkcnt_t cnt = 0; | |
8c7b0e1a | 72 | struct vvp_object *vob = cl_inode2vvp(inode); |
d7e09d03 PT |
73 | void *results[1]; |
74 | ||
03a7fc24 | 75 | if (inode->i_mapping) |
d7e09d03 PT |
76 | cnt += radix_tree_gang_lookup_tag(&inode->i_mapping->page_tree, |
77 | results, 0, 1, | |
78 | PAGECACHE_TAG_DIRTY); | |
8c7b0e1a | 79 | if (cnt == 0 && atomic_read(&vob->vob_mmap_cnt) > 0) |
d7e09d03 PT |
80 | cnt = 1; |
81 | ||
82 | return (cnt > 0) ? 1 : 0; | |
83 | } | |
84 | ||
85 | int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io, | |
86 | struct inode *inode, struct cl_object *clob, int agl) | |
87 | { | |
1929c433 | 88 | struct ll_inode_info *lli = ll_i2info(inode); |
d7e09d03 | 89 | const struct lu_fid *fid = lu_object_fid(&clob->co_lu); |
d7e09d03 PT |
90 | int result; |
91 | ||
d7e09d03 PT |
92 | result = 0; |
93 | if (!(lli->lli_flags & LLIF_MDS_SIZE_LOCK)) { | |
a7d516d6 | 94 | CDEBUG(D_DLMTRACE, "Glimpsing inode " DFID "\n", PFID(fid)); |
d7e09d03 | 95 | if (lli->lli_has_smd) { |
06563b56 JX |
96 | struct cl_lock *lock = ccc_env_lock(env); |
97 | struct cl_lock_descr *descr = &lock->cll_descr; | |
98 | ||
d7e09d03 PT |
99 | /* NOTE: this looks like DLM lock request, but it may |
100 | * not be one. Due to CEF_ASYNC flag (translated | |
101 | * to LDLM_FL_HAS_INTENT by osc), this is | |
102 | * glimpse request, that won't revoke any | |
103 | * conflicting DLM locks held. Instead, | |
104 | * ll_glimpse_callback() will be called on each | |
105 | * client holding a DLM lock against this file, | |
106 | * and resulting size will be returned for each | |
107 | * stripe. DLM lock on [0, EOF] is acquired only | |
108 | * if there were no conflicting locks. If there | |
109 | * were conflicting locks, enqueuing or waiting | |
110 | * fails with -ENAVAIL, but valid inode | |
ec9a1ac2 OD |
111 | * attributes are returned anyway. |
112 | */ | |
d7e09d03 PT |
113 | *descr = whole_file; |
114 | descr->cld_obj = clob; | |
06563b56 | 115 | descr->cld_mode = CLM_READ; |
d7e09d03 PT |
116 | descr->cld_enq_flags = CEF_ASYNC | CEF_MUST; |
117 | if (agl) | |
118 | descr->cld_enq_flags |= CEF_AGL; | |
d7e09d03 PT |
119 | /* |
120 | * CEF_ASYNC is used because glimpse sub-locks cannot | |
121 | * deadlock (because they never conflict with other | |
122 | * locks) and, hence, can be enqueued out-of-order. | |
123 | * | |
124 | * CEF_MUST protects glimpse lock from conversion into | |
125 | * a lockless mode. | |
126 | */ | |
06563b56 JX |
127 | result = cl_lock_request(env, io, lock); |
128 | if (result < 0) | |
129 | return result; | |
d7e09d03 | 130 | |
06563b56 | 131 | if (!agl) { |
d2995737 | 132 | ll_merge_attr(env, inode); |
1929c433 | 133 | if (i_size_read(inode) > 0 && |
d7e09d03 PT |
134 | inode->i_blocks == 0) { |
135 | /* | |
136 | * LU-417: Add dirty pages block count | |
137 | * lest i_blocks reports 0, some "cp" or | |
138 | * "tar" may think it's a completely | |
139 | * sparse file and skip it. | |
140 | */ | |
141 | inode->i_blocks = dirty_cnt(inode); | |
142 | } | |
d7e09d03 | 143 | } |
06563b56 | 144 | cl_lock_release(env, lock); |
d7e09d03 PT |
145 | } else { |
146 | CDEBUG(D_DLMTRACE, "No objects for inode\n"); | |
d2995737 | 147 | ll_merge_attr(env, inode); |
d7e09d03 PT |
148 | } |
149 | } | |
150 | ||
0a3bdb00 | 151 | return result; |
d7e09d03 PT |
152 | } |
153 | ||
154 | static int cl_io_get(struct inode *inode, struct lu_env **envout, | |
155 | struct cl_io **ioout, int *refcheck) | |
156 | { | |
157 | struct lu_env *env; | |
158 | struct cl_io *io; | |
1929c433 | 159 | struct ll_inode_info *lli = ll_i2info(inode); |
d7e09d03 PT |
160 | struct cl_object *clob = lli->lli_clob; |
161 | int result; | |
162 | ||
1929c433 | 163 | if (S_ISREG(inode->i_mode)) { |
d7e09d03 PT |
164 | env = cl_env_get(refcheck); |
165 | if (!IS_ERR(env)) { | |
166 | io = ccc_env_thread_io(env); | |
167 | io->ci_obj = clob; | |
168 | *envout = env; | |
169 | *ioout = io; | |
df47bd43 | 170 | result = 1; |
a7d516d6 | 171 | } else { |
d7e09d03 | 172 | result = PTR_ERR(env); |
a7d516d6 JH |
173 | } |
174 | } else { | |
d7e09d03 | 175 | result = 0; |
a7d516d6 | 176 | } |
d7e09d03 PT |
177 | return result; |
178 | } | |
179 | ||
180 | int cl_glimpse_size0(struct inode *inode, int agl) | |
181 | { | |
182 | /* | |
183 | * We don't need ast_flags argument to cl_glimpse_size(), because | |
184 | * osc_lock_enqueue() takes care of the possible deadlock that said | |
185 | * argument was introduced to avoid. | |
186 | */ | |
187 | /* | |
188 | * XXX but note that ll_file_seek() passes LDLM_FL_BLOCK_NOWAIT to | |
189 | * cl_glimpse_size(), which doesn't make sense: glimpse locks are not | |
190 | * blocking anyway. | |
191 | */ | |
192 | struct lu_env *env = NULL; | |
193 | struct cl_io *io = NULL; | |
194 | int result; | |
195 | int refcheck; | |
196 | ||
d7e09d03 PT |
197 | result = cl_io_get(inode, &env, &io, &refcheck); |
198 | if (result > 0) { | |
641cff77 | 199 | again: |
d7e09d03 PT |
200 | io->ci_verify_layout = 1; |
201 | result = cl_io_init(env, io, CIT_MISC, io->ci_obj); | |
202 | if (result > 0) | |
203 | /* | |
204 | * nothing to do for this io. This currently happens | |
205 | * when stripe sub-object's are not yet created. | |
206 | */ | |
207 | result = io->ci_result; | |
208 | else if (result == 0) | |
209 | result = cl_glimpse_lock(env, io, inode, io->ci_obj, | |
210 | agl); | |
211 | ||
212 | OBD_FAIL_TIMEOUT(OBD_FAIL_GLIMPSE_DELAY, 2); | |
213 | cl_io_fini(env, io); | |
214 | if (unlikely(io->ci_need_restart)) | |
215 | goto again; | |
216 | cl_env_put(env, &refcheck); | |
217 | } | |
0a3bdb00 | 218 | return result; |
d7e09d03 PT |
219 | } |
220 | ||
221 | int cl_local_size(struct inode *inode) | |
222 | { | |
223 | struct lu_env *env = NULL; | |
224 | struct cl_io *io = NULL; | |
d7e09d03 | 225 | struct cl_object *clob; |
d7e09d03 PT |
226 | int result; |
227 | int refcheck; | |
228 | ||
1929c433 | 229 | if (!ll_i2info(inode)->lli_has_smd) |
0a3bdb00 | 230 | return 0; |
d7e09d03 PT |
231 | |
232 | result = cl_io_get(inode, &env, &io, &refcheck); | |
233 | if (result <= 0) | |
0a3bdb00 | 234 | return result; |
d7e09d03 PT |
235 | |
236 | clob = io->ci_obj; | |
237 | result = cl_io_init(env, io, CIT_MISC, clob); | |
a7d516d6 | 238 | if (result > 0) { |
d7e09d03 | 239 | result = io->ci_result; |
a7d516d6 | 240 | } else if (result == 0) { |
06563b56 | 241 | struct cl_lock *lock = ccc_env_lock(env); |
d7e09d03 | 242 | |
06563b56 JX |
243 | lock->cll_descr = whole_file; |
244 | lock->cll_descr.cld_enq_flags = CEF_PEEK; | |
245 | lock->cll_descr.cld_obj = clob; | |
246 | result = cl_lock_request(env, io, lock); | |
247 | if (result == 0) { | |
d2995737 | 248 | ll_merge_attr(env, inode); |
06563b56 | 249 | cl_lock_release(env, lock); |
a7d516d6 | 250 | } |
d7e09d03 PT |
251 | } |
252 | cl_io_fini(env, io); | |
253 | cl_env_put(env, &refcheck); | |
0a3bdb00 | 254 | return result; |
d7e09d03 | 255 | } |