@@ -220,6 +220,83 @@ static bool cachefiles_lookup_cookie(struct fscache_cookie *cookie)
220220 return false;
221221}
222222
223+ /*
224+ * Shorten the backing object to discard any dirty data and free up
225+ * any unused granules.
226+ */
227+ static bool cachefiles_shorten_object (struct cachefiles_object * object ,
228+ struct file * file , loff_t new_size )
229+ {
230+ struct cachefiles_cache * cache = object -> volume -> cache ;
231+ struct inode * inode = file_inode (file );
232+ loff_t i_size , dio_size ;
233+ int ret ;
234+
235+ dio_size = round_up (new_size , CACHEFILES_DIO_BLOCK_SIZE );
236+ i_size = i_size_read (inode );
237+
238+ trace_cachefiles_trunc (object , inode , i_size , dio_size ,
239+ cachefiles_trunc_shrink );
240+ ret = cachefiles_inject_remove_error ();
241+ if (ret == 0 )
242+ ret = vfs_truncate (& file -> f_path , dio_size );
243+ if (ret < 0 ) {
244+ trace_cachefiles_io_error (object , file_inode (file ), ret ,
245+ cachefiles_trace_trunc_error );
246+ cachefiles_io_error_obj (object , "Trunc-to-size failed %d" , ret );
247+ cachefiles_remove_object_xattr (cache , object , file -> f_path .dentry );
248+ return false;
249+ }
250+
251+ if (new_size < dio_size ) {
252+ trace_cachefiles_trunc (object , inode , dio_size , new_size ,
253+ cachefiles_trunc_dio_adjust );
254+ ret = cachefiles_inject_write_error ();
255+ if (ret == 0 )
256+ ret = vfs_fallocate (file , FALLOC_FL_ZERO_RANGE ,
257+ new_size , dio_size );
258+ if (ret < 0 ) {
259+ trace_cachefiles_io_error (object , file_inode (file ), ret ,
260+ cachefiles_trace_fallocate_error );
261+ cachefiles_io_error_obj (object , "Trunc-to-dio-size failed %d" , ret );
262+ cachefiles_remove_object_xattr (cache , object , file -> f_path .dentry );
263+ return false;
264+ }
265+ }
266+
267+ return true;
268+ }
269+
270+ /*
271+ * Resize the backing object.
272+ */
273+ static void cachefiles_resize_cookie (struct netfs_cache_resources * cres ,
274+ loff_t new_size )
275+ {
276+ struct cachefiles_object * object = cachefiles_cres_object (cres );
277+ struct cachefiles_cache * cache = object -> volume -> cache ;
278+ struct fscache_cookie * cookie = object -> cookie ;
279+ const struct cred * saved_cred ;
280+ struct file * file = cachefiles_cres_file (cres );
281+ loff_t old_size = cookie -> object_size ;
282+
283+ _enter ("%llu->%llu" , old_size , new_size );
284+
285+ if (new_size < old_size ) {
286+ cachefiles_begin_secure (cache , & saved_cred );
287+ cachefiles_shorten_object (object , file , new_size );
288+ cachefiles_end_secure (cache , saved_cred );
289+ object -> cookie -> object_size = new_size ;
290+ return ;
291+ }
292+
293+ /* The file is being expanded. We don't need to do anything
294+ * particularly. cookie->initial_size doesn't change and so the point
295+ * at which we have to download before doesn't change.
296+ */
297+ cookie -> object_size = new_size ;
298+ }
299+
223300/*
224301 * Commit changes to the object as we drop it.
225302 */
@@ -363,5 +440,6 @@ const struct fscache_cache_ops cachefiles_cache_ops = {
363440 .withdraw_cookie = cachefiles_withdraw_cookie ,
364441 .invalidate_cookie = cachefiles_invalidate_cookie ,
365442 .begin_operation = cachefiles_begin_operation ,
443+ .resize_cookie = cachefiles_resize_cookie ,
366444 .prepare_to_write = cachefiles_prepare_to_write ,
367445};
0 commit comments