Skip to content

Commit f6075c7

Browse files
Russell KingAl Viro
authored andcommitted
fs/adfs: dir: improve update failure handling
When we update a directory, a number of errors may happen. If we failed to find the entry to update, we can just release the directory buffers as normal. However, if we have some other error, we may have partially updated the buffers, resulting in an invalid directory. In this case, we need to discard the buffers to avoid writing the contents back to the media, and later re-read the directory from the media. Signed-off-by: Russell King <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent ae5df41 commit f6075c7

File tree

1 file changed

+36
-12
lines changed

1 file changed

+36
-12
lines changed

fs/adfs/dir.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,8 @@ int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src,
6464
return 0;
6565
}
6666

67-
void adfs_dir_relse(struct adfs_dir *dir)
67+
static void __adfs_dir_cleanup(struct adfs_dir *dir)
6868
{
69-
unsigned int i;
70-
71-
for (i = 0; i < dir->nr_buffers; i++)
72-
brelse(dir->bhs[i]);
7369
dir->nr_buffers = 0;
7470

7571
if (dir->bhs != dir->bh)
@@ -78,6 +74,26 @@ void adfs_dir_relse(struct adfs_dir *dir)
7874
dir->sb = NULL;
7975
}
8076

77+
void adfs_dir_relse(struct adfs_dir *dir)
78+
{
79+
unsigned int i;
80+
81+
for (i = 0; i < dir->nr_buffers; i++)
82+
brelse(dir->bhs[i]);
83+
84+
__adfs_dir_cleanup(dir);
85+
}
86+
87+
static void adfs_dir_forget(struct adfs_dir *dir)
88+
{
89+
unsigned int i;
90+
91+
for (i = 0; i < dir->nr_buffers; i++)
92+
bforget(dir->bhs[i]);
93+
94+
__adfs_dir_cleanup(dir);
95+
}
96+
8197
int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr,
8298
unsigned int size, struct adfs_dir *dir)
8399
{
@@ -288,20 +304,28 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
288304
goto unlock;
289305

290306
ret = ops->update(&dir, obj);
307+
if (ret)
308+
goto forget;
291309
up_write(&adfs_dir_rwsem);
292310

293-
if (ret == 0)
294-
adfs_dir_mark_dirty(&dir);
311+
adfs_dir_mark_dirty(&dir);
295312

296-
if (wait) {
297-
int err = adfs_dir_sync(&dir);
298-
if (!ret)
299-
ret = err;
300-
}
313+
if (wait)
314+
ret = adfs_dir_sync(&dir);
301315

302316
adfs_dir_relse(&dir);
303317
return ret;
304318

319+
/*
320+
* If the updated failed because the entry wasn't found, we can
321+
* just release the buffers. If it was any other error, forget
322+
* the dirtied buffers so they aren't written back to the media.
323+
*/
324+
forget:
325+
if (ret == -ENOENT)
326+
adfs_dir_relse(&dir);
327+
else
328+
adfs_dir_forget(&dir);
305329
unlock:
306330
up_write(&adfs_dir_rwsem);
307331
#endif

0 commit comments

Comments
 (0)