Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'hfs-v7.0-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs

Pull hfs/hfsplus updates from Viacheslav Dubeyko:
"This pull request contains several fixes of syzbot reported issues and
HFS+ fixes of xfstests failures.

- fix an issue reported by syzbot triggering BUG_ON() in the case of
corrupted superblock, replacing the BUG_ON()s with proper error
handling (Jori Koolstra)

- fix memory leaks in the mount logic of HFS/HFS+ file systems. When
HFS/HFS+ were converted to the new mount api a bug was introduced
by changing the allocation pattern of sb->s_fs_info (Mehdi Ben Hadj
Khelifa)

- fix hfs_bnode_create() by returning ERR_PTR(-EEXIST) instead of
the node pointer when it's already hashed. This avoids a double
unload_nls() on mount failure (suggested by Shardul Bankar)

- set inode's mode as regular file for system inodes (Tetsuo Handa)

The rest fix failures in generic/020, generic/037, generic/062,
generic/480, and generic/498 xfstests for the case of HFS+ file
system. Currently, only 30 xfstests' test-cases experience failures
for HFS+ file system (initially, it was around 100 failed xfstests)"

* tag 'hfs-v7.0-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs:
hfsplus: avoid double unload_nls() on mount failure
hfsplus: fix warning issue in inode.c
hfsplus: fix generic/062 xfstests failure
hfsplus: fix generic/037 xfstests failure
hfsplus: pretend special inodes as regular files
hfsplus: return error when node already exists in hfs_bnode_create
hfs: Replace BUG_ON with error handling for CNID count checks
hfsplus: fix generic/020 xfstests failure
hfsplus: fix volume corruption issue for generic/498
hfsplus: fix volume corruption issue for generic/480
hfsplus: ensure sb->s_fs_info is always cleaned up
hfs: ensure sb->s_fs_info is always cleaned up

+407 -122
+11 -4
fs/hfs/dir.c
··· 196 196 int res; 197 197 198 198 inode = hfs_new_inode(dir, &dentry->d_name, mode); 199 - if (!inode) 200 - return -ENOMEM; 199 + if (IS_ERR(inode)) 200 + return PTR_ERR(inode); 201 201 202 202 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); 203 203 if (res) { ··· 226 226 int res; 227 227 228 228 inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode); 229 - if (!inode) 230 - return ERR_PTR(-ENOMEM); 229 + if (IS_ERR(inode)) 230 + return ERR_CAST(inode); 231 231 232 232 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); 233 233 if (res) { ··· 254 254 */ 255 255 static int hfs_remove(struct inode *dir, struct dentry *dentry) 256 256 { 257 + struct super_block *sb = dir->i_sb; 257 258 struct inode *inode = d_inode(dentry); 258 259 int res; 259 260 260 261 if (S_ISDIR(inode->i_mode) && inode->i_size != 2) 261 262 return -ENOTEMPTY; 263 + 264 + if (unlikely(!is_hfs_cnid_counts_valid(sb))) { 265 + pr_err("cannot remove file/folder\n"); 266 + return -ERANGE; 267 + } 268 + 262 269 res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name); 263 270 if (res) 264 271 return res;
+1
fs/hfs/hfs_fs.h
··· 199 199 extern const struct xattr_handler * const hfs_xattr_handlers[]; 200 200 201 201 /* mdb.c */ 202 + extern bool is_hfs_cnid_counts_valid(struct super_block *sb); 202 203 extern int hfs_mdb_get(struct super_block *sb); 203 204 extern void hfs_mdb_commit(struct super_block *sb); 204 205 extern void hfs_mdb_close(struct super_block *sb);
+24 -6
fs/hfs/inode.c
··· 187 187 s64 next_id; 188 188 s64 file_count; 189 189 s64 folder_count; 190 + int err = -ENOMEM; 190 191 191 192 if (!inode) 192 - return NULL; 193 + goto out_err; 194 + 195 + err = -ERANGE; 193 196 194 197 mutex_init(&HFS_I(inode)->extents_lock); 195 198 INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); 196 199 spin_lock_init(&HFS_I(inode)->open_dir_lock); 197 200 hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name); 198 201 next_id = atomic64_inc_return(&HFS_SB(sb)->next_id); 199 - BUG_ON(next_id > U32_MAX); 202 + if (next_id > U32_MAX) { 203 + atomic64_dec(&HFS_SB(sb)->next_id); 204 + pr_err("cannot create new inode: next CNID exceeds limit\n"); 205 + goto out_discard; 206 + } 200 207 inode->i_ino = (u32)next_id; 201 208 inode->i_mode = mode; 202 209 inode->i_uid = current_fsuid(); ··· 217 210 if (S_ISDIR(mode)) { 218 211 inode->i_size = 2; 219 212 folder_count = atomic64_inc_return(&HFS_SB(sb)->folder_count); 220 - BUG_ON(folder_count > U32_MAX); 213 + if (folder_count> U32_MAX) { 214 + atomic64_dec(&HFS_SB(sb)->folder_count); 215 + pr_err("cannot create new inode: folder count exceeds limit\n"); 216 + goto out_discard; 217 + } 221 218 if (dir->i_ino == HFS_ROOT_CNID) 222 219 HFS_SB(sb)->root_dirs++; 223 220 inode->i_op = &hfs_dir_inode_operations; ··· 231 220 } else if (S_ISREG(mode)) { 232 221 HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks; 233 222 file_count = atomic64_inc_return(&HFS_SB(sb)->file_count); 234 - BUG_ON(file_count > U32_MAX); 223 + if (file_count > U32_MAX) { 224 + atomic64_dec(&HFS_SB(sb)->file_count); 225 + pr_err("cannot create new inode: file count exceeds limit\n"); 226 + goto out_discard; 227 + } 235 228 if (dir->i_ino == HFS_ROOT_CNID) 236 229 HFS_SB(sb)->root_files++; 237 230 inode->i_op = &hfs_file_inode_operations; ··· 259 244 hfs_mark_mdb_dirty(sb); 260 245 261 246 return inode; 247 + 248 + out_discard: 249 + iput(inode); 250 + out_err: 251 + return ERR_PTR(err); 262 252 } 263 253 264 254 void hfs_delete_inode(struct inode *inode) ··· 272 252 273 253 hfs_dbg("ino %lu\n", inode->i_ino); 274 254 if (S_ISDIR(inode->i_mode)) { 275 - BUG_ON(atomic64_read(&HFS_SB(sb)->folder_count) > U32_MAX); 276 255 atomic64_dec(&HFS_SB(sb)->folder_count); 277 256 if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID)) 278 257 HFS_SB(sb)->root_dirs--; ··· 280 261 return; 281 262 } 282 263 283 - BUG_ON(atomic64_read(&HFS_SB(sb)->file_count) > U32_MAX); 284 264 atomic64_dec(&HFS_SB(sb)->file_count); 285 265 if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID)) 286 266 HFS_SB(sb)->root_files--;
+41 -25
fs/hfs/mdb.c
··· 64 64 return 0; 65 65 } 66 66 67 + bool is_hfs_cnid_counts_valid(struct super_block *sb) 68 + { 69 + struct hfs_sb_info *sbi = HFS_SB(sb); 70 + bool corrupted = false; 71 + 72 + if (unlikely(atomic64_read(&sbi->next_id) > U32_MAX)) { 73 + pr_warn("next CNID exceeds limit\n"); 74 + corrupted = true; 75 + } 76 + if (unlikely(atomic64_read(&sbi->file_count) > U32_MAX)) { 77 + pr_warn("file count exceeds limit\n"); 78 + corrupted = true; 79 + } 80 + if (unlikely(atomic64_read(&sbi->folder_count) > U32_MAX)) { 81 + pr_warn("folder count exceeds limit\n"); 82 + corrupted = true; 83 + } 84 + 85 + return !corrupted; 86 + } 87 + 67 88 /* 68 89 * hfs_mdb_get() 69 90 * ··· 113 92 /* See if this is an HFS filesystem */ 114 93 bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb); 115 94 if (!bh) 116 - goto out; 95 + return -EIO; 117 96 118 97 if (mdb->drSigWord == cpu_to_be16(HFS_SUPER_MAGIC)) 119 98 break; ··· 123 102 * (should do this only for cdrom/loop though) 124 103 */ 125 104 if (hfs_part_find(sb, &part_start, &part_size)) 126 - goto out; 105 + return -EIO; 127 106 } 128 107 129 108 HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz); 130 109 if (!size || (size & (HFS_SECTOR_SIZE - 1))) { 131 110 pr_err("bad allocation block size %d\n", size); 132 - goto out_bh; 111 + brelse(bh); 112 + return -EIO; 133 113 } 134 114 135 115 size = min(HFS_SB(sb)->alloc_blksz, (u32)PAGE_SIZE); ··· 147 125 brelse(bh); 148 126 if (!sb_set_blocksize(sb, size)) { 149 127 pr_err("unable to set blocksize to %u\n", size); 150 - goto out; 128 + return -EIO; 151 129 } 152 130 153 131 bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb); 154 132 if (!bh) 155 - goto out; 156 - if (mdb->drSigWord != cpu_to_be16(HFS_SUPER_MAGIC)) 157 - goto out_bh; 133 + return -EIO; 134 + if (mdb->drSigWord != cpu_to_be16(HFS_SUPER_MAGIC)) { 135 + brelse(bh); 136 + return -EIO; 137 + } 158 138 159 139 HFS_SB(sb)->mdb_bh = bh; 160 140 HFS_SB(sb)->mdb = mdb; ··· 180 156 atomic64_set(&HFS_SB(sb)->file_count, be32_to_cpu(mdb->drFilCnt)); 181 157 atomic64_set(&HFS_SB(sb)->folder_count, be32_to_cpu(mdb->drDirCnt)); 182 158 159 + if (!is_hfs_cnid_counts_valid(sb)) { 160 + pr_warn("filesystem possibly corrupted, running fsck.hfs is recommended. Mounting read-only.\n"); 161 + sb->s_flags |= SB_RDONLY; 162 + } 163 + 183 164 /* TRY to get the alternate (backup) MDB. */ 184 165 sect = part_start + part_size - 2; 185 166 bh = sb_bread512(sb, sect, mdb2); ··· 203 174 204 175 HFS_SB(sb)->bitmap = kzalloc(8192, GFP_KERNEL); 205 176 if (!HFS_SB(sb)->bitmap) 206 - goto out; 177 + return -EIO; 207 178 208 179 /* read in the bitmap */ 209 180 block = be16_to_cpu(mdb->drVBMSt) + part_start; ··· 214 185 bh = sb_bread(sb, off >> sb->s_blocksize_bits); 215 186 if (!bh) { 216 187 pr_err("unable to read volume bitmap\n"); 217 - goto out; 188 + return -EIO; 218 189 } 219 190 off2 = off & (sb->s_blocksize - 1); 220 191 len = min((int)sb->s_blocksize - off2, size); ··· 228 199 HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp); 229 200 if (!HFS_SB(sb)->ext_tree) { 230 201 pr_err("unable to open extent tree\n"); 231 - goto out; 202 + return -EIO; 232 203 } 233 204 HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp); 234 205 if (!HFS_SB(sb)->cat_tree) { 235 206 pr_err("unable to open catalog tree\n"); 236 - goto out; 207 + return -EIO; 237 208 } 238 209 239 210 attrib = mdb->drAtrb; 240 211 if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { 241 - pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended. mounting read-only.\n"); 212 + pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended. Mounting read-only.\n"); 242 213 sb->s_flags |= SB_RDONLY; 243 214 } 244 215 if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) { ··· 258 229 } 259 230 260 231 return 0; 261 - 262 - out_bh: 263 - brelse(bh); 264 - out: 265 - hfs_mdb_put(sb); 266 - return -EIO; 267 232 } 268 233 269 234 /* ··· 296 273 /* These parameters may have been modified, so write them back */ 297 274 mdb->drLsMod = hfs_mtime(); 298 275 mdb->drFreeBks = cpu_to_be16(HFS_SB(sb)->free_ablocks); 299 - BUG_ON(atomic64_read(&HFS_SB(sb)->next_id) > U32_MAX); 300 276 mdb->drNxtCNID = 301 277 cpu_to_be32((u32)atomic64_read(&HFS_SB(sb)->next_id)); 302 278 mdb->drNmFls = cpu_to_be16(HFS_SB(sb)->root_files); 303 279 mdb->drNmRtDirs = cpu_to_be16(HFS_SB(sb)->root_dirs); 304 - BUG_ON(atomic64_read(&HFS_SB(sb)->file_count) > U32_MAX); 305 280 mdb->drFilCnt = 306 281 cpu_to_be32((u32)atomic64_read(&HFS_SB(sb)->file_count)); 307 - BUG_ON(atomic64_read(&HFS_SB(sb)->folder_count) > U32_MAX); 308 282 mdb->drDirCnt = 309 283 cpu_to_be32((u32)atomic64_read(&HFS_SB(sb)->folder_count)); 310 284 ··· 379 359 * Release the resources associated with the in-core MDB. */ 380 360 void hfs_mdb_put(struct super_block *sb) 381 361 { 382 - if (!HFS_SB(sb)) 383 - return; 384 362 /* free the B-trees */ 385 363 hfs_btree_close(HFS_SB(sb)->ext_tree); 386 364 hfs_btree_close(HFS_SB(sb)->cat_tree); ··· 391 373 unload_nls(HFS_SB(sb)->nls_disk); 392 374 393 375 kfree(HFS_SB(sb)->bitmap); 394 - kfree(HFS_SB(sb)); 395 - sb->s_fs_info = NULL; 396 376 }
+12 -1
fs/hfs/super.c
··· 34 34 35 35 static int hfs_sync_fs(struct super_block *sb, int wait) 36 36 { 37 + is_hfs_cnid_counts_valid(sb); 37 38 hfs_mdb_commit(sb); 38 39 return 0; 39 40 } ··· 65 64 spin_lock(&sbi->work_lock); 66 65 sbi->work_queued = 0; 67 66 spin_unlock(&sbi->work_lock); 67 + 68 + is_hfs_cnid_counts_valid(sb); 68 69 69 70 hfs_mdb_commit(sb); 70 71 } ··· 434 431 return 0; 435 432 } 436 433 434 + static void hfs_kill_super(struct super_block *sb) 435 + { 436 + struct hfs_sb_info *hsb = HFS_SB(sb); 437 + 438 + kill_block_super(sb); 439 + kfree(hsb); 440 + } 441 + 437 442 static struct file_system_type hfs_fs_type = { 438 443 .owner = THIS_MODULE, 439 444 .name = "hfs", 440 - .kill_sb = kill_block_super, 445 + .kill_sb = hfs_kill_super, 441 446 .fs_flags = FS_REQUIRES_DEV, 442 447 .init_fs_context = hfs_init_fs_context, 443 448 };
+139 -50
fs/hfsplus/attributes.c
··· 117 117 entry->inline_data.record_type = cpu_to_be32(record_type); 118 118 if (size <= HFSPLUS_MAX_INLINE_DATA_SIZE) 119 119 len = size; 120 - else 120 + else { 121 + hfs_dbg("value size %zu is too big\n", size); 121 122 return HFSPLUS_INVALID_ATTR_RECORD; 123 + } 122 124 entry->inline_data.length = cpu_to_be16(len); 123 125 memcpy(entry->inline_data.raw_bytes, value, len); 124 126 /* ··· 193 191 return 0; 194 192 } 195 193 194 + static 195 + int hfsplus_create_attr_nolock(struct inode *inode, const char *name, 196 + const void *value, size_t size, 197 + struct hfs_find_data *fd, 198 + hfsplus_attr_entry *entry_ptr) 199 + { 200 + struct super_block *sb = inode->i_sb; 201 + int entry_size; 202 + int err; 203 + 204 + hfs_dbg("name %s, ino %ld\n", 205 + name ? name : NULL, inode->i_ino); 206 + 207 + if (name) { 208 + err = hfsplus_attr_build_key(sb, fd->search_key, 209 + inode->i_ino, name); 210 + if (err) 211 + return err; 212 + } else 213 + return -EINVAL; 214 + 215 + /* Mac OS X supports only inline data attributes. */ 216 + entry_size = hfsplus_attr_build_record(entry_ptr, 217 + HFSPLUS_ATTR_INLINE_DATA, 218 + inode->i_ino, 219 + value, size); 220 + if (entry_size == HFSPLUS_INVALID_ATTR_RECORD) { 221 + if (size > HFSPLUS_MAX_INLINE_DATA_SIZE) 222 + err = -E2BIG; 223 + else 224 + err = -EINVAL; 225 + hfs_dbg("unable to store value: err %d\n", err); 226 + return err; 227 + } 228 + 229 + err = hfs_brec_find(fd, hfs_find_rec_by_key); 230 + if (err != -ENOENT) { 231 + if (!err) 232 + err = -EEXIST; 233 + return err; 234 + } 235 + 236 + err = hfs_brec_insert(fd, entry_ptr, entry_size); 237 + if (err) { 238 + hfs_dbg("unable to store value: err %d\n", err); 239 + return err; 240 + } 241 + 242 + hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY); 243 + 244 + return 0; 245 + } 246 + 196 247 int hfsplus_create_attr(struct inode *inode, 197 - const char *name, 198 - const void *value, size_t size) 248 + const char *name, 249 + const void *value, size_t size) 199 250 { 200 251 struct super_block *sb = inode->i_sb; 201 252 struct hfs_find_data fd; 202 253 hfsplus_attr_entry *entry_ptr; 203 - int entry_size; 204 254 int err; 205 255 206 256 hfs_dbg("name %s, ino %ld\n", ··· 276 222 if (err) 277 223 goto failed_create_attr; 278 224 279 - if (name) { 280 - err = hfsplus_attr_build_key(sb, fd.search_key, 281 - inode->i_ino, name); 282 - if (err) 283 - goto failed_create_attr; 284 - } else { 285 - err = -EINVAL; 286 - goto failed_create_attr; 287 - } 288 - 289 - /* Mac OS X supports only inline data attributes. */ 290 - entry_size = hfsplus_attr_build_record(entry_ptr, 291 - HFSPLUS_ATTR_INLINE_DATA, 292 - inode->i_ino, 293 - value, size); 294 - if (entry_size == HFSPLUS_INVALID_ATTR_RECORD) { 295 - err = -EINVAL; 296 - goto failed_create_attr; 297 - } 298 - 299 - err = hfs_brec_find(&fd, hfs_find_rec_by_key); 300 - if (err != -ENOENT) { 301 - if (!err) 302 - err = -EEXIST; 303 - goto failed_create_attr; 304 - } 305 - 306 - err = hfs_brec_insert(&fd, entry_ptr, entry_size); 225 + err = hfsplus_create_attr_nolock(inode, name, value, size, 226 + &fd, entry_ptr); 307 227 if (err) 308 228 goto failed_create_attr; 309 - 310 - hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY); 311 229 312 230 failed_create_attr: 313 231 hfs_find_exit(&fd); ··· 330 304 return err; 331 305 } 332 306 307 + static 308 + int hfsplus_delete_attr_nolock(struct inode *inode, const char *name, 309 + struct hfs_find_data *fd) 310 + { 311 + struct super_block *sb = inode->i_sb; 312 + int err; 313 + 314 + hfs_dbg("name %s, ino %ld\n", 315 + name ? name : NULL, inode->i_ino); 316 + 317 + if (name) { 318 + err = hfsplus_attr_build_key(sb, fd->search_key, 319 + inode->i_ino, name); 320 + if (err) 321 + return err; 322 + } else { 323 + pr_err("invalid extended attribute name\n"); 324 + return -EINVAL; 325 + } 326 + 327 + err = hfs_brec_find(fd, hfs_find_rec_by_key); 328 + if (err) 329 + return err; 330 + 331 + err = __hfsplus_delete_attr(inode, inode->i_ino, fd); 332 + if (err) 333 + return err; 334 + 335 + return 0; 336 + } 337 + 333 338 int hfsplus_delete_attr(struct inode *inode, const char *name) 334 339 { 335 340 int err = 0; ··· 384 327 if (err) 385 328 goto out; 386 329 387 - if (name) { 388 - err = hfsplus_attr_build_key(sb, fd.search_key, 389 - inode->i_ino, name); 390 - if (err) 391 - goto out; 392 - } else { 393 - pr_err("invalid extended attribute name\n"); 394 - err = -EINVAL; 395 - goto out; 396 - } 397 - 398 - err = hfs_brec_find(&fd, hfs_find_rec_by_key); 399 - if (err) 400 - goto out; 401 - 402 - err = __hfsplus_delete_attr(inode, inode->i_ino, &fd); 330 + err = hfsplus_delete_attr_nolock(inode, name, &fd); 403 331 if (err) 404 332 goto out; 405 333 ··· 424 382 425 383 end_delete_all: 426 384 hfs_find_exit(&fd); 385 + return err; 386 + } 387 + 388 + int hfsplus_replace_attr(struct inode *inode, 389 + const char *name, 390 + const void *value, size_t size) 391 + { 392 + struct super_block *sb = inode->i_sb; 393 + struct hfs_find_data fd; 394 + hfsplus_attr_entry *entry_ptr; 395 + int err = 0; 396 + 397 + hfs_dbg("name %s, ino %ld\n", 398 + name ? name : NULL, inode->i_ino); 399 + 400 + if (!HFSPLUS_SB(sb)->attr_tree) { 401 + pr_err("attributes file doesn't exist\n"); 402 + return -EINVAL; 403 + } 404 + 405 + entry_ptr = hfsplus_alloc_attr_entry(); 406 + if (!entry_ptr) 407 + return -ENOMEM; 408 + 409 + err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd); 410 + if (err) 411 + goto failed_init_replace_attr; 412 + 413 + /* Fail early and avoid ENOSPC during the btree operation */ 414 + err = hfs_bmap_reserve(fd.tree, fd.tree->depth + 1); 415 + if (err) 416 + goto failed_replace_attr; 417 + 418 + err = hfsplus_delete_attr_nolock(inode, name, &fd); 419 + if (err) 420 + goto failed_replace_attr; 421 + 422 + err = hfsplus_create_attr_nolock(inode, name, value, size, 423 + &fd, entry_ptr); 424 + if (err) 425 + goto failed_replace_attr; 426 + 427 + failed_replace_attr: 428 + hfs_find_exit(&fd); 429 + 430 + failed_init_replace_attr: 431 + hfsplus_destroy_attr_entry(entry_ptr); 427 432 return err; 428 433 }
+1 -1
fs/hfsplus/bnode.c
··· 629 629 if (node) { 630 630 pr_crit("new node %u already hashed?\n", num); 631 631 WARN_ON(1); 632 - return node; 632 + return ERR_PTR(-EEXIST); 633 633 } 634 634 node = __hfs_bnode_create(tree, num); 635 635 if (!node)
+45 -1
fs/hfsplus/dir.c
··· 313 313 if (!S_ISREG(inode->i_mode)) 314 314 return -EPERM; 315 315 316 + hfs_dbg("src_dir->i_ino %lu, dst_dir->i_ino %lu, inode->i_ino %lu\n", 317 + src_dir->i_ino, dst_dir->i_ino, inode->i_ino); 318 + 316 319 mutex_lock(&sbi->vh_mutex); 317 320 if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) { 318 321 for (;;) { ··· 335 332 cnid = sbi->next_cnid++; 336 333 src_dentry->d_fsdata = (void *)(unsigned long)cnid; 337 334 res = hfsplus_create_cat(cnid, src_dir, 338 - &src_dentry->d_name, inode); 335 + &src_dentry->d_name, inode); 339 336 if (res) 340 337 /* panic? */ 341 338 goto out; ··· 353 350 mark_inode_dirty(inode); 354 351 sbi->file_count++; 355 352 hfsplus_mark_mdb_dirty(dst_dir->i_sb); 353 + 354 + res = hfsplus_cat_write_inode(src_dir); 355 + if (res) 356 + goto out; 357 + 358 + res = hfsplus_cat_write_inode(dst_dir); 359 + if (res) 360 + goto out; 361 + 362 + res = hfsplus_cat_write_inode(sbi->hidden_dir); 363 + if (res) 364 + goto out; 365 + 366 + res = hfsplus_cat_write_inode(inode); 367 + 356 368 out: 357 369 mutex_unlock(&sbi->vh_mutex); 358 370 return res; ··· 384 366 385 367 if (HFSPLUS_IS_RSRC(inode)) 386 368 return -EPERM; 369 + 370 + hfs_dbg("dir->i_ino %lu, inode->i_ino %lu\n", 371 + dir->i_ino, inode->i_ino); 387 372 388 373 mutex_lock(&sbi->vh_mutex); 389 374 cnid = (u32)(unsigned long)dentry->d_fsdata; ··· 429 408 inode_set_ctime_current(inode); 430 409 mark_inode_dirty(inode); 431 410 out: 411 + if (!res) { 412 + res = hfsplus_cat_write_inode(dir); 413 + if (!res) { 414 + res = hfsplus_cat_write_inode(sbi->hidden_dir); 415 + if (!res) 416 + res = hfsplus_cat_write_inode(inode); 417 + } 418 + } 419 + 432 420 mutex_unlock(&sbi->vh_mutex); 433 421 return res; 434 422 } ··· 459 429 inode_set_ctime_current(inode); 460 430 hfsplus_delete_inode(inode); 461 431 mark_inode_dirty(inode); 432 + 433 + res = hfsplus_cat_write_inode(dir); 462 434 out: 463 435 mutex_unlock(&sbi->vh_mutex); 464 436 return res; ··· 497 465 498 466 hfsplus_instantiate(dentry, inode, inode->i_ino); 499 467 mark_inode_dirty(inode); 468 + 469 + res = hfsplus_cat_write_inode(dir); 470 + if (res) 471 + goto out; 472 + 473 + res = hfsplus_cat_write_inode(inode); 500 474 goto out; 501 475 502 476 out_err: ··· 544 506 545 507 hfsplus_instantiate(dentry, inode, inode->i_ino); 546 508 mark_inode_dirty(inode); 509 + 510 + res = hfsplus_cat_write_inode(dir); 511 + if (res) 512 + goto out; 513 + 514 + res = hfsplus_cat_write_inode(inode); 547 515 goto out; 548 516 549 517 failed_mknod:
+3
fs/hfsplus/hfsplus_fs.h
··· 344 344 const void *value, size_t size); 345 345 int hfsplus_delete_attr(struct inode *inode, const char *name); 346 346 int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid); 347 + int hfsplus_replace_attr(struct inode *inode, 348 + const char *name, 349 + const void *value, size_t size); 347 350 348 351 /* bitmap.c */ 349 352 int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset,
+37 -3
fs/hfsplus/inode.c
··· 328 328 struct hfsplus_vh *vhdr = sbi->s_vhdr; 329 329 int error = 0, error2; 330 330 331 + hfs_dbg("inode->i_ino %lu, start %llu, end %llu\n", 332 + inode->i_ino, start, end); 333 + 331 334 error = file_write_and_wait_range(file, start, end); 332 335 if (error) 333 336 return error; ··· 396 393 .fileattr_set = hfsplus_fileattr_set, 397 394 }; 398 395 396 + static const struct inode_operations hfsplus_symlink_inode_operations = { 397 + .get_link = page_get_link, 398 + .setattr = hfsplus_setattr, 399 + .getattr = hfsplus_getattr, 400 + .listxattr = hfsplus_listxattr, 401 + }; 402 + 403 + static const struct inode_operations hfsplus_special_inode_operations = { 404 + .setattr = hfsplus_setattr, 405 + .getattr = hfsplus_getattr, 406 + .listxattr = hfsplus_listxattr, 407 + }; 408 + 399 409 static const struct file_operations hfsplus_file_operations = { 400 410 .llseek = generic_file_llseek, 401 411 .read_iter = generic_file_read_iter, ··· 468 452 hip->clump_blocks = sbi->data_clump_blocks; 469 453 } else if (S_ISLNK(inode->i_mode)) { 470 454 sbi->file_count++; 471 - inode->i_op = &page_symlink_inode_operations; 455 + inode->i_op = &hfsplus_symlink_inode_operations; 472 456 inode_nohighmem(inode); 473 457 inode->i_mapping->a_ops = &hfsplus_aops; 474 458 hip->clump_blocks = 1; 459 + } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || 460 + S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { 461 + sbi->file_count++; 462 + inode->i_op = &hfsplus_special_inode_operations; 475 463 } else 476 464 sbi->file_count++; 465 + 477 466 insert_inode_hash(inode); 478 467 mark_inode_dirty(inode); 479 468 hfsplus_mark_mdb_dirty(sb); ··· 609 588 inode->i_fop = &hfsplus_file_operations; 610 589 inode->i_mapping->a_ops = &hfsplus_aops; 611 590 } else if (S_ISLNK(inode->i_mode)) { 612 - inode->i_op = &page_symlink_inode_operations; 591 + inode->i_op = &hfsplus_symlink_inode_operations; 613 592 inode_nohighmem(inode); 614 593 inode->i_mapping->a_ops = &hfsplus_aops; 615 594 } else { 595 + inode->i_op = &hfsplus_special_inode_operations; 616 596 init_special_inode(inode, inode->i_mode, 617 597 be32_to_cpu(file->permissions.dev)); 618 598 } ··· 634 612 int hfsplus_cat_write_inode(struct inode *inode) 635 613 { 636 614 struct inode *main_inode = inode; 615 + struct hfs_btree *tree = HFSPLUS_SB(inode->i_sb)->cat_tree; 637 616 struct hfs_find_data fd; 638 617 hfsplus_cat_entry entry; 639 618 int res = 0; 619 + 620 + hfs_dbg("inode->i_ino %lu\n", inode->i_ino); 640 621 641 622 if (HFSPLUS_IS_RSRC(inode)) 642 623 main_inode = HFSPLUS_I(inode)->rsrc_inode; ··· 647 622 if (!main_inode->i_nlink) 648 623 return 0; 649 624 650 - if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd)) 625 + if (hfs_find_init(tree, &fd)) 651 626 /* panic? */ 652 627 return -EIO; 653 628 ··· 712 687 set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags); 713 688 out: 714 689 hfs_find_exit(&fd); 690 + 691 + if (!res) { 692 + res = hfs_btree_write(tree); 693 + if (res) { 694 + pr_err("b-tree write err: %d, ino %lu\n", 695 + res, inode->i_ino); 696 + } 697 + } 698 + 715 699 return res; 716 700 } 717 701
+15 -5
fs/hfsplus/super.c
··· 53 53 return -EIO; 54 54 } 55 55 56 + /* 57 + * Assign a dummy file type, for may_open() requires that 58 + * an inode has a valid file type. 59 + */ 60 + inode->i_mode = S_IFREG; 61 + 56 62 return 0; 57 63 } 58 64 ··· 350 344 hfs_btree_close(sbi->ext_tree); 351 345 kfree(sbi->s_vhdr_buf); 352 346 kfree(sbi->s_backup_vhdr_buf); 353 - call_rcu(&sbi->rcu, delayed_free); 354 - 355 347 hfs_dbg("finished\n"); 356 348 } 357 349 ··· 652 648 kfree(sbi->s_vhdr_buf); 653 649 kfree(sbi->s_backup_vhdr_buf); 654 650 out_unload_nls: 655 - unload_nls(sbi->nls); 656 651 unload_nls(nls); 657 - kfree(sbi); 658 652 return err; 659 653 } 660 654 ··· 711 709 return 0; 712 710 } 713 711 712 + static void hfsplus_kill_super(struct super_block *sb) 713 + { 714 + struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 715 + 716 + kill_block_super(sb); 717 + call_rcu(&sbi->rcu, delayed_free); 718 + } 719 + 714 720 static struct file_system_type hfsplus_fs_type = { 715 721 .owner = THIS_MODULE, 716 722 .name = "hfsplus", 717 - .kill_sb = kill_block_super, 723 + .kill_sb = hfsplus_kill_super, 718 724 .fs_flags = FS_REQUIRES_DEV, 719 725 .init_fs_context = hfsplus_init_fs_context, 720 726 };
+78 -26
fs/hfsplus/xattr.c
··· 258 258 return err; 259 259 } 260 260 261 + static inline 262 + bool is_xattr_operation_supported(struct inode *inode) 263 + { 264 + if (HFSPLUS_IS_RSRC(inode)) 265 + return false; 266 + 267 + return true; 268 + } 269 + 261 270 int __hfsplus_setxattr(struct inode *inode, const char *name, 262 271 const void *value, size_t size, int flags) 263 272 { ··· 277 268 u16 folder_finderinfo_len = sizeof(DInfo) + sizeof(DXInfo); 278 269 u16 file_finderinfo_len = sizeof(FInfo) + sizeof(FXInfo); 279 270 280 - if ((!S_ISREG(inode->i_mode) && 281 - !S_ISDIR(inode->i_mode)) || 282 - HFSPLUS_IS_RSRC(inode)) 271 + hfs_dbg("ino %lu, name %s, value %p, size %zu\n", 272 + inode->i_ino, name ? name : NULL, 273 + value, size); 274 + 275 + if (!is_xattr_operation_supported(inode)) 283 276 return -EOPNOTSUPP; 284 277 285 278 if (value == NULL) ··· 352 341 err = -EOPNOTSUPP; 353 342 goto end_setxattr; 354 343 } 355 - err = hfsplus_delete_attr(inode, name); 356 - if (err) 344 + err = hfsplus_replace_attr(inode, name, value, size); 345 + if (err) { 346 + hfs_dbg("unable to replace xattr: err %d\n", err); 357 347 goto end_setxattr; 358 - err = hfsplus_create_attr(inode, name, value, size); 359 - if (err) 360 - goto end_setxattr; 348 + } 361 349 } else { 362 350 if (flags & XATTR_REPLACE) { 363 351 pr_err("cannot replace xattr\n"); ··· 364 354 goto end_setxattr; 365 355 } 366 356 err = hfsplus_create_attr(inode, name, value, size); 367 - if (err) 357 + if (err) { 358 + hfs_dbg("unable to store value: err %d\n", err); 368 359 goto end_setxattr; 360 + } 369 361 } 370 362 371 363 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); ··· 401 389 402 390 end_setxattr: 403 391 hfs_find_exit(&cat_fd); 392 + hfs_dbg("finished: res %d\n", err); 404 393 return err; 405 394 } 406 395 407 - static int name_len(const char *xattr_name, int xattr_name_len) 396 + static size_t name_len(const char *xattr_name, size_t xattr_name_len) 408 397 { 409 - int len = xattr_name_len + 1; 398 + size_t len = xattr_name_len + 1; 410 399 411 400 if (!is_known_namespace(xattr_name)) 412 401 len += XATTR_MAC_OSX_PREFIX_LEN; ··· 415 402 return len; 416 403 } 417 404 418 - static ssize_t copy_name(char *buffer, const char *xattr_name, int name_len) 405 + static ssize_t copy_name(char *buffer, const char *xattr_name, size_t name_len) 419 406 { 420 407 ssize_t len; 421 408 422 - if (!is_known_namespace(xattr_name)) 409 + memset(buffer, 0, name_len); 410 + 411 + if (!is_known_namespace(xattr_name)) { 423 412 len = scnprintf(buffer, name_len + XATTR_MAC_OSX_PREFIX_LEN, 424 413 "%s%s", XATTR_MAC_OSX_PREFIX, xattr_name); 425 - else 414 + } else { 426 415 len = strscpy(buffer, xattr_name, name_len + 1); 416 + if (len < 0) { 417 + pr_err("fail to copy name: err %zd\n", len); 418 + len = 0; 419 + } 420 + } 427 421 428 422 /* include NUL-byte in length for non-empty name */ 429 423 if (len >= 0) ··· 443 423 const char *prefix, size_t prefixlen) 444 424 { 445 425 char *xattr_name; 426 + size_t xattr_name_len = 427 + NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1; 446 428 int res; 447 429 448 - xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, 449 - GFP_KERNEL); 430 + hfs_dbg("ino %lu, name %s, prefix %s, prefixlen %zu, " 431 + "value %p, size %zu\n", 432 + inode->i_ino, name ? name : NULL, 433 + prefix ? prefix : NULL, prefixlen, 434 + value, size); 435 + 436 + xattr_name = kmalloc(xattr_name_len, GFP_KERNEL); 450 437 if (!xattr_name) 451 438 return -ENOMEM; 452 439 strcpy(xattr_name, prefix); 453 440 strcpy(xattr_name + prefixlen, name); 454 441 res = __hfsplus_setxattr(inode, xattr_name, value, size, flags); 455 442 kfree(xattr_name); 443 + 444 + hfs_dbg("finished: res %d\n", res); 445 + 456 446 return res; 457 447 } 458 448 ··· 526 496 u16 record_length = 0; 527 497 ssize_t res; 528 498 529 - if ((!S_ISREG(inode->i_mode) && 530 - !S_ISDIR(inode->i_mode)) || 531 - HFSPLUS_IS_RSRC(inode)) 499 + if (!is_xattr_operation_supported(inode)) 532 500 return -EOPNOTSUPP; 533 501 534 502 if (!strcmp_xattr_finder_info(name)) ··· 607 579 int res; 608 580 char *xattr_name; 609 581 582 + hfs_dbg("ino %lu, name %s, prefix %s\n", 583 + inode->i_ino, name ? name : NULL, 584 + prefix ? prefix : NULL); 585 + 610 586 xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, 611 587 GFP_KERNEL); 612 588 if (!xattr_name) ··· 621 589 622 590 res = __hfsplus_getxattr(inode, xattr_name, value, size); 623 591 kfree(xattr_name); 592 + 593 + hfs_dbg("finished: res %d\n", res); 594 + 624 595 return res; 625 596 626 597 } ··· 714 679 struct hfs_find_data fd; 715 680 struct hfsplus_attr_key attr_key; 716 681 char *strbuf; 682 + size_t strbuf_size; 717 683 int xattr_name_len; 718 684 719 - if ((!S_ISREG(inode->i_mode) && 720 - !S_ISDIR(inode->i_mode)) || 721 - HFSPLUS_IS_RSRC(inode)) 685 + hfs_dbg("ino %lu\n", inode->i_ino); 686 + 687 + if (!is_xattr_operation_supported(inode)) 722 688 return -EOPNOTSUPP; 723 689 724 690 res = hfsplus_listxattr_finder_info(dentry, buffer, size); ··· 734 698 return err; 735 699 } 736 700 737 - strbuf = kzalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 738 - XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL); 701 + strbuf_size = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 702 + XATTR_MAC_OSX_PREFIX_LEN + 1; 703 + strbuf = kzalloc(strbuf_size, GFP_KERNEL); 739 704 if (!strbuf) { 740 705 res = -ENOMEM; 741 706 goto out; ··· 745 708 err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd); 746 709 if (err) { 747 710 if (err == -ENOENT) { 748 - if (res == 0) 749 - res = -ENODATA; 711 + res = 0; 750 712 goto end_listxattr; 751 713 } else { 752 714 res = err; ··· 782 746 res += name_len(strbuf, xattr_name_len); 783 747 } else if (can_list(strbuf)) { 784 748 if (size < (res + name_len(strbuf, xattr_name_len))) { 749 + pr_err("size %zu, res %zd, name_len %zu\n", 750 + size, res, 751 + name_len(strbuf, xattr_name_len)); 785 752 res = -ERANGE; 786 753 goto end_listxattr; 787 754 } else 788 755 res += copy_name(buffer + res, 789 756 strbuf, xattr_name_len); 790 757 } 758 + 759 + memset(fd.key->attr.key_name.unicode, 0, 760 + sizeof(fd.key->attr.key_name.unicode)); 761 + memset(strbuf, 0, strbuf_size); 791 762 792 763 if (hfs_brec_goto(&fd, 1)) 793 764 goto end_listxattr; ··· 804 761 kfree(strbuf); 805 762 out: 806 763 hfs_find_exit(&fd); 764 + 765 + hfs_dbg("finished: res %zd\n", res); 766 + 807 767 return res; 808 768 } 809 769 ··· 818 772 u16 cat_entry_type; 819 773 int is_xattr_acl_deleted; 820 774 int is_all_xattrs_deleted; 775 + 776 + hfs_dbg("ino %lu, name %s\n", 777 + inode->i_ino, name ? name : NULL); 821 778 822 779 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 823 780 return -EOPNOTSUPP; ··· 882 833 883 834 end_removexattr: 884 835 hfs_find_exit(&cat_fd); 836 + 837 + hfs_dbg("finished: err %d\n", err); 838 + 885 839 return err; 886 840 } 887 841