@@ -99,8 +99,268 @@ void cachefiles_put_object(struct cachefiles_object *object,
99
99
_leave ("" );
100
100
}
101
101
102
+ /*
103
+ * Adjust the size of a cache file if necessary to match the DIO size. We keep
104
+ * the EOF marker a multiple of DIO blocks so that we don't fall back to doing
105
+ * non-DIO for a partial block straddling the EOF, but we also have to be
106
+ * careful of someone expanding the file and accidentally accreting the
107
+ * padding.
108
+ */
109
+ static int cachefiles_adjust_size (struct cachefiles_object * object )
110
+ {
111
+ struct iattr newattrs ;
112
+ struct file * file = object -> file ;
113
+ uint64_t ni_size ;
114
+ loff_t oi_size ;
115
+ int ret ;
116
+
117
+ ni_size = object -> cookie -> object_size ;
118
+ ni_size = round_up (ni_size , CACHEFILES_DIO_BLOCK_SIZE );
119
+
120
+ _enter ("{OBJ%x},[%llu]" ,
121
+ object -> debug_id , (unsigned long long ) ni_size );
122
+
123
+ if (!file )
124
+ return - ENOBUFS ;
125
+
126
+ oi_size = i_size_read (file_inode (file ));
127
+ if (oi_size == ni_size )
128
+ return 0 ;
129
+
130
+ inode_lock (file_inode (file ));
131
+
132
+ /* if there's an extension to a partial page at the end of the backing
133
+ * file, we need to discard the partial page so that we pick up new
134
+ * data after it */
135
+ if (oi_size & ~PAGE_MASK && ni_size > oi_size ) {
136
+ _debug ("discard tail %llx" , oi_size );
137
+ newattrs .ia_valid = ATTR_SIZE ;
138
+ newattrs .ia_size = oi_size & PAGE_MASK ;
139
+ ret = cachefiles_inject_remove_error ();
140
+ if (ret == 0 )
141
+ ret = notify_change (& init_user_ns , file -> f_path .dentry ,
142
+ & newattrs , NULL );
143
+ if (ret < 0 )
144
+ goto truncate_failed ;
145
+ }
146
+
147
+ newattrs .ia_valid = ATTR_SIZE ;
148
+ newattrs .ia_size = ni_size ;
149
+ ret = cachefiles_inject_write_error ();
150
+ if (ret == 0 )
151
+ ret = notify_change (& init_user_ns , file -> f_path .dentry ,
152
+ & newattrs , NULL );
153
+
154
+ truncate_failed :
155
+ inode_unlock (file_inode (file ));
156
+
157
+ if (ret < 0 )
158
+ trace_cachefiles_io_error (NULL , file_inode (file ), ret ,
159
+ cachefiles_trace_notify_change_error );
160
+ if (ret == - EIO ) {
161
+ cachefiles_io_error_obj (object , "Size set failed" );
162
+ ret = - ENOBUFS ;
163
+ }
164
+
165
+ _leave (" = %d" , ret );
166
+ return ret ;
167
+ }
168
+
169
+ /*
170
+ * Attempt to look up the nominated node in this cache
171
+ */
172
+ static bool cachefiles_lookup_cookie (struct fscache_cookie * cookie )
173
+ {
174
+ struct cachefiles_object * object ;
175
+ struct cachefiles_cache * cache = cookie -> volume -> cache -> cache_priv ;
176
+ const struct cred * saved_cred ;
177
+ bool success ;
178
+
179
+ object = cachefiles_alloc_object (cookie );
180
+ if (!object )
181
+ goto fail ;
182
+
183
+ _enter ("{OBJ%x}" , object -> debug_id );
184
+
185
+ if (!cachefiles_cook_key (object ))
186
+ goto fail_put ;
187
+
188
+ cookie -> cache_priv = object ;
189
+
190
+ cachefiles_begin_secure (cache , & saved_cred );
191
+
192
+ success = cachefiles_look_up_object (object );
193
+ if (!success )
194
+ goto fail_withdraw ;
195
+
196
+ cachefiles_see_object (object , cachefiles_obj_see_lookup_cookie );
197
+
198
+ spin_lock (& cache -> object_list_lock );
199
+ list_add (& object -> cache_link , & cache -> object_list );
200
+ spin_unlock (& cache -> object_list_lock );
201
+ cachefiles_adjust_size (object );
202
+
203
+ cachefiles_end_secure (cache , saved_cred );
204
+ _leave (" = t" );
205
+ return true;
206
+
207
+ fail_withdraw :
208
+ cachefiles_end_secure (cache , saved_cred );
209
+ cachefiles_see_object (object , cachefiles_obj_see_lookup_failed );
210
+ fscache_caching_failed (cookie );
211
+ _debug ("failed c=%08x o=%08x" , cookie -> debug_id , object -> debug_id );
212
+ /* The caller holds an access count on the cookie, so we need them to
213
+ * drop it before we can withdraw the object.
214
+ */
215
+ return false;
216
+
217
+ fail_put :
218
+ cachefiles_put_object (object , cachefiles_obj_put_alloc_fail );
219
+ fail :
220
+ return false;
221
+ }
222
+
223
+ /*
224
+ * Commit changes to the object as we drop it.
225
+ */
226
+ static void cachefiles_commit_object (struct cachefiles_object * object ,
227
+ struct cachefiles_cache * cache )
228
+ {
229
+ bool update = false;
230
+
231
+ if (test_and_clear_bit (FSCACHE_COOKIE_LOCAL_WRITE , & object -> cookie -> flags ))
232
+ update = true;
233
+ if (test_and_clear_bit (FSCACHE_COOKIE_NEEDS_UPDATE , & object -> cookie -> flags ))
234
+ update = true;
235
+ if (update )
236
+ cachefiles_set_object_xattr (object );
237
+
238
+ if (test_bit (CACHEFILES_OBJECT_USING_TMPFILE , & object -> flags ))
239
+ cachefiles_commit_tmpfile (cache , object );
240
+ }
241
+
242
+ /*
243
+ * Finalise and object and close the VFS structs that we have.
244
+ */
245
+ static void cachefiles_clean_up_object (struct cachefiles_object * object ,
246
+ struct cachefiles_cache * cache )
247
+ {
248
+ if (test_bit (FSCACHE_COOKIE_RETIRED , & object -> cookie -> flags )) {
249
+ if (!test_bit (CACHEFILES_OBJECT_USING_TMPFILE , & object -> flags )) {
250
+ cachefiles_see_object (object , cachefiles_obj_see_clean_delete );
251
+ _debug ("- inval object OBJ%x" , object -> debug_id );
252
+ cachefiles_delete_object (object , FSCACHE_OBJECT_WAS_RETIRED );
253
+ } else {
254
+ cachefiles_see_object (object , cachefiles_obj_see_clean_drop_tmp );
255
+ _debug ("- inval object OBJ%x tmpfile" , object -> debug_id );
256
+ }
257
+ } else {
258
+ cachefiles_see_object (object , cachefiles_obj_see_clean_commit );
259
+ cachefiles_commit_object (object , cache );
260
+ }
261
+
262
+ cachefiles_unmark_inode_in_use (object , object -> file );
263
+ if (object -> file ) {
264
+ fput (object -> file );
265
+ object -> file = NULL ;
266
+ }
267
+ }
268
+
269
+ /*
270
+ * Withdraw caching for a cookie.
271
+ */
272
+ static void cachefiles_withdraw_cookie (struct fscache_cookie * cookie )
273
+ {
274
+ struct cachefiles_object * object = cookie -> cache_priv ;
275
+ struct cachefiles_cache * cache = object -> volume -> cache ;
276
+ const struct cred * saved_cred ;
277
+
278
+ _enter ("o=%x" , object -> debug_id );
279
+ cachefiles_see_object (object , cachefiles_obj_see_withdraw_cookie );
280
+
281
+ if (!list_empty (& object -> cache_link )) {
282
+ spin_lock (& cache -> object_list_lock );
283
+ cachefiles_see_object (object , cachefiles_obj_see_withdrawal );
284
+ list_del_init (& object -> cache_link );
285
+ spin_unlock (& cache -> object_list_lock );
286
+ }
287
+
288
+ if (object -> file ) {
289
+ cachefiles_begin_secure (cache , & saved_cred );
290
+ cachefiles_clean_up_object (object , cache );
291
+ cachefiles_end_secure (cache , saved_cred );
292
+ }
293
+
294
+ cookie -> cache_priv = NULL ;
295
+ cachefiles_put_object (object , cachefiles_obj_put_detach );
296
+ }
297
+
298
+ /*
299
+ * Invalidate the storage associated with a cookie.
300
+ */
301
+ static bool cachefiles_invalidate_cookie (struct fscache_cookie * cookie )
302
+ {
303
+ struct cachefiles_object * object = cookie -> cache_priv ;
304
+ struct file * new_file , * old_file ;
305
+ bool old_tmpfile ;
306
+
307
+ _enter ("o=%x,[%llu]" , object -> debug_id , object -> cookie -> object_size );
308
+
309
+ old_tmpfile = test_bit (CACHEFILES_OBJECT_USING_TMPFILE , & object -> flags );
310
+
311
+ if (!object -> file ) {
312
+ fscache_resume_after_invalidation (cookie );
313
+ _leave (" = t [light]" );
314
+ return true;
315
+ }
316
+
317
+ new_file = cachefiles_create_tmpfile (object );
318
+ if (IS_ERR (new_file ))
319
+ goto failed ;
320
+
321
+ /* Substitute the VFS target */
322
+ _debug ("sub" );
323
+ spin_lock (& object -> lock );
324
+
325
+ old_file = object -> file ;
326
+ object -> file = new_file ;
327
+ object -> content_info = CACHEFILES_CONTENT_NO_DATA ;
328
+ set_bit (CACHEFILES_OBJECT_USING_TMPFILE , & object -> flags );
329
+ set_bit (FSCACHE_COOKIE_NEEDS_UPDATE , & object -> cookie -> flags );
330
+
331
+ spin_unlock (& object -> lock );
332
+ _debug ("subbed" );
333
+
334
+ /* Allow I/O to take place again */
335
+ fscache_resume_after_invalidation (cookie );
336
+
337
+ if (old_file ) {
338
+ if (!old_tmpfile ) {
339
+ struct cachefiles_volume * volume = object -> volume ;
340
+ struct dentry * fan = volume -> fanout [(u8 )cookie -> key_hash ];
341
+
342
+ inode_lock_nested (d_inode (fan ), I_MUTEX_PARENT );
343
+ cachefiles_bury_object (volume -> cache , object , fan ,
344
+ old_file -> f_path .dentry ,
345
+ FSCACHE_OBJECT_INVALIDATED );
346
+ }
347
+ fput (old_file );
348
+ }
349
+
350
+ _leave (" = t" );
351
+ return true;
352
+
353
+ failed :
354
+ _leave (" = f" );
355
+ return false;
356
+ }
357
+
102
358
const struct fscache_cache_ops cachefiles_cache_ops = {
103
359
.name = "cachefiles" ,
104
360
.acquire_volume = cachefiles_acquire_volume ,
105
361
.free_volume = cachefiles_free_volume ,
362
+ .lookup_cookie = cachefiles_lookup_cookie ,
363
+ .withdraw_cookie = cachefiles_withdraw_cookie ,
364
+ .invalidate_cookie = cachefiles_invalidate_cookie ,
365
+ .prepare_to_write = cachefiles_prepare_to_write ,
106
366
};
0 commit comments