Commit 19d1b787 authored by Konstantin Komarov's avatar Konstantin Komarov

fs/ntfs3: Refactor ni_try_remove_attr_list function

Now we save a copy of primary record for restoration.
Also now we remove all attributes from subrecords.
Signed-off-by: default avatarKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
parent cd39981f
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/fiemap.h> #include <linux/fiemap.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/minmax.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include "debug.h" #include "debug.h"
...@@ -649,6 +650,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ...@@ -649,6 +650,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
struct mft_inode *mi; struct mft_inode *mi;
u32 asize, free; u32 asize, free;
struct MFT_REF ref; struct MFT_REF ref;
struct MFT_REC *mrec;
__le16 id; __le16 id;
if (!ni->attr_list.dirty) if (!ni->attr_list.dirty)
...@@ -692,11 +694,17 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ...@@ -692,11 +694,17 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
free -= asize; free -= asize;
} }
/* Make a copy of primary record to restore if error. */
mrec = kmemdup(ni->mi.mrec, sbi->record_size, GFP_NOFS);
if (!mrec)
return 0; /* Not critical. */
/* It seems that attribute list can be removed from primary record. */ /* It seems that attribute list can be removed from primary record. */
mi_remove_attr(NULL, &ni->mi, attr_list); mi_remove_attr(NULL, &ni->mi, attr_list);
/* /*
* Repeat the cycle above and move all attributes to primary record. * Repeat the cycle above and copy all attributes to primary record.
* Do not remove original attributes from subrecords!
* It should be success! * It should be success!
*/ */
le = NULL; le = NULL;
...@@ -707,14 +715,14 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ...@@ -707,14 +715,14 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
mi = ni_find_mi(ni, ino_get(&le->ref)); mi = ni_find_mi(ni, ino_get(&le->ref));
if (!mi) { if (!mi) {
/* Should never happened, 'cause already checked. */ /* Should never happened, 'cause already checked. */
goto bad; goto out;
} }
attr = mi_find_attr(mi, NULL, le->type, le_name(le), attr = mi_find_attr(mi, NULL, le->type, le_name(le),
le->name_len, &le->id); le->name_len, &le->id);
if (!attr) { if (!attr) {
/* Should never happened, 'cause already checked. */ /* Should never happened, 'cause already checked. */
goto bad; goto out;
} }
asize = le32_to_cpu(attr->size); asize = le32_to_cpu(attr->size);
...@@ -724,18 +732,33 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ...@@ -724,18 +732,33 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
le16_to_cpu(attr->name_off)); le16_to_cpu(attr->name_off));
if (!attr_ins) { if (!attr_ins) {
/* /*
* Internal error. * No space in primary record (already checked).
* Either no space in primary record (already checked).
* Either tried to insert another
* non indexed attribute (logic error).
*/ */
goto bad; goto out;
} }
/* Copy all except id. */ /* Copy all except id. */
id = attr_ins->id; id = attr_ins->id;
memcpy(attr_ins, attr, asize); memcpy(attr_ins, attr, asize);
attr_ins->id = id; attr_ins->id = id;
}
/*
* Repeat the cycle above and remove all attributes from subrecords.
*/
le = NULL;
while ((le = al_enumerate(ni, le))) {
if (!memcmp(&le->ref, &ref, sizeof(ref)))
continue;
mi = ni_find_mi(ni, ino_get(&le->ref));
if (!mi)
continue;
attr = mi_find_attr(mi, NULL, le->type, le_name(le),
le->name_len, &le->id);
if (!attr)
continue;
/* Remove from original record. */ /* Remove from original record. */
mi_remove_attr(NULL, mi, attr); mi_remove_attr(NULL, mi, attr);
...@@ -748,11 +771,13 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ...@@ -748,11 +771,13 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
ni->attr_list.le = NULL; ni->attr_list.le = NULL;
ni->attr_list.dirty = false; ni->attr_list.dirty = false;
kfree(mrec);
return 0;
out:
/* Restore primary record. */
swap(mrec, ni->mi.mrec);
kfree(mrec);
return 0; return 0;
bad:
ntfs_inode_err(&ni->vfs_inode, "Internal error");
make_bad_inode(&ni->vfs_inode);
return -EINVAL;
} }
/* /*
......
...@@ -445,12 +445,11 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, ...@@ -445,12 +445,11 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
attr = NULL; attr = NULL;
while ((attr = mi_enum_attr(mi, attr))) { while ((attr = mi_enum_attr(mi, attr))) {
diff = compare_attr(attr, type, name, name_len, upcase); diff = compare_attr(attr, type, name, name_len, upcase);
if (diff > 0)
break;
if (diff < 0) if (diff < 0)
continue; continue;
if (!is_attr_indexed(attr)) if (!diff && !is_attr_indexed(attr))
return NULL; return NULL;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment