Commit | Line | Data |
---|---|---|
c14dd9d5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
d7e09d03 PT |
2 | /* |
3 | * GPL HEADER START | |
4 | * | |
5 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 only, | |
9 | * as published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License version 2 for more details (a copy is included | |
15 | * in the LICENSE file that accompanied this code). | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * version 2 along with this program; If not, see | |
6a5b99a4 | 19 | * http://www.gnu.org/licenses/gpl-2.0.html |
d7e09d03 | 20 | * |
d7e09d03 PT |
21 | * GPL HEADER END |
22 | */ | |
23 | /* | |
24 | * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. | |
25 | * Use is subject to license terms. | |
26 | * | |
27 | * Copyright (c) 2011, 2012, Intel Corporation. | |
28 | */ | |
29 | /* | |
30 | * This file is part of Lustre, http://www.lustre.org/ | |
31 | * Lustre is a trademark of Sun Microsystems, Inc. | |
32 | * | |
33 | * glimpse code shared between vvp and liblustre (and other Lustre clients in | |
34 | * the future). | |
35 | * | |
36 | * Author: Nikita Danilov <nikita.danilov@sun.com> | |
37 | * Author: Oleg Drokin <oleg.drokin@sun.com> | |
38 | */ | |
39 | ||
b2e475b1 JS |
40 | #include <linux/libcfs/libcfs.h> |
41 | #include <obd_class.h> | |
42 | #include <obd_support.h> | |
43 | #include <obd.h> | |
d7e09d03 | 44 | |
b2e475b1 JS |
45 | #include <lustre_dlm.h> |
46 | #include <lustre_mdc.h> | |
67a235f5 GKH |
47 | #include <linux/pagemap.h> |
48 | #include <linux/file.h> | |
d7e09d03 | 49 | |
b2e475b1 JS |
50 | #include <cl_object.h> |
51 | #include "llite_internal.h" | |
d7e09d03 PT |
52 | |
53 | static const struct cl_lock_descr whole_file = { | |
54 | .cld_start = 0, | |
55 | .cld_end = CL_PAGE_EOF, | |
56 | .cld_mode = CLM_READ | |
57 | }; | |
58 | ||
59 | /* | |
60 | * Check whether file has possible unwriten pages. | |
61 | * | |
62 | * \retval 1 file is mmap-ed or has dirty pages | |
63 | * 0 otherwise | |
64 | */ | |
65 | blkcnt_t dirty_cnt(struct inode *inode) | |
66 | { | |
67 | blkcnt_t cnt = 0; | |
8c7b0e1a | 68 | struct vvp_object *vob = cl_inode2vvp(inode); |
d7e09d03 PT |
69 | void *results[1]; |
70 | ||
03a7fc24 | 71 | if (inode->i_mapping) |
b93b0163 | 72 | cnt += radix_tree_gang_lookup_tag(&inode->i_mapping->i_pages, |
d7e09d03 PT |
73 | results, 0, 1, |
74 | PAGECACHE_TAG_DIRTY); | |
8c7b0e1a | 75 | if (cnt == 0 && atomic_read(&vob->vob_mmap_cnt) > 0) |
d7e09d03 PT |
76 | cnt = 1; |
77 | ||
78 | return (cnt > 0) ? 1 : 0; | |
79 | } | |
80 | ||
81 | int cl_glimpse_lock(const struct lu_env *env, struct cl_io *io, | |
82 | struct inode *inode, struct cl_object *clob, int agl) | |
83 | { | |
d7e09d03 | 84 | const struct lu_fid *fid = lu_object_fid(&clob->co_lu); |
85cb63bc JX |
85 | struct cl_lock *lock = vvp_env_lock(env); |
86 | struct cl_lock_descr *descr = &lock->cll_descr; | |
0cd99931 | 87 | int result = 0; |
d7e09d03 | 88 | |
0cd99931 | 89 | CDEBUG(D_DLMTRACE, "Glimpsing inode " DFID "\n", PFID(fid)); |
0cd99931 | 90 | |
85cb63bc JX |
91 | /* NOTE: this looks like DLM lock request, but it may |
92 | * not be one. Due to CEF_ASYNC flag (translated | |
93 | * to LDLM_FL_HAS_INTENT by osc), this is | |
94 | * glimpse request, that won't revoke any | |
95 | * conflicting DLM locks held. Instead, | |
96 | * ll_glimpse_callback() will be called on each | |
97 | * client holding a DLM lock against this file, | |
98 | * and resulting size will be returned for each | |
99 | * stripe. DLM lock on [0, EOF] is acquired only | |
100 | * if there were no conflicting locks. If there | |
101 | * were conflicting locks, enqueuing or waiting | |
102 | * fails with -ENAVAIL, but valid inode | |
103 | * attributes are returned anyway. | |
104 | */ | |
105 | *descr = whole_file; | |
106 | descr->cld_obj = clob; | |
107 | descr->cld_mode = CLM_READ; | |
108 | descr->cld_enq_flags = CEF_ASYNC | CEF_MUST; | |
109 | if (agl) | |
110 | descr->cld_enq_flags |= CEF_AGL; | |
111 | /* | |
112 | * CEF_ASYNC is used because glimpse sub-locks cannot | |
113 | * deadlock (because they never conflict with other | |
114 | * locks) and, hence, can be enqueued out-of-order. | |
115 | * | |
116 | * CEF_MUST protects glimpse lock from conversion into | |
117 | * a lockless mode. | |
118 | */ | |
119 | result = cl_lock_request(env, io, lock); | |
120 | if (result < 0) | |
121 | return result; | |
122 | ||
123 | if (!agl) { | |
0cd99931 | 124 | ll_merge_attr(env, inode); |
85cb63bc JX |
125 | if (i_size_read(inode) > 0 && !inode->i_blocks) { |
126 | /* | |
127 | * LU-417: Add dirty pages block count | |
128 | * lest i_blocks reports 0, some "cp" or | |
129 | * "tar" may think it's a completely | |
130 | * sparse file and skip it. | |
131 | */ | |
132 | inode->i_blocks = dirty_cnt(inode); | |
133 | } | |
d7e09d03 PT |
134 | } |
135 | ||
85cb63bc JX |
136 | cl_lock_release(env, lock); |
137 | ||
0a3bdb00 | 138 | return result; |
d7e09d03 PT |
139 | } |
140 | ||
141 | static int cl_io_get(struct inode *inode, struct lu_env **envout, | |
3ee45c7e | 142 | struct cl_io **ioout, u16 *refcheck) |
d7e09d03 PT |
143 | { |
144 | struct lu_env *env; | |
145 | struct cl_io *io; | |
1929c433 | 146 | struct ll_inode_info *lli = ll_i2info(inode); |
d7e09d03 PT |
147 | struct cl_object *clob = lli->lli_clob; |
148 | int result; | |
149 | ||
1929c433 | 150 | if (S_ISREG(inode->i_mode)) { |
d7e09d03 PT |
151 | env = cl_env_get(refcheck); |
152 | if (!IS_ERR(env)) { | |
9acc4500 | 153 | io = vvp_env_thread_io(env); |
d7e09d03 PT |
154 | io->ci_obj = clob; |
155 | *envout = env; | |
156 | *ioout = io; | |
df47bd43 | 157 | result = 1; |
a7d516d6 | 158 | } else { |
d7e09d03 | 159 | result = PTR_ERR(env); |
a7d516d6 JH |
160 | } |
161 | } else { | |
d7e09d03 | 162 | result = 0; |
a7d516d6 | 163 | } |
d7e09d03 PT |
164 | return result; |
165 | } | |
166 | ||
167 | int cl_glimpse_size0(struct inode *inode, int agl) | |
168 | { | |
169 | /* | |
170 | * We don't need ast_flags argument to cl_glimpse_size(), because | |
171 | * osc_lock_enqueue() takes care of the possible deadlock that said | |
172 | * argument was introduced to avoid. | |
173 | */ | |
174 | /* | |
175 | * XXX but note that ll_file_seek() passes LDLM_FL_BLOCK_NOWAIT to | |
176 | * cl_glimpse_size(), which doesn't make sense: glimpse locks are not | |
177 | * blocking anyway. | |
178 | */ | |
179 | struct lu_env *env = NULL; | |
180 | struct cl_io *io = NULL; | |
181 | int result; | |
3ee45c7e | 182 | u16 refcheck; |
d7e09d03 | 183 | |
d7e09d03 PT |
184 | result = cl_io_get(inode, &env, &io, &refcheck); |
185 | if (result > 0) { | |
641cff77 | 186 | again: |
d7e09d03 PT |
187 | io->ci_verify_layout = 1; |
188 | result = cl_io_init(env, io, CIT_MISC, io->ci_obj); | |
189 | if (result > 0) | |
190 | /* | |
191 | * nothing to do for this io. This currently happens | |
192 | * when stripe sub-object's are not yet created. | |
193 | */ | |
194 | result = io->ci_result; | |
195 | else if (result == 0) | |
196 | result = cl_glimpse_lock(env, io, inode, io->ci_obj, | |
197 | agl); | |
198 | ||
199 | OBD_FAIL_TIMEOUT(OBD_FAIL_GLIMPSE_DELAY, 2); | |
200 | cl_io_fini(env, io); | |
201 | if (unlikely(io->ci_need_restart)) | |
202 | goto again; | |
203 | cl_env_put(env, &refcheck); | |
204 | } | |
0a3bdb00 | 205 | return result; |
d7e09d03 | 206 | } |