diff options
| -rw-r--r-- | .mailmap | 4 | ||||
| -rw-r--r-- | fs/hfsplus/catalog.c | 89 | ||||
| -rw-r--r-- | fs/hfsplus/dir.c | 11 | ||||
| -rw-r--r-- | fs/hfsplus/hfsplus_fs.h | 4 | ||||
| -rw-r--r-- | fs/hfsplus/super.c | 4 | ||||
| -rw-r--r-- | fs/ocfs2/alloc.c | 28 | ||||
| -rw-r--r-- | fs/ocfs2/alloc.h | 2 | ||||
| -rw-r--r-- | fs/ocfs2/aops.c | 16 | ||||
| -rw-r--r-- | fs/ocfs2/dir.c | 2 | ||||
| -rw-r--r-- | fs/ocfs2/dlm/dlmmaster.c | 12 | ||||
| -rw-r--r-- | fs/ocfs2/file.c | 2 | ||||
| -rw-r--r-- | fs/proc/meminfo.c | 15 | ||||
| -rw-r--r-- | include/linux/cma.h | 1 | ||||
| -rw-r--r-- | lib/show_mem.c | 6 | ||||
| -rw-r--r-- | mm/cma.c | 1 | ||||
| -rw-r--r-- | mm/memory.c | 6 | ||||
| -rw-r--r-- | mm/mempolicy.c | 10 | ||||
| -rw-r--r-- | mm/page_alloc.c | 6 | ||||
| -rw-r--r-- | mm/zsmalloc.c | 374 | ||||
| -rw-r--r-- | tools/testing/selftests/Makefile | 17 |
20 files changed, 352 insertions, 258 deletions
| @@ -17,7 +17,7 @@ Aleksey Gorelov <aleksey_gorelov@phoenix.com> | |||
| 17 | Al Viro <viro@ftp.linux.org.uk> | 17 | Al Viro <viro@ftp.linux.org.uk> |
| 18 | Al Viro <viro@zenIV.linux.org.uk> | 18 | Al Viro <viro@zenIV.linux.org.uk> |
| 19 | Andreas Herrmann <aherrman@de.ibm.com> | 19 | Andreas Herrmann <aherrman@de.ibm.com> |
| 20 | Andrew Morton <akpm@osdl.org> | 20 | Andrew Morton <akpm@linux-foundation.org> |
| 21 | Andrew Vasquez <andrew.vasquez@qlogic.com> | 21 | Andrew Vasquez <andrew.vasquez@qlogic.com> |
| 22 | Andy Adamson <andros@citi.umich.edu> | 22 | Andy Adamson <andros@citi.umich.edu> |
| 23 | Archit Taneja <archit@ti.com> | 23 | Archit Taneja <archit@ti.com> |
| @@ -102,6 +102,8 @@ Rudolf Marek <R.Marek@sh.cvut.cz> | |||
| 102 | Rui Saraiva <rmps@joel.ist.utl.pt> | 102 | Rui Saraiva <rmps@joel.ist.utl.pt> |
| 103 | Sachin P Sant <ssant@in.ibm.com> | 103 | Sachin P Sant <ssant@in.ibm.com> |
| 104 | Sam Ravnborg <sam@mars.ravnborg.org> | 104 | Sam Ravnborg <sam@mars.ravnborg.org> |
| 105 | Santosh Shilimkar <ssantosh@kernel.org> | ||
| 106 | Santosh Shilimkar <santosh.shilimkar@oracle.org> | ||
| 105 | Sascha Hauer <s.hauer@pengutronix.de> | 107 | Sascha Hauer <s.hauer@pengutronix.de> |
| 106 | S.Çağlar Onur <caglar@pardus.org.tr> | 108 | S.Çağlar Onur <caglar@pardus.org.tr> |
| 107 | Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com> | 109 | Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com> |
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 32602c667b4a..7892e6fddb66 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c | |||
| @@ -38,21 +38,30 @@ int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, | |||
| 38 | return hfsplus_strcmp(&k1->cat.name, &k2->cat.name); | 38 | return hfsplus_strcmp(&k1->cat.name, &k2->cat.name); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, | 41 | /* Generates key for catalog file/folders record. */ |
| 42 | u32 parent, struct qstr *str) | 42 | int hfsplus_cat_build_key(struct super_block *sb, |
| 43 | hfsplus_btree_key *key, u32 parent, struct qstr *str) | ||
| 43 | { | 44 | { |
| 44 | int len; | 45 | int len, err; |
| 45 | 46 | ||
| 46 | key->cat.parent = cpu_to_be32(parent); | 47 | key->cat.parent = cpu_to_be32(parent); |
| 47 | if (str) { | 48 | err = hfsplus_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN, |
| 48 | hfsplus_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN, | 49 | str->name, str->len); |
| 49 | str->name, str->len); | 50 | if (unlikely(err < 0)) |
| 50 | len = be16_to_cpu(key->cat.name.length); | 51 | return err; |
| 51 | } else { | 52 | |
| 52 | key->cat.name.length = 0; | 53 | len = be16_to_cpu(key->cat.name.length); |
| 53 | len = 0; | ||
| 54 | } | ||
| 55 | key->key_len = cpu_to_be16(6 + 2 * len); | 54 | key->key_len = cpu_to_be16(6 + 2 * len); |
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | /* Generates key for catalog thread record. */ | ||
| 59 | void hfsplus_cat_build_key_with_cnid(struct super_block *sb, | ||
| 60 | hfsplus_btree_key *key, u32 parent) | ||
| 61 | { | ||
| 62 | key->cat.parent = cpu_to_be32(parent); | ||
| 63 | key->cat.name.length = 0; | ||
| 64 | key->key_len = cpu_to_be16(6); | ||
| 56 | } | 65 | } |
| 57 | 66 | ||
| 58 | static void hfsplus_cat_build_key_uni(hfsplus_btree_key *key, u32 parent, | 67 | static void hfsplus_cat_build_key_uni(hfsplus_btree_key *key, u32 parent, |
| @@ -167,11 +176,16 @@ static int hfsplus_fill_cat_thread(struct super_block *sb, | |||
| 167 | hfsplus_cat_entry *entry, int type, | 176 | hfsplus_cat_entry *entry, int type, |
| 168 | u32 parentid, struct qstr *str) | 177 | u32 parentid, struct qstr *str) |
| 169 | { | 178 | { |
| 179 | int err; | ||
| 180 | |||
| 170 | entry->type = cpu_to_be16(type); | 181 | entry->type = cpu_to_be16(type); |
| 171 | entry->thread.reserved = 0; | 182 | entry->thread.reserved = 0; |
| 172 | entry->thread.parentID = cpu_to_be32(parentid); | 183 | entry->thread.parentID = cpu_to_be32(parentid); |
| 173 | hfsplus_asc2uni(sb, &entry->thread.nodeName, HFSPLUS_MAX_STRLEN, | 184 | err = hfsplus_asc2uni(sb, &entry->thread.nodeName, HFSPLUS_MAX_STRLEN, |
| 174 | str->name, str->len); | 185 | str->name, str->len); |
| 186 | if (unlikely(err < 0)) | ||
| 187 | return err; | ||
| 188 | |||
| 175 | return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2; | 189 | return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2; |
| 176 | } | 190 | } |
| 177 | 191 | ||
| @@ -183,7 +197,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid, | |||
| 183 | int err; | 197 | int err; |
| 184 | u16 type; | 198 | u16 type; |
| 185 | 199 | ||
| 186 | hfsplus_cat_build_key(sb, fd->search_key, cnid, NULL); | 200 | hfsplus_cat_build_key_with_cnid(sb, fd->search_key, cnid); |
| 187 | err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry)); | 201 | err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry)); |
| 188 | if (err) | 202 | if (err) |
| 189 | return err; | 203 | return err; |
| @@ -250,11 +264,16 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, | |||
| 250 | if (err) | 264 | if (err) |
| 251 | return err; | 265 | return err; |
| 252 | 266 | ||
| 253 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 267 | hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); |
| 254 | entry_size = hfsplus_fill_cat_thread(sb, &entry, | 268 | entry_size = hfsplus_fill_cat_thread(sb, &entry, |
| 255 | S_ISDIR(inode->i_mode) ? | 269 | S_ISDIR(inode->i_mode) ? |
| 256 | HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, | 270 | HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, |
| 257 | dir->i_ino, str); | 271 | dir->i_ino, str); |
| 272 | if (unlikely(entry_size < 0)) { | ||
| 273 | err = entry_size; | ||
| 274 | goto err2; | ||
| 275 | } | ||
| 276 | |||
| 258 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); | 277 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 259 | if (err != -ENOENT) { | 278 | if (err != -ENOENT) { |
| 260 | if (!err) | 279 | if (!err) |
| @@ -265,7 +284,10 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, | |||
| 265 | if (err) | 284 | if (err) |
| 266 | goto err2; | 285 | goto err2; |
| 267 | 286 | ||
| 268 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); | 287 | err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); |
| 288 | if (unlikely(err)) | ||
| 289 | goto err1; | ||
| 290 | |||
| 269 | entry_size = hfsplus_cat_build_record(&entry, cnid, inode); | 291 | entry_size = hfsplus_cat_build_record(&entry, cnid, inode); |
| 270 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); | 292 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 271 | if (err != -ENOENT) { | 293 | if (err != -ENOENT) { |
| @@ -288,7 +310,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, | |||
| 288 | return 0; | 310 | return 0; |
| 289 | 311 | ||
| 290 | err1: | 312 | err1: |
| 291 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 313 | hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); |
| 292 | if (!hfs_brec_find(&fd, hfs_find_rec_by_key)) | 314 | if (!hfs_brec_find(&fd, hfs_find_rec_by_key)) |
| 293 | hfs_brec_remove(&fd); | 315 | hfs_brec_remove(&fd); |
| 294 | err2: | 316 | err2: |
| @@ -313,7 +335,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
| 313 | if (!str) { | 335 | if (!str) { |
| 314 | int len; | 336 | int len; |
| 315 | 337 | ||
| 316 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 338 | hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); |
| 317 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); | 339 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 318 | if (err) | 340 | if (err) |
| 319 | goto out; | 341 | goto out; |
| @@ -329,7 +351,9 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
| 329 | off + 2, len); | 351 | off + 2, len); |
| 330 | fd.search_key->key_len = cpu_to_be16(6 + len); | 352 | fd.search_key->key_len = cpu_to_be16(6 + len); |
| 331 | } else | 353 | } else |
| 332 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); | 354 | err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); |
| 355 | if (unlikely(err)) | ||
| 356 | goto out; | ||
| 333 | 357 | ||
| 334 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); | 358 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 335 | if (err) | 359 | if (err) |
| @@ -360,7 +384,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
| 360 | if (err) | 384 | if (err) |
| 361 | goto out; | 385 | goto out; |
| 362 | 386 | ||
| 363 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 387 | hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); |
| 364 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); | 388 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 365 | if (err) | 389 | if (err) |
| 366 | goto out; | 390 | goto out; |
| @@ -405,7 +429,11 @@ int hfsplus_rename_cat(u32 cnid, | |||
| 405 | dst_fd = src_fd; | 429 | dst_fd = src_fd; |
| 406 | 430 | ||
| 407 | /* find the old dir entry and read the data */ | 431 | /* find the old dir entry and read the data */ |
| 408 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); | 432 | err = hfsplus_cat_build_key(sb, src_fd.search_key, |
| 433 | src_dir->i_ino, src_name); | ||
| 434 | if (unlikely(err)) | ||
| 435 | goto out; | ||
| 436 | |||
| 409 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); | 437 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); |
| 410 | if (err) | 438 | if (err) |
| 411 | goto out; | 439 | goto out; |
| @@ -419,7 +447,11 @@ int hfsplus_rename_cat(u32 cnid, | |||
| 419 | type = be16_to_cpu(entry.type); | 447 | type = be16_to_cpu(entry.type); |
| 420 | 448 | ||
| 421 | /* create new dir entry with the data from the old entry */ | 449 | /* create new dir entry with the data from the old entry */ |
| 422 | hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name); | 450 | err = hfsplus_cat_build_key(sb, dst_fd.search_key, |
| 451 | dst_dir->i_ino, dst_name); | ||
| 452 | if (unlikely(err)) | ||
| 453 | goto out; | ||
| 454 | |||
| 423 | err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); | 455 | err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); |
| 424 | if (err != -ENOENT) { | 456 | if (err != -ENOENT) { |
| 425 | if (!err) | 457 | if (!err) |
| @@ -436,7 +468,11 @@ int hfsplus_rename_cat(u32 cnid, | |||
| 436 | dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC; | 468 | dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC; |
| 437 | 469 | ||
| 438 | /* finally remove the old entry */ | 470 | /* finally remove the old entry */ |
| 439 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); | 471 | err = hfsplus_cat_build_key(sb, src_fd.search_key, |
| 472 | src_dir->i_ino, src_name); | ||
| 473 | if (unlikely(err)) | ||
| 474 | goto out; | ||
| 475 | |||
| 440 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); | 476 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); |
| 441 | if (err) | 477 | if (err) |
| 442 | goto out; | 478 | goto out; |
| @@ -449,7 +485,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
| 449 | src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC; | 485 | src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC; |
| 450 | 486 | ||
| 451 | /* remove old thread entry */ | 487 | /* remove old thread entry */ |
| 452 | hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); | 488 | hfsplus_cat_build_key_with_cnid(sb, src_fd.search_key, cnid); |
| 453 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); | 489 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); |
| 454 | if (err) | 490 | if (err) |
| 455 | goto out; | 491 | goto out; |
| @@ -459,9 +495,14 @@ int hfsplus_rename_cat(u32 cnid, | |||
| 459 | goto out; | 495 | goto out; |
| 460 | 496 | ||
| 461 | /* create new thread entry */ | 497 | /* create new thread entry */ |
| 462 | hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL); | 498 | hfsplus_cat_build_key_with_cnid(sb, dst_fd.search_key, cnid); |
| 463 | entry_size = hfsplus_fill_cat_thread(sb, &entry, type, | 499 | entry_size = hfsplus_fill_cat_thread(sb, &entry, type, |
| 464 | dst_dir->i_ino, dst_name); | 500 | dst_dir->i_ino, dst_name); |
| 501 | if (unlikely(entry_size < 0)) { | ||
| 502 | err = entry_size; | ||
| 503 | goto out; | ||
| 504 | } | ||
| 505 | |||
| 465 | err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); | 506 | err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); |
| 466 | if (err != -ENOENT) { | 507 | if (err != -ENOENT) { |
| 467 | if (!err) | 508 | if (!err) |
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 610a3260bef1..435bea231cc6 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c | |||
| @@ -44,7 +44,10 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, | |||
| 44 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 44 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
| 45 | if (err) | 45 | if (err) |
| 46 | return ERR_PTR(err); | 46 | return ERR_PTR(err); |
| 47 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); | 47 | err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, |
| 48 | &dentry->d_name); | ||
| 49 | if (unlikely(err < 0)) | ||
| 50 | goto fail; | ||
| 48 | again: | 51 | again: |
| 49 | err = hfs_brec_read(&fd, &entry, sizeof(entry)); | 52 | err = hfs_brec_read(&fd, &entry, sizeof(entry)); |
| 50 | if (err) { | 53 | if (err) { |
| @@ -97,9 +100,11 @@ again: | |||
| 97 | be32_to_cpu(entry.file.permissions.dev); | 100 | be32_to_cpu(entry.file.permissions.dev); |
| 98 | str.len = sprintf(name, "iNode%d", linkid); | 101 | str.len = sprintf(name, "iNode%d", linkid); |
| 99 | str.name = name; | 102 | str.name = name; |
| 100 | hfsplus_cat_build_key(sb, fd.search_key, | 103 | err = hfsplus_cat_build_key(sb, fd.search_key, |
| 101 | HFSPLUS_SB(sb)->hidden_dir->i_ino, | 104 | HFSPLUS_SB(sb)->hidden_dir->i_ino, |
| 102 | &str); | 105 | &str); |
| 106 | if (unlikely(err < 0)) | ||
| 107 | goto fail; | ||
| 103 | goto again; | 108 | goto again; |
| 104 | } | 109 | } |
| 105 | } else if (!dentry->d_fsdata) | 110 | } else if (!dentry->d_fsdata) |
| @@ -145,7 +150,7 @@ static int hfsplus_readdir(struct file *file, struct dir_context *ctx) | |||
| 145 | err = -ENOMEM; | 150 | err = -ENOMEM; |
| 146 | goto out; | 151 | goto out; |
| 147 | } | 152 | } |
| 148 | hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); | 153 | hfsplus_cat_build_key_with_cnid(sb, fd.search_key, inode->i_ino); |
| 149 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); | 154 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 150 | if (err) | 155 | if (err) |
| 151 | goto out; | 156 | goto out; |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index eb5e059f481a..b0441d65fa54 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
| @@ -443,8 +443,10 @@ int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1, | |||
| 443 | const hfsplus_btree_key *k2); | 443 | const hfsplus_btree_key *k2); |
| 444 | int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, | 444 | int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, |
| 445 | const hfsplus_btree_key *k2); | 445 | const hfsplus_btree_key *k2); |
| 446 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, | 446 | int hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, |
| 447 | u32 parent, struct qstr *str); | 447 | u32 parent, struct qstr *str); |
| 448 | void hfsplus_cat_build_key_with_cnid(struct super_block *sb, | ||
| 449 | hfsplus_btree_key *key, u32 parent); | ||
| 448 | void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms); | 450 | void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms); |
| 449 | int hfsplus_find_cat(struct super_block *sb, u32 cnid, | 451 | int hfsplus_find_cat(struct super_block *sb, u32 cnid, |
| 450 | struct hfs_find_data *fd); | 452 | struct hfs_find_data *fd); |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 4cf2024b87da..593af2fdcc2d 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
| @@ -515,7 +515,9 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
| 515 | err = hfs_find_init(sbi->cat_tree, &fd); | 515 | err = hfs_find_init(sbi->cat_tree, &fd); |
| 516 | if (err) | 516 | if (err) |
| 517 | goto out_put_root; | 517 | goto out_put_root; |
| 518 | hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); | 518 | err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); |
| 519 | if (unlikely(err < 0)) | ||
| 520 | goto out_put_root; | ||
| 519 | if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { | 521 | if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { |
| 520 | hfs_find_exit(&fd); | 522 | hfs_find_exit(&fd); |
| 521 | if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) | 523 | if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) |
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index a93bf9892256..fcae9ef1a328 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
| @@ -5662,7 +5662,7 @@ int ocfs2_remove_btree_range(struct inode *inode, | |||
| 5662 | struct ocfs2_extent_tree *et, | 5662 | struct ocfs2_extent_tree *et, |
| 5663 | u32 cpos, u32 phys_cpos, u32 len, int flags, | 5663 | u32 cpos, u32 phys_cpos, u32 len, int flags, |
| 5664 | struct ocfs2_cached_dealloc_ctxt *dealloc, | 5664 | struct ocfs2_cached_dealloc_ctxt *dealloc, |
| 5665 | u64 refcount_loc) | 5665 | u64 refcount_loc, bool refcount_tree_locked) |
| 5666 | { | 5666 | { |
| 5667 | int ret, credits = 0, extra_blocks = 0; | 5667 | int ret, credits = 0, extra_blocks = 0; |
| 5668 | u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); | 5668 | u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); |
| @@ -5676,11 +5676,13 @@ int ocfs2_remove_btree_range(struct inode *inode, | |||
| 5676 | BUG_ON(!(OCFS2_I(inode)->ip_dyn_features & | 5676 | BUG_ON(!(OCFS2_I(inode)->ip_dyn_features & |
| 5677 | OCFS2_HAS_REFCOUNT_FL)); | 5677 | OCFS2_HAS_REFCOUNT_FL)); |
| 5678 | 5678 | ||
| 5679 | ret = ocfs2_lock_refcount_tree(osb, refcount_loc, 1, | 5679 | if (!refcount_tree_locked) { |
| 5680 | &ref_tree, NULL); | 5680 | ret = ocfs2_lock_refcount_tree(osb, refcount_loc, 1, |
| 5681 | if (ret) { | 5681 | &ref_tree, NULL); |
| 5682 | mlog_errno(ret); | 5682 | if (ret) { |
| 5683 | goto bail; | 5683 | mlog_errno(ret); |
| 5684 | goto bail; | ||
| 5685 | } | ||
| 5684 | } | 5686 | } |
| 5685 | 5687 | ||
| 5686 | ret = ocfs2_prepare_refcount_change_for_del(inode, | 5688 | ret = ocfs2_prepare_refcount_change_for_del(inode, |
| @@ -7021,6 +7023,7 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb, | |||
| 7021 | u64 refcount_loc = le64_to_cpu(di->i_refcount_loc); | 7023 | u64 refcount_loc = le64_to_cpu(di->i_refcount_loc); |
| 7022 | struct ocfs2_extent_tree et; | 7024 | struct ocfs2_extent_tree et; |
| 7023 | struct ocfs2_cached_dealloc_ctxt dealloc; | 7025 | struct ocfs2_cached_dealloc_ctxt dealloc; |
| 7026 | struct ocfs2_refcount_tree *ref_tree = NULL; | ||
| 7024 | 7027 | ||
| 7025 | ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh); | 7028 | ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh); |
| 7026 | ocfs2_init_dealloc_ctxt(&dealloc); | 7029 | ocfs2_init_dealloc_ctxt(&dealloc); |
| @@ -7130,9 +7133,18 @@ start: | |||
| 7130 | 7133 | ||
| 7131 | phys_cpos = ocfs2_blocks_to_clusters(inode->i_sb, blkno); | 7134 | phys_cpos = ocfs2_blocks_to_clusters(inode->i_sb, blkno); |
| 7132 | 7135 | ||
| 7136 | if ((flags & OCFS2_EXT_REFCOUNTED) && trunc_len && !ref_tree) { | ||
| 7137 | status = ocfs2_lock_refcount_tree(osb, refcount_loc, 1, | ||
| 7138 | &ref_tree, NULL); | ||
| 7139 | if (status) { | ||
| 7140 | mlog_errno(status); | ||
| 7141 | goto bail; | ||
| 7142 | } | ||
| 7143 | } | ||
| 7144 | |||
| 7133 | status = ocfs2_remove_btree_range(inode, &et, trunc_cpos, | 7145 | status = ocfs2_remove_btree_range(inode, &et, trunc_cpos, |
| 7134 | phys_cpos, trunc_len, flags, &dealloc, | 7146 | phys_cpos, trunc_len, flags, &dealloc, |
| 7135 | refcount_loc); | 7147 | refcount_loc, true); |
| 7136 | if (status < 0) { | 7148 | if (status < 0) { |
| 7137 | mlog_errno(status); | 7149 | mlog_errno(status); |
| 7138 | goto bail; | 7150 | goto bail; |
| @@ -7147,6 +7159,8 @@ start: | |||
| 7147 | goto start; | 7159 | goto start; |
| 7148 | 7160 | ||
| 7149 | bail: | 7161 | bail: |
| 7162 | if (ref_tree) | ||
| 7163 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); | ||
| 7150 | 7164 | ||
| 7151 | ocfs2_schedule_truncate_log_flush(osb, 1); | 7165 | ocfs2_schedule_truncate_log_flush(osb, 1); |
| 7152 | 7166 | ||
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h index ca381c584127..fb09b97db162 100644 --- a/fs/ocfs2/alloc.h +++ b/fs/ocfs2/alloc.h | |||
| @@ -142,7 +142,7 @@ int ocfs2_remove_btree_range(struct inode *inode, | |||
| 142 | struct ocfs2_extent_tree *et, | 142 | struct ocfs2_extent_tree *et, |
| 143 | u32 cpos, u32 phys_cpos, u32 len, int flags, | 143 | u32 cpos, u32 phys_cpos, u32 len, int flags, |
| 144 | struct ocfs2_cached_dealloc_ctxt *dealloc, | 144 | struct ocfs2_cached_dealloc_ctxt *dealloc, |
| 145 | u64 refcount_loc); | 145 | u64 refcount_loc, bool refcount_tree_locked); |
| 146 | 146 | ||
| 147 | int ocfs2_num_free_extents(struct ocfs2_super *osb, | 147 | int ocfs2_num_free_extents(struct ocfs2_super *osb, |
| 148 | struct ocfs2_extent_tree *et); | 148 | struct ocfs2_extent_tree *et); |
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index d9f222987f24..46d93e941f3d 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
| @@ -894,7 +894,7 @@ void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages) | |||
| 894 | } | 894 | } |
| 895 | } | 895 | } |
| 896 | 896 | ||
| 897 | static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) | 897 | static void ocfs2_unlock_pages(struct ocfs2_write_ctxt *wc) |
| 898 | { | 898 | { |
| 899 | int i; | 899 | int i; |
| 900 | 900 | ||
| @@ -915,7 +915,11 @@ static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) | |||
| 915 | page_cache_release(wc->w_target_page); | 915 | page_cache_release(wc->w_target_page); |
| 916 | } | 916 | } |
| 917 | ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages); | 917 | ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages); |
| 918 | } | ||
| 918 | 919 | ||
| 920 | static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) | ||
| 921 | { | ||
| 922 | ocfs2_unlock_pages(wc); | ||
| 919 | brelse(wc->w_di_bh); | 923 | brelse(wc->w_di_bh); |
| 920 | kfree(wc); | 924 | kfree(wc); |
| 921 | } | 925 | } |
| @@ -2042,11 +2046,19 @@ out_write_size: | |||
| 2042 | ocfs2_update_inode_fsync_trans(handle, inode, 1); | 2046 | ocfs2_update_inode_fsync_trans(handle, inode, 1); |
| 2043 | ocfs2_journal_dirty(handle, wc->w_di_bh); | 2047 | ocfs2_journal_dirty(handle, wc->w_di_bh); |
| 2044 | 2048 | ||
| 2049 | /* unlock pages before dealloc since it needs acquiring j_trans_barrier | ||
| 2050 | * lock, or it will cause a deadlock since journal commit threads holds | ||
| 2051 | * this lock and will ask for the page lock when flushing the data. | ||
| 2052 | * put it here to preserve the unlock order. | ||
| 2053 | */ | ||
| 2054 | ocfs2_unlock_pages(wc); | ||
| 2055 | |||
| 2045 | ocfs2_commit_trans(osb, handle); | 2056 | ocfs2_commit_trans(osb, handle); |
| 2046 | 2057 | ||
| 2047 | ocfs2_run_deallocs(osb, &wc->w_dealloc); | 2058 | ocfs2_run_deallocs(osb, &wc->w_dealloc); |
| 2048 | 2059 | ||
| 2049 | ocfs2_free_write_ctxt(wc); | 2060 | brelse(wc->w_di_bh); |
| 2061 | kfree(wc); | ||
| 2050 | 2062 | ||
| 2051 | return copied; | 2063 | return copied; |
| 2052 | } | 2064 | } |
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 79d56dc981bc..319e786175af 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
| @@ -4479,7 +4479,7 @@ int ocfs2_dx_dir_truncate(struct inode *dir, struct buffer_head *di_bh) | |||
| 4479 | p_cpos = ocfs2_blocks_to_clusters(dir->i_sb, blkno); | 4479 | p_cpos = ocfs2_blocks_to_clusters(dir->i_sb, blkno); |
| 4480 | 4480 | ||
| 4481 | ret = ocfs2_remove_btree_range(dir, &et, cpos, p_cpos, clen, 0, | 4481 | ret = ocfs2_remove_btree_range(dir, &et, cpos, p_cpos, clen, 0, |
| 4482 | &dealloc, 0); | 4482 | &dealloc, 0, false); |
| 4483 | if (ret) { | 4483 | if (ret) { |
| 4484 | mlog_errno(ret); | 4484 | mlog_errno(ret); |
| 4485 | goto out; | 4485 | goto out; |
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 3689b3592042..a6944b25fd5b 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c | |||
| @@ -695,14 +695,6 @@ void __dlm_lockres_grab_inflight_worker(struct dlm_ctxt *dlm, | |||
| 695 | res->inflight_assert_workers); | 695 | res->inflight_assert_workers); |
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | static void dlm_lockres_grab_inflight_worker(struct dlm_ctxt *dlm, | ||
| 699 | struct dlm_lock_resource *res) | ||
| 700 | { | ||
| 701 | spin_lock(&res->spinlock); | ||
| 702 | __dlm_lockres_grab_inflight_worker(dlm, res); | ||
| 703 | spin_unlock(&res->spinlock); | ||
| 704 | } | ||
| 705 | |||
| 706 | static void __dlm_lockres_drop_inflight_worker(struct dlm_ctxt *dlm, | 698 | static void __dlm_lockres_drop_inflight_worker(struct dlm_ctxt *dlm, |
| 707 | struct dlm_lock_resource *res) | 699 | struct dlm_lock_resource *res) |
| 708 | { | 700 | { |
| @@ -1646,6 +1638,7 @@ send_response: | |||
| 1646 | } | 1638 | } |
| 1647 | mlog(0, "%u is the owner of %.*s, cleaning everyone else\n", | 1639 | mlog(0, "%u is the owner of %.*s, cleaning everyone else\n", |
| 1648 | dlm->node_num, res->lockname.len, res->lockname.name); | 1640 | dlm->node_num, res->lockname.len, res->lockname.name); |
| 1641 | spin_lock(&res->spinlock); | ||
| 1649 | ret = dlm_dispatch_assert_master(dlm, res, 0, request->node_idx, | 1642 | ret = dlm_dispatch_assert_master(dlm, res, 0, request->node_idx, |
| 1650 | DLM_ASSERT_MASTER_MLE_CLEANUP); | 1643 | DLM_ASSERT_MASTER_MLE_CLEANUP); |
| 1651 | if (ret < 0) { | 1644 | if (ret < 0) { |
| @@ -1653,7 +1646,8 @@ send_response: | |||
| 1653 | response = DLM_MASTER_RESP_ERROR; | 1646 | response = DLM_MASTER_RESP_ERROR; |
| 1654 | dlm_lockres_put(res); | 1647 | dlm_lockres_put(res); |
| 1655 | } else | 1648 | } else |
| 1656 | dlm_lockres_grab_inflight_worker(dlm, res); | 1649 | __dlm_lockres_grab_inflight_worker(dlm, res); |
| 1650 | spin_unlock(&res->spinlock); | ||
| 1657 | } else { | 1651 | } else { |
| 1658 | if (res) | 1652 | if (res) |
| 1659 | dlm_lockres_put(res); | 1653 | dlm_lockres_put(res); |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 69fb9f75b082..3950693dd0f6 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
| @@ -1803,7 +1803,7 @@ static int ocfs2_remove_inode_range(struct inode *inode, | |||
| 1803 | 1803 | ||
| 1804 | ret = ocfs2_remove_btree_range(inode, &et, trunc_cpos, | 1804 | ret = ocfs2_remove_btree_range(inode, &et, trunc_cpos, |
| 1805 | phys_cpos, trunc_len, flags, | 1805 | phys_cpos, trunc_len, flags, |
| 1806 | &dealloc, refcount_loc); | 1806 | &dealloc, refcount_loc, false); |
| 1807 | if (ret < 0) { | 1807 | if (ret < 0) { |
| 1808 | mlog_errno(ret); | 1808 | mlog_errno(ret); |
| 1809 | goto out; | 1809 | goto out; |
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index aa1eee06420f..d3ebf2e61853 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c | |||
| @@ -12,6 +12,9 @@ | |||
| 12 | #include <linux/vmstat.h> | 12 | #include <linux/vmstat.h> |
| 13 | #include <linux/atomic.h> | 13 | #include <linux/atomic.h> |
| 14 | #include <linux/vmalloc.h> | 14 | #include <linux/vmalloc.h> |
| 15 | #ifdef CONFIG_CMA | ||
| 16 | #include <linux/cma.h> | ||
| 17 | #endif | ||
| 15 | #include <asm/page.h> | 18 | #include <asm/page.h> |
| 16 | #include <asm/pgtable.h> | 19 | #include <asm/pgtable.h> |
| 17 | #include "internal.h" | 20 | #include "internal.h" |
| @@ -138,6 +141,10 @@ static int meminfo_proc_show(struct seq_file *m, void *v) | |||
| 138 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 141 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
| 139 | "AnonHugePages: %8lu kB\n" | 142 | "AnonHugePages: %8lu kB\n" |
| 140 | #endif | 143 | #endif |
| 144 | #ifdef CONFIG_CMA | ||
| 145 | "CmaTotal: %8lu kB\n" | ||
| 146 | "CmaFree: %8lu kB\n" | ||
| 147 | #endif | ||
| 141 | , | 148 | , |
| 142 | K(i.totalram), | 149 | K(i.totalram), |
| 143 | K(i.freeram), | 150 | K(i.freeram), |
| @@ -187,12 +194,16 @@ static int meminfo_proc_show(struct seq_file *m, void *v) | |||
| 187 | vmi.used >> 10, | 194 | vmi.used >> 10, |
| 188 | vmi.largest_chunk >> 10 | 195 | vmi.largest_chunk >> 10 |
| 189 | #ifdef CONFIG_MEMORY_FAILURE | 196 | #ifdef CONFIG_MEMORY_FAILURE |
| 190 | ,atomic_long_read(&num_poisoned_pages) << (PAGE_SHIFT - 10) | 197 | , atomic_long_read(&num_poisoned_pages) << (PAGE_SHIFT - 10) |
| 191 | #endif | 198 | #endif |
| 192 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 199 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
| 193 | ,K(global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) * | 200 | , K(global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) * |
| 194 | HPAGE_PMD_NR) | 201 | HPAGE_PMD_NR) |
| 195 | #endif | 202 | #endif |
| 203 | #ifdef CONFIG_CMA | ||
| 204 | , K(totalcma_pages) | ||
| 205 | , K(global_page_state(NR_FREE_CMA_PAGES)) | ||
| 206 | #endif | ||
| 196 | ); | 207 | ); |
| 197 | 208 | ||
| 198 | hugetlb_report_meminfo(m); | 209 | hugetlb_report_meminfo(m); |
diff --git a/include/linux/cma.h b/include/linux/cma.h index a93438beb33c..9384ba66e975 100644 --- a/include/linux/cma.h +++ b/include/linux/cma.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | struct cma; | 16 | struct cma; |
| 17 | 17 | ||
| 18 | extern unsigned long totalcma_pages; | ||
| 18 | extern phys_addr_t cma_get_base(struct cma *cma); | 19 | extern phys_addr_t cma_get_base(struct cma *cma); |
| 19 | extern unsigned long cma_get_size(struct cma *cma); | 20 | extern unsigned long cma_get_size(struct cma *cma); |
| 20 | 21 | ||
diff --git a/lib/show_mem.c b/lib/show_mem.c index 5e256271b47b..7de89f4a36cf 100644 --- a/lib/show_mem.c +++ b/lib/show_mem.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/mm.h> | 8 | #include <linux/mm.h> |
| 9 | #include <linux/nmi.h> | 9 | #include <linux/nmi.h> |
| 10 | #include <linux/quicklist.h> | 10 | #include <linux/quicklist.h> |
| 11 | #include <linux/cma.h> | ||
| 11 | 12 | ||
| 12 | void show_mem(unsigned int filter) | 13 | void show_mem(unsigned int filter) |
| 13 | { | 14 | { |
| @@ -38,7 +39,12 @@ void show_mem(unsigned int filter) | |||
| 38 | 39 | ||
| 39 | printk("%lu pages RAM\n", total); | 40 | printk("%lu pages RAM\n", total); |
| 40 | printk("%lu pages HighMem/MovableOnly\n", highmem); | 41 | printk("%lu pages HighMem/MovableOnly\n", highmem); |
| 42 | #ifdef CONFIG_CMA | ||
| 43 | printk("%lu pages reserved\n", (reserved - totalcma_pages)); | ||
| 44 | printk("%lu pages cma reserved\n", totalcma_pages); | ||
| 45 | #else | ||
| 41 | printk("%lu pages reserved\n", reserved); | 46 | printk("%lu pages reserved\n", reserved); |
| 47 | #endif | ||
| 42 | #ifdef CONFIG_QUICKLIST | 48 | #ifdef CONFIG_QUICKLIST |
| 43 | printk("%lu pages in pagetable cache\n", | 49 | printk("%lu pages in pagetable cache\n", |
| 44 | quicklist_total_size()); | 50 | quicklist_total_size()); |
| @@ -337,6 +337,7 @@ int __init cma_declare_contiguous(phys_addr_t base, | |||
| 337 | if (ret) | 337 | if (ret) |
| 338 | goto err; | 338 | goto err; |
| 339 | 339 | ||
| 340 | totalcma_pages += (size / PAGE_SIZE); | ||
| 340 | pr_info("Reserved %ld MiB at %pa\n", (unsigned long)size / SZ_1M, | 341 | pr_info("Reserved %ld MiB at %pa\n", (unsigned long)size / SZ_1M, |
| 341 | &base); | 342 | &base); |
| 342 | return 0; | 343 | return 0; |
diff --git a/mm/memory.c b/mm/memory.c index 6efe36a998ba..d8aebc52265f 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
| @@ -2996,6 +2996,12 @@ static int do_shared_fault(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 2996 | 2996 | ||
| 2997 | if (set_page_dirty(fault_page)) | 2997 | if (set_page_dirty(fault_page)) |
| 2998 | dirtied = 1; | 2998 | dirtied = 1; |
| 2999 | /* | ||
| 3000 | * Take a local copy of the address_space - page.mapping may be zeroed | ||
| 3001 | * by truncate after unlock_page(). The address_space itself remains | ||
| 3002 | * pinned by vma->vm_file's reference. We rely on unlock_page()'s | ||
| 3003 | * release semantics to prevent the compiler from undoing this copying. | ||
| 3004 | */ | ||
| 2999 | mapping = fault_page->mapping; | 3005 | mapping = fault_page->mapping; |
| 3000 | unlock_page(fault_page); | 3006 | unlock_page(fault_page); |
| 3001 | if ((dirtied || vma->vm_ops->page_mkwrite) && mapping) { | 3007 | if ((dirtied || vma->vm_ops->page_mkwrite) && mapping) { |
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index e58725aff7e9..f22c55947181 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
| @@ -162,12 +162,6 @@ static const struct mempolicy_operations { | |||
| 162 | enum mpol_rebind_step step); | 162 | enum mpol_rebind_step step); |
| 163 | } mpol_ops[MPOL_MAX]; | 163 | } mpol_ops[MPOL_MAX]; |
| 164 | 164 | ||
| 165 | /* Check that the nodemask contains at least one populated zone */ | ||
| 166 | static int is_valid_nodemask(const nodemask_t *nodemask) | ||
| 167 | { | ||
| 168 | return nodes_intersects(*nodemask, node_states[N_MEMORY]); | ||
| 169 | } | ||
| 170 | |||
| 171 | static inline int mpol_store_user_nodemask(const struct mempolicy *pol) | 165 | static inline int mpol_store_user_nodemask(const struct mempolicy *pol) |
| 172 | { | 166 | { |
| 173 | return pol->flags & MPOL_MODE_FLAGS; | 167 | return pol->flags & MPOL_MODE_FLAGS; |
| @@ -202,7 +196,7 @@ static int mpol_new_preferred(struct mempolicy *pol, const nodemask_t *nodes) | |||
| 202 | 196 | ||
| 203 | static int mpol_new_bind(struct mempolicy *pol, const nodemask_t *nodes) | 197 | static int mpol_new_bind(struct mempolicy *pol, const nodemask_t *nodes) |
| 204 | { | 198 | { |
| 205 | if (!is_valid_nodemask(nodes)) | 199 | if (nodes_empty(*nodes)) |
| 206 | return -EINVAL; | 200 | return -EINVAL; |
| 207 | pol->v.nodes = *nodes; | 201 | pol->v.nodes = *nodes; |
| 208 | return 0; | 202 | return 0; |
| @@ -234,7 +228,7 @@ static int mpol_set_nodemask(struct mempolicy *pol, | |||
| 234 | nodes = NULL; /* explicit local allocation */ | 228 | nodes = NULL; /* explicit local allocation */ |
| 235 | else { | 229 | else { |
| 236 | if (pol->flags & MPOL_F_RELATIVE_NODES) | 230 | if (pol->flags & MPOL_F_RELATIVE_NODES) |
| 237 | mpol_relative_nodemask(&nsc->mask2, nodes,&nsc->mask1); | 231 | mpol_relative_nodemask(&nsc->mask2, nodes, &nsc->mask1); |
| 238 | else | 232 | else |
| 239 | nodes_and(nsc->mask2, *nodes, nsc->mask1); | 233 | nodes_and(nsc->mask2, *nodes, nsc->mask1); |
| 240 | 234 | ||
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index fa974d87f60d..7633c503a116 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
| @@ -111,6 +111,7 @@ static DEFINE_SPINLOCK(managed_page_count_lock); | |||
| 111 | 111 | ||
| 112 | unsigned long totalram_pages __read_mostly; | 112 | unsigned long totalram_pages __read_mostly; |
| 113 | unsigned long totalreserve_pages __read_mostly; | 113 | unsigned long totalreserve_pages __read_mostly; |
| 114 | unsigned long totalcma_pages __read_mostly; | ||
| 114 | /* | 115 | /* |
| 115 | * When calculating the number of globally allowed dirty pages, there | 116 | * When calculating the number of globally allowed dirty pages, there |
| 116 | * is a certain number of per-zone reserves that should not be | 117 | * is a certain number of per-zone reserves that should not be |
| @@ -5586,7 +5587,7 @@ void __init mem_init_print_info(const char *str) | |||
| 5586 | 5587 | ||
| 5587 | pr_info("Memory: %luK/%luK available " | 5588 | pr_info("Memory: %luK/%luK available " |
| 5588 | "(%luK kernel code, %luK rwdata, %luK rodata, " | 5589 | "(%luK kernel code, %luK rwdata, %luK rodata, " |
| 5589 | "%luK init, %luK bss, %luK reserved" | 5590 | "%luK init, %luK bss, %luK reserved, %luK cma-reserved" |
| 5590 | #ifdef CONFIG_HIGHMEM | 5591 | #ifdef CONFIG_HIGHMEM |
| 5591 | ", %luK highmem" | 5592 | ", %luK highmem" |
| 5592 | #endif | 5593 | #endif |
| @@ -5594,7 +5595,8 @@ void __init mem_init_print_info(const char *str) | |||
| 5594 | nr_free_pages() << (PAGE_SHIFT-10), physpages << (PAGE_SHIFT-10), | 5595 | nr_free_pages() << (PAGE_SHIFT-10), physpages << (PAGE_SHIFT-10), |
| 5595 | codesize >> 10, datasize >> 10, rosize >> 10, | 5596 | codesize >> 10, datasize >> 10, rosize >> 10, |
| 5596 | (init_data_size + init_code_size) >> 10, bss_size >> 10, | 5597 | (init_data_size + init_code_size) >> 10, bss_size >> 10, |
| 5597 | (physpages - totalram_pages) << (PAGE_SHIFT-10), | 5598 | (physpages - totalram_pages - totalcma_pages) << (PAGE_SHIFT-10), |
| 5599 | totalcma_pages << (PAGE_SHIFT-10), | ||
| 5598 | #ifdef CONFIG_HIGHMEM | 5600 | #ifdef CONFIG_HIGHMEM |
| 5599 | totalhigh_pages << (PAGE_SHIFT-10), | 5601 | totalhigh_pages << (PAGE_SHIFT-10), |
| 5600 | #endif | 5602 | #endif |
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 4d0a063145ec..b72403927aa4 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c | |||
| @@ -884,19 +884,6 @@ static struct notifier_block zs_cpu_nb = { | |||
| 884 | .notifier_call = zs_cpu_notifier | 884 | .notifier_call = zs_cpu_notifier |
| 885 | }; | 885 | }; |
| 886 | 886 | ||
| 887 | static void zs_unregister_cpu_notifier(void) | ||
| 888 | { | ||
| 889 | int cpu; | ||
| 890 | |||
| 891 | cpu_notifier_register_begin(); | ||
| 892 | |||
| 893 | for_each_online_cpu(cpu) | ||
| 894 | zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu); | ||
| 895 | __unregister_cpu_notifier(&zs_cpu_nb); | ||
| 896 | |||
| 897 | cpu_notifier_register_done(); | ||
| 898 | } | ||
| 899 | |||
| 900 | static int zs_register_cpu_notifier(void) | 887 | static int zs_register_cpu_notifier(void) |
| 901 | { | 888 | { |
| 902 | int cpu, uninitialized_var(ret); | 889 | int cpu, uninitialized_var(ret); |
| @@ -914,40 +901,28 @@ static int zs_register_cpu_notifier(void) | |||
| 914 | return notifier_to_errno(ret); | 901 | return notifier_to_errno(ret); |
| 915 | } | 902 | } |
| 916 | 903 | ||
| 917 | static void init_zs_size_classes(void) | 904 | static void zs_unregister_cpu_notifier(void) |
| 918 | { | 905 | { |
| 919 | int nr; | 906 | int cpu; |
| 920 | 907 | ||
| 921 | nr = (ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / ZS_SIZE_CLASS_DELTA + 1; | 908 | cpu_notifier_register_begin(); |
| 922 | if ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) % ZS_SIZE_CLASS_DELTA) | ||
| 923 | nr += 1; | ||
| 924 | 909 | ||
| 925 | zs_size_classes = nr; | 910 | for_each_online_cpu(cpu) |
| 926 | } | 911 | zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu); |
| 912 | __unregister_cpu_notifier(&zs_cpu_nb); | ||
| 927 | 913 | ||
| 928 | static void __exit zs_exit(void) | 914 | cpu_notifier_register_done(); |
| 929 | { | ||
| 930 | #ifdef CONFIG_ZPOOL | ||
| 931 | zpool_unregister_driver(&zs_zpool_driver); | ||
| 932 | #endif | ||
| 933 | zs_unregister_cpu_notifier(); | ||
| 934 | } | 915 | } |
| 935 | 916 | ||
| 936 | static int __init zs_init(void) | 917 | static void init_zs_size_classes(void) |
| 937 | { | 918 | { |
| 938 | int ret = zs_register_cpu_notifier(); | 919 | int nr; |
| 939 | |||
| 940 | if (ret) { | ||
| 941 | zs_unregister_cpu_notifier(); | ||
| 942 | return ret; | ||
| 943 | } | ||
| 944 | 920 | ||
| 945 | init_zs_size_classes(); | 921 | nr = (ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / ZS_SIZE_CLASS_DELTA + 1; |
| 922 | if ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) % ZS_SIZE_CLASS_DELTA) | ||
| 923 | nr += 1; | ||
| 946 | 924 | ||
| 947 | #ifdef CONFIG_ZPOOL | 925 | zs_size_classes = nr; |
| 948 | zpool_register_driver(&zs_zpool_driver); | ||
| 949 | #endif | ||
| 950 | return 0; | ||
| 951 | } | 926 | } |
| 952 | 927 | ||
| 953 | static unsigned int get_maxobj_per_zspage(int size, int pages_per_zspage) | 928 | static unsigned int get_maxobj_per_zspage(int size, int pages_per_zspage) |
| @@ -967,113 +942,101 @@ static bool can_merge(struct size_class *prev, int size, int pages_per_zspage) | |||
| 967 | return true; | 942 | return true; |
| 968 | } | 943 | } |
| 969 | 944 | ||
| 945 | unsigned long zs_get_total_pages(struct zs_pool *pool) | ||
| 946 | { | ||
| 947 | return atomic_long_read(&pool->pages_allocated); | ||
| 948 | } | ||
| 949 | EXPORT_SYMBOL_GPL(zs_get_total_pages); | ||
| 950 | |||
| 970 | /** | 951 | /** |
| 971 | * zs_create_pool - Creates an allocation pool to work from. | 952 | * zs_map_object - get address of allocated object from handle. |
| 972 | * @flags: allocation flags used to allocate pool metadata | 953 | * @pool: pool from which the object was allocated |
| 954 | * @handle: handle returned from zs_malloc | ||
| 973 | * | 955 | * |
| 974 | * This function must be called before anything when using | 956 | * Before using an object allocated from zs_malloc, it must be mapped using |
| 975 | * the zsmalloc allocator. | 957 | * this function. When done with the object, it must be unmapped using |
| 958 | * zs_unmap_object. | ||
| 976 | * | 959 | * |
| 977 | * On success, a pointer to the newly created pool is returned, | 960 | * Only one object can be mapped per cpu at a time. There is no protection |
| 978 | * otherwise NULL. | 961 | * against nested mappings. |
| 962 | * | ||
| 963 | * This function returns with preemption and page faults disabled. | ||
| 979 | */ | 964 | */ |
| 980 | struct zs_pool *zs_create_pool(gfp_t flags) | 965 | void *zs_map_object(struct zs_pool *pool, unsigned long handle, |
| 966 | enum zs_mapmode mm) | ||
| 981 | { | 967 | { |
| 982 | int i; | 968 | struct page *page; |
| 983 | struct zs_pool *pool; | 969 | unsigned long obj_idx, off; |
| 984 | struct size_class *prev_class = NULL; | ||
| 985 | 970 | ||
| 986 | pool = kzalloc(sizeof(*pool), GFP_KERNEL); | 971 | unsigned int class_idx; |
| 987 | if (!pool) | 972 | enum fullness_group fg; |
| 988 | return NULL; | 973 | struct size_class *class; |
| 974 | struct mapping_area *area; | ||
| 975 | struct page *pages[2]; | ||
| 989 | 976 | ||
| 990 | pool->size_class = kcalloc(zs_size_classes, sizeof(struct size_class *), | 977 | BUG_ON(!handle); |
| 991 | GFP_KERNEL); | ||
| 992 | if (!pool->size_class) { | ||
| 993 | kfree(pool); | ||
| 994 | return NULL; | ||
| 995 | } | ||
| 996 | 978 | ||
| 997 | /* | 979 | /* |
| 998 | * Iterate reversly, because, size of size_class that we want to use | 980 | * Because we use per-cpu mapping areas shared among the |
| 999 | * for merging should be larger or equal to current size. | 981 | * pools/users, we can't allow mapping in interrupt context |
| 982 | * because it can corrupt another users mappings. | ||
| 1000 | */ | 983 | */ |
| 1001 | for (i = zs_size_classes - 1; i >= 0; i--) { | 984 | BUG_ON(in_interrupt()); |
| 1002 | int size; | ||
| 1003 | int pages_per_zspage; | ||
| 1004 | struct size_class *class; | ||
| 1005 | |||
| 1006 | size = ZS_MIN_ALLOC_SIZE + i * ZS_SIZE_CLASS_DELTA; | ||
| 1007 | if (size > ZS_MAX_ALLOC_SIZE) | ||
| 1008 | size = ZS_MAX_ALLOC_SIZE; | ||
| 1009 | pages_per_zspage = get_pages_per_zspage(size); | ||
| 1010 | |||
| 1011 | /* | ||
| 1012 | * size_class is used for normal zsmalloc operation such | ||
| 1013 | * as alloc/free for that size. Although it is natural that we | ||
| 1014 | * have one size_class for each size, there is a chance that we | ||
| 1015 | * can get more memory utilization if we use one size_class for | ||
| 1016 | * many different sizes whose size_class have same | ||
| 1017 | * characteristics. So, we makes size_class point to | ||
| 1018 | * previous size_class if possible. | ||
| 1019 | */ | ||
| 1020 | if (prev_class) { | ||
| 1021 | if (can_merge(prev_class, size, pages_per_zspage)) { | ||
| 1022 | pool->size_class[i] = prev_class; | ||
| 1023 | continue; | ||
| 1024 | } | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | class = kzalloc(sizeof(struct size_class), GFP_KERNEL); | ||
| 1028 | if (!class) | ||
| 1029 | goto err; | ||
| 1030 | 985 | ||
| 1031 | class->size = size; | 986 | obj_handle_to_location(handle, &page, &obj_idx); |
| 1032 | class->index = i; | 987 | get_zspage_mapping(get_first_page(page), &class_idx, &fg); |
| 1033 | class->pages_per_zspage = pages_per_zspage; | 988 | class = pool->size_class[class_idx]; |
| 1034 | spin_lock_init(&class->lock); | 989 | off = obj_idx_to_offset(page, obj_idx, class->size); |
| 1035 | pool->size_class[i] = class; | ||
| 1036 | 990 | ||
| 1037 | prev_class = class; | 991 | area = &get_cpu_var(zs_map_area); |
| 992 | area->vm_mm = mm; | ||
| 993 | if (off + class->size <= PAGE_SIZE) { | ||
| 994 | /* this object is contained entirely within a page */ | ||
| 995 | area->vm_addr = kmap_atomic(page); | ||
| 996 | return area->vm_addr + off; | ||
| 1038 | } | 997 | } |
| 1039 | 998 | ||
| 1040 | pool->flags = flags; | 999 | /* this object spans two pages */ |
| 1041 | 1000 | pages[0] = page; | |
| 1042 | return pool; | 1001 | pages[1] = get_next_page(page); |
| 1002 | BUG_ON(!pages[1]); | ||
| 1043 | 1003 | ||
| 1044 | err: | 1004 | return __zs_map_object(area, pages, off, class->size); |
| 1045 | zs_destroy_pool(pool); | ||
| 1046 | return NULL; | ||
| 1047 | } | 1005 | } |
| 1048 | EXPORT_SYMBOL_GPL(zs_create_pool); | 1006 | EXPORT_SYMBOL_GPL(zs_map_object); |
| 1049 | 1007 | ||
| 1050 | void zs_destroy_pool(struct zs_pool *pool) | 1008 | void zs_unmap_object(struct zs_pool *pool, unsigned long handle) |
| 1051 | { | 1009 | { |
| 1052 | int i; | 1010 | struct page *page; |
| 1011 | unsigned long obj_idx, off; | ||
| 1053 | 1012 | ||
| 1054 | for (i = 0; i < zs_size_classes; i++) { | 1013 | unsigned int class_idx; |
| 1055 | int fg; | 1014 | enum fullness_group fg; |
| 1056 | struct size_class *class = pool->size_class[i]; | 1015 | struct size_class *class; |
| 1016 | struct mapping_area *area; | ||
| 1057 | 1017 | ||
| 1058 | if (!class) | 1018 | BUG_ON(!handle); |
| 1059 | continue; | ||
| 1060 | 1019 | ||
| 1061 | if (class->index != i) | 1020 | obj_handle_to_location(handle, &page, &obj_idx); |
| 1062 | continue; | 1021 | get_zspage_mapping(get_first_page(page), &class_idx, &fg); |
| 1022 | class = pool->size_class[class_idx]; | ||
| 1023 | off = obj_idx_to_offset(page, obj_idx, class->size); | ||
| 1063 | 1024 | ||
| 1064 | for (fg = 0; fg < _ZS_NR_FULLNESS_GROUPS; fg++) { | 1025 | area = this_cpu_ptr(&zs_map_area); |
| 1065 | if (class->fullness_list[fg]) { | 1026 | if (off + class->size <= PAGE_SIZE) |
| 1066 | pr_info("Freeing non-empty class with size %db, fullness group %d\n", | 1027 | kunmap_atomic(area->vm_addr); |
| 1067 | class->size, fg); | 1028 | else { |
| 1068 | } | 1029 | struct page *pages[2]; |
| 1069 | } | ||
| 1070 | kfree(class); | ||
| 1071 | } | ||
| 1072 | 1030 | ||
| 1073 | kfree(pool->size_class); | 1031 | pages[0] = page; |
| 1074 | kfree(pool); | 1032 | pages[1] = get_next_page(page); |
| 1033 | BUG_ON(!pages[1]); | ||
| 1034 | |||
| 1035 | __zs_unmap_object(area, pages, off, class->size); | ||
| 1036 | } | ||
| 1037 | put_cpu_var(zs_map_area); | ||
| 1075 | } | 1038 | } |
| 1076 | EXPORT_SYMBOL_GPL(zs_destroy_pool); | 1039 | EXPORT_SYMBOL_GPL(zs_unmap_object); |
| 1077 | 1040 | ||
| 1078 | /** | 1041 | /** |
| 1079 | * zs_malloc - Allocate block of given size from pool. | 1042 | * zs_malloc - Allocate block of given size from pool. |
| @@ -1176,100 +1139,137 @@ void zs_free(struct zs_pool *pool, unsigned long obj) | |||
| 1176 | EXPORT_SYMBOL_GPL(zs_free); | 1139 | EXPORT_SYMBOL_GPL(zs_free); |
| 1177 | 1140 | ||
| 1178 | /** | 1141 | /** |
| 1179 | * zs_map_object - get address of allocated object from handle. | 1142 | * zs_create_pool - Creates an allocation pool to work from. |
| 1180 | * @pool: pool from which the object was allocated | 1143 | * @flags: allocation flags used to allocate pool metadata |
| 1181 | * @handle: handle returned from zs_malloc | ||
| 1182 | * | ||
| 1183 | * Before using an object allocated from zs_malloc, it must be mapped using | ||
| 1184 | * this function. When done with the object, it must be unmapped using | ||
| 1185 | * zs_unmap_object. | ||
| 1186 | * | 1144 | * |
| 1187 | * Only one object can be mapped per cpu at a time. There is no protection | 1145 | * This function must be called before anything when using |
| 1188 | * against nested mappings. | 1146 | * the zsmalloc allocator. |
| 1189 | * | 1147 | * |
| 1190 | * This function returns with preemption and page faults disabled. | 1148 | * On success, a pointer to the newly created pool is returned, |
| 1149 | * otherwise NULL. | ||
| 1191 | */ | 1150 | */ |
| 1192 | void *zs_map_object(struct zs_pool *pool, unsigned long handle, | 1151 | struct zs_pool *zs_create_pool(gfp_t flags) |
| 1193 | enum zs_mapmode mm) | ||
| 1194 | { | 1152 | { |
| 1195 | struct page *page; | 1153 | int i; |
| 1196 | unsigned long obj_idx, off; | 1154 | struct zs_pool *pool; |
| 1155 | struct size_class *prev_class = NULL; | ||
| 1197 | 1156 | ||
| 1198 | unsigned int class_idx; | 1157 | pool = kzalloc(sizeof(*pool), GFP_KERNEL); |
| 1199 | enum fullness_group fg; | 1158 | if (!pool) |
| 1200 | struct size_class *class; | 1159 | return NULL; |
| 1201 | struct mapping_area *area; | ||
| 1202 | struct page *pages[2]; | ||
| 1203 | 1160 | ||
| 1204 | BUG_ON(!handle); | 1161 | pool->size_class = kcalloc(zs_size_classes, sizeof(struct size_class *), |
| 1162 | GFP_KERNEL); | ||
| 1163 | if (!pool->size_class) { | ||
| 1164 | kfree(pool); | ||
| 1165 | return NULL; | ||
| 1166 | } | ||
| 1205 | 1167 | ||
| 1206 | /* | 1168 | /* |
| 1207 | * Because we use per-cpu mapping areas shared among the | 1169 | * Iterate reversly, because, size of size_class that we want to use |
| 1208 | * pools/users, we can't allow mapping in interrupt context | 1170 | * for merging should be larger or equal to current size. |
| 1209 | * because it can corrupt another users mappings. | ||
| 1210 | */ | 1171 | */ |
| 1211 | BUG_ON(in_interrupt()); | 1172 | for (i = zs_size_classes - 1; i >= 0; i--) { |
| 1173 | int size; | ||
| 1174 | int pages_per_zspage; | ||
| 1175 | struct size_class *class; | ||
| 1212 | 1176 | ||
| 1213 | obj_handle_to_location(handle, &page, &obj_idx); | 1177 | size = ZS_MIN_ALLOC_SIZE + i * ZS_SIZE_CLASS_DELTA; |
| 1214 | get_zspage_mapping(get_first_page(page), &class_idx, &fg); | 1178 | if (size > ZS_MAX_ALLOC_SIZE) |
| 1215 | class = pool->size_class[class_idx]; | 1179 | size = ZS_MAX_ALLOC_SIZE; |
| 1216 | off = obj_idx_to_offset(page, obj_idx, class->size); | 1180 | pages_per_zspage = get_pages_per_zspage(size); |
| 1217 | 1181 | ||
| 1218 | area = &get_cpu_var(zs_map_area); | 1182 | /* |
| 1219 | area->vm_mm = mm; | 1183 | * size_class is used for normal zsmalloc operation such |
| 1220 | if (off + class->size <= PAGE_SIZE) { | 1184 | * as alloc/free for that size. Although it is natural that we |
| 1221 | /* this object is contained entirely within a page */ | 1185 | * have one size_class for each size, there is a chance that we |
| 1222 | area->vm_addr = kmap_atomic(page); | 1186 | * can get more memory utilization if we use one size_class for |
| 1223 | return area->vm_addr + off; | 1187 | * many different sizes whose size_class have same |
| 1188 | * characteristics. So, we makes size_class point to | ||
| 1189 | * previous size_class if possible. | ||
| 1190 | */ | ||
| 1191 | if (prev_class) { | ||
| 1192 | if (can_merge(prev_class, size, pages_per_zspage)) { | ||
| 1193 | pool->size_class[i] = prev_class; | ||
| 1194 | continue; | ||
| 1195 | } | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | class = kzalloc(sizeof(struct size_class), GFP_KERNEL); | ||
| 1199 | if (!class) | ||
| 1200 | goto err; | ||
| 1201 | |||
| 1202 | class->size = size; | ||
| 1203 | class->index = i; | ||
| 1204 | class->pages_per_zspage = pages_per_zspage; | ||
| 1205 | spin_lock_init(&class->lock); | ||
| 1206 | pool->size_class[i] = class; | ||
| 1207 | |||
| 1208 | prev_class = class; | ||
| 1224 | } | 1209 | } |
| 1225 | 1210 | ||
| 1226 | /* this object spans two pages */ | 1211 | pool->flags = flags; |
| 1227 | pages[0] = page; | ||
| 1228 | pages[1] = get_next_page(page); | ||
| 1229 | BUG_ON(!pages[1]); | ||
| 1230 | 1212 | ||
| 1231 | return __zs_map_object(area, pages, off, class->size); | 1213 | return pool; |
| 1214 | |||
| 1215 | err: | ||
| 1216 | zs_destroy_pool(pool); | ||
| 1217 | return NULL; | ||
| 1232 | } | 1218 | } |
| 1233 | EXPORT_SYMBOL_GPL(zs_map_object); | 1219 | EXPORT_SYMBOL_GPL(zs_create_pool); |
| 1234 | 1220 | ||
| 1235 | void zs_unmap_object(struct zs_pool *pool, unsigned long handle) | 1221 | void zs_destroy_pool(struct zs_pool *pool) |
| 1236 | { | 1222 | { |
| 1237 | struct page *page; | 1223 | int i; |
| 1238 | unsigned long obj_idx, off; | ||
| 1239 | 1224 | ||
| 1240 | unsigned int class_idx; | 1225 | for (i = 0; i < zs_size_classes; i++) { |
| 1241 | enum fullness_group fg; | 1226 | int fg; |
| 1242 | struct size_class *class; | 1227 | struct size_class *class = pool->size_class[i]; |
| 1243 | struct mapping_area *area; | ||
| 1244 | 1228 | ||
| 1245 | BUG_ON(!handle); | 1229 | if (!class) |
| 1230 | continue; | ||
| 1246 | 1231 | ||
| 1247 | obj_handle_to_location(handle, &page, &obj_idx); | 1232 | if (class->index != i) |
| 1248 | get_zspage_mapping(get_first_page(page), &class_idx, &fg); | 1233 | continue; |
| 1249 | class = pool->size_class[class_idx]; | ||
| 1250 | off = obj_idx_to_offset(page, obj_idx, class->size); | ||
| 1251 | 1234 | ||
| 1252 | area = this_cpu_ptr(&zs_map_area); | 1235 | for (fg = 0; fg < _ZS_NR_FULLNESS_GROUPS; fg++) { |
| 1253 | if (off + class->size <= PAGE_SIZE) | 1236 | if (class->fullness_list[fg]) { |
| 1254 | kunmap_atomic(area->vm_addr); | 1237 | pr_info("Freeing non-empty class with size %db, fullness group %d\n", |
| 1255 | else { | 1238 | class->size, fg); |
| 1256 | struct page *pages[2]; | 1239 | } |
| 1240 | } | ||
| 1241 | kfree(class); | ||
| 1242 | } | ||
| 1257 | 1243 | ||
| 1258 | pages[0] = page; | 1244 | kfree(pool->size_class); |
| 1259 | pages[1] = get_next_page(page); | 1245 | kfree(pool); |
| 1260 | BUG_ON(!pages[1]); | 1246 | } |
| 1247 | EXPORT_SYMBOL_GPL(zs_destroy_pool); | ||
| 1261 | 1248 | ||
| 1262 | __zs_unmap_object(area, pages, off, class->size); | 1249 | static int __init zs_init(void) |
| 1250 | { | ||
| 1251 | int ret = zs_register_cpu_notifier(); | ||
| 1252 | |||
| 1253 | if (ret) { | ||
| 1254 | zs_unregister_cpu_notifier(); | ||
| 1255 | return ret; | ||
| 1263 | } | 1256 | } |
| 1264 | put_cpu_var(zs_map_area); | 1257 | |
| 1258 | init_zs_size_classes(); | ||
| 1259 | |||
| 1260 | #ifdef CONFIG_ZPOOL | ||
| 1261 | zpool_register_driver(&zs_zpool_driver); | ||
| 1262 | #endif | ||
| 1263 | return 0; | ||
| 1265 | } | 1264 | } |
| 1266 | EXPORT_SYMBOL_GPL(zs_unmap_object); | ||
| 1267 | 1265 | ||
| 1268 | unsigned long zs_get_total_pages(struct zs_pool *pool) | 1266 | static void __exit zs_exit(void) |
| 1269 | { | 1267 | { |
| 1270 | return atomic_long_read(&pool->pages_allocated); | 1268 | #ifdef CONFIG_ZPOOL |
| 1269 | zpool_unregister_driver(&zs_zpool_driver); | ||
| 1270 | #endif | ||
| 1271 | zs_unregister_cpu_notifier(); | ||
| 1271 | } | 1272 | } |
| 1272 | EXPORT_SYMBOL_GPL(zs_get_total_pages); | ||
| 1273 | 1273 | ||
| 1274 | module_init(zs_init); | 1274 | module_init(zs_init); |
| 1275 | module_exit(zs_exit); | 1275 | module_exit(zs_exit); |
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index b3831f4ba845..4e511221a0c1 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
| @@ -1,22 +1,23 @@ | |||
| 1 | TARGETS = breakpoints | 1 | TARGETS = breakpoints |
| 2 | TARGETS += cpu-hotplug | 2 | TARGETS += cpu-hotplug |
| 3 | TARGETS += efivarfs | 3 | TARGETS += efivarfs |
| 4 | TARGETS += exec | ||
| 5 | TARGETS += firmware | ||
| 6 | TARGETS += ftrace | ||
| 4 | TARGETS += kcmp | 7 | TARGETS += kcmp |
| 5 | TARGETS += memfd | 8 | TARGETS += memfd |
| 6 | TARGETS += memory-hotplug | 9 | TARGETS += memory-hotplug |
| 7 | TARGETS += mqueue | ||
| 8 | TARGETS += mount | 10 | TARGETS += mount |
| 11 | TARGETS += mqueue | ||
| 9 | TARGETS += net | 12 | TARGETS += net |
| 13 | TARGETS += powerpc | ||
| 10 | TARGETS += ptrace | 14 | TARGETS += ptrace |
| 15 | TARGETS += size | ||
| 16 | TARGETS += sysctl | ||
| 11 | TARGETS += timers | 17 | TARGETS += timers |
| 12 | TARGETS += vm | ||
| 13 | TARGETS += powerpc | ||
| 14 | TARGETS += user | 18 | TARGETS += user |
| 15 | TARGETS += sysctl | 19 | TARGETS += vm |
| 16 | TARGETS += firmware | 20 | #Please keep the TARGETS list alphabetically sorted |
| 17 | TARGETS += ftrace | ||
| 18 | TARGETS += exec | ||
| 19 | TARGETS += size | ||
| 20 | 21 | ||
| 21 | TARGETS_HOTPLUG = cpu-hotplug | 22 | TARGETS_HOTPLUG = cpu-hotplug |
| 22 | TARGETS_HOTPLUG += memory-hotplug | 23 | TARGETS_HOTPLUG += memory-hotplug |
