diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-27 23:58:09 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-27 23:58:09 -0500 |
commit | 2a7d2b96d5cba7568139d9ab157a0e97ab32440f (patch) | |
tree | ad029d8cc7b7068b7250e914360ec6315fdfa114 /fs | |
parent | e3c4877de8b9d93bd47b6ee88eb594b1c1e10da5 (diff) | |
parent | b67bfe0d42cac56c512dd5da4b1b347a23f4b70a (diff) |
Merge branch 'akpm' (final batch from Andrew)
Merge third patch-bumb from Andrew Morton:
"This wraps me up for -rc1.
- Lots of misc stuff and things which were deferred/missed from
patchbombings 1 & 2.
- ocfs2 things
- lib/scatterlist
- hfsplus
- fatfs
- documentation
- signals
- procfs
- lockdep
- coredump
- seqfile core
- kexec
- Tejun's large IDR tree reworkings
- ipmi
- partitions
- nbd
- random() things
- kfifo
- tools/testing/selftests updates
- Sasha's large and pointless hlist cleanup"
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (163 commits)
hlist: drop the node parameter from iterators
kcmp: make it depend on CHECKPOINT_RESTORE
selftests: add a simple doc
tools/testing/selftests/Makefile: rearrange targets
selftests/efivarfs: add create-read test
selftests/efivarfs: add empty file creation test
selftests: add tests for efivarfs
kfifo: fix kfifo_alloc() and kfifo_init()
kfifo: move kfifo.c from kernel/ to lib/
arch Kconfig: centralise CONFIG_ARCH_NO_VIRT_TO_BUS
w1: add support for DS2413 Dual Channel Addressable Switch
memstick: move the dereference below the NULL test
drivers/pps/clients/pps-gpio.c: use devm_kzalloc
Documentation/DMA-API-HOWTO.txt: fix typo
include/linux/eventfd.h: fix incorrect filename is a comment
mtd: mtd_stresstest: use prandom_bytes()
mtd: mtd_subpagetest: convert to use prandom library
mtd: mtd_speedtest: use prandom_bytes
mtd: mtd_pagetest: convert to use prandom library
mtd: mtd_oobtest: convert to use prandom library
...
Diffstat (limited to 'fs')
66 files changed, 2034 insertions, 479 deletions
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index eb82ee53ee0b..d9a43674cb94 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c | |||
@@ -125,9 +125,8 @@ static void | |||
125 | affs_fix_dcache(struct inode *inode, u32 entry_ino) | 125 | affs_fix_dcache(struct inode *inode, u32 entry_ino) |
126 | { | 126 | { |
127 | struct dentry *dentry; | 127 | struct dentry *dentry; |
128 | struct hlist_node *p; | ||
129 | spin_lock(&inode->i_lock); | 128 | spin_lock(&inode->i_lock); |
130 | hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) { | 129 | hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
131 | if (entry_ino == (u32)(long)dentry->d_fsdata) { | 130 | if (entry_ino == (u32)(long)dentry->d_fsdata) { |
132 | dentry->d_fsdata = (void *)inode->i_ino; | 131 | dentry->d_fsdata = (void *)inode->i_ino; |
133 | break; | 132 | break; |
@@ -591,11 +591,10 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id) | |||
591 | { | 591 | { |
592 | struct mm_struct *mm = current->mm; | 592 | struct mm_struct *mm = current->mm; |
593 | struct kioctx *ctx, *ret = NULL; | 593 | struct kioctx *ctx, *ret = NULL; |
594 | struct hlist_node *n; | ||
595 | 594 | ||
596 | rcu_read_lock(); | 595 | rcu_read_lock(); |
597 | 596 | ||
598 | hlist_for_each_entry_rcu(ctx, n, &mm->ioctx_list, list) { | 597 | hlist_for_each_entry_rcu(ctx, &mm->ioctx_list, list) { |
599 | /* | 598 | /* |
600 | * RCU protects us against accessing freed memory but | 599 | * RCU protects us against accessing freed memory but |
601 | * we have to be careful not to get a reference when the | 600 | * we have to be careful not to get a reference when the |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index d2a833999bcc..83f2606c76d0 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -816,10 +816,9 @@ static bool | |||
816 | inode_has_hashed_dentries(struct inode *inode) | 816 | inode_has_hashed_dentries(struct inode *inode) |
817 | { | 817 | { |
818 | struct dentry *dentry; | 818 | struct dentry *dentry; |
819 | struct hlist_node *p; | ||
820 | 819 | ||
821 | spin_lock(&inode->i_lock); | 820 | spin_lock(&inode->i_lock); |
822 | hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) { | 821 | hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
823 | if (!d_unhashed(dentry) || IS_ROOT(dentry)) { | 822 | if (!d_unhashed(dentry) || IS_ROOT(dentry)) { |
824 | spin_unlock(&inode->i_lock); | 823 | spin_unlock(&inode->i_lock); |
825 | return true; | 824 | return true; |
diff --git a/fs/coredump.c b/fs/coredump.c index 69baf903d3bd..c6479658d487 100644 --- a/fs/coredump.c +++ b/fs/coredump.c | |||
@@ -501,7 +501,7 @@ void do_coredump(siginfo_t *siginfo) | |||
501 | * so we dump it as root in mode 2, and only into a controlled | 501 | * so we dump it as root in mode 2, and only into a controlled |
502 | * environment (pipe handler or fully qualified path). | 502 | * environment (pipe handler or fully qualified path). |
503 | */ | 503 | */ |
504 | if (__get_dumpable(cprm.mm_flags) == SUID_DUMPABLE_SAFE) { | 504 | if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) { |
505 | /* Setuid core dump mode */ | 505 | /* Setuid core dump mode */ |
506 | flag = O_EXCL; /* Stop rewrite attacks */ | 506 | flag = O_EXCL; /* Stop rewrite attacks */ |
507 | cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ | 507 | cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ |
diff --git a/fs/dcache.c b/fs/dcache.c index 68220dd0c135..fbfae008ba44 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -675,11 +675,10 @@ EXPORT_SYMBOL(dget_parent); | |||
675 | static struct dentry *__d_find_alias(struct inode *inode, int want_discon) | 675 | static struct dentry *__d_find_alias(struct inode *inode, int want_discon) |
676 | { | 676 | { |
677 | struct dentry *alias, *discon_alias; | 677 | struct dentry *alias, *discon_alias; |
678 | struct hlist_node *p; | ||
679 | 678 | ||
680 | again: | 679 | again: |
681 | discon_alias = NULL; | 680 | discon_alias = NULL; |
682 | hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) { | 681 | hlist_for_each_entry(alias, &inode->i_dentry, d_alias) { |
683 | spin_lock(&alias->d_lock); | 682 | spin_lock(&alias->d_lock); |
684 | if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { | 683 | if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { |
685 | if (IS_ROOT(alias) && | 684 | if (IS_ROOT(alias) && |
@@ -730,10 +729,9 @@ EXPORT_SYMBOL(d_find_alias); | |||
730 | void d_prune_aliases(struct inode *inode) | 729 | void d_prune_aliases(struct inode *inode) |
731 | { | 730 | { |
732 | struct dentry *dentry; | 731 | struct dentry *dentry; |
733 | struct hlist_node *p; | ||
734 | restart: | 732 | restart: |
735 | spin_lock(&inode->i_lock); | 733 | spin_lock(&inode->i_lock); |
736 | hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) { | 734 | hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
737 | spin_lock(&dentry->d_lock); | 735 | spin_lock(&dentry->d_lock); |
738 | if (!dentry->d_count) { | 736 | if (!dentry->d_count) { |
739 | __dget_dlock(dentry); | 737 | __dget_dlock(dentry); |
@@ -1443,14 +1441,13 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry, | |||
1443 | int len = entry->d_name.len; | 1441 | int len = entry->d_name.len; |
1444 | const char *name = entry->d_name.name; | 1442 | const char *name = entry->d_name.name; |
1445 | unsigned int hash = entry->d_name.hash; | 1443 | unsigned int hash = entry->d_name.hash; |
1446 | struct hlist_node *p; | ||
1447 | 1444 | ||
1448 | if (!inode) { | 1445 | if (!inode) { |
1449 | __d_instantiate(entry, NULL); | 1446 | __d_instantiate(entry, NULL); |
1450 | return NULL; | 1447 | return NULL; |
1451 | } | 1448 | } |
1452 | 1449 | ||
1453 | hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) { | 1450 | hlist_for_each_entry(alias, &inode->i_dentry, d_alias) { |
1454 | /* | 1451 | /* |
1455 | * Don't need alias->d_lock here, because aliases with | 1452 | * Don't need alias->d_lock here, because aliases with |
1456 | * d_parent == entry->d_parent are not subject to name or | 1453 | * d_parent == entry->d_parent are not subject to name or |
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index f7501651762d..1b1146670c4b 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c | |||
@@ -1183,7 +1183,7 @@ static void detach_lkb(struct dlm_lkb *lkb) | |||
1183 | static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) | 1183 | static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) |
1184 | { | 1184 | { |
1185 | struct dlm_lkb *lkb; | 1185 | struct dlm_lkb *lkb; |
1186 | int rv, id; | 1186 | int rv; |
1187 | 1187 | ||
1188 | lkb = dlm_allocate_lkb(ls); | 1188 | lkb = dlm_allocate_lkb(ls); |
1189 | if (!lkb) | 1189 | if (!lkb) |
@@ -1199,19 +1199,13 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) | |||
1199 | mutex_init(&lkb->lkb_cb_mutex); | 1199 | mutex_init(&lkb->lkb_cb_mutex); |
1200 | INIT_WORK(&lkb->lkb_cb_work, dlm_callback_work); | 1200 | INIT_WORK(&lkb->lkb_cb_work, dlm_callback_work); |
1201 | 1201 | ||
1202 | retry: | 1202 | idr_preload(GFP_NOFS); |
1203 | rv = idr_pre_get(&ls->ls_lkbidr, GFP_NOFS); | ||
1204 | if (!rv) | ||
1205 | return -ENOMEM; | ||
1206 | |||
1207 | spin_lock(&ls->ls_lkbidr_spin); | 1203 | spin_lock(&ls->ls_lkbidr_spin); |
1208 | rv = idr_get_new_above(&ls->ls_lkbidr, lkb, 1, &id); | 1204 | rv = idr_alloc(&ls->ls_lkbidr, lkb, 1, 0, GFP_NOWAIT); |
1209 | if (!rv) | 1205 | if (rv >= 0) |
1210 | lkb->lkb_id = id; | 1206 | lkb->lkb_id = rv; |
1211 | spin_unlock(&ls->ls_lkbidr_spin); | 1207 | spin_unlock(&ls->ls_lkbidr_spin); |
1212 | 1208 | idr_preload_end(); | |
1213 | if (rv == -EAGAIN) | ||
1214 | goto retry; | ||
1215 | 1209 | ||
1216 | if (rv < 0) { | 1210 | if (rv < 0) { |
1217 | log_error(ls, "create_lkb idr error %d", rv); | 1211 | log_error(ls, "create_lkb idr error %d", rv); |
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 2e99fb0c9737..3ca79d3253b9 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c | |||
@@ -796,7 +796,6 @@ static int release_lockspace(struct dlm_ls *ls, int force) | |||
796 | */ | 796 | */ |
797 | 797 | ||
798 | idr_for_each(&ls->ls_lkbidr, lkb_idr_free, ls); | 798 | idr_for_each(&ls->ls_lkbidr, lkb_idr_free, ls); |
799 | idr_remove_all(&ls->ls_lkbidr); | ||
800 | idr_destroy(&ls->ls_lkbidr); | 799 | idr_destroy(&ls->ls_lkbidr); |
801 | 800 | ||
802 | /* | 801 | /* |
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index dd87a31bcc21..4f5ad246582f 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c | |||
@@ -177,12 +177,11 @@ static inline int nodeid_hash(int nodeid) | |||
177 | static struct connection *__find_con(int nodeid) | 177 | static struct connection *__find_con(int nodeid) |
178 | { | 178 | { |
179 | int r; | 179 | int r; |
180 | struct hlist_node *h; | ||
181 | struct connection *con; | 180 | struct connection *con; |
182 | 181 | ||
183 | r = nodeid_hash(nodeid); | 182 | r = nodeid_hash(nodeid); |
184 | 183 | ||
185 | hlist_for_each_entry(con, h, &connection_hash[r], list) { | 184 | hlist_for_each_entry(con, &connection_hash[r], list) { |
186 | if (con->nodeid == nodeid) | 185 | if (con->nodeid == nodeid) |
187 | return con; | 186 | return con; |
188 | } | 187 | } |
@@ -232,13 +231,12 @@ static struct connection *__nodeid2con(int nodeid, gfp_t alloc) | |||
232 | static void foreach_conn(void (*conn_func)(struct connection *c)) | 231 | static void foreach_conn(void (*conn_func)(struct connection *c)) |
233 | { | 232 | { |
234 | int i; | 233 | int i; |
235 | struct hlist_node *h, *n; | 234 | struct hlist_node *n; |
236 | struct connection *con; | 235 | struct connection *con; |
237 | 236 | ||
238 | for (i = 0; i < CONN_HASH_SIZE; i++) { | 237 | for (i = 0; i < CONN_HASH_SIZE; i++) { |
239 | hlist_for_each_entry_safe(con, h, n, &connection_hash[i], list){ | 238 | hlist_for_each_entry_safe(con, n, &connection_hash[i], list) |
240 | conn_func(con); | 239 | conn_func(con); |
241 | } | ||
242 | } | 240 | } |
243 | } | 241 | } |
244 | 242 | ||
@@ -257,13 +255,12 @@ static struct connection *nodeid2con(int nodeid, gfp_t allocation) | |||
257 | static struct connection *assoc2con(int assoc_id) | 255 | static struct connection *assoc2con(int assoc_id) |
258 | { | 256 | { |
259 | int i; | 257 | int i; |
260 | struct hlist_node *h; | ||
261 | struct connection *con; | 258 | struct connection *con; |
262 | 259 | ||
263 | mutex_lock(&connections_lock); | 260 | mutex_lock(&connections_lock); |
264 | 261 | ||
265 | for (i = 0 ; i < CONN_HASH_SIZE; i++) { | 262 | for (i = 0 ; i < CONN_HASH_SIZE; i++) { |
266 | hlist_for_each_entry(con, h, &connection_hash[i], list) { | 263 | hlist_for_each_entry(con, &connection_hash[i], list) { |
267 | if (con->sctp_assoc == assoc_id) { | 264 | if (con->sctp_assoc == assoc_id) { |
268 | mutex_unlock(&connections_lock); | 265 | mutex_unlock(&connections_lock); |
269 | return con; | 266 | return con; |
diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c index aedea28a86a1..a6bc63f6e31b 100644 --- a/fs/dlm/recover.c +++ b/fs/dlm/recover.c | |||
@@ -305,27 +305,26 @@ static int recover_idr_empty(struct dlm_ls *ls) | |||
305 | static int recover_idr_add(struct dlm_rsb *r) | 305 | static int recover_idr_add(struct dlm_rsb *r) |
306 | { | 306 | { |
307 | struct dlm_ls *ls = r->res_ls; | 307 | struct dlm_ls *ls = r->res_ls; |
308 | int rv, id; | 308 | int rv; |
309 | |||
310 | rv = idr_pre_get(&ls->ls_recover_idr, GFP_NOFS); | ||
311 | if (!rv) | ||
312 | return -ENOMEM; | ||
313 | 309 | ||
310 | idr_preload(GFP_NOFS); | ||
314 | spin_lock(&ls->ls_recover_idr_lock); | 311 | spin_lock(&ls->ls_recover_idr_lock); |
315 | if (r->res_id) { | 312 | if (r->res_id) { |
316 | spin_unlock(&ls->ls_recover_idr_lock); | 313 | rv = -1; |
317 | return -1; | 314 | goto out_unlock; |
318 | } | ||
319 | rv = idr_get_new_above(&ls->ls_recover_idr, r, 1, &id); | ||
320 | if (rv) { | ||
321 | spin_unlock(&ls->ls_recover_idr_lock); | ||
322 | return rv; | ||
323 | } | 315 | } |
324 | r->res_id = id; | 316 | rv = idr_alloc(&ls->ls_recover_idr, r, 1, 0, GFP_NOWAIT); |
317 | if (rv < 0) | ||
318 | goto out_unlock; | ||
319 | |||
320 | r->res_id = rv; | ||
325 | ls->ls_recover_list_count++; | 321 | ls->ls_recover_list_count++; |
326 | dlm_hold_rsb(r); | 322 | dlm_hold_rsb(r); |
323 | rv = 0; | ||
324 | out_unlock: | ||
327 | spin_unlock(&ls->ls_recover_idr_lock); | 325 | spin_unlock(&ls->ls_recover_idr_lock); |
328 | return 0; | 326 | idr_preload_end(); |
327 | return rv; | ||
329 | } | 328 | } |
330 | 329 | ||
331 | static void recover_idr_del(struct dlm_rsb *r) | 330 | static void recover_idr_del(struct dlm_rsb *r) |
@@ -351,24 +350,21 @@ static struct dlm_rsb *recover_idr_find(struct dlm_ls *ls, uint64_t id) | |||
351 | return r; | 350 | return r; |
352 | } | 351 | } |
353 | 352 | ||
354 | static int recover_idr_clear_rsb(int id, void *p, void *data) | 353 | static void recover_idr_clear(struct dlm_ls *ls) |
355 | { | 354 | { |
356 | struct dlm_ls *ls = data; | 355 | struct dlm_rsb *r; |
357 | struct dlm_rsb *r = p; | 356 | int id; |
358 | 357 | ||
359 | r->res_id = 0; | 358 | spin_lock(&ls->ls_recover_idr_lock); |
360 | r->res_recover_locks_count = 0; | ||
361 | ls->ls_recover_list_count--; | ||
362 | 359 | ||
363 | dlm_put_rsb(r); | 360 | idr_for_each_entry(&ls->ls_recover_idr, r, id) { |
364 | return 0; | 361 | idr_remove(&ls->ls_recover_idr, id); |
365 | } | 362 | r->res_id = 0; |
363 | r->res_recover_locks_count = 0; | ||
364 | ls->ls_recover_list_count--; | ||
366 | 365 | ||
367 | static void recover_idr_clear(struct dlm_ls *ls) | 366 | dlm_put_rsb(r); |
368 | { | 367 | } |
369 | spin_lock(&ls->ls_recover_idr_lock); | ||
370 | idr_for_each(&ls->ls_recover_idr, recover_idr_clear_rsb, ls); | ||
371 | idr_remove_all(&ls->ls_recover_idr); | ||
372 | 368 | ||
373 | if (ls->ls_recover_list_count != 0) { | 369 | if (ls->ls_recover_list_count != 0) { |
374 | log_error(ls, "warning: recover_list_count %d", | 370 | log_error(ls, "warning: recover_list_count %d", |
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index 5fa2471796c2..8d7a577ae497 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c | |||
@@ -115,10 +115,9 @@ void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx) | |||
115 | */ | 115 | */ |
116 | int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon) | 116 | int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon) |
117 | { | 117 | { |
118 | struct hlist_node *elem; | ||
119 | int rc; | 118 | int rc; |
120 | 119 | ||
121 | hlist_for_each_entry(*daemon, elem, | 120 | hlist_for_each_entry(*daemon, |
122 | &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()], | 121 | &ecryptfs_daemon_hash[ecryptfs_current_euid_hash()], |
123 | euid_chain) { | 122 | euid_chain) { |
124 | if (uid_eq((*daemon)->file->f_cred->euid, current_euid())) { | 123 | if (uid_eq((*daemon)->file->f_cred->euid, current_euid())) { |
@@ -445,7 +444,6 @@ void ecryptfs_release_messaging(void) | |||
445 | mutex_unlock(&ecryptfs_msg_ctx_lists_mux); | 444 | mutex_unlock(&ecryptfs_msg_ctx_lists_mux); |
446 | } | 445 | } |
447 | if (ecryptfs_daemon_hash) { | 446 | if (ecryptfs_daemon_hash) { |
448 | struct hlist_node *elem; | ||
449 | struct ecryptfs_daemon *daemon; | 447 | struct ecryptfs_daemon *daemon; |
450 | int i; | 448 | int i; |
451 | 449 | ||
@@ -453,7 +451,7 @@ void ecryptfs_release_messaging(void) | |||
453 | for (i = 0; i < (1 << ecryptfs_hash_bits); i++) { | 451 | for (i = 0; i < (1 << ecryptfs_hash_bits); i++) { |
454 | int rc; | 452 | int rc; |
455 | 453 | ||
456 | hlist_for_each_entry(daemon, elem, | 454 | hlist_for_each_entry(daemon, |
457 | &ecryptfs_daemon_hash[i], | 455 | &ecryptfs_daemon_hash[i], |
458 | euid_chain) { | 456 | euid_chain) { |
459 | rc = ecryptfs_exorcise_daemon(daemon); | 457 | rc = ecryptfs_exorcise_daemon(daemon); |
@@ -1111,7 +1111,7 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
1111 | current->sas_ss_sp = current->sas_ss_size = 0; | 1111 | current->sas_ss_sp = current->sas_ss_size = 0; |
1112 | 1112 | ||
1113 | if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid())) | 1113 | if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid())) |
1114 | set_dumpable(current->mm, SUID_DUMPABLE_ENABLED); | 1114 | set_dumpable(current->mm, SUID_DUMP_USER); |
1115 | else | 1115 | else |
1116 | set_dumpable(current->mm, suid_dumpable); | 1116 | set_dumpable(current->mm, suid_dumpable); |
1117 | 1117 | ||
@@ -1639,17 +1639,17 @@ EXPORT_SYMBOL(set_binfmt); | |||
1639 | void set_dumpable(struct mm_struct *mm, int value) | 1639 | void set_dumpable(struct mm_struct *mm, int value) |
1640 | { | 1640 | { |
1641 | switch (value) { | 1641 | switch (value) { |
1642 | case SUID_DUMPABLE_DISABLED: | 1642 | case SUID_DUMP_DISABLE: |
1643 | clear_bit(MMF_DUMPABLE, &mm->flags); | 1643 | clear_bit(MMF_DUMPABLE, &mm->flags); |
1644 | smp_wmb(); | 1644 | smp_wmb(); |
1645 | clear_bit(MMF_DUMP_SECURELY, &mm->flags); | 1645 | clear_bit(MMF_DUMP_SECURELY, &mm->flags); |
1646 | break; | 1646 | break; |
1647 | case SUID_DUMPABLE_ENABLED: | 1647 | case SUID_DUMP_USER: |
1648 | set_bit(MMF_DUMPABLE, &mm->flags); | 1648 | set_bit(MMF_DUMPABLE, &mm->flags); |
1649 | smp_wmb(); | 1649 | smp_wmb(); |
1650 | clear_bit(MMF_DUMP_SECURELY, &mm->flags); | 1650 | clear_bit(MMF_DUMP_SECURELY, &mm->flags); |
1651 | break; | 1651 | break; |
1652 | case SUID_DUMPABLE_SAFE: | 1652 | case SUID_DUMP_ROOT: |
1653 | set_bit(MMF_DUMP_SECURELY, &mm->flags); | 1653 | set_bit(MMF_DUMP_SECURELY, &mm->flags); |
1654 | smp_wmb(); | 1654 | smp_wmb(); |
1655 | set_bit(MMF_DUMPABLE, &mm->flags); | 1655 | set_bit(MMF_DUMPABLE, &mm->flags); |
@@ -1662,7 +1662,7 @@ int __get_dumpable(unsigned long mm_flags) | |||
1662 | int ret; | 1662 | int ret; |
1663 | 1663 | ||
1664 | ret = mm_flags & MMF_DUMPABLE_MASK; | 1664 | ret = mm_flags & MMF_DUMPABLE_MASK; |
1665 | return (ret > SUID_DUMPABLE_ENABLED) ? SUID_DUMPABLE_SAFE : ret; | 1665 | return (ret > SUID_DUMP_USER) ? SUID_DUMP_ROOT : ret; |
1666 | } | 1666 | } |
1667 | 1667 | ||
1668 | int get_dumpable(struct mm_struct *mm) | 1668 | int get_dumpable(struct mm_struct *mm) |
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 5df4bb4aab14..262fc9940982 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -44,14 +44,13 @@ find_acceptable_alias(struct dentry *result, | |||
44 | { | 44 | { |
45 | struct dentry *dentry, *toput = NULL; | 45 | struct dentry *dentry, *toput = NULL; |
46 | struct inode *inode; | 46 | struct inode *inode; |
47 | struct hlist_node *p; | ||
48 | 47 | ||
49 | if (acceptable(context, result)) | 48 | if (acceptable(context, result)) |
50 | return result; | 49 | return result; |
51 | 50 | ||
52 | inode = result->d_inode; | 51 | inode = result->d_inode; |
53 | spin_lock(&inode->i_lock); | 52 | spin_lock(&inode->i_lock); |
54 | hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) { | 53 | hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
55 | dget(dentry); | 54 | dget(dentry); |
56 | spin_unlock(&inode->i_lock); | 55 | spin_unlock(&inode->i_lock); |
57 | if (toput) | 56 | if (toput) |
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 12701a567752..e9cc3f0d58e2 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
@@ -95,6 +95,8 @@ struct msdos_sb_info { | |||
95 | 95 | ||
96 | spinlock_t dir_hash_lock; | 96 | spinlock_t dir_hash_lock; |
97 | struct hlist_head dir_hashtable[FAT_HASH_SIZE]; | 97 | struct hlist_head dir_hashtable[FAT_HASH_SIZE]; |
98 | |||
99 | unsigned int dirty; /* fs state before mount */ | ||
98 | }; | 100 | }; |
99 | 101 | ||
100 | #define FAT_CACHE_VALID 0 /* special case for valid cache */ | 102 | #define FAT_CACHE_VALID 0 /* special case for valid cache */ |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index f8f491677a4a..acf6e479b443 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -341,12 +341,11 @@ struct inode *fat_iget(struct super_block *sb, loff_t i_pos) | |||
341 | { | 341 | { |
342 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 342 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
343 | struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos); | 343 | struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos); |
344 | struct hlist_node *_p; | ||
345 | struct msdos_inode_info *i; | 344 | struct msdos_inode_info *i; |
346 | struct inode *inode = NULL; | 345 | struct inode *inode = NULL; |
347 | 346 | ||
348 | spin_lock(&sbi->inode_hash_lock); | 347 | spin_lock(&sbi->inode_hash_lock); |
349 | hlist_for_each_entry(i, _p, head, i_fat_hash) { | 348 | hlist_for_each_entry(i, head, i_fat_hash) { |
350 | BUG_ON(i->vfs_inode.i_sb != sb); | 349 | BUG_ON(i->vfs_inode.i_sb != sb); |
351 | if (i->i_pos != i_pos) | 350 | if (i->i_pos != i_pos) |
352 | continue; | 351 | continue; |
@@ -488,10 +487,59 @@ static void fat_evict_inode(struct inode *inode) | |||
488 | fat_detach(inode); | 487 | fat_detach(inode); |
489 | } | 488 | } |
490 | 489 | ||
490 | static void fat_set_state(struct super_block *sb, | ||
491 | unsigned int set, unsigned int force) | ||
492 | { | ||
493 | struct buffer_head *bh; | ||
494 | struct fat_boot_sector *b; | ||
495 | struct msdos_sb_info *sbi = sb->s_fs_info; | ||
496 | |||
497 | /* do not change any thing if mounted read only */ | ||
498 | if ((sb->s_flags & MS_RDONLY) && !force) | ||
499 | return; | ||
500 | |||
501 | /* do not change state if fs was dirty */ | ||
502 | if (sbi->dirty) { | ||
503 | /* warn only on set (mount). */ | ||
504 | if (set) | ||
505 | fat_msg(sb, KERN_WARNING, "Volume was not properly " | ||
506 | "unmounted. Some data may be corrupt. " | ||
507 | "Please run fsck."); | ||
508 | return; | ||
509 | } | ||
510 | |||
511 | bh = sb_bread(sb, 0); | ||
512 | if (bh == NULL) { | ||
513 | fat_msg(sb, KERN_ERR, "unable to read boot sector " | ||
514 | "to mark fs as dirty"); | ||
515 | return; | ||
516 | } | ||
517 | |||
518 | b = (struct fat_boot_sector *) bh->b_data; | ||
519 | |||
520 | if (sbi->fat_bits == 32) { | ||
521 | if (set) | ||
522 | b->fat32.state |= FAT_STATE_DIRTY; | ||
523 | else | ||
524 | b->fat32.state &= ~FAT_STATE_DIRTY; | ||
525 | } else /* fat 16 and 12 */ { | ||
526 | if (set) | ||
527 | b->fat16.state |= FAT_STATE_DIRTY; | ||
528 | else | ||
529 | b->fat16.state &= ~FAT_STATE_DIRTY; | ||
530 | } | ||
531 | |||
532 | mark_buffer_dirty(bh); | ||
533 | sync_dirty_buffer(bh); | ||
534 | brelse(bh); | ||
535 | } | ||
536 | |||
491 | static void fat_put_super(struct super_block *sb) | 537 | static void fat_put_super(struct super_block *sb) |
492 | { | 538 | { |
493 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 539 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
494 | 540 | ||
541 | fat_set_state(sb, 0, 0); | ||
542 | |||
495 | iput(sbi->fsinfo_inode); | 543 | iput(sbi->fsinfo_inode); |
496 | iput(sbi->fat_inode); | 544 | iput(sbi->fat_inode); |
497 | 545 | ||
@@ -566,8 +614,18 @@ static void __exit fat_destroy_inodecache(void) | |||
566 | 614 | ||
567 | static int fat_remount(struct super_block *sb, int *flags, char *data) | 615 | static int fat_remount(struct super_block *sb, int *flags, char *data) |
568 | { | 616 | { |
617 | int new_rdonly; | ||
569 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 618 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
570 | *flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME); | 619 | *flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME); |
620 | |||
621 | /* make sure we update state on remount. */ | ||
622 | new_rdonly = *flags & MS_RDONLY; | ||
623 | if (new_rdonly != (sb->s_flags & MS_RDONLY)) { | ||
624 | if (new_rdonly) | ||
625 | fat_set_state(sb, 0, 0); | ||
626 | else | ||
627 | fat_set_state(sb, 1, 1); | ||
628 | } | ||
571 | return 0; | 629 | return 0; |
572 | } | 630 | } |
573 | 631 | ||
@@ -1298,17 +1356,17 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1298 | sbi->prev_free = FAT_START_ENT; | 1356 | sbi->prev_free = FAT_START_ENT; |
1299 | sb->s_maxbytes = 0xffffffff; | 1357 | sb->s_maxbytes = 0xffffffff; |
1300 | 1358 | ||
1301 | if (!sbi->fat_length && b->fat32_length) { | 1359 | if (!sbi->fat_length && b->fat32.length) { |
1302 | struct fat_boot_fsinfo *fsinfo; | 1360 | struct fat_boot_fsinfo *fsinfo; |
1303 | struct buffer_head *fsinfo_bh; | 1361 | struct buffer_head *fsinfo_bh; |
1304 | 1362 | ||
1305 | /* Must be FAT32 */ | 1363 | /* Must be FAT32 */ |
1306 | sbi->fat_bits = 32; | 1364 | sbi->fat_bits = 32; |
1307 | sbi->fat_length = le32_to_cpu(b->fat32_length); | 1365 | sbi->fat_length = le32_to_cpu(b->fat32.length); |
1308 | sbi->root_cluster = le32_to_cpu(b->root_cluster); | 1366 | sbi->root_cluster = le32_to_cpu(b->fat32.root_cluster); |
1309 | 1367 | ||
1310 | /* MC - if info_sector is 0, don't multiply by 0 */ | 1368 | /* MC - if info_sector is 0, don't multiply by 0 */ |
1311 | sbi->fsinfo_sector = le16_to_cpu(b->info_sector); | 1369 | sbi->fsinfo_sector = le16_to_cpu(b->fat32.info_sector); |
1312 | if (sbi->fsinfo_sector == 0) | 1370 | if (sbi->fsinfo_sector == 0) |
1313 | sbi->fsinfo_sector = 1; | 1371 | sbi->fsinfo_sector = 1; |
1314 | 1372 | ||
@@ -1362,6 +1420,12 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1362 | if (sbi->fat_bits != 32) | 1420 | if (sbi->fat_bits != 32) |
1363 | sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12; | 1421 | sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12; |
1364 | 1422 | ||
1423 | /* some OSes set FAT_STATE_DIRTY and clean it on unmount. */ | ||
1424 | if (sbi->fat_bits == 32) | ||
1425 | sbi->dirty = b->fat32.state & FAT_STATE_DIRTY; | ||
1426 | else /* fat 16 or 12 */ | ||
1427 | sbi->dirty = b->fat16.state & FAT_STATE_DIRTY; | ||
1428 | |||
1365 | /* check that FAT table does not overflow */ | 1429 | /* check that FAT table does not overflow */ |
1366 | fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits; | 1430 | fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits; |
1367 | total_clusters = min(total_clusters, fat_clusters - FAT_START_ENT); | 1431 | total_clusters = min(total_clusters, fat_clusters - FAT_START_ENT); |
@@ -1456,6 +1520,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1456 | "the device does not support discard"); | 1520 | "the device does not support discard"); |
1457 | } | 1521 | } |
1458 | 1522 | ||
1523 | fat_set_state(sb, 1, 0); | ||
1459 | return 0; | 1524 | return 0; |
1460 | 1525 | ||
1461 | out_invalid: | 1526 | out_invalid: |
diff --git a/fs/fat/nfs.c b/fs/fat/nfs.c index ef4b5faba87b..499c10438ca2 100644 --- a/fs/fat/nfs.c +++ b/fs/fat/nfs.c | |||
@@ -21,13 +21,12 @@ static struct inode *fat_dget(struct super_block *sb, int i_logstart) | |||
21 | { | 21 | { |
22 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 22 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
23 | struct hlist_head *head; | 23 | struct hlist_head *head; |
24 | struct hlist_node *_p; | ||
25 | struct msdos_inode_info *i; | 24 | struct msdos_inode_info *i; |
26 | struct inode *inode = NULL; | 25 | struct inode *inode = NULL; |
27 | 26 | ||
28 | head = sbi->dir_hashtable + fat_dir_hash(i_logstart); | 27 | head = sbi->dir_hashtable + fat_dir_hash(i_logstart); |
29 | spin_lock(&sbi->dir_hash_lock); | 28 | spin_lock(&sbi->dir_hash_lock); |
30 | hlist_for_each_entry(i, _p, head, i_dir_hash) { | 29 | hlist_for_each_entry(i, head, i_dir_hash) { |
31 | BUG_ON(i->vfs_inode.i_sb != sb); | 30 | BUG_ON(i->vfs_inode.i_sb != sb); |
32 | if (i->i_logstart != i_logstart) | 31 | if (i->i_logstart != i_logstart) |
33 | continue; | 32 | continue; |
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 8dcb114758e3..e2cba1f60c21 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
@@ -237,13 +237,12 @@ static int fscache_alloc_object(struct fscache_cache *cache, | |||
237 | struct fscache_cookie *cookie) | 237 | struct fscache_cookie *cookie) |
238 | { | 238 | { |
239 | struct fscache_object *object; | 239 | struct fscache_object *object; |
240 | struct hlist_node *_n; | ||
241 | int ret; | 240 | int ret; |
242 | 241 | ||
243 | _enter("%p,%p{%s}", cache, cookie, cookie->def->name); | 242 | _enter("%p,%p{%s}", cache, cookie, cookie->def->name); |
244 | 243 | ||
245 | spin_lock(&cookie->lock); | 244 | spin_lock(&cookie->lock); |
246 | hlist_for_each_entry(object, _n, &cookie->backing_objects, | 245 | hlist_for_each_entry(object, &cookie->backing_objects, |
247 | cookie_link) { | 246 | cookie_link) { |
248 | if (object->cache == cache) | 247 | if (object->cache == cache) |
249 | goto object_already_extant; | 248 | goto object_already_extant; |
@@ -311,7 +310,6 @@ static int fscache_attach_object(struct fscache_cookie *cookie, | |||
311 | { | 310 | { |
312 | struct fscache_object *p; | 311 | struct fscache_object *p; |
313 | struct fscache_cache *cache = object->cache; | 312 | struct fscache_cache *cache = object->cache; |
314 | struct hlist_node *_n; | ||
315 | int ret; | 313 | int ret; |
316 | 314 | ||
317 | _enter("{%s},{OBJ%x}", cookie->def->name, object->debug_id); | 315 | _enter("{%s},{OBJ%x}", cookie->def->name, object->debug_id); |
@@ -321,7 +319,7 @@ static int fscache_attach_object(struct fscache_cookie *cookie, | |||
321 | /* there may be multiple initial creations of this object, but we only | 319 | /* there may be multiple initial creations of this object, but we only |
322 | * want one */ | 320 | * want one */ |
323 | ret = -EEXIST; | 321 | ret = -EEXIST; |
324 | hlist_for_each_entry(p, _n, &cookie->backing_objects, cookie_link) { | 322 | hlist_for_each_entry(p, &cookie->backing_objects, cookie_link) { |
325 | if (p->cache == object->cache) { | 323 | if (p->cache == object->cache) { |
326 | if (p->state >= FSCACHE_OBJECT_DYING) | 324 | if (p->state >= FSCACHE_OBJECT_DYING) |
327 | ret = -ENOBUFS; | 325 | ret = -ENOBUFS; |
@@ -331,7 +329,7 @@ static int fscache_attach_object(struct fscache_cookie *cookie, | |||
331 | 329 | ||
332 | /* pin the parent object */ | 330 | /* pin the parent object */ |
333 | spin_lock_nested(&cookie->parent->lock, 1); | 331 | spin_lock_nested(&cookie->parent->lock, 1); |
334 | hlist_for_each_entry(p, _n, &cookie->parent->backing_objects, | 332 | hlist_for_each_entry(p, &cookie->parent->backing_objects, |
335 | cookie_link) { | 333 | cookie_link) { |
336 | if (p->cache == object->cache) { | 334 | if (p->cache == object->cache) { |
337 | if (p->state >= FSCACHE_OBJECT_DYING) { | 335 | if (p->state >= FSCACHE_OBJECT_DYING) { |
@@ -435,7 +433,6 @@ EXPORT_SYMBOL(__fscache_wait_on_invalidate); | |||
435 | void __fscache_update_cookie(struct fscache_cookie *cookie) | 433 | void __fscache_update_cookie(struct fscache_cookie *cookie) |
436 | { | 434 | { |
437 | struct fscache_object *object; | 435 | struct fscache_object *object; |
438 | struct hlist_node *_p; | ||
439 | 436 | ||
440 | fscache_stat(&fscache_n_updates); | 437 | fscache_stat(&fscache_n_updates); |
441 | 438 | ||
@@ -452,7 +449,7 @@ void __fscache_update_cookie(struct fscache_cookie *cookie) | |||
452 | spin_lock(&cookie->lock); | 449 | spin_lock(&cookie->lock); |
453 | 450 | ||
454 | /* update the index entry on disk in each cache backing this cookie */ | 451 | /* update the index entry on disk in each cache backing this cookie */ |
455 | hlist_for_each_entry(object, _p, | 452 | hlist_for_each_entry(object, |
456 | &cookie->backing_objects, cookie_link) { | 453 | &cookie->backing_objects, cookie_link) { |
457 | fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); | 454 | fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); |
458 | } | 455 | } |
diff --git a/fs/hfsplus/Makefile b/fs/hfsplus/Makefile index 3cc0df730156..09d278bb7b91 100644 --- a/fs/hfsplus/Makefile +++ b/fs/hfsplus/Makefile | |||
@@ -5,5 +5,5 @@ | |||
5 | obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o | 5 | obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o |
6 | 6 | ||
7 | hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o btree.o \ | 7 | hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o btree.o \ |
8 | bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o | 8 | bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o \ |
9 | 9 | attributes.o xattr.o xattr_user.o xattr_security.o xattr_trusted.o | |
diff --git a/fs/hfsplus/attributes.c b/fs/hfsplus/attributes.c new file mode 100644 index 000000000000..8d691f124714 --- /dev/null +++ b/fs/hfsplus/attributes.c | |||
@@ -0,0 +1,399 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/attributes.c | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Handling of records in attributes tree | ||
7 | */ | ||
8 | |||
9 | #include "hfsplus_fs.h" | ||
10 | #include "hfsplus_raw.h" | ||
11 | |||
12 | static struct kmem_cache *hfsplus_attr_tree_cachep; | ||
13 | |||
14 | int hfsplus_create_attr_tree_cache(void) | ||
15 | { | ||
16 | if (hfsplus_attr_tree_cachep) | ||
17 | return -EEXIST; | ||
18 | |||
19 | hfsplus_attr_tree_cachep = | ||
20 | kmem_cache_create("hfsplus_attr_cache", | ||
21 | sizeof(hfsplus_attr_entry), 0, | ||
22 | SLAB_HWCACHE_ALIGN, NULL); | ||
23 | if (!hfsplus_attr_tree_cachep) | ||
24 | return -ENOMEM; | ||
25 | |||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | void hfsplus_destroy_attr_tree_cache(void) | ||
30 | { | ||
31 | kmem_cache_destroy(hfsplus_attr_tree_cachep); | ||
32 | } | ||
33 | |||
34 | int hfsplus_attr_bin_cmp_key(const hfsplus_btree_key *k1, | ||
35 | const hfsplus_btree_key *k2) | ||
36 | { | ||
37 | __be32 k1_cnid, k2_cnid; | ||
38 | |||
39 | k1_cnid = k1->attr.cnid; | ||
40 | k2_cnid = k2->attr.cnid; | ||
41 | if (k1_cnid != k2_cnid) | ||
42 | return be32_to_cpu(k1_cnid) < be32_to_cpu(k2_cnid) ? -1 : 1; | ||
43 | |||
44 | return hfsplus_strcmp( | ||
45 | (const struct hfsplus_unistr *)&k1->attr.key_name, | ||
46 | (const struct hfsplus_unistr *)&k2->attr.key_name); | ||
47 | } | ||
48 | |||
49 | int hfsplus_attr_build_key(struct super_block *sb, hfsplus_btree_key *key, | ||
50 | u32 cnid, const char *name) | ||
51 | { | ||
52 | int len; | ||
53 | |||
54 | memset(key, 0, sizeof(struct hfsplus_attr_key)); | ||
55 | key->attr.cnid = cpu_to_be32(cnid); | ||
56 | if (name) { | ||
57 | len = strlen(name); | ||
58 | if (len > HFSPLUS_ATTR_MAX_STRLEN) { | ||
59 | printk(KERN_ERR "hfs: invalid xattr name's length\n"); | ||
60 | return -EINVAL; | ||
61 | } | ||
62 | hfsplus_asc2uni(sb, | ||
63 | (struct hfsplus_unistr *)&key->attr.key_name, | ||
64 | HFSPLUS_ATTR_MAX_STRLEN, name, len); | ||
65 | len = be16_to_cpu(key->attr.key_name.length); | ||
66 | } else { | ||
67 | key->attr.key_name.length = 0; | ||
68 | len = 0; | ||
69 | } | ||
70 | |||
71 | /* The length of the key, as stored in key_len field, does not include | ||
72 | * the size of the key_len field itself. | ||
73 | * So, offsetof(hfsplus_attr_key, key_name) is a trick because | ||
74 | * it takes into consideration key_len field (__be16) of | ||
75 | * hfsplus_attr_key structure instead of length field (__be16) of | ||
76 | * hfsplus_attr_unistr structure. | ||
77 | */ | ||
78 | key->key_len = | ||
79 | cpu_to_be16(offsetof(struct hfsplus_attr_key, key_name) + | ||
80 | 2 * len); | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | void hfsplus_attr_build_key_uni(hfsplus_btree_key *key, | ||
86 | u32 cnid, | ||
87 | struct hfsplus_attr_unistr *name) | ||
88 | { | ||
89 | int ustrlen; | ||
90 | |||
91 | memset(key, 0, sizeof(struct hfsplus_attr_key)); | ||
92 | ustrlen = be16_to_cpu(name->length); | ||
93 | key->attr.cnid = cpu_to_be32(cnid); | ||
94 | key->attr.key_name.length = cpu_to_be16(ustrlen); | ||
95 | ustrlen *= 2; | ||
96 | memcpy(key->attr.key_name.unicode, name->unicode, ustrlen); | ||
97 | |||
98 | /* The length of the key, as stored in key_len field, does not include | ||
99 | * the size of the key_len field itself. | ||
100 | * So, offsetof(hfsplus_attr_key, key_name) is a trick because | ||
101 | * it takes into consideration key_len field (__be16) of | ||
102 | * hfsplus_attr_key structure instead of length field (__be16) of | ||
103 | * hfsplus_attr_unistr structure. | ||
104 | */ | ||
105 | key->key_len = | ||
106 | cpu_to_be16(offsetof(struct hfsplus_attr_key, key_name) + | ||
107 | ustrlen); | ||
108 | } | ||
109 | |||
110 | hfsplus_attr_entry *hfsplus_alloc_attr_entry(void) | ||
111 | { | ||
112 | return kmem_cache_alloc(hfsplus_attr_tree_cachep, GFP_KERNEL); | ||
113 | } | ||
114 | |||
115 | void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry) | ||
116 | { | ||
117 | if (entry) | ||
118 | kmem_cache_free(hfsplus_attr_tree_cachep, entry); | ||
119 | } | ||
120 | |||
121 | #define HFSPLUS_INVALID_ATTR_RECORD -1 | ||
122 | |||
123 | static int hfsplus_attr_build_record(hfsplus_attr_entry *entry, int record_type, | ||
124 | u32 cnid, const void *value, size_t size) | ||
125 | { | ||
126 | if (record_type == HFSPLUS_ATTR_FORK_DATA) { | ||
127 | /* | ||
128 | * Mac OS X supports only inline data attributes. | ||
129 | * Do nothing | ||
130 | */ | ||
131 | memset(entry, 0, sizeof(*entry)); | ||
132 | return sizeof(struct hfsplus_attr_fork_data); | ||
133 | } else if (record_type == HFSPLUS_ATTR_EXTENTS) { | ||
134 | /* | ||
135 | * Mac OS X supports only inline data attributes. | ||
136 | * Do nothing. | ||
137 | */ | ||
138 | memset(entry, 0, sizeof(*entry)); | ||
139 | return sizeof(struct hfsplus_attr_extents); | ||
140 | } else if (record_type == HFSPLUS_ATTR_INLINE_DATA) { | ||
141 | u16 len; | ||
142 | |||
143 | memset(entry, 0, sizeof(struct hfsplus_attr_inline_data)); | ||
144 | entry->inline_data.record_type = cpu_to_be32(record_type); | ||
145 | if (size <= HFSPLUS_MAX_INLINE_DATA_SIZE) | ||
146 | len = size; | ||
147 | else | ||
148 | return HFSPLUS_INVALID_ATTR_RECORD; | ||
149 | entry->inline_data.length = cpu_to_be16(len); | ||
150 | memcpy(entry->inline_data.raw_bytes, value, len); | ||
151 | /* | ||
152 | * Align len on two-byte boundary. | ||
153 | * It needs to add pad byte if we have odd len. | ||
154 | */ | ||
155 | len = round_up(len, 2); | ||
156 | return offsetof(struct hfsplus_attr_inline_data, raw_bytes) + | ||
157 | len; | ||
158 | } else /* invalid input */ | ||
159 | memset(entry, 0, sizeof(*entry)); | ||
160 | |||
161 | return HFSPLUS_INVALID_ATTR_RECORD; | ||
162 | } | ||
163 | |||
164 | int hfsplus_find_attr(struct super_block *sb, u32 cnid, | ||
165 | const char *name, struct hfs_find_data *fd) | ||
166 | { | ||
167 | int err = 0; | ||
168 | |||
169 | dprint(DBG_ATTR_MOD, "find_attr: %s,%d\n", name ? name : NULL, cnid); | ||
170 | |||
171 | if (!HFSPLUS_SB(sb)->attr_tree) { | ||
172 | printk(KERN_ERR "hfs: attributes file doesn't exist\n"); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | if (name) { | ||
177 | err = hfsplus_attr_build_key(sb, fd->search_key, cnid, name); | ||
178 | if (err) | ||
179 | goto failed_find_attr; | ||
180 | err = hfs_brec_find(fd, hfs_find_rec_by_key); | ||
181 | if (err) | ||
182 | goto failed_find_attr; | ||
183 | } else { | ||
184 | err = hfsplus_attr_build_key(sb, fd->search_key, cnid, NULL); | ||
185 | if (err) | ||
186 | goto failed_find_attr; | ||
187 | err = hfs_brec_find(fd, hfs_find_1st_rec_by_cnid); | ||
188 | if (err) | ||
189 | goto failed_find_attr; | ||
190 | } | ||
191 | |||
192 | failed_find_attr: | ||
193 | return err; | ||
194 | } | ||
195 | |||
196 | int hfsplus_attr_exists(struct inode *inode, const char *name) | ||
197 | { | ||
198 | int err = 0; | ||
199 | struct super_block *sb = inode->i_sb; | ||
200 | struct hfs_find_data fd; | ||
201 | |||
202 | if (!HFSPLUS_SB(sb)->attr_tree) | ||
203 | return 0; | ||
204 | |||
205 | err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd); | ||
206 | if (err) | ||
207 | return 0; | ||
208 | |||
209 | err = hfsplus_find_attr(sb, inode->i_ino, name, &fd); | ||
210 | if (err) | ||
211 | goto attr_not_found; | ||
212 | |||
213 | hfs_find_exit(&fd); | ||
214 | return 1; | ||
215 | |||
216 | attr_not_found: | ||
217 | hfs_find_exit(&fd); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | int hfsplus_create_attr(struct inode *inode, | ||
222 | const char *name, | ||
223 | const void *value, size_t size) | ||
224 | { | ||
225 | struct super_block *sb = inode->i_sb; | ||
226 | struct hfs_find_data fd; | ||
227 | hfsplus_attr_entry *entry_ptr; | ||
228 | int entry_size; | ||
229 | int err; | ||
230 | |||
231 | dprint(DBG_ATTR_MOD, "create_attr: %s,%ld\n", | ||
232 | name ? name : NULL, inode->i_ino); | ||
233 | |||
234 | if (!HFSPLUS_SB(sb)->attr_tree) { | ||
235 | printk(KERN_ERR "hfs: attributes file doesn't exist\n"); | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | entry_ptr = hfsplus_alloc_attr_entry(); | ||
240 | if (!entry_ptr) | ||
241 | return -ENOMEM; | ||
242 | |||
243 | err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd); | ||
244 | if (err) | ||
245 | goto failed_init_create_attr; | ||
246 | |||
247 | if (name) { | ||
248 | err = hfsplus_attr_build_key(sb, fd.search_key, | ||
249 | inode->i_ino, name); | ||
250 | if (err) | ||
251 | goto failed_create_attr; | ||
252 | } else { | ||
253 | err = -EINVAL; | ||
254 | goto failed_create_attr; | ||
255 | } | ||
256 | |||
257 | /* Mac OS X supports only inline data attributes. */ | ||
258 | entry_size = hfsplus_attr_build_record(entry_ptr, | ||
259 | HFSPLUS_ATTR_INLINE_DATA, | ||
260 | inode->i_ino, | ||
261 | value, size); | ||
262 | if (entry_size == HFSPLUS_INVALID_ATTR_RECORD) { | ||
263 | err = -EINVAL; | ||
264 | goto failed_create_attr; | ||
265 | } | ||
266 | |||
267 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); | ||
268 | if (err != -ENOENT) { | ||
269 | if (!err) | ||
270 | err = -EEXIST; | ||
271 | goto failed_create_attr; | ||
272 | } | ||
273 | |||
274 | err = hfs_brec_insert(&fd, entry_ptr, entry_size); | ||
275 | if (err) | ||
276 | goto failed_create_attr; | ||
277 | |||
278 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY); | ||
279 | |||
280 | failed_create_attr: | ||
281 | hfs_find_exit(&fd); | ||
282 | |||
283 | failed_init_create_attr: | ||
284 | hfsplus_destroy_attr_entry(entry_ptr); | ||
285 | return err; | ||
286 | } | ||
287 | |||
288 | static int __hfsplus_delete_attr(struct inode *inode, u32 cnid, | ||
289 | struct hfs_find_data *fd) | ||
290 | { | ||
291 | int err = 0; | ||
292 | __be32 found_cnid, record_type; | ||
293 | |||
294 | hfs_bnode_read(fd->bnode, &found_cnid, | ||
295 | fd->keyoffset + | ||
296 | offsetof(struct hfsplus_attr_key, cnid), | ||
297 | sizeof(__be32)); | ||
298 | if (cnid != be32_to_cpu(found_cnid)) | ||
299 | return -ENOENT; | ||
300 | |||
301 | hfs_bnode_read(fd->bnode, &record_type, | ||
302 | fd->entryoffset, sizeof(record_type)); | ||
303 | |||
304 | switch (be32_to_cpu(record_type)) { | ||
305 | case HFSPLUS_ATTR_INLINE_DATA: | ||
306 | /* All is OK. Do nothing. */ | ||
307 | break; | ||
308 | case HFSPLUS_ATTR_FORK_DATA: | ||
309 | case HFSPLUS_ATTR_EXTENTS: | ||
310 | printk(KERN_ERR "hfs: only inline data xattr are supported\n"); | ||
311 | return -EOPNOTSUPP; | ||
312 | default: | ||
313 | printk(KERN_ERR "hfs: invalid extended attribute record\n"); | ||
314 | return -ENOENT; | ||
315 | } | ||
316 | |||
317 | err = hfs_brec_remove(fd); | ||
318 | if (err) | ||
319 | return err; | ||
320 | |||
321 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY); | ||
322 | return err; | ||
323 | } | ||
324 | |||
325 | int hfsplus_delete_attr(struct inode *inode, const char *name) | ||
326 | { | ||
327 | int err = 0; | ||
328 | struct super_block *sb = inode->i_sb; | ||
329 | struct hfs_find_data fd; | ||
330 | |||
331 | dprint(DBG_ATTR_MOD, "delete_attr: %s,%ld\n", | ||
332 | name ? name : NULL, inode->i_ino); | ||
333 | |||
334 | if (!HFSPLUS_SB(sb)->attr_tree) { | ||
335 | printk(KERN_ERR "hfs: attributes file doesn't exist\n"); | ||
336 | return -EINVAL; | ||
337 | } | ||
338 | |||
339 | err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd); | ||
340 | if (err) | ||
341 | return err; | ||
342 | |||
343 | if (name) { | ||
344 | err = hfsplus_attr_build_key(sb, fd.search_key, | ||
345 | inode->i_ino, name); | ||
346 | if (err) | ||
347 | goto out; | ||
348 | } else { | ||
349 | printk(KERN_ERR "hfs: invalid extended attribute name\n"); | ||
350 | err = -EINVAL; | ||
351 | goto out; | ||
352 | } | ||
353 | |||
354 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); | ||
355 | if (err) | ||
356 | goto out; | ||
357 | |||
358 | err = __hfsplus_delete_attr(inode, inode->i_ino, &fd); | ||
359 | if (err) | ||
360 | goto out; | ||
361 | |||
362 | out: | ||
363 | hfs_find_exit(&fd); | ||
364 | return err; | ||
365 | } | ||
366 | |||
367 | int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid) | ||
368 | { | ||
369 | int err = 0; | ||
370 | struct hfs_find_data fd; | ||
371 | |||
372 | dprint(DBG_ATTR_MOD, "delete_all_attrs: %d\n", cnid); | ||
373 | |||
374 | if (!HFSPLUS_SB(dir->i_sb)->attr_tree) { | ||
375 | printk(KERN_ERR "hfs: attributes file doesn't exist\n"); | ||
376 | return -EINVAL; | ||
377 | } | ||
378 | |||
379 | err = hfs_find_init(HFSPLUS_SB(dir->i_sb)->attr_tree, &fd); | ||
380 | if (err) | ||
381 | return err; | ||
382 | |||
383 | for (;;) { | ||
384 | err = hfsplus_find_attr(dir->i_sb, cnid, NULL, &fd); | ||
385 | if (err) { | ||
386 | if (err != -ENOENT) | ||
387 | printk(KERN_ERR "hfs: xattr search failed.\n"); | ||
388 | goto end_delete_all; | ||
389 | } | ||
390 | |||
391 | err = __hfsplus_delete_attr(dir, cnid, &fd); | ||
392 | if (err) | ||
393 | goto end_delete_all; | ||
394 | } | ||
395 | |||
396 | end_delete_all: | ||
397 | hfs_find_exit(&fd); | ||
398 | return err; | ||
399 | } | ||
diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c index 5d799c13205f..d73c98d1ee99 100644 --- a/fs/hfsplus/bfind.c +++ b/fs/hfsplus/bfind.c | |||
@@ -24,7 +24,19 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd) | |||
24 | fd->key = ptr + tree->max_key_len + 2; | 24 | fd->key = ptr + tree->max_key_len + 2; |
25 | dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", | 25 | dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", |
26 | tree->cnid, __builtin_return_address(0)); | 26 | tree->cnid, __builtin_return_address(0)); |
27 | mutex_lock(&tree->tree_lock); | 27 | switch (tree->cnid) { |
28 | case HFSPLUS_CAT_CNID: | ||
29 | mutex_lock_nested(&tree->tree_lock, CATALOG_BTREE_MUTEX); | ||
30 | break; | ||
31 | case HFSPLUS_EXT_CNID: | ||
32 | mutex_lock_nested(&tree->tree_lock, EXTENTS_BTREE_MUTEX); | ||
33 | break; | ||
34 | case HFSPLUS_ATTR_CNID: | ||
35 | mutex_lock_nested(&tree->tree_lock, ATTR_BTREE_MUTEX); | ||
36 | break; | ||
37 | default: | ||
38 | BUG(); | ||
39 | } | ||
28 | return 0; | 40 | return 0; |
29 | } | 41 | } |
30 | 42 | ||
@@ -38,15 +50,73 @@ void hfs_find_exit(struct hfs_find_data *fd) | |||
38 | fd->tree = NULL; | 50 | fd->tree = NULL; |
39 | } | 51 | } |
40 | 52 | ||
41 | /* Find the record in bnode that best matches key (not greater than...)*/ | 53 | int hfs_find_1st_rec_by_cnid(struct hfs_bnode *bnode, |
42 | int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) | 54 | struct hfs_find_data *fd, |
55 | int *begin, | ||
56 | int *end, | ||
57 | int *cur_rec) | ||
58 | { | ||
59 | __be32 cur_cnid, search_cnid; | ||
60 | |||
61 | if (bnode->tree->cnid == HFSPLUS_EXT_CNID) { | ||
62 | cur_cnid = fd->key->ext.cnid; | ||
63 | search_cnid = fd->search_key->ext.cnid; | ||
64 | } else if (bnode->tree->cnid == HFSPLUS_CAT_CNID) { | ||
65 | cur_cnid = fd->key->cat.parent; | ||
66 | search_cnid = fd->search_key->cat.parent; | ||
67 | } else if (bnode->tree->cnid == HFSPLUS_ATTR_CNID) { | ||
68 | cur_cnid = fd->key->attr.cnid; | ||
69 | search_cnid = fd->search_key->attr.cnid; | ||
70 | } else | ||
71 | BUG(); | ||
72 | |||
73 | if (cur_cnid == search_cnid) { | ||
74 | (*end) = (*cur_rec); | ||
75 | if ((*begin) == (*end)) | ||
76 | return 1; | ||
77 | } else { | ||
78 | if (be32_to_cpu(cur_cnid) < be32_to_cpu(search_cnid)) | ||
79 | (*begin) = (*cur_rec) + 1; | ||
80 | else | ||
81 | (*end) = (*cur_rec) - 1; | ||
82 | } | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | int hfs_find_rec_by_key(struct hfs_bnode *bnode, | ||
88 | struct hfs_find_data *fd, | ||
89 | int *begin, | ||
90 | int *end, | ||
91 | int *cur_rec) | ||
43 | { | 92 | { |
44 | int cmpval; | 93 | int cmpval; |
94 | |||
95 | cmpval = bnode->tree->keycmp(fd->key, fd->search_key); | ||
96 | if (!cmpval) { | ||
97 | (*end) = (*cur_rec); | ||
98 | return 1; | ||
99 | } | ||
100 | if (cmpval < 0) | ||
101 | (*begin) = (*cur_rec) + 1; | ||
102 | else | ||
103 | *(end) = (*cur_rec) - 1; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | /* Find the record in bnode that best matches key (not greater than...)*/ | ||
109 | int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd, | ||
110 | search_strategy_t rec_found) | ||
111 | { | ||
45 | u16 off, len, keylen; | 112 | u16 off, len, keylen; |
46 | int rec; | 113 | int rec; |
47 | int b, e; | 114 | int b, e; |
48 | int res; | 115 | int res; |
49 | 116 | ||
117 | if (!rec_found) | ||
118 | BUG(); | ||
119 | |||
50 | b = 0; | 120 | b = 0; |
51 | e = bnode->num_recs - 1; | 121 | e = bnode->num_recs - 1; |
52 | res = -ENOENT; | 122 | res = -ENOENT; |
@@ -59,17 +129,12 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) | |||
59 | goto fail; | 129 | goto fail; |
60 | } | 130 | } |
61 | hfs_bnode_read(bnode, fd->key, off, keylen); | 131 | hfs_bnode_read(bnode, fd->key, off, keylen); |
62 | cmpval = bnode->tree->keycmp(fd->key, fd->search_key); | 132 | if (rec_found(bnode, fd, &b, &e, &rec)) { |
63 | if (!cmpval) { | ||
64 | e = rec; | ||
65 | res = 0; | 133 | res = 0; |
66 | goto done; | 134 | goto done; |
67 | } | 135 | } |
68 | if (cmpval < 0) | ||
69 | b = rec + 1; | ||
70 | else | ||
71 | e = rec - 1; | ||
72 | } while (b <= e); | 136 | } while (b <= e); |
137 | |||
73 | if (rec != e && e >= 0) { | 138 | if (rec != e && e >= 0) { |
74 | len = hfs_brec_lenoff(bnode, e, &off); | 139 | len = hfs_brec_lenoff(bnode, e, &off); |
75 | keylen = hfs_brec_keylen(bnode, e); | 140 | keylen = hfs_brec_keylen(bnode, e); |
@@ -79,19 +144,21 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) | |||
79 | } | 144 | } |
80 | hfs_bnode_read(bnode, fd->key, off, keylen); | 145 | hfs_bnode_read(bnode, fd->key, off, keylen); |
81 | } | 146 | } |
147 | |||
82 | done: | 148 | done: |
83 | fd->record = e; | 149 | fd->record = e; |
84 | fd->keyoffset = off; | 150 | fd->keyoffset = off; |
85 | fd->keylength = keylen; | 151 | fd->keylength = keylen; |
86 | fd->entryoffset = off + keylen; | 152 | fd->entryoffset = off + keylen; |
87 | fd->entrylength = len - keylen; | 153 | fd->entrylength = len - keylen; |
154 | |||
88 | fail: | 155 | fail: |
89 | return res; | 156 | return res; |
90 | } | 157 | } |
91 | 158 | ||
92 | /* Traverse a B*Tree from the root to a leaf finding best fit to key */ | 159 | /* Traverse a B*Tree from the root to a leaf finding best fit to key */ |
93 | /* Return allocated copy of node found, set recnum to best record */ | 160 | /* Return allocated copy of node found, set recnum to best record */ |
94 | int hfs_brec_find(struct hfs_find_data *fd) | 161 | int hfs_brec_find(struct hfs_find_data *fd, search_strategy_t do_key_compare) |
95 | { | 162 | { |
96 | struct hfs_btree *tree; | 163 | struct hfs_btree *tree; |
97 | struct hfs_bnode *bnode; | 164 | struct hfs_bnode *bnode; |
@@ -122,7 +189,7 @@ int hfs_brec_find(struct hfs_find_data *fd) | |||
122 | goto invalid; | 189 | goto invalid; |
123 | bnode->parent = parent; | 190 | bnode->parent = parent; |
124 | 191 | ||
125 | res = __hfs_brec_find(bnode, fd); | 192 | res = __hfs_brec_find(bnode, fd, do_key_compare); |
126 | if (!height) | 193 | if (!height) |
127 | break; | 194 | break; |
128 | if (fd->record < 0) | 195 | if (fd->record < 0) |
@@ -149,7 +216,7 @@ int hfs_brec_read(struct hfs_find_data *fd, void *rec, int rec_len) | |||
149 | { | 216 | { |
150 | int res; | 217 | int res; |
151 | 218 | ||
152 | res = hfs_brec_find(fd); | 219 | res = hfs_brec_find(fd, hfs_find_rec_by_key); |
153 | if (res) | 220 | if (res) |
154 | return res; | 221 | return res; |
155 | if (fd->entrylength > rec_len) | 222 | if (fd->entrylength > rec_len) |
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 1c42cc5b899f..f31ac6f404f1 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c | |||
@@ -62,7 +62,8 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off) | |||
62 | 62 | ||
63 | tree = node->tree; | 63 | tree = node->tree; |
64 | if (node->type == HFS_NODE_LEAF || | 64 | if (node->type == HFS_NODE_LEAF || |
65 | tree->attributes & HFS_TREE_VARIDXKEYS) | 65 | tree->attributes & HFS_TREE_VARIDXKEYS || |
66 | node->tree->cnid == HFSPLUS_ATTR_CNID) | ||
66 | key_len = hfs_bnode_read_u16(node, off) + 2; | 67 | key_len = hfs_bnode_read_u16(node, off) + 2; |
67 | else | 68 | else |
68 | key_len = tree->max_key_len + 2; | 69 | key_len = tree->max_key_len + 2; |
@@ -314,7 +315,8 @@ void hfs_bnode_dump(struct hfs_bnode *node) | |||
314 | if (i && node->type == HFS_NODE_INDEX) { | 315 | if (i && node->type == HFS_NODE_INDEX) { |
315 | int tmp; | 316 | int tmp; |
316 | 317 | ||
317 | if (node->tree->attributes & HFS_TREE_VARIDXKEYS) | 318 | if (node->tree->attributes & HFS_TREE_VARIDXKEYS || |
319 | node->tree->cnid == HFSPLUS_ATTR_CNID) | ||
318 | tmp = hfs_bnode_read_u16(node, key_off) + 2; | 320 | tmp = hfs_bnode_read_u16(node, key_off) + 2; |
319 | else | 321 | else |
320 | tmp = node->tree->max_key_len + 2; | 322 | tmp = node->tree->max_key_len + 2; |
@@ -646,6 +648,8 @@ void hfs_bnode_put(struct hfs_bnode *node) | |||
646 | if (test_bit(HFS_BNODE_DELETED, &node->flags)) { | 648 | if (test_bit(HFS_BNODE_DELETED, &node->flags)) { |
647 | hfs_bnode_unhash(node); | 649 | hfs_bnode_unhash(node); |
648 | spin_unlock(&tree->hash_lock); | 650 | spin_unlock(&tree->hash_lock); |
651 | hfs_bnode_clear(node, 0, | ||
652 | PAGE_CACHE_SIZE * tree->pages_per_bnode); | ||
649 | hfs_bmap_free(node); | 653 | hfs_bmap_free(node); |
650 | hfs_bnode_free(node); | 654 | hfs_bnode_free(node); |
651 | return; | 655 | return; |
diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c index 2a734cfccc92..298d4e45604b 100644 --- a/fs/hfsplus/brec.c +++ b/fs/hfsplus/brec.c | |||
@@ -36,7 +36,8 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec) | |||
36 | return 0; | 36 | return 0; |
37 | 37 | ||
38 | if ((node->type == HFS_NODE_INDEX) && | 38 | if ((node->type == HFS_NODE_INDEX) && |
39 | !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) { | 39 | !(node->tree->attributes & HFS_TREE_VARIDXKEYS) && |
40 | (node->tree->cnid != HFSPLUS_ATTR_CNID)) { | ||
40 | retval = node->tree->max_key_len + 2; | 41 | retval = node->tree->max_key_len + 2; |
41 | } else { | 42 | } else { |
42 | recoff = hfs_bnode_read_u16(node, | 43 | recoff = hfs_bnode_read_u16(node, |
@@ -151,12 +152,13 @@ skip: | |||
151 | 152 | ||
152 | /* get index key */ | 153 | /* get index key */ |
153 | hfs_bnode_read_key(new_node, fd->search_key, 14); | 154 | hfs_bnode_read_key(new_node, fd->search_key, 14); |
154 | __hfs_brec_find(fd->bnode, fd); | 155 | __hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key); |
155 | 156 | ||
156 | hfs_bnode_put(new_node); | 157 | hfs_bnode_put(new_node); |
157 | new_node = NULL; | 158 | new_node = NULL; |
158 | 159 | ||
159 | if (tree->attributes & HFS_TREE_VARIDXKEYS) | 160 | if ((tree->attributes & HFS_TREE_VARIDXKEYS) || |
161 | (tree->cnid == HFSPLUS_ATTR_CNID)) | ||
160 | key_len = be16_to_cpu(fd->search_key->key_len) + 2; | 162 | key_len = be16_to_cpu(fd->search_key->key_len) + 2; |
161 | else { | 163 | else { |
162 | fd->search_key->key_len = | 164 | fd->search_key->key_len = |
@@ -201,7 +203,7 @@ again: | |||
201 | hfs_bnode_put(node); | 203 | hfs_bnode_put(node); |
202 | node = fd->bnode = parent; | 204 | node = fd->bnode = parent; |
203 | 205 | ||
204 | __hfs_brec_find(node, fd); | 206 | __hfs_brec_find(node, fd, hfs_find_rec_by_key); |
205 | goto again; | 207 | goto again; |
206 | } | 208 | } |
207 | hfs_bnode_write_u16(node, | 209 | hfs_bnode_write_u16(node, |
@@ -367,12 +369,13 @@ again: | |||
367 | parent = hfs_bnode_find(tree, node->parent); | 369 | parent = hfs_bnode_find(tree, node->parent); |
368 | if (IS_ERR(parent)) | 370 | if (IS_ERR(parent)) |
369 | return PTR_ERR(parent); | 371 | return PTR_ERR(parent); |
370 | __hfs_brec_find(parent, fd); | 372 | __hfs_brec_find(parent, fd, hfs_find_rec_by_key); |
371 | hfs_bnode_dump(parent); | 373 | hfs_bnode_dump(parent); |
372 | rec = fd->record; | 374 | rec = fd->record; |
373 | 375 | ||
374 | /* size difference between old and new key */ | 376 | /* size difference between old and new key */ |
375 | if (tree->attributes & HFS_TREE_VARIDXKEYS) | 377 | if ((tree->attributes & HFS_TREE_VARIDXKEYS) || |
378 | (tree->cnid == HFSPLUS_ATTR_CNID)) | ||
376 | newkeylen = hfs_bnode_read_u16(node, 14) + 2; | 379 | newkeylen = hfs_bnode_read_u16(node, 14) + 2; |
377 | else | 380 | else |
378 | fd->keylength = newkeylen = tree->max_key_len + 2; | 381 | fd->keylength = newkeylen = tree->max_key_len + 2; |
@@ -427,7 +430,7 @@ skip: | |||
427 | hfs_bnode_read_key(new_node, fd->search_key, 14); | 430 | hfs_bnode_read_key(new_node, fd->search_key, 14); |
428 | cnid = cpu_to_be32(new_node->this); | 431 | cnid = cpu_to_be32(new_node->this); |
429 | 432 | ||
430 | __hfs_brec_find(fd->bnode, fd); | 433 | __hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key); |
431 | hfs_brec_insert(fd, &cnid, sizeof(cnid)); | 434 | hfs_brec_insert(fd, &cnid, sizeof(cnid)); |
432 | hfs_bnode_put(fd->bnode); | 435 | hfs_bnode_put(fd->bnode); |
433 | hfs_bnode_put(new_node); | 436 | hfs_bnode_put(new_node); |
@@ -495,13 +498,15 @@ static int hfs_btree_inc_height(struct hfs_btree *tree) | |||
495 | /* insert old root idx into new root */ | 498 | /* insert old root idx into new root */ |
496 | node->parent = tree->root; | 499 | node->parent = tree->root; |
497 | if (node->type == HFS_NODE_LEAF || | 500 | if (node->type == HFS_NODE_LEAF || |
498 | tree->attributes & HFS_TREE_VARIDXKEYS) | 501 | tree->attributes & HFS_TREE_VARIDXKEYS || |
502 | tree->cnid == HFSPLUS_ATTR_CNID) | ||
499 | key_size = hfs_bnode_read_u16(node, 14) + 2; | 503 | key_size = hfs_bnode_read_u16(node, 14) + 2; |
500 | else | 504 | else |
501 | key_size = tree->max_key_len + 2; | 505 | key_size = tree->max_key_len + 2; |
502 | hfs_bnode_copy(new_node, 14, node, 14, key_size); | 506 | hfs_bnode_copy(new_node, 14, node, 14, key_size); |
503 | 507 | ||
504 | if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) { | 508 | if (!(tree->attributes & HFS_TREE_VARIDXKEYS) && |
509 | (tree->cnid != HFSPLUS_ATTR_CNID)) { | ||
505 | key_size = tree->max_key_len + 2; | 510 | key_size = tree->max_key_len + 2; |
506 | hfs_bnode_write_u16(new_node, 14, tree->max_key_len); | 511 | hfs_bnode_write_u16(new_node, 14, tree->max_key_len); |
507 | } | 512 | } |
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 685d07d0ed18..efb689c21a95 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c | |||
@@ -98,6 +98,14 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
98 | set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); | 98 | set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); |
99 | } | 99 | } |
100 | break; | 100 | break; |
101 | case HFSPLUS_ATTR_CNID: | ||
102 | if (tree->max_key_len != HFSPLUS_ATTR_KEYLEN - sizeof(u16)) { | ||
103 | printk(KERN_ERR "hfs: invalid attributes max_key_len %d\n", | ||
104 | tree->max_key_len); | ||
105 | goto fail_page; | ||
106 | } | ||
107 | tree->keycmp = hfsplus_attr_bin_cmp_key; | ||
108 | break; | ||
101 | default: | 109 | default: |
102 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | 110 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); |
103 | goto fail_page; | 111 | goto fail_page; |
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 798d9c4c5e71..840d71edd193 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c | |||
@@ -45,7 +45,8 @@ void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, | |||
45 | 45 | ||
46 | key->cat.parent = cpu_to_be32(parent); | 46 | key->cat.parent = cpu_to_be32(parent); |
47 | if (str) { | 47 | if (str) { |
48 | hfsplus_asc2uni(sb, &key->cat.name, str->name, str->len); | 48 | hfsplus_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN, |
49 | str->name, str->len); | ||
49 | len = be16_to_cpu(key->cat.name.length); | 50 | len = be16_to_cpu(key->cat.name.length); |
50 | } else { | 51 | } else { |
51 | key->cat.name.length = 0; | 52 | key->cat.name.length = 0; |
@@ -167,7 +168,8 @@ static int hfsplus_fill_cat_thread(struct super_block *sb, | |||
167 | entry->type = cpu_to_be16(type); | 168 | entry->type = cpu_to_be16(type); |
168 | entry->thread.reserved = 0; | 169 | entry->thread.reserved = 0; |
169 | entry->thread.parentID = cpu_to_be32(parentid); | 170 | entry->thread.parentID = cpu_to_be32(parentid); |
170 | hfsplus_asc2uni(sb, &entry->thread.nodeName, str->name, str->len); | 171 | hfsplus_asc2uni(sb, &entry->thread.nodeName, HFSPLUS_MAX_STRLEN, |
172 | str->name, str->len); | ||
171 | return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2; | 173 | return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2; |
172 | } | 174 | } |
173 | 175 | ||
@@ -198,7 +200,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid, | |||
198 | hfsplus_cat_build_key_uni(fd->search_key, | 200 | hfsplus_cat_build_key_uni(fd->search_key, |
199 | be32_to_cpu(tmp.thread.parentID), | 201 | be32_to_cpu(tmp.thread.parentID), |
200 | &tmp.thread.nodeName); | 202 | &tmp.thread.nodeName); |
201 | return hfs_brec_find(fd); | 203 | return hfs_brec_find(fd, hfs_find_rec_by_key); |
202 | } | 204 | } |
203 | 205 | ||
204 | int hfsplus_create_cat(u32 cnid, struct inode *dir, | 206 | int hfsplus_create_cat(u32 cnid, struct inode *dir, |
@@ -221,7 +223,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, | |||
221 | S_ISDIR(inode->i_mode) ? | 223 | S_ISDIR(inode->i_mode) ? |
222 | HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, | 224 | HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, |
223 | dir->i_ino, str); | 225 | dir->i_ino, str); |
224 | err = hfs_brec_find(&fd); | 226 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
225 | if (err != -ENOENT) { | 227 | if (err != -ENOENT) { |
226 | if (!err) | 228 | if (!err) |
227 | err = -EEXIST; | 229 | err = -EEXIST; |
@@ -233,7 +235,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, | |||
233 | 235 | ||
234 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); | 236 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); |
235 | entry_size = hfsplus_cat_build_record(&entry, cnid, inode); | 237 | entry_size = hfsplus_cat_build_record(&entry, cnid, inode); |
236 | err = hfs_brec_find(&fd); | 238 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
237 | if (err != -ENOENT) { | 239 | if (err != -ENOENT) { |
238 | /* panic? */ | 240 | /* panic? */ |
239 | if (!err) | 241 | if (!err) |
@@ -253,7 +255,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, | |||
253 | 255 | ||
254 | err1: | 256 | err1: |
255 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 257 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); |
256 | if (!hfs_brec_find(&fd)) | 258 | if (!hfs_brec_find(&fd, hfs_find_rec_by_key)) |
257 | hfs_brec_remove(&fd); | 259 | hfs_brec_remove(&fd); |
258 | err2: | 260 | err2: |
259 | hfs_find_exit(&fd); | 261 | hfs_find_exit(&fd); |
@@ -279,7 +281,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
279 | int len; | 281 | int len; |
280 | 282 | ||
281 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 283 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); |
282 | err = hfs_brec_find(&fd); | 284 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
283 | if (err) | 285 | if (err) |
284 | goto out; | 286 | goto out; |
285 | 287 | ||
@@ -296,7 +298,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
296 | } else | 298 | } else |
297 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); | 299 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); |
298 | 300 | ||
299 | err = hfs_brec_find(&fd); | 301 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
300 | if (err) | 302 | if (err) |
301 | goto out; | 303 | goto out; |
302 | 304 | ||
@@ -326,7 +328,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
326 | goto out; | 328 | goto out; |
327 | 329 | ||
328 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 330 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); |
329 | err = hfs_brec_find(&fd); | 331 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
330 | if (err) | 332 | if (err) |
331 | goto out; | 333 | goto out; |
332 | 334 | ||
@@ -337,6 +339,12 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
337 | dir->i_size--; | 339 | dir->i_size--; |
338 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | 340 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; |
339 | hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); | 341 | hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); |
342 | |||
343 | if (type == HFSPLUS_FILE || type == HFSPLUS_FOLDER) { | ||
344 | if (HFSPLUS_SB(sb)->attr_tree) | ||
345 | hfsplus_delete_all_attrs(dir, cnid); | ||
346 | } | ||
347 | |||
340 | out: | 348 | out: |
341 | hfs_find_exit(&fd); | 349 | hfs_find_exit(&fd); |
342 | 350 | ||
@@ -363,7 +371,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
363 | 371 | ||
364 | /* find the old dir entry and read the data */ | 372 | /* find the old dir entry and read the data */ |
365 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); | 373 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); |
366 | err = hfs_brec_find(&src_fd); | 374 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); |
367 | if (err) | 375 | if (err) |
368 | goto out; | 376 | goto out; |
369 | if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) { | 377 | if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) { |
@@ -376,7 +384,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
376 | 384 | ||
377 | /* create new dir entry with the data from the old entry */ | 385 | /* create new dir entry with the data from the old entry */ |
378 | hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name); | 386 | hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name); |
379 | err = hfs_brec_find(&dst_fd); | 387 | err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); |
380 | if (err != -ENOENT) { | 388 | if (err != -ENOENT) { |
381 | if (!err) | 389 | if (!err) |
382 | err = -EEXIST; | 390 | err = -EEXIST; |
@@ -391,7 +399,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
391 | 399 | ||
392 | /* finally remove the old entry */ | 400 | /* finally remove the old entry */ |
393 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); | 401 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); |
394 | err = hfs_brec_find(&src_fd); | 402 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); |
395 | if (err) | 403 | if (err) |
396 | goto out; | 404 | goto out; |
397 | err = hfs_brec_remove(&src_fd); | 405 | err = hfs_brec_remove(&src_fd); |
@@ -402,7 +410,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
402 | 410 | ||
403 | /* remove old thread entry */ | 411 | /* remove old thread entry */ |
404 | hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); | 412 | hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); |
405 | err = hfs_brec_find(&src_fd); | 413 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); |
406 | if (err) | 414 | if (err) |
407 | goto out; | 415 | goto out; |
408 | type = hfs_bnode_read_u16(src_fd.bnode, src_fd.entryoffset); | 416 | type = hfs_bnode_read_u16(src_fd.bnode, src_fd.entryoffset); |
@@ -414,7 +422,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
414 | hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL); | 422 | hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL); |
415 | entry_size = hfsplus_fill_cat_thread(sb, &entry, type, | 423 | entry_size = hfsplus_fill_cat_thread(sb, &entry, type, |
416 | dst_dir->i_ino, dst_name); | 424 | dst_dir->i_ino, dst_name); |
417 | err = hfs_brec_find(&dst_fd); | 425 | err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); |
418 | if (err != -ENOENT) { | 426 | if (err != -ENOENT) { |
419 | if (!err) | 427 | if (!err) |
420 | err = -EEXIST; | 428 | err = -EEXIST; |
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 074e04589248..031c24e50521 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include "hfsplus_fs.h" | 16 | #include "hfsplus_fs.h" |
17 | #include "hfsplus_raw.h" | 17 | #include "hfsplus_raw.h" |
18 | #include "xattr.h" | ||
18 | 19 | ||
19 | static inline void hfsplus_instantiate(struct dentry *dentry, | 20 | static inline void hfsplus_instantiate(struct dentry *dentry, |
20 | struct inode *inode, u32 cnid) | 21 | struct inode *inode, u32 cnid) |
@@ -138,7 +139,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
138 | if (err) | 139 | if (err) |
139 | return err; | 140 | return err; |
140 | hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); | 141 | hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); |
141 | err = hfs_brec_find(&fd); | 142 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
142 | if (err) | 143 | if (err) |
143 | goto out; | 144 | goto out; |
144 | 145 | ||
@@ -421,6 +422,15 @@ static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, | |||
421 | if (res) | 422 | if (res) |
422 | goto out_err; | 423 | goto out_err; |
423 | 424 | ||
425 | res = hfsplus_init_inode_security(inode, dir, &dentry->d_name); | ||
426 | if (res == -EOPNOTSUPP) | ||
427 | res = 0; /* Operation is not supported. */ | ||
428 | else if (res) { | ||
429 | /* Try to delete anyway without error analysis. */ | ||
430 | hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); | ||
431 | goto out_err; | ||
432 | } | ||
433 | |||
424 | hfsplus_instantiate(dentry, inode, inode->i_ino); | 434 | hfsplus_instantiate(dentry, inode, inode->i_ino); |
425 | mark_inode_dirty(inode); | 435 | mark_inode_dirty(inode); |
426 | goto out; | 436 | goto out; |
@@ -450,15 +460,26 @@ static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, | |||
450 | init_special_inode(inode, mode, rdev); | 460 | init_special_inode(inode, mode, rdev); |
451 | 461 | ||
452 | res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); | 462 | res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); |
453 | if (res) { | 463 | if (res) |
454 | clear_nlink(inode); | 464 | goto failed_mknod; |
455 | hfsplus_delete_inode(inode); | 465 | |
456 | iput(inode); | 466 | res = hfsplus_init_inode_security(inode, dir, &dentry->d_name); |
457 | goto out; | 467 | if (res == -EOPNOTSUPP) |
468 | res = 0; /* Operation is not supported. */ | ||
469 | else if (res) { | ||
470 | /* Try to delete anyway without error analysis. */ | ||
471 | hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); | ||
472 | goto failed_mknod; | ||
458 | } | 473 | } |
459 | 474 | ||
460 | hfsplus_instantiate(dentry, inode, inode->i_ino); | 475 | hfsplus_instantiate(dentry, inode, inode->i_ino); |
461 | mark_inode_dirty(inode); | 476 | mark_inode_dirty(inode); |
477 | goto out; | ||
478 | |||
479 | failed_mknod: | ||
480 | clear_nlink(inode); | ||
481 | hfsplus_delete_inode(inode); | ||
482 | iput(inode); | ||
462 | out: | 483 | out: |
463 | mutex_unlock(&sbi->vh_mutex); | 484 | mutex_unlock(&sbi->vh_mutex); |
464 | return res; | 485 | return res; |
@@ -499,15 +520,19 @@ static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
499 | } | 520 | } |
500 | 521 | ||
501 | const struct inode_operations hfsplus_dir_inode_operations = { | 522 | const struct inode_operations hfsplus_dir_inode_operations = { |
502 | .lookup = hfsplus_lookup, | 523 | .lookup = hfsplus_lookup, |
503 | .create = hfsplus_create, | 524 | .create = hfsplus_create, |
504 | .link = hfsplus_link, | 525 | .link = hfsplus_link, |
505 | .unlink = hfsplus_unlink, | 526 | .unlink = hfsplus_unlink, |
506 | .mkdir = hfsplus_mkdir, | 527 | .mkdir = hfsplus_mkdir, |
507 | .rmdir = hfsplus_rmdir, | 528 | .rmdir = hfsplus_rmdir, |
508 | .symlink = hfsplus_symlink, | 529 | .symlink = hfsplus_symlink, |
509 | .mknod = hfsplus_mknod, | 530 | .mknod = hfsplus_mknod, |
510 | .rename = hfsplus_rename, | 531 | .rename = hfsplus_rename, |
532 | .setxattr = generic_setxattr, | ||
533 | .getxattr = generic_getxattr, | ||
534 | .listxattr = hfsplus_listxattr, | ||
535 | .removexattr = hfsplus_removexattr, | ||
511 | }; | 536 | }; |
512 | 537 | ||
513 | const struct file_operations hfsplus_dir_operations = { | 538 | const struct file_operations hfsplus_dir_operations = { |
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index eba76eab6d62..a94f0f779d5e 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c | |||
@@ -95,7 +95,7 @@ static void __hfsplus_ext_write_extent(struct inode *inode, | |||
95 | HFSPLUS_IS_RSRC(inode) ? | 95 | HFSPLUS_IS_RSRC(inode) ? |
96 | HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); | 96 | HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); |
97 | 97 | ||
98 | res = hfs_brec_find(fd); | 98 | res = hfs_brec_find(fd, hfs_find_rec_by_key); |
99 | if (hip->extent_state & HFSPLUS_EXT_NEW) { | 99 | if (hip->extent_state & HFSPLUS_EXT_NEW) { |
100 | if (res != -ENOENT) | 100 | if (res != -ENOENT) |
101 | return; | 101 | return; |
@@ -154,7 +154,7 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, | |||
154 | 154 | ||
155 | hfsplus_ext_build_key(fd->search_key, cnid, block, type); | 155 | hfsplus_ext_build_key(fd->search_key, cnid, block, type); |
156 | fd->key->ext.cnid = 0; | 156 | fd->key->ext.cnid = 0; |
157 | res = hfs_brec_find(fd); | 157 | res = hfs_brec_find(fd, hfs_find_rec_by_key); |
158 | if (res && res != -ENOENT) | 158 | if (res && res != -ENOENT) |
159 | return res; | 159 | return res; |
160 | if (fd->key->ext.cnid != fd->search_key->ext.cnid || | 160 | if (fd->key->ext.cnid != fd->search_key->ext.cnid || |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index a6da86b1b4c1..05b11f36024c 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #define DBG_SUPER 0x00000010 | 23 | #define DBG_SUPER 0x00000010 |
24 | #define DBG_EXTENT 0x00000020 | 24 | #define DBG_EXTENT 0x00000020 |
25 | #define DBG_BITMAP 0x00000040 | 25 | #define DBG_BITMAP 0x00000040 |
26 | #define DBG_ATTR_MOD 0x00000080 | ||
26 | 27 | ||
27 | #if 0 | 28 | #if 0 |
28 | #define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD) | 29 | #define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD) |
@@ -46,6 +47,13 @@ typedef int (*btree_keycmp)(const hfsplus_btree_key *, | |||
46 | 47 | ||
47 | #define NODE_HASH_SIZE 256 | 48 | #define NODE_HASH_SIZE 256 |
48 | 49 | ||
50 | /* B-tree mutex nested subclasses */ | ||
51 | enum hfsplus_btree_mutex_classes { | ||
52 | CATALOG_BTREE_MUTEX, | ||
53 | EXTENTS_BTREE_MUTEX, | ||
54 | ATTR_BTREE_MUTEX, | ||
55 | }; | ||
56 | |||
49 | /* An HFS+ BTree held in memory */ | 57 | /* An HFS+ BTree held in memory */ |
50 | struct hfs_btree { | 58 | struct hfs_btree { |
51 | struct super_block *sb; | 59 | struct super_block *sb; |
@@ -223,6 +231,7 @@ struct hfsplus_inode_info { | |||
223 | #define HFSPLUS_I_CAT_DIRTY 1 /* has changes in the catalog tree */ | 231 | #define HFSPLUS_I_CAT_DIRTY 1 /* has changes in the catalog tree */ |
224 | #define HFSPLUS_I_EXT_DIRTY 2 /* has changes in the extent tree */ | 232 | #define HFSPLUS_I_EXT_DIRTY 2 /* has changes in the extent tree */ |
225 | #define HFSPLUS_I_ALLOC_DIRTY 3 /* has changes in the allocation file */ | 233 | #define HFSPLUS_I_ALLOC_DIRTY 3 /* has changes in the allocation file */ |
234 | #define HFSPLUS_I_ATTR_DIRTY 4 /* has changes in the attributes tree */ | ||
226 | 235 | ||
227 | #define HFSPLUS_IS_RSRC(inode) \ | 236 | #define HFSPLUS_IS_RSRC(inode) \ |
228 | test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags) | 237 | test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags) |
@@ -302,7 +311,7 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb) | |||
302 | #define hfs_brec_remove hfsplus_brec_remove | 311 | #define hfs_brec_remove hfsplus_brec_remove |
303 | #define hfs_find_init hfsplus_find_init | 312 | #define hfs_find_init hfsplus_find_init |
304 | #define hfs_find_exit hfsplus_find_exit | 313 | #define hfs_find_exit hfsplus_find_exit |
305 | #define __hfs_brec_find __hplusfs_brec_find | 314 | #define __hfs_brec_find __hfsplus_brec_find |
306 | #define hfs_brec_find hfsplus_brec_find | 315 | #define hfs_brec_find hfsplus_brec_find |
307 | #define hfs_brec_read hfsplus_brec_read | 316 | #define hfs_brec_read hfsplus_brec_read |
308 | #define hfs_brec_goto hfsplus_brec_goto | 317 | #define hfs_brec_goto hfsplus_brec_goto |
@@ -324,10 +333,33 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb) | |||
324 | */ | 333 | */ |
325 | #define HFSPLUS_IOC_BLESS _IO('h', 0x80) | 334 | #define HFSPLUS_IOC_BLESS _IO('h', 0x80) |
326 | 335 | ||
336 | typedef int (*search_strategy_t)(struct hfs_bnode *, | ||
337 | struct hfs_find_data *, | ||
338 | int *, int *, int *); | ||
339 | |||
327 | /* | 340 | /* |
328 | * Functions in any *.c used in other files | 341 | * Functions in any *.c used in other files |
329 | */ | 342 | */ |
330 | 343 | ||
344 | /* attributes.c */ | ||
345 | int hfsplus_create_attr_tree_cache(void); | ||
346 | void hfsplus_destroy_attr_tree_cache(void); | ||
347 | hfsplus_attr_entry *hfsplus_alloc_attr_entry(void); | ||
348 | void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry_p); | ||
349 | int hfsplus_attr_bin_cmp_key(const hfsplus_btree_key *, | ||
350 | const hfsplus_btree_key *); | ||
351 | int hfsplus_attr_build_key(struct super_block *, hfsplus_btree_key *, | ||
352 | u32, const char *); | ||
353 | void hfsplus_attr_build_key_uni(hfsplus_btree_key *key, | ||
354 | u32 cnid, | ||
355 | struct hfsplus_attr_unistr *name); | ||
356 | int hfsplus_find_attr(struct super_block *, u32, | ||
357 | const char *, struct hfs_find_data *); | ||
358 | int hfsplus_attr_exists(struct inode *inode, const char *name); | ||
359 | int hfsplus_create_attr(struct inode *, const char *, const void *, size_t); | ||
360 | int hfsplus_delete_attr(struct inode *, const char *); | ||
361 | int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid); | ||
362 | |||
331 | /* bitmap.c */ | 363 | /* bitmap.c */ |
332 | int hfsplus_block_allocate(struct super_block *, u32, u32, u32 *); | 364 | int hfsplus_block_allocate(struct super_block *, u32, u32, u32 *); |
333 | int hfsplus_block_free(struct super_block *, u32, u32); | 365 | int hfsplus_block_free(struct super_block *, u32, u32); |
@@ -369,8 +401,15 @@ int hfs_brec_remove(struct hfs_find_data *); | |||
369 | /* bfind.c */ | 401 | /* bfind.c */ |
370 | int hfs_find_init(struct hfs_btree *, struct hfs_find_data *); | 402 | int hfs_find_init(struct hfs_btree *, struct hfs_find_data *); |
371 | void hfs_find_exit(struct hfs_find_data *); | 403 | void hfs_find_exit(struct hfs_find_data *); |
372 | int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *); | 404 | int hfs_find_1st_rec_by_cnid(struct hfs_bnode *, |
373 | int hfs_brec_find(struct hfs_find_data *); | 405 | struct hfs_find_data *, |
406 | int *, int *, int *); | ||
407 | int hfs_find_rec_by_key(struct hfs_bnode *, | ||
408 | struct hfs_find_data *, | ||
409 | int *, int *, int *); | ||
410 | int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *, | ||
411 | search_strategy_t); | ||
412 | int hfs_brec_find(struct hfs_find_data *, search_strategy_t); | ||
374 | int hfs_brec_read(struct hfs_find_data *, void *, int); | 413 | int hfs_brec_read(struct hfs_find_data *, void *, int); |
375 | int hfs_brec_goto(struct hfs_find_data *, int); | 414 | int hfs_brec_goto(struct hfs_find_data *, int); |
376 | 415 | ||
@@ -417,11 +456,6 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, | |||
417 | 456 | ||
418 | /* ioctl.c */ | 457 | /* ioctl.c */ |
419 | long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); | 458 | long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); |
420 | int hfsplus_setxattr(struct dentry *dentry, const char *name, | ||
421 | const void *value, size_t size, int flags); | ||
422 | ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, | ||
423 | void *value, size_t size); | ||
424 | ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); | ||
425 | 459 | ||
426 | /* options.c */ | 460 | /* options.c */ |
427 | int hfsplus_parse_options(char *, struct hfsplus_sb_info *); | 461 | int hfsplus_parse_options(char *, struct hfsplus_sb_info *); |
@@ -446,7 +480,7 @@ int hfsplus_strcmp(const struct hfsplus_unistr *, | |||
446 | int hfsplus_uni2asc(struct super_block *, | 480 | int hfsplus_uni2asc(struct super_block *, |
447 | const struct hfsplus_unistr *, char *, int *); | 481 | const struct hfsplus_unistr *, char *, int *); |
448 | int hfsplus_asc2uni(struct super_block *, | 482 | int hfsplus_asc2uni(struct super_block *, |
449 | struct hfsplus_unistr *, const char *, int); | 483 | struct hfsplus_unistr *, int, const char *, int); |
450 | int hfsplus_hash_dentry(const struct dentry *dentry, | 484 | int hfsplus_hash_dentry(const struct dentry *dentry, |
451 | const struct inode *inode, struct qstr *str); | 485 | const struct inode *inode, struct qstr *str); |
452 | int hfsplus_compare_dentry(const struct dentry *parent, | 486 | int hfsplus_compare_dentry(const struct dentry *parent, |
diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index 921967e5abb1..452ede01b036 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h | |||
@@ -52,13 +52,23 @@ | |||
52 | typedef __be32 hfsplus_cnid; | 52 | typedef __be32 hfsplus_cnid; |
53 | typedef __be16 hfsplus_unichr; | 53 | typedef __be16 hfsplus_unichr; |
54 | 54 | ||
55 | #define HFSPLUS_MAX_STRLEN 255 | ||
56 | #define HFSPLUS_ATTR_MAX_STRLEN 127 | ||
57 | |||
55 | /* A "string" as used in filenames, etc. */ | 58 | /* A "string" as used in filenames, etc. */ |
56 | struct hfsplus_unistr { | 59 | struct hfsplus_unistr { |
57 | __be16 length; | 60 | __be16 length; |
58 | hfsplus_unichr unicode[255]; | 61 | hfsplus_unichr unicode[HFSPLUS_MAX_STRLEN]; |
59 | } __packed; | 62 | } __packed; |
60 | 63 | ||
61 | #define HFSPLUS_MAX_STRLEN 255 | 64 | /* |
65 | * A "string" is used in attributes file | ||
66 | * for name of extended attribute | ||
67 | */ | ||
68 | struct hfsplus_attr_unistr { | ||
69 | __be16 length; | ||
70 | hfsplus_unichr unicode[HFSPLUS_ATTR_MAX_STRLEN]; | ||
71 | } __packed; | ||
62 | 72 | ||
63 | /* POSIX permissions */ | 73 | /* POSIX permissions */ |
64 | struct hfsplus_perm { | 74 | struct hfsplus_perm { |
@@ -291,6 +301,8 @@ struct hfsplus_cat_file { | |||
291 | /* File attribute bits */ | 301 | /* File attribute bits */ |
292 | #define HFSPLUS_FILE_LOCKED 0x0001 | 302 | #define HFSPLUS_FILE_LOCKED 0x0001 |
293 | #define HFSPLUS_FILE_THREAD_EXISTS 0x0002 | 303 | #define HFSPLUS_FILE_THREAD_EXISTS 0x0002 |
304 | #define HFSPLUS_XATTR_EXISTS 0x0004 | ||
305 | #define HFSPLUS_ACL_EXISTS 0x0008 | ||
294 | 306 | ||
295 | /* HFS+ catalog thread (part of a cat_entry) */ | 307 | /* HFS+ catalog thread (part of a cat_entry) */ |
296 | struct hfsplus_cat_thread { | 308 | struct hfsplus_cat_thread { |
@@ -327,11 +339,63 @@ struct hfsplus_ext_key { | |||
327 | 339 | ||
328 | #define HFSPLUS_EXT_KEYLEN sizeof(struct hfsplus_ext_key) | 340 | #define HFSPLUS_EXT_KEYLEN sizeof(struct hfsplus_ext_key) |
329 | 341 | ||
342 | #define HFSPLUS_XATTR_FINDER_INFO_NAME "com.apple.FinderInfo" | ||
343 | #define HFSPLUS_XATTR_ACL_NAME "com.apple.system.Security" | ||
344 | |||
345 | #define HFSPLUS_ATTR_INLINE_DATA 0x10 | ||
346 | #define HFSPLUS_ATTR_FORK_DATA 0x20 | ||
347 | #define HFSPLUS_ATTR_EXTENTS 0x30 | ||
348 | |||
349 | /* HFS+ attributes tree key */ | ||
350 | struct hfsplus_attr_key { | ||
351 | __be16 key_len; | ||
352 | __be16 pad; | ||
353 | hfsplus_cnid cnid; | ||
354 | __be32 start_block; | ||
355 | struct hfsplus_attr_unistr key_name; | ||
356 | } __packed; | ||
357 | |||
358 | #define HFSPLUS_ATTR_KEYLEN sizeof(struct hfsplus_attr_key) | ||
359 | |||
360 | /* HFS+ fork data attribute */ | ||
361 | struct hfsplus_attr_fork_data { | ||
362 | __be32 record_type; | ||
363 | __be32 reserved; | ||
364 | struct hfsplus_fork_raw the_fork; | ||
365 | } __packed; | ||
366 | |||
367 | /* HFS+ extension attribute */ | ||
368 | struct hfsplus_attr_extents { | ||
369 | __be32 record_type; | ||
370 | __be32 reserved; | ||
371 | struct hfsplus_extent extents; | ||
372 | } __packed; | ||
373 | |||
374 | #define HFSPLUS_MAX_INLINE_DATA_SIZE 3802 | ||
375 | |||
376 | /* HFS+ attribute inline data */ | ||
377 | struct hfsplus_attr_inline_data { | ||
378 | __be32 record_type; | ||
379 | __be32 reserved1; | ||
380 | u8 reserved2[6]; | ||
381 | __be16 length; | ||
382 | u8 raw_bytes[HFSPLUS_MAX_INLINE_DATA_SIZE]; | ||
383 | } __packed; | ||
384 | |||
385 | /* A data record in the attributes tree */ | ||
386 | typedef union { | ||
387 | __be32 record_type; | ||
388 | struct hfsplus_attr_fork_data fork_data; | ||
389 | struct hfsplus_attr_extents extents; | ||
390 | struct hfsplus_attr_inline_data inline_data; | ||
391 | } __packed hfsplus_attr_entry; | ||
392 | |||
330 | /* HFS+ generic BTree key */ | 393 | /* HFS+ generic BTree key */ |
331 | typedef union { | 394 | typedef union { |
332 | __be16 key_len; | 395 | __be16 key_len; |
333 | struct hfsplus_cat_key cat; | 396 | struct hfsplus_cat_key cat; |
334 | struct hfsplus_ext_key ext; | 397 | struct hfsplus_ext_key ext; |
398 | struct hfsplus_attr_key attr; | ||
335 | } __packed hfsplus_btree_key; | 399 | } __packed hfsplus_btree_key; |
336 | 400 | ||
337 | #endif | 401 | #endif |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index dcd05be5344b..160ccc9cdb4b 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include "hfsplus_fs.h" | 18 | #include "hfsplus_fs.h" |
19 | #include "hfsplus_raw.h" | 19 | #include "hfsplus_raw.h" |
20 | #include "xattr.h" | ||
20 | 21 | ||
21 | static int hfsplus_readpage(struct file *file, struct page *page) | 22 | static int hfsplus_readpage(struct file *file, struct page *page) |
22 | { | 23 | { |
@@ -348,6 +349,18 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, | |||
348 | error = error2; | 349 | error = error2; |
349 | } | 350 | } |
350 | 351 | ||
352 | if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags)) { | ||
353 | if (sbi->attr_tree) { | ||
354 | error2 = | ||
355 | filemap_write_and_wait( | ||
356 | sbi->attr_tree->inode->i_mapping); | ||
357 | if (!error) | ||
358 | error = error2; | ||
359 | } else { | ||
360 | printk(KERN_ERR "hfs: sync non-existent attributes tree\n"); | ||
361 | } | ||
362 | } | ||
363 | |||
351 | if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { | 364 | if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { |
352 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); | 365 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); |
353 | if (!error) | 366 | if (!error) |
@@ -365,9 +378,10 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, | |||
365 | static const struct inode_operations hfsplus_file_inode_operations = { | 378 | static const struct inode_operations hfsplus_file_inode_operations = { |
366 | .lookup = hfsplus_file_lookup, | 379 | .lookup = hfsplus_file_lookup, |
367 | .setattr = hfsplus_setattr, | 380 | .setattr = hfsplus_setattr, |
368 | .setxattr = hfsplus_setxattr, | 381 | .setxattr = generic_setxattr, |
369 | .getxattr = hfsplus_getxattr, | 382 | .getxattr = generic_getxattr, |
370 | .listxattr = hfsplus_listxattr, | 383 | .listxattr = hfsplus_listxattr, |
384 | .removexattr = hfsplus_removexattr, | ||
371 | }; | 385 | }; |
372 | 386 | ||
373 | static const struct file_operations hfsplus_file_operations = { | 387 | static const struct file_operations hfsplus_file_operations = { |
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index e3c4c4209428..d3ff5cc317d7 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/mount.h> | 17 | #include <linux/mount.h> |
18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
19 | #include <linux/xattr.h> | ||
20 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
21 | #include "hfsplus_fs.h" | 20 | #include "hfsplus_fs.h" |
22 | 21 | ||
@@ -151,110 +150,3 @@ long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
151 | return -ENOTTY; | 150 | return -ENOTTY; |
152 | } | 151 | } |
153 | } | 152 | } |
154 | |||
155 | int hfsplus_setxattr(struct dentry *dentry, const char *name, | ||
156 | const void *value, size_t size, int flags) | ||
157 | { | ||
158 | struct inode *inode = dentry->d_inode; | ||
159 | struct hfs_find_data fd; | ||
160 | hfsplus_cat_entry entry; | ||
161 | struct hfsplus_cat_file *file; | ||
162 | int res; | ||
163 | |||
164 | if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) | ||
165 | return -EOPNOTSUPP; | ||
166 | |||
167 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); | ||
168 | if (res) | ||
169 | return res; | ||
170 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | ||
171 | if (res) | ||
172 | goto out; | ||
173 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, | ||
174 | sizeof(struct hfsplus_cat_file)); | ||
175 | file = &entry.file; | ||
176 | |||
177 | if (!strcmp(name, "hfs.type")) { | ||
178 | if (size == 4) | ||
179 | memcpy(&file->user_info.fdType, value, 4); | ||
180 | else | ||
181 | res = -ERANGE; | ||
182 | } else if (!strcmp(name, "hfs.creator")) { | ||
183 | if (size == 4) | ||
184 | memcpy(&file->user_info.fdCreator, value, 4); | ||
185 | else | ||
186 | res = -ERANGE; | ||
187 | } else | ||
188 | res = -EOPNOTSUPP; | ||
189 | if (!res) { | ||
190 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, | ||
191 | sizeof(struct hfsplus_cat_file)); | ||
192 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
193 | } | ||
194 | out: | ||
195 | hfs_find_exit(&fd); | ||
196 | return res; | ||
197 | } | ||
198 | |||
199 | ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, | ||
200 | void *value, size_t size) | ||
201 | { | ||
202 | struct inode *inode = dentry->d_inode; | ||
203 | struct hfs_find_data fd; | ||
204 | hfsplus_cat_entry entry; | ||
205 | struct hfsplus_cat_file *file; | ||
206 | ssize_t res = 0; | ||
207 | |||
208 | if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) | ||
209 | return -EOPNOTSUPP; | ||
210 | |||
211 | if (size) { | ||
212 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); | ||
213 | if (res) | ||
214 | return res; | ||
215 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | ||
216 | if (res) | ||
217 | goto out; | ||
218 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, | ||
219 | sizeof(struct hfsplus_cat_file)); | ||
220 | } | ||
221 | file = &entry.file; | ||
222 | |||
223 | if (!strcmp(name, "hfs.type")) { | ||
224 | if (size >= 4) { | ||
225 | memcpy(value, &file->user_info.fdType, 4); | ||
226 | res = 4; | ||
227 | } else | ||
228 | res = size ? -ERANGE : 4; | ||
229 | } else if (!strcmp(name, "hfs.creator")) { | ||
230 | if (size >= 4) { | ||
231 | memcpy(value, &file->user_info.fdCreator, 4); | ||
232 | res = 4; | ||
233 | } else | ||
234 | res = size ? -ERANGE : 4; | ||
235 | } else | ||
236 | res = -EOPNOTSUPP; | ||
237 | out: | ||
238 | if (size) | ||
239 | hfs_find_exit(&fd); | ||
240 | return res; | ||
241 | } | ||
242 | |||
243 | #define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type")) | ||
244 | |||
245 | ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
246 | { | ||
247 | struct inode *inode = dentry->d_inode; | ||
248 | |||
249 | if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) | ||
250 | return -EOPNOTSUPP; | ||
251 | |||
252 | if (!buffer || !size) | ||
253 | return HFSPLUS_ATTRLIST_SIZE; | ||
254 | if (size < HFSPLUS_ATTRLIST_SIZE) | ||
255 | return -ERANGE; | ||
256 | strcpy(buffer, "hfs.type"); | ||
257 | strcpy(buffer + sizeof("hfs.type"), "hfs.creator"); | ||
258 | |||
259 | return HFSPLUS_ATTRLIST_SIZE; | ||
260 | } | ||
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 796198d26553..974c26f96fae 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
@@ -20,6 +20,7 @@ static struct inode *hfsplus_alloc_inode(struct super_block *sb); | |||
20 | static void hfsplus_destroy_inode(struct inode *inode); | 20 | static void hfsplus_destroy_inode(struct inode *inode); |
21 | 21 | ||
22 | #include "hfsplus_fs.h" | 22 | #include "hfsplus_fs.h" |
23 | #include "xattr.h" | ||
23 | 24 | ||
24 | static int hfsplus_system_read_inode(struct inode *inode) | 25 | static int hfsplus_system_read_inode(struct inode *inode) |
25 | { | 26 | { |
@@ -118,6 +119,7 @@ static int hfsplus_system_write_inode(struct inode *inode) | |||
118 | case HFSPLUS_ATTR_CNID: | 119 | case HFSPLUS_ATTR_CNID: |
119 | fork = &vhdr->attr_file; | 120 | fork = &vhdr->attr_file; |
120 | tree = sbi->attr_tree; | 121 | tree = sbi->attr_tree; |
122 | break; | ||
121 | default: | 123 | default: |
122 | return -EIO; | 124 | return -EIO; |
123 | } | 125 | } |
@@ -191,6 +193,12 @@ static int hfsplus_sync_fs(struct super_block *sb, int wait) | |||
191 | error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); | 193 | error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); |
192 | if (!error) | 194 | if (!error) |
193 | error = error2; | 195 | error = error2; |
196 | if (sbi->attr_tree) { | ||
197 | error2 = | ||
198 | filemap_write_and_wait(sbi->attr_tree->inode->i_mapping); | ||
199 | if (!error) | ||
200 | error = error2; | ||
201 | } | ||
194 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); | 202 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); |
195 | if (!error) | 203 | if (!error) |
196 | error = error2; | 204 | error = error2; |
@@ -281,6 +289,7 @@ static void hfsplus_put_super(struct super_block *sb) | |||
281 | hfsplus_sync_fs(sb, 1); | 289 | hfsplus_sync_fs(sb, 1); |
282 | } | 290 | } |
283 | 291 | ||
292 | hfs_btree_close(sbi->attr_tree); | ||
284 | hfs_btree_close(sbi->cat_tree); | 293 | hfs_btree_close(sbi->cat_tree); |
285 | hfs_btree_close(sbi->ext_tree); | 294 | hfs_btree_close(sbi->ext_tree); |
286 | iput(sbi->alloc_file); | 295 | iput(sbi->alloc_file); |
@@ -477,12 +486,20 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
477 | printk(KERN_ERR "hfs: failed to load catalog file\n"); | 486 | printk(KERN_ERR "hfs: failed to load catalog file\n"); |
478 | goto out_close_ext_tree; | 487 | goto out_close_ext_tree; |
479 | } | 488 | } |
489 | if (vhdr->attr_file.total_blocks != 0) { | ||
490 | sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID); | ||
491 | if (!sbi->attr_tree) { | ||
492 | printk(KERN_ERR "hfs: failed to load attributes file\n"); | ||
493 | goto out_close_cat_tree; | ||
494 | } | ||
495 | } | ||
496 | sb->s_xattr = hfsplus_xattr_handlers; | ||
480 | 497 | ||
481 | inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID); | 498 | inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID); |
482 | if (IS_ERR(inode)) { | 499 | if (IS_ERR(inode)) { |
483 | printk(KERN_ERR "hfs: failed to load allocation file\n"); | 500 | printk(KERN_ERR "hfs: failed to load allocation file\n"); |
484 | err = PTR_ERR(inode); | 501 | err = PTR_ERR(inode); |
485 | goto out_close_cat_tree; | 502 | goto out_close_attr_tree; |
486 | } | 503 | } |
487 | sbi->alloc_file = inode; | 504 | sbi->alloc_file = inode; |
488 | 505 | ||
@@ -542,10 +559,27 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
542 | } | 559 | } |
543 | err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root, | 560 | err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root, |
544 | &str, sbi->hidden_dir); | 561 | &str, sbi->hidden_dir); |
545 | mutex_unlock(&sbi->vh_mutex); | 562 | if (err) { |
546 | if (err) | 563 | mutex_unlock(&sbi->vh_mutex); |
564 | goto out_put_hidden_dir; | ||
565 | } | ||
566 | |||
567 | err = hfsplus_init_inode_security(sbi->hidden_dir, | ||
568 | root, &str); | ||
569 | if (err == -EOPNOTSUPP) | ||
570 | err = 0; /* Operation is not supported. */ | ||
571 | else if (err) { | ||
572 | /* | ||
573 | * Try to delete anyway without | ||
574 | * error analysis. | ||
575 | */ | ||
576 | hfsplus_delete_cat(sbi->hidden_dir->i_ino, | ||
577 | root, &str); | ||
578 | mutex_unlock(&sbi->vh_mutex); | ||
547 | goto out_put_hidden_dir; | 579 | goto out_put_hidden_dir; |
580 | } | ||
548 | 581 | ||
582 | mutex_unlock(&sbi->vh_mutex); | ||
549 | hfsplus_mark_inode_dirty(sbi->hidden_dir, | 583 | hfsplus_mark_inode_dirty(sbi->hidden_dir, |
550 | HFSPLUS_I_CAT_DIRTY); | 584 | HFSPLUS_I_CAT_DIRTY); |
551 | } | 585 | } |
@@ -562,6 +596,8 @@ out_put_root: | |||
562 | sb->s_root = NULL; | 596 | sb->s_root = NULL; |
563 | out_put_alloc_file: | 597 | out_put_alloc_file: |
564 | iput(sbi->alloc_file); | 598 | iput(sbi->alloc_file); |
599 | out_close_attr_tree: | ||
600 | hfs_btree_close(sbi->attr_tree); | ||
565 | out_close_cat_tree: | 601 | out_close_cat_tree: |
566 | hfs_btree_close(sbi->cat_tree); | 602 | hfs_btree_close(sbi->cat_tree); |
567 | out_close_ext_tree: | 603 | out_close_ext_tree: |
@@ -635,9 +671,20 @@ static int __init init_hfsplus_fs(void) | |||
635 | hfsplus_init_once); | 671 | hfsplus_init_once); |
636 | if (!hfsplus_inode_cachep) | 672 | if (!hfsplus_inode_cachep) |
637 | return -ENOMEM; | 673 | return -ENOMEM; |
674 | err = hfsplus_create_attr_tree_cache(); | ||
675 | if (err) | ||
676 | goto destroy_inode_cache; | ||
638 | err = register_filesystem(&hfsplus_fs_type); | 677 | err = register_filesystem(&hfsplus_fs_type); |
639 | if (err) | 678 | if (err) |
640 | kmem_cache_destroy(hfsplus_inode_cachep); | 679 | goto destroy_attr_tree_cache; |
680 | return 0; | ||
681 | |||
682 | destroy_attr_tree_cache: | ||
683 | hfsplus_destroy_attr_tree_cache(); | ||
684 | |||
685 | destroy_inode_cache: | ||
686 | kmem_cache_destroy(hfsplus_inode_cachep); | ||
687 | |||
641 | return err; | 688 | return err; |
642 | } | 689 | } |
643 | 690 | ||
@@ -650,6 +697,7 @@ static void __exit exit_hfsplus_fs(void) | |||
650 | * destroy cache. | 697 | * destroy cache. |
651 | */ | 698 | */ |
652 | rcu_barrier(); | 699 | rcu_barrier(); |
700 | hfsplus_destroy_attr_tree_cache(); | ||
653 | kmem_cache_destroy(hfsplus_inode_cachep); | 701 | kmem_cache_destroy(hfsplus_inode_cachep); |
654 | } | 702 | } |
655 | 703 | ||
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index a32998f29f0b..2c2e47dcfdd8 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c | |||
@@ -295,7 +295,8 @@ static inline u16 *decompose_unichar(wchar_t uc, int *size) | |||
295 | return hfsplus_decompose_table + (off / 4); | 295 | return hfsplus_decompose_table + (off / 4); |
296 | } | 296 | } |
297 | 297 | ||
298 | int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | 298 | int hfsplus_asc2uni(struct super_block *sb, |
299 | struct hfsplus_unistr *ustr, int max_unistr_len, | ||
299 | const char *astr, int len) | 300 | const char *astr, int len) |
300 | { | 301 | { |
301 | int size, dsize, decompose; | 302 | int size, dsize, decompose; |
@@ -303,7 +304,7 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | |||
303 | wchar_t c; | 304 | wchar_t c; |
304 | 305 | ||
305 | decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); | 306 | decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); |
306 | while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { | 307 | while (outlen < max_unistr_len && len > 0) { |
307 | size = asc2unichar(sb, astr, len, &c); | 308 | size = asc2unichar(sb, astr, len, &c); |
308 | 309 | ||
309 | if (decompose) | 310 | if (decompose) |
@@ -311,7 +312,7 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | |||
311 | else | 312 | else |
312 | dstr = NULL; | 313 | dstr = NULL; |
313 | if (dstr) { | 314 | if (dstr) { |
314 | if (outlen + dsize > HFSPLUS_MAX_STRLEN) | 315 | if (outlen + dsize > max_unistr_len) |
315 | break; | 316 | break; |
316 | do { | 317 | do { |
317 | ustr->unicode[outlen++] = cpu_to_be16(*dstr++); | 318 | ustr->unicode[outlen++] = cpu_to_be16(*dstr++); |
diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c new file mode 100644 index 000000000000..e8a4b0815c61 --- /dev/null +++ b/fs/hfsplus/xattr.c | |||
@@ -0,0 +1,709 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/xattr.c | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Logic of processing extended attributes | ||
7 | */ | ||
8 | |||
9 | #include "hfsplus_fs.h" | ||
10 | #include "xattr.h" | ||
11 | |||
12 | const struct xattr_handler *hfsplus_xattr_handlers[] = { | ||
13 | &hfsplus_xattr_osx_handler, | ||
14 | &hfsplus_xattr_user_handler, | ||
15 | &hfsplus_xattr_trusted_handler, | ||
16 | &hfsplus_xattr_security_handler, | ||
17 | NULL | ||
18 | }; | ||
19 | |||
20 | static int strcmp_xattr_finder_info(const char *name) | ||
21 | { | ||
22 | if (name) { | ||
23 | return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME, | ||
24 | sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME)); | ||
25 | } | ||
26 | return -1; | ||
27 | } | ||
28 | |||
29 | static int strcmp_xattr_acl(const char *name) | ||
30 | { | ||
31 | if (name) { | ||
32 | return strncmp(name, HFSPLUS_XATTR_ACL_NAME, | ||
33 | sizeof(HFSPLUS_XATTR_ACL_NAME)); | ||
34 | } | ||
35 | return -1; | ||
36 | } | ||
37 | |||
38 | static inline int is_known_namespace(const char *name) | ||
39 | { | ||
40 | if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) && | ||
41 | strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && | ||
42 | strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && | ||
43 | strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) | ||
44 | return false; | ||
45 | |||
46 | return true; | ||
47 | } | ||
48 | |||
49 | static int can_set_xattr(struct inode *inode, const char *name, | ||
50 | const void *value, size_t value_len) | ||
51 | { | ||
52 | if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) | ||
53 | return -EOPNOTSUPP; /* TODO: implement ACL support */ | ||
54 | |||
55 | if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) { | ||
56 | /* | ||
57 | * This makes sure that we aren't trying to set an | ||
58 | * attribute in a different namespace by prefixing it | ||
59 | * with "osx." | ||
60 | */ | ||
61 | if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN)) | ||
62 | return -EOPNOTSUPP; | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * Don't allow setting an attribute in an unknown namespace. | ||
69 | */ | ||
70 | if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && | ||
71 | strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && | ||
72 | strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) | ||
73 | return -EOPNOTSUPP; | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | int __hfsplus_setxattr(struct inode *inode, const char *name, | ||
79 | const void *value, size_t size, int flags) | ||
80 | { | ||
81 | int err = 0; | ||
82 | struct hfs_find_data cat_fd; | ||
83 | hfsplus_cat_entry entry; | ||
84 | u16 cat_entry_flags, cat_entry_type; | ||
85 | u16 folder_finderinfo_len = sizeof(struct DInfo) + | ||
86 | sizeof(struct DXInfo); | ||
87 | u16 file_finderinfo_len = sizeof(struct FInfo) + | ||
88 | sizeof(struct FXInfo); | ||
89 | |||
90 | if ((!S_ISREG(inode->i_mode) && | ||
91 | !S_ISDIR(inode->i_mode)) || | ||
92 | HFSPLUS_IS_RSRC(inode)) | ||
93 | return -EOPNOTSUPP; | ||
94 | |||
95 | err = can_set_xattr(inode, name, value, size); | ||
96 | if (err) | ||
97 | return err; | ||
98 | |||
99 | if (strncmp(name, XATTR_MAC_OSX_PREFIX, | ||
100 | XATTR_MAC_OSX_PREFIX_LEN) == 0) | ||
101 | name += XATTR_MAC_OSX_PREFIX_LEN; | ||
102 | |||
103 | if (value == NULL) { | ||
104 | value = ""; | ||
105 | size = 0; | ||
106 | } | ||
107 | |||
108 | err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); | ||
109 | if (err) { | ||
110 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
111 | return err; | ||
112 | } | ||
113 | |||
114 | err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); | ||
115 | if (err) { | ||
116 | printk(KERN_ERR "hfs: catalog searching failed\n"); | ||
117 | goto end_setxattr; | ||
118 | } | ||
119 | |||
120 | if (!strcmp_xattr_finder_info(name)) { | ||
121 | if (flags & XATTR_CREATE) { | ||
122 | printk(KERN_ERR "hfs: xattr exists yet\n"); | ||
123 | err = -EOPNOTSUPP; | ||
124 | goto end_setxattr; | ||
125 | } | ||
126 | hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset, | ||
127 | sizeof(hfsplus_cat_entry)); | ||
128 | if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) { | ||
129 | if (size == folder_finderinfo_len) { | ||
130 | memcpy(&entry.folder.user_info, value, | ||
131 | folder_finderinfo_len); | ||
132 | hfs_bnode_write(cat_fd.bnode, &entry, | ||
133 | cat_fd.entryoffset, | ||
134 | sizeof(struct hfsplus_cat_folder)); | ||
135 | hfsplus_mark_inode_dirty(inode, | ||
136 | HFSPLUS_I_CAT_DIRTY); | ||
137 | } else { | ||
138 | err = -ERANGE; | ||
139 | goto end_setxattr; | ||
140 | } | ||
141 | } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) { | ||
142 | if (size == file_finderinfo_len) { | ||
143 | memcpy(&entry.file.user_info, value, | ||
144 | file_finderinfo_len); | ||
145 | hfs_bnode_write(cat_fd.bnode, &entry, | ||
146 | cat_fd.entryoffset, | ||
147 | sizeof(struct hfsplus_cat_file)); | ||
148 | hfsplus_mark_inode_dirty(inode, | ||
149 | HFSPLUS_I_CAT_DIRTY); | ||
150 | } else { | ||
151 | err = -ERANGE; | ||
152 | goto end_setxattr; | ||
153 | } | ||
154 | } else { | ||
155 | err = -EOPNOTSUPP; | ||
156 | goto end_setxattr; | ||
157 | } | ||
158 | goto end_setxattr; | ||
159 | } | ||
160 | |||
161 | if (!HFSPLUS_SB(inode->i_sb)->attr_tree) { | ||
162 | err = -EOPNOTSUPP; | ||
163 | goto end_setxattr; | ||
164 | } | ||
165 | |||
166 | if (hfsplus_attr_exists(inode, name)) { | ||
167 | if (flags & XATTR_CREATE) { | ||
168 | printk(KERN_ERR "hfs: xattr exists yet\n"); | ||
169 | err = -EOPNOTSUPP; | ||
170 | goto end_setxattr; | ||
171 | } | ||
172 | err = hfsplus_delete_attr(inode, name); | ||
173 | if (err) | ||
174 | goto end_setxattr; | ||
175 | err = hfsplus_create_attr(inode, name, value, size); | ||
176 | if (err) | ||
177 | goto end_setxattr; | ||
178 | } else { | ||
179 | if (flags & XATTR_REPLACE) { | ||
180 | printk(KERN_ERR "hfs: cannot replace xattr\n"); | ||
181 | err = -EOPNOTSUPP; | ||
182 | goto end_setxattr; | ||
183 | } | ||
184 | err = hfsplus_create_attr(inode, name, value, size); | ||
185 | if (err) | ||
186 | goto end_setxattr; | ||
187 | } | ||
188 | |||
189 | cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); | ||
190 | if (cat_entry_type == HFSPLUS_FOLDER) { | ||
191 | cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, | ||
192 | cat_fd.entryoffset + | ||
193 | offsetof(struct hfsplus_cat_folder, flags)); | ||
194 | cat_entry_flags |= HFSPLUS_XATTR_EXISTS; | ||
195 | if (!strcmp_xattr_acl(name)) | ||
196 | cat_entry_flags |= HFSPLUS_ACL_EXISTS; | ||
197 | hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
198 | offsetof(struct hfsplus_cat_folder, flags), | ||
199 | cat_entry_flags); | ||
200 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
201 | } else if (cat_entry_type == HFSPLUS_FILE) { | ||
202 | cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, | ||
203 | cat_fd.entryoffset + | ||
204 | offsetof(struct hfsplus_cat_file, flags)); | ||
205 | cat_entry_flags |= HFSPLUS_XATTR_EXISTS; | ||
206 | if (!strcmp_xattr_acl(name)) | ||
207 | cat_entry_flags |= HFSPLUS_ACL_EXISTS; | ||
208 | hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
209 | offsetof(struct hfsplus_cat_file, flags), | ||
210 | cat_entry_flags); | ||
211 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
212 | } else { | ||
213 | printk(KERN_ERR "hfs: invalid catalog entry type\n"); | ||
214 | err = -EIO; | ||
215 | goto end_setxattr; | ||
216 | } | ||
217 | |||
218 | end_setxattr: | ||
219 | hfs_find_exit(&cat_fd); | ||
220 | return err; | ||
221 | } | ||
222 | |||
223 | static inline int is_osx_xattr(const char *xattr_name) | ||
224 | { | ||
225 | return !is_known_namespace(xattr_name); | ||
226 | } | ||
227 | |||
228 | static int name_len(const char *xattr_name, int xattr_name_len) | ||
229 | { | ||
230 | int len = xattr_name_len + 1; | ||
231 | |||
232 | if (is_osx_xattr(xattr_name)) | ||
233 | len += XATTR_MAC_OSX_PREFIX_LEN; | ||
234 | |||
235 | return len; | ||
236 | } | ||
237 | |||
238 | static int copy_name(char *buffer, const char *xattr_name, int name_len) | ||
239 | { | ||
240 | int len = name_len; | ||
241 | int offset = 0; | ||
242 | |||
243 | if (is_osx_xattr(xattr_name)) { | ||
244 | strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN); | ||
245 | offset += XATTR_MAC_OSX_PREFIX_LEN; | ||
246 | len += XATTR_MAC_OSX_PREFIX_LEN; | ||
247 | } | ||
248 | |||
249 | strncpy(buffer + offset, xattr_name, name_len); | ||
250 | memset(buffer + offset + name_len, 0, 1); | ||
251 | len += 1; | ||
252 | |||
253 | return len; | ||
254 | } | ||
255 | |||
256 | static ssize_t hfsplus_getxattr_finder_info(struct dentry *dentry, | ||
257 | void *value, size_t size) | ||
258 | { | ||
259 | ssize_t res = 0; | ||
260 | struct inode *inode = dentry->d_inode; | ||
261 | struct hfs_find_data fd; | ||
262 | u16 entry_type; | ||
263 | u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo); | ||
264 | u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo); | ||
265 | u16 record_len = max(folder_rec_len, file_rec_len); | ||
266 | u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; | ||
267 | u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; | ||
268 | |||
269 | if (size >= record_len) { | ||
270 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); | ||
271 | if (res) { | ||
272 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
273 | return res; | ||
274 | } | ||
275 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | ||
276 | if (res) | ||
277 | goto end_getxattr_finder_info; | ||
278 | entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); | ||
279 | |||
280 | if (entry_type == HFSPLUS_FOLDER) { | ||
281 | hfs_bnode_read(fd.bnode, folder_finder_info, | ||
282 | fd.entryoffset + | ||
283 | offsetof(struct hfsplus_cat_folder, user_info), | ||
284 | folder_rec_len); | ||
285 | memcpy(value, folder_finder_info, folder_rec_len); | ||
286 | res = folder_rec_len; | ||
287 | } else if (entry_type == HFSPLUS_FILE) { | ||
288 | hfs_bnode_read(fd.bnode, file_finder_info, | ||
289 | fd.entryoffset + | ||
290 | offsetof(struct hfsplus_cat_file, user_info), | ||
291 | file_rec_len); | ||
292 | memcpy(value, file_finder_info, file_rec_len); | ||
293 | res = file_rec_len; | ||
294 | } else { | ||
295 | res = -EOPNOTSUPP; | ||
296 | goto end_getxattr_finder_info; | ||
297 | } | ||
298 | } else | ||
299 | res = size ? -ERANGE : record_len; | ||
300 | |||
301 | end_getxattr_finder_info: | ||
302 | if (size >= record_len) | ||
303 | hfs_find_exit(&fd); | ||
304 | return res; | ||
305 | } | ||
306 | |||
307 | ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, | ||
308 | void *value, size_t size) | ||
309 | { | ||
310 | struct inode *inode = dentry->d_inode; | ||
311 | struct hfs_find_data fd; | ||
312 | hfsplus_attr_entry *entry; | ||
313 | __be32 xattr_record_type; | ||
314 | u32 record_type; | ||
315 | u16 record_length = 0; | ||
316 | ssize_t res = 0; | ||
317 | |||
318 | if ((!S_ISREG(inode->i_mode) && | ||
319 | !S_ISDIR(inode->i_mode)) || | ||
320 | HFSPLUS_IS_RSRC(inode)) | ||
321 | return -EOPNOTSUPP; | ||
322 | |||
323 | if (strncmp(name, XATTR_MAC_OSX_PREFIX, | ||
324 | XATTR_MAC_OSX_PREFIX_LEN) == 0) { | ||
325 | /* skip "osx." prefix */ | ||
326 | name += XATTR_MAC_OSX_PREFIX_LEN; | ||
327 | /* | ||
328 | * Don't allow retrieving properly prefixed attributes | ||
329 | * by prepending them with "osx." | ||
330 | */ | ||
331 | if (is_known_namespace(name)) | ||
332 | return -EOPNOTSUPP; | ||
333 | } | ||
334 | |||
335 | if (!strcmp_xattr_finder_info(name)) | ||
336 | return hfsplus_getxattr_finder_info(dentry, value, size); | ||
337 | |||
338 | if (!HFSPLUS_SB(inode->i_sb)->attr_tree) | ||
339 | return -EOPNOTSUPP; | ||
340 | |||
341 | entry = hfsplus_alloc_attr_entry(); | ||
342 | if (!entry) { | ||
343 | printk(KERN_ERR "hfs: can't allocate xattr entry\n"); | ||
344 | return -ENOMEM; | ||
345 | } | ||
346 | |||
347 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); | ||
348 | if (res) { | ||
349 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
350 | goto failed_getxattr_init; | ||
351 | } | ||
352 | |||
353 | res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd); | ||
354 | if (res) { | ||
355 | if (res == -ENOENT) | ||
356 | res = -ENODATA; | ||
357 | else | ||
358 | printk(KERN_ERR "hfs: xattr searching failed\n"); | ||
359 | goto out; | ||
360 | } | ||
361 | |||
362 | hfs_bnode_read(fd.bnode, &xattr_record_type, | ||
363 | fd.entryoffset, sizeof(xattr_record_type)); | ||
364 | record_type = be32_to_cpu(xattr_record_type); | ||
365 | if (record_type == HFSPLUS_ATTR_INLINE_DATA) { | ||
366 | record_length = hfs_bnode_read_u16(fd.bnode, | ||
367 | fd.entryoffset + | ||
368 | offsetof(struct hfsplus_attr_inline_data, | ||
369 | length)); | ||
370 | if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) { | ||
371 | printk(KERN_ERR "hfs: invalid xattr record size\n"); | ||
372 | res = -EIO; | ||
373 | goto out; | ||
374 | } | ||
375 | } else if (record_type == HFSPLUS_ATTR_FORK_DATA || | ||
376 | record_type == HFSPLUS_ATTR_EXTENTS) { | ||
377 | printk(KERN_ERR "hfs: only inline data xattr are supported\n"); | ||
378 | res = -EOPNOTSUPP; | ||
379 | goto out; | ||
380 | } else { | ||
381 | printk(KERN_ERR "hfs: invalid xattr record\n"); | ||
382 | res = -EIO; | ||
383 | goto out; | ||
384 | } | ||
385 | |||
386 | if (size) { | ||
387 | hfs_bnode_read(fd.bnode, entry, fd.entryoffset, | ||
388 | offsetof(struct hfsplus_attr_inline_data, | ||
389 | raw_bytes) + record_length); | ||
390 | } | ||
391 | |||
392 | if (size >= record_length) { | ||
393 | memcpy(value, entry->inline_data.raw_bytes, record_length); | ||
394 | res = record_length; | ||
395 | } else | ||
396 | res = size ? -ERANGE : record_length; | ||
397 | |||
398 | out: | ||
399 | hfs_find_exit(&fd); | ||
400 | |||
401 | failed_getxattr_init: | ||
402 | hfsplus_destroy_attr_entry(entry); | ||
403 | return res; | ||
404 | } | ||
405 | |||
406 | static inline int can_list(const char *xattr_name) | ||
407 | { | ||
408 | if (!xattr_name) | ||
409 | return 0; | ||
410 | |||
411 | return strncmp(xattr_name, XATTR_TRUSTED_PREFIX, | ||
412 | XATTR_TRUSTED_PREFIX_LEN) || | ||
413 | capable(CAP_SYS_ADMIN); | ||
414 | } | ||
415 | |||
416 | static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry, | ||
417 | char *buffer, size_t size) | ||
418 | { | ||
419 | ssize_t res = 0; | ||
420 | struct inode *inode = dentry->d_inode; | ||
421 | struct hfs_find_data fd; | ||
422 | u16 entry_type; | ||
423 | u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; | ||
424 | u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; | ||
425 | unsigned long len, found_bit; | ||
426 | int xattr_name_len, symbols_count; | ||
427 | |||
428 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); | ||
429 | if (res) { | ||
430 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
431 | return res; | ||
432 | } | ||
433 | |||
434 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | ||
435 | if (res) | ||
436 | goto end_listxattr_finder_info; | ||
437 | |||
438 | entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); | ||
439 | if (entry_type == HFSPLUS_FOLDER) { | ||
440 | len = sizeof(struct DInfo) + sizeof(struct DXInfo); | ||
441 | hfs_bnode_read(fd.bnode, folder_finder_info, | ||
442 | fd.entryoffset + | ||
443 | offsetof(struct hfsplus_cat_folder, user_info), | ||
444 | len); | ||
445 | found_bit = find_first_bit((void *)folder_finder_info, len*8); | ||
446 | } else if (entry_type == HFSPLUS_FILE) { | ||
447 | len = sizeof(struct FInfo) + sizeof(struct FXInfo); | ||
448 | hfs_bnode_read(fd.bnode, file_finder_info, | ||
449 | fd.entryoffset + | ||
450 | offsetof(struct hfsplus_cat_file, user_info), | ||
451 | len); | ||
452 | found_bit = find_first_bit((void *)file_finder_info, len*8); | ||
453 | } else { | ||
454 | res = -EOPNOTSUPP; | ||
455 | goto end_listxattr_finder_info; | ||
456 | } | ||
457 | |||
458 | if (found_bit >= (len*8)) | ||
459 | res = 0; | ||
460 | else { | ||
461 | symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1; | ||
462 | xattr_name_len = | ||
463 | name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count); | ||
464 | if (!buffer || !size) { | ||
465 | if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) | ||
466 | res = xattr_name_len; | ||
467 | } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) { | ||
468 | if (size < xattr_name_len) | ||
469 | res = -ERANGE; | ||
470 | else { | ||
471 | res = copy_name(buffer, | ||
472 | HFSPLUS_XATTR_FINDER_INFO_NAME, | ||
473 | symbols_count); | ||
474 | } | ||
475 | } | ||
476 | } | ||
477 | |||
478 | end_listxattr_finder_info: | ||
479 | hfs_find_exit(&fd); | ||
480 | |||
481 | return res; | ||
482 | } | ||
483 | |||
484 | ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
485 | { | ||
486 | ssize_t err; | ||
487 | ssize_t res = 0; | ||
488 | struct inode *inode = dentry->d_inode; | ||
489 | struct hfs_find_data fd; | ||
490 | u16 key_len = 0; | ||
491 | struct hfsplus_attr_key attr_key; | ||
492 | char strbuf[HFSPLUS_ATTR_MAX_STRLEN + | ||
493 | XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; | ||
494 | int xattr_name_len; | ||
495 | |||
496 | if ((!S_ISREG(inode->i_mode) && | ||
497 | !S_ISDIR(inode->i_mode)) || | ||
498 | HFSPLUS_IS_RSRC(inode)) | ||
499 | return -EOPNOTSUPP; | ||
500 | |||
501 | res = hfsplus_listxattr_finder_info(dentry, buffer, size); | ||
502 | if (res < 0) | ||
503 | return res; | ||
504 | else if (!HFSPLUS_SB(inode->i_sb)->attr_tree) | ||
505 | return (res == 0) ? -EOPNOTSUPP : res; | ||
506 | |||
507 | err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); | ||
508 | if (err) { | ||
509 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
510 | return err; | ||
511 | } | ||
512 | |||
513 | err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd); | ||
514 | if (err) { | ||
515 | if (err == -ENOENT) { | ||
516 | if (res == 0) | ||
517 | res = -ENODATA; | ||
518 | goto end_listxattr; | ||
519 | } else { | ||
520 | res = err; | ||
521 | goto end_listxattr; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | for (;;) { | ||
526 | key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset); | ||
527 | if (key_len == 0 || key_len > fd.tree->max_key_len) { | ||
528 | printk(KERN_ERR "hfs: invalid xattr key length: %d\n", | ||
529 | key_len); | ||
530 | res = -EIO; | ||
531 | goto end_listxattr; | ||
532 | } | ||
533 | |||
534 | hfs_bnode_read(fd.bnode, &attr_key, | ||
535 | fd.keyoffset, key_len + sizeof(key_len)); | ||
536 | |||
537 | if (be32_to_cpu(attr_key.cnid) != inode->i_ino) | ||
538 | goto end_listxattr; | ||
539 | |||
540 | xattr_name_len = HFSPLUS_ATTR_MAX_STRLEN; | ||
541 | if (hfsplus_uni2asc(inode->i_sb, | ||
542 | (const struct hfsplus_unistr *)&fd.key->attr.key_name, | ||
543 | strbuf, &xattr_name_len)) { | ||
544 | printk(KERN_ERR "hfs: unicode conversion failed\n"); | ||
545 | res = -EIO; | ||
546 | goto end_listxattr; | ||
547 | } | ||
548 | |||
549 | if (!buffer || !size) { | ||
550 | if (can_list(strbuf)) | ||
551 | res += name_len(strbuf, xattr_name_len); | ||
552 | } else if (can_list(strbuf)) { | ||
553 | if (size < (res + name_len(strbuf, xattr_name_len))) { | ||
554 | res = -ERANGE; | ||
555 | goto end_listxattr; | ||
556 | } else | ||
557 | res += copy_name(buffer + res, | ||
558 | strbuf, xattr_name_len); | ||
559 | } | ||
560 | |||
561 | if (hfs_brec_goto(&fd, 1)) | ||
562 | goto end_listxattr; | ||
563 | } | ||
564 | |||
565 | end_listxattr: | ||
566 | hfs_find_exit(&fd); | ||
567 | return res; | ||
568 | } | ||
569 | |||
570 | int hfsplus_removexattr(struct dentry *dentry, const char *name) | ||
571 | { | ||
572 | int err = 0; | ||
573 | struct inode *inode = dentry->d_inode; | ||
574 | struct hfs_find_data cat_fd; | ||
575 | u16 flags; | ||
576 | u16 cat_entry_type; | ||
577 | int is_xattr_acl_deleted = 0; | ||
578 | int is_all_xattrs_deleted = 0; | ||
579 | |||
580 | if ((!S_ISREG(inode->i_mode) && | ||
581 | !S_ISDIR(inode->i_mode)) || | ||
582 | HFSPLUS_IS_RSRC(inode)) | ||
583 | return -EOPNOTSUPP; | ||
584 | |||
585 | if (!HFSPLUS_SB(inode->i_sb)->attr_tree) | ||
586 | return -EOPNOTSUPP; | ||
587 | |||
588 | err = can_set_xattr(inode, name, NULL, 0); | ||
589 | if (err) | ||
590 | return err; | ||
591 | |||
592 | if (strncmp(name, XATTR_MAC_OSX_PREFIX, | ||
593 | XATTR_MAC_OSX_PREFIX_LEN) == 0) | ||
594 | name += XATTR_MAC_OSX_PREFIX_LEN; | ||
595 | |||
596 | if (!strcmp_xattr_finder_info(name)) | ||
597 | return -EOPNOTSUPP; | ||
598 | |||
599 | err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); | ||
600 | if (err) { | ||
601 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
602 | return err; | ||
603 | } | ||
604 | |||
605 | err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); | ||
606 | if (err) { | ||
607 | printk(KERN_ERR "hfs: catalog searching failed\n"); | ||
608 | goto end_removexattr; | ||
609 | } | ||
610 | |||
611 | err = hfsplus_delete_attr(inode, name); | ||
612 | if (err) | ||
613 | goto end_removexattr; | ||
614 | |||
615 | is_xattr_acl_deleted = !strcmp_xattr_acl(name); | ||
616 | is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL); | ||
617 | |||
618 | if (!is_xattr_acl_deleted && !is_all_xattrs_deleted) | ||
619 | goto end_removexattr; | ||
620 | |||
621 | cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); | ||
622 | |||
623 | if (cat_entry_type == HFSPLUS_FOLDER) { | ||
624 | flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
625 | offsetof(struct hfsplus_cat_folder, flags)); | ||
626 | if (is_xattr_acl_deleted) | ||
627 | flags &= ~HFSPLUS_ACL_EXISTS; | ||
628 | if (is_all_xattrs_deleted) | ||
629 | flags &= ~HFSPLUS_XATTR_EXISTS; | ||
630 | hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
631 | offsetof(struct hfsplus_cat_folder, flags), | ||
632 | flags); | ||
633 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
634 | } else if (cat_entry_type == HFSPLUS_FILE) { | ||
635 | flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
636 | offsetof(struct hfsplus_cat_file, flags)); | ||
637 | if (is_xattr_acl_deleted) | ||
638 | flags &= ~HFSPLUS_ACL_EXISTS; | ||
639 | if (is_all_xattrs_deleted) | ||
640 | flags &= ~HFSPLUS_XATTR_EXISTS; | ||
641 | hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
642 | offsetof(struct hfsplus_cat_file, flags), | ||
643 | flags); | ||
644 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
645 | } else { | ||
646 | printk(KERN_ERR "hfs: invalid catalog entry type\n"); | ||
647 | err = -EIO; | ||
648 | goto end_removexattr; | ||
649 | } | ||
650 | |||
651 | end_removexattr: | ||
652 | hfs_find_exit(&cat_fd); | ||
653 | return err; | ||
654 | } | ||
655 | |||
656 | static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name, | ||
657 | void *buffer, size_t size, int type) | ||
658 | { | ||
659 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + | ||
660 | XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; | ||
661 | size_t len = strlen(name); | ||
662 | |||
663 | if (!strcmp(name, "")) | ||
664 | return -EINVAL; | ||
665 | |||
666 | if (len > HFSPLUS_ATTR_MAX_STRLEN) | ||
667 | return -EOPNOTSUPP; | ||
668 | |||
669 | strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); | ||
670 | strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); | ||
671 | |||
672 | return hfsplus_getxattr(dentry, xattr_name, buffer, size); | ||
673 | } | ||
674 | |||
675 | static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, | ||
676 | const void *buffer, size_t size, int flags, int type) | ||
677 | { | ||
678 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + | ||
679 | XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; | ||
680 | size_t len = strlen(name); | ||
681 | |||
682 | if (!strcmp(name, "")) | ||
683 | return -EINVAL; | ||
684 | |||
685 | if (len > HFSPLUS_ATTR_MAX_STRLEN) | ||
686 | return -EOPNOTSUPP; | ||
687 | |||
688 | strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); | ||
689 | strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); | ||
690 | |||
691 | return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); | ||
692 | } | ||
693 | |||
694 | static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list, | ||
695 | size_t list_size, const char *name, size_t name_len, int type) | ||
696 | { | ||
697 | /* | ||
698 | * This method is not used. | ||
699 | * It is used hfsplus_listxattr() instead of generic_listxattr(). | ||
700 | */ | ||
701 | return -EOPNOTSUPP; | ||
702 | } | ||
703 | |||
704 | const struct xattr_handler hfsplus_xattr_osx_handler = { | ||
705 | .prefix = XATTR_MAC_OSX_PREFIX, | ||
706 | .list = hfsplus_osx_listxattr, | ||
707 | .get = hfsplus_osx_getxattr, | ||
708 | .set = hfsplus_osx_setxattr, | ||
709 | }; | ||
diff --git a/fs/hfsplus/xattr.h b/fs/hfsplus/xattr.h new file mode 100644 index 000000000000..847b695b984d --- /dev/null +++ b/fs/hfsplus/xattr.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/xattr.h | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Logic of processing extended attributes | ||
7 | */ | ||
8 | |||
9 | #ifndef _LINUX_HFSPLUS_XATTR_H | ||
10 | #define _LINUX_HFSPLUS_XATTR_H | ||
11 | |||
12 | #include <linux/xattr.h> | ||
13 | |||
14 | extern const struct xattr_handler hfsplus_xattr_osx_handler; | ||
15 | extern const struct xattr_handler hfsplus_xattr_user_handler; | ||
16 | extern const struct xattr_handler hfsplus_xattr_trusted_handler; | ||
17 | /*extern const struct xattr_handler hfsplus_xattr_acl_access_handler;*/ | ||
18 | /*extern const struct xattr_handler hfsplus_xattr_acl_default_handler;*/ | ||
19 | extern const struct xattr_handler hfsplus_xattr_security_handler; | ||
20 | |||
21 | extern const struct xattr_handler *hfsplus_xattr_handlers[]; | ||
22 | |||
23 | int __hfsplus_setxattr(struct inode *inode, const char *name, | ||
24 | const void *value, size_t size, int flags); | ||
25 | |||
26 | static inline int hfsplus_setxattr(struct dentry *dentry, const char *name, | ||
27 | const void *value, size_t size, int flags) | ||
28 | { | ||
29 | return __hfsplus_setxattr(dentry->d_inode, name, value, size, flags); | ||
30 | } | ||
31 | |||
32 | ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, | ||
33 | void *value, size_t size); | ||
34 | |||
35 | ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); | ||
36 | |||
37 | int hfsplus_removexattr(struct dentry *dentry, const char *name); | ||
38 | |||
39 | int hfsplus_init_security(struct inode *inode, struct inode *dir, | ||
40 | const struct qstr *qstr); | ||
41 | |||
42 | static inline int hfsplus_init_acl(struct inode *inode, struct inode *dir) | ||
43 | { | ||
44 | /*TODO: implement*/ | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static inline int hfsplus_init_inode_security(struct inode *inode, | ||
49 | struct inode *dir, | ||
50 | const struct qstr *qstr) | ||
51 | { | ||
52 | int err; | ||
53 | |||
54 | err = hfsplus_init_acl(inode, dir); | ||
55 | if (!err) | ||
56 | err = hfsplus_init_security(inode, dir, qstr); | ||
57 | return err; | ||
58 | } | ||
59 | |||
60 | #endif | ||
diff --git a/fs/hfsplus/xattr_security.c b/fs/hfsplus/xattr_security.c new file mode 100644 index 000000000000..83b842f113c5 --- /dev/null +++ b/fs/hfsplus/xattr_security.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/xattr_trusted.c | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Handler for storing security labels as extended attributes. | ||
7 | */ | ||
8 | |||
9 | #include <linux/security.h> | ||
10 | #include "hfsplus_fs.h" | ||
11 | #include "xattr.h" | ||
12 | |||
13 | static int hfsplus_security_getxattr(struct dentry *dentry, const char *name, | ||
14 | void *buffer, size_t size, int type) | ||
15 | { | ||
16 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
17 | size_t len = strlen(name); | ||
18 | |||
19 | if (!strcmp(name, "")) | ||
20 | return -EINVAL; | ||
21 | |||
22 | if (len + XATTR_SECURITY_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
23 | return -EOPNOTSUPP; | ||
24 | |||
25 | strcpy(xattr_name, XATTR_SECURITY_PREFIX); | ||
26 | strcpy(xattr_name + XATTR_SECURITY_PREFIX_LEN, name); | ||
27 | |||
28 | return hfsplus_getxattr(dentry, xattr_name, buffer, size); | ||
29 | } | ||
30 | |||
31 | static int hfsplus_security_setxattr(struct dentry *dentry, const char *name, | ||
32 | const void *buffer, size_t size, int flags, int type) | ||
33 | { | ||
34 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
35 | size_t len = strlen(name); | ||
36 | |||
37 | if (!strcmp(name, "")) | ||
38 | return -EINVAL; | ||
39 | |||
40 | if (len + XATTR_SECURITY_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
41 | return -EOPNOTSUPP; | ||
42 | |||
43 | strcpy(xattr_name, XATTR_SECURITY_PREFIX); | ||
44 | strcpy(xattr_name + XATTR_SECURITY_PREFIX_LEN, name); | ||
45 | |||
46 | return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); | ||
47 | } | ||
48 | |||
49 | static size_t hfsplus_security_listxattr(struct dentry *dentry, char *list, | ||
50 | size_t list_size, const char *name, size_t name_len, int type) | ||
51 | { | ||
52 | /* | ||
53 | * This method is not used. | ||
54 | * It is used hfsplus_listxattr() instead of generic_listxattr(). | ||
55 | */ | ||
56 | return -EOPNOTSUPP; | ||
57 | } | ||
58 | |||
59 | static int hfsplus_initxattrs(struct inode *inode, | ||
60 | const struct xattr *xattr_array, | ||
61 | void *fs_info) | ||
62 | { | ||
63 | const struct xattr *xattr; | ||
64 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
65 | size_t xattr_name_len; | ||
66 | int err = 0; | ||
67 | |||
68 | for (xattr = xattr_array; xattr->name != NULL; xattr++) { | ||
69 | xattr_name_len = strlen(xattr->name); | ||
70 | |||
71 | if (xattr_name_len == 0) | ||
72 | continue; | ||
73 | |||
74 | if (xattr_name_len + XATTR_SECURITY_PREFIX_LEN > | ||
75 | HFSPLUS_ATTR_MAX_STRLEN) | ||
76 | return -EOPNOTSUPP; | ||
77 | |||
78 | strcpy(xattr_name, XATTR_SECURITY_PREFIX); | ||
79 | strcpy(xattr_name + | ||
80 | XATTR_SECURITY_PREFIX_LEN, xattr->name); | ||
81 | memset(xattr_name + | ||
82 | XATTR_SECURITY_PREFIX_LEN + xattr_name_len, 0, 1); | ||
83 | |||
84 | err = __hfsplus_setxattr(inode, xattr_name, | ||
85 | xattr->value, xattr->value_len, 0); | ||
86 | if (err) | ||
87 | break; | ||
88 | } | ||
89 | return err; | ||
90 | } | ||
91 | |||
92 | int hfsplus_init_security(struct inode *inode, struct inode *dir, | ||
93 | const struct qstr *qstr) | ||
94 | { | ||
95 | return security_inode_init_security(inode, dir, qstr, | ||
96 | &hfsplus_initxattrs, NULL); | ||
97 | } | ||
98 | |||
99 | const struct xattr_handler hfsplus_xattr_security_handler = { | ||
100 | .prefix = XATTR_SECURITY_PREFIX, | ||
101 | .list = hfsplus_security_listxattr, | ||
102 | .get = hfsplus_security_getxattr, | ||
103 | .set = hfsplus_security_setxattr, | ||
104 | }; | ||
diff --git a/fs/hfsplus/xattr_trusted.c b/fs/hfsplus/xattr_trusted.c new file mode 100644 index 000000000000..426cee277542 --- /dev/null +++ b/fs/hfsplus/xattr_trusted.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/xattr_trusted.c | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Handler for trusted extended attributes. | ||
7 | */ | ||
8 | |||
9 | #include "hfsplus_fs.h" | ||
10 | #include "xattr.h" | ||
11 | |||
12 | static int hfsplus_trusted_getxattr(struct dentry *dentry, const char *name, | ||
13 | void *buffer, size_t size, int type) | ||
14 | { | ||
15 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
16 | size_t len = strlen(name); | ||
17 | |||
18 | if (!strcmp(name, "")) | ||
19 | return -EINVAL; | ||
20 | |||
21 | if (len + XATTR_TRUSTED_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
22 | return -EOPNOTSUPP; | ||
23 | |||
24 | strcpy(xattr_name, XATTR_TRUSTED_PREFIX); | ||
25 | strcpy(xattr_name + XATTR_TRUSTED_PREFIX_LEN, name); | ||
26 | |||
27 | return hfsplus_getxattr(dentry, xattr_name, buffer, size); | ||
28 | } | ||
29 | |||
30 | static int hfsplus_trusted_setxattr(struct dentry *dentry, const char *name, | ||
31 | const void *buffer, size_t size, int flags, int type) | ||
32 | { | ||
33 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
34 | size_t len = strlen(name); | ||
35 | |||
36 | if (!strcmp(name, "")) | ||
37 | return -EINVAL; | ||
38 | |||
39 | if (len + XATTR_TRUSTED_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
40 | return -EOPNOTSUPP; | ||
41 | |||
42 | strcpy(xattr_name, XATTR_TRUSTED_PREFIX); | ||
43 | strcpy(xattr_name + XATTR_TRUSTED_PREFIX_LEN, name); | ||
44 | |||
45 | return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); | ||
46 | } | ||
47 | |||
48 | static size_t hfsplus_trusted_listxattr(struct dentry *dentry, char *list, | ||
49 | size_t list_size, const char *name, size_t name_len, int type) | ||
50 | { | ||
51 | /* | ||
52 | * This method is not used. | ||
53 | * It is used hfsplus_listxattr() instead of generic_listxattr(). | ||
54 | */ | ||
55 | return -EOPNOTSUPP; | ||
56 | } | ||
57 | |||
58 | const struct xattr_handler hfsplus_xattr_trusted_handler = { | ||
59 | .prefix = XATTR_TRUSTED_PREFIX, | ||
60 | .list = hfsplus_trusted_listxattr, | ||
61 | .get = hfsplus_trusted_getxattr, | ||
62 | .set = hfsplus_trusted_setxattr, | ||
63 | }; | ||
diff --git a/fs/hfsplus/xattr_user.c b/fs/hfsplus/xattr_user.c new file mode 100644 index 000000000000..e34016561ae0 --- /dev/null +++ b/fs/hfsplus/xattr_user.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/xattr_user.c | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Handler for user extended attributes. | ||
7 | */ | ||
8 | |||
9 | #include "hfsplus_fs.h" | ||
10 | #include "xattr.h" | ||
11 | |||
12 | static int hfsplus_user_getxattr(struct dentry *dentry, const char *name, | ||
13 | void *buffer, size_t size, int type) | ||
14 | { | ||
15 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
16 | size_t len = strlen(name); | ||
17 | |||
18 | if (!strcmp(name, "")) | ||
19 | return -EINVAL; | ||
20 | |||
21 | if (len + XATTR_USER_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
22 | return -EOPNOTSUPP; | ||
23 | |||
24 | strcpy(xattr_name, XATTR_USER_PREFIX); | ||
25 | strcpy(xattr_name + XATTR_USER_PREFIX_LEN, name); | ||
26 | |||
27 | return hfsplus_getxattr(dentry, xattr_name, buffer, size); | ||
28 | } | ||
29 | |||
30 | static int hfsplus_user_setxattr(struct dentry *dentry, const char *name, | ||
31 | const void *buffer, size_t size, int flags, int type) | ||
32 | { | ||
33 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
34 | size_t len = strlen(name); | ||
35 | |||
36 | if (!strcmp(name, "")) | ||
37 | return -EINVAL; | ||
38 | |||
39 | if (len + XATTR_USER_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
40 | return -EOPNOTSUPP; | ||
41 | |||
42 | strcpy(xattr_name, XATTR_USER_PREFIX); | ||
43 | strcpy(xattr_name + XATTR_USER_PREFIX_LEN, name); | ||
44 | |||
45 | return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); | ||
46 | } | ||
47 | |||
48 | static size_t hfsplus_user_listxattr(struct dentry *dentry, char *list, | ||
49 | size_t list_size, const char *name, size_t name_len, int type) | ||
50 | { | ||
51 | /* | ||
52 | * This method is not used. | ||
53 | * It is used hfsplus_listxattr() instead of generic_listxattr(). | ||
54 | */ | ||
55 | return -EOPNOTSUPP; | ||
56 | } | ||
57 | |||
58 | const struct xattr_handler hfsplus_xattr_user_handler = { | ||
59 | .prefix = XATTR_USER_PREFIX, | ||
60 | .list = hfsplus_user_listxattr, | ||
61 | .get = hfsplus_user_getxattr, | ||
62 | .set = hfsplus_user_setxattr, | ||
63 | }; | ||
diff --git a/fs/inode.c b/fs/inode.c index 67880e604399..f5f7c06c36fb 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -798,11 +798,10 @@ static struct inode *find_inode(struct super_block *sb, | |||
798 | int (*test)(struct inode *, void *), | 798 | int (*test)(struct inode *, void *), |
799 | void *data) | 799 | void *data) |
800 | { | 800 | { |
801 | struct hlist_node *node; | ||
802 | struct inode *inode = NULL; | 801 | struct inode *inode = NULL; |
803 | 802 | ||
804 | repeat: | 803 | repeat: |
805 | hlist_for_each_entry(inode, node, head, i_hash) { | 804 | hlist_for_each_entry(inode, head, i_hash) { |
806 | spin_lock(&inode->i_lock); | 805 | spin_lock(&inode->i_lock); |
807 | if (inode->i_sb != sb) { | 806 | if (inode->i_sb != sb) { |
808 | spin_unlock(&inode->i_lock); | 807 | spin_unlock(&inode->i_lock); |
@@ -830,11 +829,10 @@ repeat: | |||
830 | static struct inode *find_inode_fast(struct super_block *sb, | 829 | static struct inode *find_inode_fast(struct super_block *sb, |
831 | struct hlist_head *head, unsigned long ino) | 830 | struct hlist_head *head, unsigned long ino) |
832 | { | 831 | { |
833 | struct hlist_node *node; | ||
834 | struct inode *inode = NULL; | 832 | struct inode *inode = NULL; |
835 | 833 | ||
836 | repeat: | 834 | repeat: |
837 | hlist_for_each_entry(inode, node, head, i_hash) { | 835 | hlist_for_each_entry(inode, head, i_hash) { |
838 | spin_lock(&inode->i_lock); | 836 | spin_lock(&inode->i_lock); |
839 | if (inode->i_ino != ino) { | 837 | if (inode->i_ino != ino) { |
840 | spin_unlock(&inode->i_lock); | 838 | spin_unlock(&inode->i_lock); |
@@ -1132,11 +1130,10 @@ EXPORT_SYMBOL(iget_locked); | |||
1132 | static int test_inode_iunique(struct super_block *sb, unsigned long ino) | 1130 | static int test_inode_iunique(struct super_block *sb, unsigned long ino) |
1133 | { | 1131 | { |
1134 | struct hlist_head *b = inode_hashtable + hash(sb, ino); | 1132 | struct hlist_head *b = inode_hashtable + hash(sb, ino); |
1135 | struct hlist_node *node; | ||
1136 | struct inode *inode; | 1133 | struct inode *inode; |
1137 | 1134 | ||
1138 | spin_lock(&inode_hash_lock); | 1135 | spin_lock(&inode_hash_lock); |
1139 | hlist_for_each_entry(inode, node, b, i_hash) { | 1136 | hlist_for_each_entry(inode, b, i_hash) { |
1140 | if (inode->i_ino == ino && inode->i_sb == sb) { | 1137 | if (inode->i_ino == ino && inode->i_sb == sb) { |
1141 | spin_unlock(&inode_hash_lock); | 1138 | spin_unlock(&inode_hash_lock); |
1142 | return 0; | 1139 | return 0; |
@@ -1291,10 +1288,9 @@ int insert_inode_locked(struct inode *inode) | |||
1291 | struct hlist_head *head = inode_hashtable + hash(sb, ino); | 1288 | struct hlist_head *head = inode_hashtable + hash(sb, ino); |
1292 | 1289 | ||
1293 | while (1) { | 1290 | while (1) { |
1294 | struct hlist_node *node; | ||
1295 | struct inode *old = NULL; | 1291 | struct inode *old = NULL; |
1296 | spin_lock(&inode_hash_lock); | 1292 | spin_lock(&inode_hash_lock); |
1297 | hlist_for_each_entry(old, node, head, i_hash) { | 1293 | hlist_for_each_entry(old, head, i_hash) { |
1298 | if (old->i_ino != ino) | 1294 | if (old->i_ino != ino) |
1299 | continue; | 1295 | continue; |
1300 | if (old->i_sb != sb) | 1296 | if (old->i_sb != sb) |
@@ -1306,7 +1302,7 @@ int insert_inode_locked(struct inode *inode) | |||
1306 | } | 1302 | } |
1307 | break; | 1303 | break; |
1308 | } | 1304 | } |
1309 | if (likely(!node)) { | 1305 | if (likely(!old)) { |
1310 | spin_lock(&inode->i_lock); | 1306 | spin_lock(&inode->i_lock); |
1311 | inode->i_state |= I_NEW; | 1307 | inode->i_state |= I_NEW; |
1312 | hlist_add_head(&inode->i_hash, head); | 1308 | hlist_add_head(&inode->i_hash, head); |
@@ -1334,11 +1330,10 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval, | |||
1334 | struct hlist_head *head = inode_hashtable + hash(sb, hashval); | 1330 | struct hlist_head *head = inode_hashtable + hash(sb, hashval); |
1335 | 1331 | ||
1336 | while (1) { | 1332 | while (1) { |
1337 | struct hlist_node *node; | ||
1338 | struct inode *old = NULL; | 1333 | struct inode *old = NULL; |
1339 | 1334 | ||
1340 | spin_lock(&inode_hash_lock); | 1335 | spin_lock(&inode_hash_lock); |
1341 | hlist_for_each_entry(old, node, head, i_hash) { | 1336 | hlist_for_each_entry(old, head, i_hash) { |
1342 | if (old->i_sb != sb) | 1337 | if (old->i_sb != sb) |
1343 | continue; | 1338 | continue; |
1344 | if (!test(old, data)) | 1339 | if (!test(old, data)) |
@@ -1350,7 +1345,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval, | |||
1350 | } | 1345 | } |
1351 | break; | 1346 | break; |
1352 | } | 1347 | } |
1353 | if (likely(!node)) { | 1348 | if (likely(!old)) { |
1354 | spin_lock(&inode->i_lock); | 1349 | spin_lock(&inode->i_lock); |
1355 | inode->i_state |= I_NEW; | 1350 | inode->i_state |= I_NEW; |
1356 | hlist_add_head(&inode->i_hash, head); | 1351 | hlist_add_head(&inode->i_hash, head); |
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 0e17090c310f..abdd75d44dd4 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -32,15 +32,15 @@ | |||
32 | static struct hlist_head nlm_server_hosts[NLM_HOST_NRHASH]; | 32 | static struct hlist_head nlm_server_hosts[NLM_HOST_NRHASH]; |
33 | static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH]; | 33 | static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH]; |
34 | 34 | ||
35 | #define for_each_host(host, pos, chain, table) \ | 35 | #define for_each_host(host, chain, table) \ |
36 | for ((chain) = (table); \ | 36 | for ((chain) = (table); \ |
37 | (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \ | 37 | (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \ |
38 | hlist_for_each_entry((host), (pos), (chain), h_hash) | 38 | hlist_for_each_entry((host), (chain), h_hash) |
39 | 39 | ||
40 | #define for_each_host_safe(host, pos, next, chain, table) \ | 40 | #define for_each_host_safe(host, next, chain, table) \ |
41 | for ((chain) = (table); \ | 41 | for ((chain) = (table); \ |
42 | (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \ | 42 | (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \ |
43 | hlist_for_each_entry_safe((host), (pos), (next), \ | 43 | hlist_for_each_entry_safe((host), (next), \ |
44 | (chain), h_hash) | 44 | (chain), h_hash) |
45 | 45 | ||
46 | static unsigned long nrhosts; | 46 | static unsigned long nrhosts; |
@@ -225,7 +225,6 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | |||
225 | .net = net, | 225 | .net = net, |
226 | }; | 226 | }; |
227 | struct hlist_head *chain; | 227 | struct hlist_head *chain; |
228 | struct hlist_node *pos; | ||
229 | struct nlm_host *host; | 228 | struct nlm_host *host; |
230 | struct nsm_handle *nsm = NULL; | 229 | struct nsm_handle *nsm = NULL; |
231 | struct lockd_net *ln = net_generic(net, lockd_net_id); | 230 | struct lockd_net *ln = net_generic(net, lockd_net_id); |
@@ -237,7 +236,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, | |||
237 | mutex_lock(&nlm_host_mutex); | 236 | mutex_lock(&nlm_host_mutex); |
238 | 237 | ||
239 | chain = &nlm_client_hosts[nlm_hash_address(sap)]; | 238 | chain = &nlm_client_hosts[nlm_hash_address(sap)]; |
240 | hlist_for_each_entry(host, pos, chain, h_hash) { | 239 | hlist_for_each_entry(host, chain, h_hash) { |
241 | if (host->net != net) | 240 | if (host->net != net) |
242 | continue; | 241 | continue; |
243 | if (!rpc_cmp_addr(nlm_addr(host), sap)) | 242 | if (!rpc_cmp_addr(nlm_addr(host), sap)) |
@@ -322,7 +321,6 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, | |||
322 | const size_t hostname_len) | 321 | const size_t hostname_len) |
323 | { | 322 | { |
324 | struct hlist_head *chain; | 323 | struct hlist_head *chain; |
325 | struct hlist_node *pos; | ||
326 | struct nlm_host *host = NULL; | 324 | struct nlm_host *host = NULL; |
327 | struct nsm_handle *nsm = NULL; | 325 | struct nsm_handle *nsm = NULL; |
328 | struct sockaddr *src_sap = svc_daddr(rqstp); | 326 | struct sockaddr *src_sap = svc_daddr(rqstp); |
@@ -350,7 +348,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, | |||
350 | nlm_gc_hosts(net); | 348 | nlm_gc_hosts(net); |
351 | 349 | ||
352 | chain = &nlm_server_hosts[nlm_hash_address(ni.sap)]; | 350 | chain = &nlm_server_hosts[nlm_hash_address(ni.sap)]; |
353 | hlist_for_each_entry(host, pos, chain, h_hash) { | 351 | hlist_for_each_entry(host, chain, h_hash) { |
354 | if (host->net != net) | 352 | if (host->net != net) |
355 | continue; | 353 | continue; |
356 | if (!rpc_cmp_addr(nlm_addr(host), ni.sap)) | 354 | if (!rpc_cmp_addr(nlm_addr(host), ni.sap)) |
@@ -515,10 +513,9 @@ static struct nlm_host *next_host_state(struct hlist_head *cache, | |||
515 | { | 513 | { |
516 | struct nlm_host *host; | 514 | struct nlm_host *host; |
517 | struct hlist_head *chain; | 515 | struct hlist_head *chain; |
518 | struct hlist_node *pos; | ||
519 | 516 | ||
520 | mutex_lock(&nlm_host_mutex); | 517 | mutex_lock(&nlm_host_mutex); |
521 | for_each_host(host, pos, chain, cache) { | 518 | for_each_host(host, chain, cache) { |
522 | if (host->h_nsmhandle == nsm | 519 | if (host->h_nsmhandle == nsm |
523 | && host->h_nsmstate != info->state) { | 520 | && host->h_nsmstate != info->state) { |
524 | host->h_nsmstate = info->state; | 521 | host->h_nsmstate = info->state; |
@@ -570,7 +567,6 @@ void nlm_host_rebooted(const struct nlm_reboot *info) | |||
570 | static void nlm_complain_hosts(struct net *net) | 567 | static void nlm_complain_hosts(struct net *net) |
571 | { | 568 | { |
572 | struct hlist_head *chain; | 569 | struct hlist_head *chain; |
573 | struct hlist_node *pos; | ||
574 | struct nlm_host *host; | 570 | struct nlm_host *host; |
575 | 571 | ||
576 | if (net) { | 572 | if (net) { |
@@ -587,7 +583,7 @@ static void nlm_complain_hosts(struct net *net) | |||
587 | dprintk("lockd: %lu hosts left:\n", nrhosts); | 583 | dprintk("lockd: %lu hosts left:\n", nrhosts); |
588 | } | 584 | } |
589 | 585 | ||
590 | for_each_host(host, pos, chain, nlm_server_hosts) { | 586 | for_each_host(host, chain, nlm_server_hosts) { |
591 | if (net && host->net != net) | 587 | if (net && host->net != net) |
592 | continue; | 588 | continue; |
593 | dprintk(" %s (cnt %d use %d exp %ld net %p)\n", | 589 | dprintk(" %s (cnt %d use %d exp %ld net %p)\n", |
@@ -600,14 +596,13 @@ void | |||
600 | nlm_shutdown_hosts_net(struct net *net) | 596 | nlm_shutdown_hosts_net(struct net *net) |
601 | { | 597 | { |
602 | struct hlist_head *chain; | 598 | struct hlist_head *chain; |
603 | struct hlist_node *pos; | ||
604 | struct nlm_host *host; | 599 | struct nlm_host *host; |
605 | 600 | ||
606 | mutex_lock(&nlm_host_mutex); | 601 | mutex_lock(&nlm_host_mutex); |
607 | 602 | ||
608 | /* First, make all hosts eligible for gc */ | 603 | /* First, make all hosts eligible for gc */ |
609 | dprintk("lockd: nuking all hosts in net %p...\n", net); | 604 | dprintk("lockd: nuking all hosts in net %p...\n", net); |
610 | for_each_host(host, pos, chain, nlm_server_hosts) { | 605 | for_each_host(host, chain, nlm_server_hosts) { |
611 | if (net && host->net != net) | 606 | if (net && host->net != net) |
612 | continue; | 607 | continue; |
613 | host->h_expires = jiffies - 1; | 608 | host->h_expires = jiffies - 1; |
@@ -644,11 +639,11 @@ static void | |||
644 | nlm_gc_hosts(struct net *net) | 639 | nlm_gc_hosts(struct net *net) |
645 | { | 640 | { |
646 | struct hlist_head *chain; | 641 | struct hlist_head *chain; |
647 | struct hlist_node *pos, *next; | 642 | struct hlist_node *next; |
648 | struct nlm_host *host; | 643 | struct nlm_host *host; |
649 | 644 | ||
650 | dprintk("lockd: host garbage collection for net %p\n", net); | 645 | dprintk("lockd: host garbage collection for net %p\n", net); |
651 | for_each_host(host, pos, chain, nlm_server_hosts) { | 646 | for_each_host(host, chain, nlm_server_hosts) { |
652 | if (net && host->net != net) | 647 | if (net && host->net != net) |
653 | continue; | 648 | continue; |
654 | host->h_inuse = 0; | 649 | host->h_inuse = 0; |
@@ -657,7 +652,7 @@ nlm_gc_hosts(struct net *net) | |||
657 | /* Mark all hosts that hold locks, blocks or shares */ | 652 | /* Mark all hosts that hold locks, blocks or shares */ |
658 | nlmsvc_mark_resources(net); | 653 | nlmsvc_mark_resources(net); |
659 | 654 | ||
660 | for_each_host_safe(host, pos, next, chain, nlm_server_hosts) { | 655 | for_each_host_safe(host, next, chain, nlm_server_hosts) { |
661 | if (net && host->net != net) | 656 | if (net && host->net != net) |
662 | continue; | 657 | continue; |
663 | if (atomic_read(&host->h_count) || host->h_inuse | 658 | if (atomic_read(&host->h_count) || host->h_inuse |
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index b3a24b07d981..d17bb62b06d6 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
@@ -84,7 +84,6 @@ __be32 | |||
84 | nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, | 84 | nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, |
85 | struct nfs_fh *f) | 85 | struct nfs_fh *f) |
86 | { | 86 | { |
87 | struct hlist_node *pos; | ||
88 | struct nlm_file *file; | 87 | struct nlm_file *file; |
89 | unsigned int hash; | 88 | unsigned int hash; |
90 | __be32 nfserr; | 89 | __be32 nfserr; |
@@ -96,7 +95,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, | |||
96 | /* Lock file table */ | 95 | /* Lock file table */ |
97 | mutex_lock(&nlm_file_mutex); | 96 | mutex_lock(&nlm_file_mutex); |
98 | 97 | ||
99 | hlist_for_each_entry(file, pos, &nlm_files[hash], f_list) | 98 | hlist_for_each_entry(file, &nlm_files[hash], f_list) |
100 | if (!nfs_compare_fh(&file->f_handle, f)) | 99 | if (!nfs_compare_fh(&file->f_handle, f)) |
101 | goto found; | 100 | goto found; |
102 | 101 | ||
@@ -248,13 +247,13 @@ static int | |||
248 | nlm_traverse_files(void *data, nlm_host_match_fn_t match, | 247 | nlm_traverse_files(void *data, nlm_host_match_fn_t match, |
249 | int (*is_failover_file)(void *data, struct nlm_file *file)) | 248 | int (*is_failover_file)(void *data, struct nlm_file *file)) |
250 | { | 249 | { |
251 | struct hlist_node *pos, *next; | 250 | struct hlist_node *next; |
252 | struct nlm_file *file; | 251 | struct nlm_file *file; |
253 | int i, ret = 0; | 252 | int i, ret = 0; |
254 | 253 | ||
255 | mutex_lock(&nlm_file_mutex); | 254 | mutex_lock(&nlm_file_mutex); |
256 | for (i = 0; i < FILE_NRHASH; i++) { | 255 | for (i = 0; i < FILE_NRHASH; i++) { |
257 | hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) { | 256 | hlist_for_each_entry_safe(file, next, &nlm_files[i], f_list) { |
258 | if (is_failover_file && !is_failover_file(data, file)) | 257 | if (is_failover_file && !is_failover_file(data, file)) |
259 | continue; | 258 | continue; |
260 | file->f_count++; | 259 | file->f_count++; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 9f3c66438d0e..84d8eae203a7 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -197,7 +197,6 @@ error_0: | |||
197 | EXPORT_SYMBOL_GPL(nfs_alloc_client); | 197 | EXPORT_SYMBOL_GPL(nfs_alloc_client); |
198 | 198 | ||
199 | #if IS_ENABLED(CONFIG_NFS_V4) | 199 | #if IS_ENABLED(CONFIG_NFS_V4) |
200 | /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ | ||
201 | void nfs_cleanup_cb_ident_idr(struct net *net) | 200 | void nfs_cleanup_cb_ident_idr(struct net *net) |
202 | { | 201 | { |
203 | struct nfs_net *nn = net_generic(net, nfs_net_id); | 202 | struct nfs_net *nn = net_generic(net, nfs_net_id); |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 2e9779b58b7a..47d100872390 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -29,15 +29,14 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) | |||
29 | 29 | ||
30 | if (clp->rpc_ops->version != 4 || minorversion != 0) | 30 | if (clp->rpc_ops->version != 4 || minorversion != 0) |
31 | return ret; | 31 | return ret; |
32 | retry: | 32 | idr_preload(GFP_KERNEL); |
33 | if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL)) | ||
34 | return -ENOMEM; | ||
35 | spin_lock(&nn->nfs_client_lock); | 33 | spin_lock(&nn->nfs_client_lock); |
36 | ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident); | 34 | ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT); |
35 | if (ret >= 0) | ||
36 | clp->cl_cb_ident = ret; | ||
37 | spin_unlock(&nn->nfs_client_lock); | 37 | spin_unlock(&nn->nfs_client_lock); |
38 | if (ret == -EAGAIN) | 38 | idr_preload_end(); |
39 | goto retry; | 39 | return ret < 0 ? ret : 0; |
40 | return ret; | ||
41 | } | 40 | } |
42 | 41 | ||
43 | #ifdef CONFIG_NFS_V4_1 | 42 | #ifdef CONFIG_NFS_V4_1 |
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c index d35b62e83ea6..6da209bd9408 100644 --- a/fs/nfs/pnfs_dev.c +++ b/fs/nfs/pnfs_dev.c | |||
@@ -77,9 +77,8 @@ _lookup_deviceid(const struct pnfs_layoutdriver_type *ld, | |||
77 | long hash) | 77 | long hash) |
78 | { | 78 | { |
79 | struct nfs4_deviceid_node *d; | 79 | struct nfs4_deviceid_node *d; |
80 | struct hlist_node *n; | ||
81 | 80 | ||
82 | hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[hash], node) | 81 | hlist_for_each_entry_rcu(d, &nfs4_deviceid_cache[hash], node) |
83 | if (d->ld == ld && d->nfs_client == clp && | 82 | if (d->ld == ld && d->nfs_client == clp && |
84 | !memcmp(&d->deviceid, id, sizeof(*id))) { | 83 | !memcmp(&d->deviceid, id, sizeof(*id))) { |
85 | if (atomic_read(&d->ref)) | 84 | if (atomic_read(&d->ref)) |
@@ -248,12 +247,11 @@ static void | |||
248 | _deviceid_purge_client(const struct nfs_client *clp, long hash) | 247 | _deviceid_purge_client(const struct nfs_client *clp, long hash) |
249 | { | 248 | { |
250 | struct nfs4_deviceid_node *d; | 249 | struct nfs4_deviceid_node *d; |
251 | struct hlist_node *n; | ||
252 | HLIST_HEAD(tmp); | 250 | HLIST_HEAD(tmp); |
253 | 251 | ||
254 | spin_lock(&nfs4_deviceid_lock); | 252 | spin_lock(&nfs4_deviceid_lock); |
255 | rcu_read_lock(); | 253 | rcu_read_lock(); |
256 | hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[hash], node) | 254 | hlist_for_each_entry_rcu(d, &nfs4_deviceid_cache[hash], node) |
257 | if (d->nfs_client == clp && atomic_read(&d->ref)) { | 255 | if (d->nfs_client == clp && atomic_read(&d->ref)) { |
258 | hlist_del_init_rcu(&d->node); | 256 | hlist_del_init_rcu(&d->node); |
259 | hlist_add_head(&d->tmpnode, &tmp); | 257 | hlist_add_head(&d->tmpnode, &tmp); |
@@ -291,12 +289,11 @@ void | |||
291 | nfs4_deviceid_mark_client_invalid(struct nfs_client *clp) | 289 | nfs4_deviceid_mark_client_invalid(struct nfs_client *clp) |
292 | { | 290 | { |
293 | struct nfs4_deviceid_node *d; | 291 | struct nfs4_deviceid_node *d; |
294 | struct hlist_node *n; | ||
295 | int i; | 292 | int i; |
296 | 293 | ||
297 | rcu_read_lock(); | 294 | rcu_read_lock(); |
298 | for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i ++){ | 295 | for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i ++){ |
299 | hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[i], node) | 296 | hlist_for_each_entry_rcu(d, &nfs4_deviceid_cache[i], node) |
300 | if (d->nfs_client == clp) | 297 | if (d->nfs_client == clp) |
301 | set_bit(NFS_DEVICEID_INVALID, &d->flags); | 298 | set_bit(NFS_DEVICEID_INVALID, &d->flags); |
302 | } | 299 | } |
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 2cbac34a55da..da3dbd0f8979 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c | |||
@@ -120,7 +120,6 @@ hash_refile(struct svc_cacherep *rp) | |||
120 | int | 120 | int |
121 | nfsd_cache_lookup(struct svc_rqst *rqstp) | 121 | nfsd_cache_lookup(struct svc_rqst *rqstp) |
122 | { | 122 | { |
123 | struct hlist_node *hn; | ||
124 | struct hlist_head *rh; | 123 | struct hlist_head *rh; |
125 | struct svc_cacherep *rp; | 124 | struct svc_cacherep *rp; |
126 | __be32 xid = rqstp->rq_xid; | 125 | __be32 xid = rqstp->rq_xid; |
@@ -141,7 +140,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp) | |||
141 | rtn = RC_DOIT; | 140 | rtn = RC_DOIT; |
142 | 141 | ||
143 | rh = &cache_hash[request_hash(xid)]; | 142 | rh = &cache_hash[request_hash(xid)]; |
144 | hlist_for_each_entry(rp, hn, rh, c_hash) { | 143 | hlist_for_each_entry(rp, rh, c_hash) { |
145 | if (rp->c_state != RC_UNUSED && | 144 | if (rp->c_state != RC_UNUSED && |
146 | xid == rp->c_xid && proc == rp->c_proc && | 145 | xid == rp->c_xid && proc == rp->c_proc && |
147 | proto == rp->c_prot && vers == rp->c_vers && | 146 | proto == rp->c_prot && vers == rp->c_vers && |
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 6baadb5a8430..4bb21d67d9b1 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
@@ -52,7 +52,6 @@ void __fsnotify_vfsmount_delete(struct vfsmount *mnt) | |||
52 | void __fsnotify_update_child_dentry_flags(struct inode *inode) | 52 | void __fsnotify_update_child_dentry_flags(struct inode *inode) |
53 | { | 53 | { |
54 | struct dentry *alias; | 54 | struct dentry *alias; |
55 | struct hlist_node *p; | ||
56 | int watched; | 55 | int watched; |
57 | 56 | ||
58 | if (!S_ISDIR(inode->i_mode)) | 57 | if (!S_ISDIR(inode->i_mode)) |
@@ -64,7 +63,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) | |||
64 | spin_lock(&inode->i_lock); | 63 | spin_lock(&inode->i_lock); |
65 | /* run all of the dentries associated with this inode. Since this is a | 64 | /* run all of the dentries associated with this inode. Since this is a |
66 | * directory, there damn well better only be one item on this list */ | 65 | * directory, there damn well better only be one item on this list */ |
67 | hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) { | 66 | hlist_for_each_entry(alias, &inode->i_dentry, d_alias) { |
68 | struct dentry *child; | 67 | struct dentry *child; |
69 | 68 | ||
70 | /* run all of the children of the original inode and fix their | 69 | /* run all of the children of the original inode and fix their |
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index f31e90fc050d..74825be65b7b 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c | |||
@@ -36,12 +36,11 @@ | |||
36 | static void fsnotify_recalc_inode_mask_locked(struct inode *inode) | 36 | static void fsnotify_recalc_inode_mask_locked(struct inode *inode) |
37 | { | 37 | { |
38 | struct fsnotify_mark *mark; | 38 | struct fsnotify_mark *mark; |
39 | struct hlist_node *pos; | ||
40 | __u32 new_mask = 0; | 39 | __u32 new_mask = 0; |
41 | 40 | ||
42 | assert_spin_locked(&inode->i_lock); | 41 | assert_spin_locked(&inode->i_lock); |
43 | 42 | ||
44 | hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list) | 43 | hlist_for_each_entry(mark, &inode->i_fsnotify_marks, i.i_list) |
45 | new_mask |= mark->mask; | 44 | new_mask |= mark->mask; |
46 | inode->i_fsnotify_mask = new_mask; | 45 | inode->i_fsnotify_mask = new_mask; |
47 | } | 46 | } |
@@ -87,11 +86,11 @@ void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) | |||
87 | void fsnotify_clear_marks_by_inode(struct inode *inode) | 86 | void fsnotify_clear_marks_by_inode(struct inode *inode) |
88 | { | 87 | { |
89 | struct fsnotify_mark *mark, *lmark; | 88 | struct fsnotify_mark *mark, *lmark; |
90 | struct hlist_node *pos, *n; | 89 | struct hlist_node *n; |
91 | LIST_HEAD(free_list); | 90 | LIST_HEAD(free_list); |
92 | 91 | ||
93 | spin_lock(&inode->i_lock); | 92 | spin_lock(&inode->i_lock); |
94 | hlist_for_each_entry_safe(mark, pos, n, &inode->i_fsnotify_marks, i.i_list) { | 93 | hlist_for_each_entry_safe(mark, n, &inode->i_fsnotify_marks, i.i_list) { |
95 | list_add(&mark->i.free_i_list, &free_list); | 94 | list_add(&mark->i.free_i_list, &free_list); |
96 | hlist_del_init_rcu(&mark->i.i_list); | 95 | hlist_del_init_rcu(&mark->i.i_list); |
97 | fsnotify_get_mark(mark); | 96 | fsnotify_get_mark(mark); |
@@ -129,11 +128,10 @@ static struct fsnotify_mark *fsnotify_find_inode_mark_locked( | |||
129 | struct inode *inode) | 128 | struct inode *inode) |
130 | { | 129 | { |
131 | struct fsnotify_mark *mark; | 130 | struct fsnotify_mark *mark; |
132 | struct hlist_node *pos; | ||
133 | 131 | ||
134 | assert_spin_locked(&inode->i_lock); | 132 | assert_spin_locked(&inode->i_lock); |
135 | 133 | ||
136 | hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list) { | 134 | hlist_for_each_entry(mark, &inode->i_fsnotify_marks, i.i_list) { |
137 | if (mark->group == group) { | 135 | if (mark->group == group) { |
138 | fsnotify_get_mark(mark); | 136 | fsnotify_get_mark(mark); |
139 | return mark; | 137 | return mark; |
@@ -194,8 +192,7 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
194 | struct fsnotify_group *group, struct inode *inode, | 192 | struct fsnotify_group *group, struct inode *inode, |
195 | int allow_dups) | 193 | int allow_dups) |
196 | { | 194 | { |
197 | struct fsnotify_mark *lmark; | 195 | struct fsnotify_mark *lmark, *last = NULL; |
198 | struct hlist_node *node, *last = NULL; | ||
199 | int ret = 0; | 196 | int ret = 0; |
200 | 197 | ||
201 | mark->flags |= FSNOTIFY_MARK_FLAG_INODE; | 198 | mark->flags |= FSNOTIFY_MARK_FLAG_INODE; |
@@ -214,8 +211,8 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
214 | } | 211 | } |
215 | 212 | ||
216 | /* should mark be in the middle of the current list? */ | 213 | /* should mark be in the middle of the current list? */ |
217 | hlist_for_each_entry(lmark, node, &inode->i_fsnotify_marks, i.i_list) { | 214 | hlist_for_each_entry(lmark, &inode->i_fsnotify_marks, i.i_list) { |
218 | last = node; | 215 | last = lmark; |
219 | 216 | ||
220 | if ((lmark->group == group) && !allow_dups) { | 217 | if ((lmark->group == group) && !allow_dups) { |
221 | ret = -EEXIST; | 218 | ret = -EEXIST; |
@@ -235,7 +232,7 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
235 | 232 | ||
236 | BUG_ON(last == NULL); | 233 | BUG_ON(last == NULL); |
237 | /* mark should be the last entry. last is the current last entry */ | 234 | /* mark should be the last entry. last is the current last entry */ |
238 | hlist_add_after_rcu(last, &mark->i.i_list); | 235 | hlist_add_after_rcu(&last->i.i_list, &mark->i.i_list); |
239 | out: | 236 | out: |
240 | fsnotify_recalc_inode_mask_locked(inode); | 237 | fsnotify_recalc_inode_mask_locked(inode); |
241 | spin_unlock(&inode->i_lock); | 238 | spin_unlock(&inode->i_lock); |
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 871569c7d609..4216308b81b4 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c | |||
@@ -197,7 +197,6 @@ static void inotify_free_group_priv(struct fsnotify_group *group) | |||
197 | { | 197 | { |
198 | /* ideally the idr is empty and we won't hit the BUG in the callback */ | 198 | /* ideally the idr is empty and we won't hit the BUG in the callback */ |
199 | idr_for_each(&group->inotify_data.idr, idr_callback, group); | 199 | idr_for_each(&group->inotify_data.idr, idr_callback, group); |
200 | idr_remove_all(&group->inotify_data.idr); | ||
201 | idr_destroy(&group->inotify_data.idr); | 200 | idr_destroy(&group->inotify_data.idr); |
202 | atomic_dec(&group->inotify_data.user->inotify_devs); | 201 | atomic_dec(&group->inotify_data.user->inotify_devs); |
203 | free_uid(group->inotify_data.user); | 202 | free_uid(group->inotify_data.user); |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 07f7a92fe88e..e0f7c1241a6a 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -364,22 +364,20 @@ static int inotify_add_to_idr(struct idr *idr, spinlock_t *idr_lock, | |||
364 | { | 364 | { |
365 | int ret; | 365 | int ret; |
366 | 366 | ||
367 | do { | 367 | idr_preload(GFP_KERNEL); |
368 | if (unlikely(!idr_pre_get(idr, GFP_KERNEL))) | 368 | spin_lock(idr_lock); |
369 | return -ENOMEM; | ||
370 | 369 | ||
371 | spin_lock(idr_lock); | 370 | ret = idr_alloc(idr, i_mark, *last_wd + 1, 0, GFP_NOWAIT); |
372 | ret = idr_get_new_above(idr, i_mark, *last_wd + 1, | 371 | if (ret >= 0) { |
373 | &i_mark->wd); | ||
374 | /* we added the mark to the idr, take a reference */ | 372 | /* we added the mark to the idr, take a reference */ |
375 | if (!ret) { | 373 | i_mark->wd = ret; |
376 | *last_wd = i_mark->wd; | 374 | *last_wd = i_mark->wd; |
377 | fsnotify_get_mark(&i_mark->fsn_mark); | 375 | fsnotify_get_mark(&i_mark->fsn_mark); |
378 | } | 376 | } |
379 | spin_unlock(idr_lock); | ||
380 | } while (ret == -EAGAIN); | ||
381 | 377 | ||
382 | return ret; | 378 | spin_unlock(idr_lock); |
379 | idr_preload_end(); | ||
380 | return ret < 0 ? ret : 0; | ||
383 | } | 381 | } |
384 | 382 | ||
385 | static struct inotify_inode_mark *inotify_idr_find_locked(struct fsnotify_group *group, | 383 | static struct inotify_inode_mark *inotify_idr_find_locked(struct fsnotify_group *group, |
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index 4df58b8ea64a..68ca5a8704b5 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c | |||
@@ -33,12 +33,12 @@ | |||
33 | void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) | 33 | void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) |
34 | { | 34 | { |
35 | struct fsnotify_mark *mark, *lmark; | 35 | struct fsnotify_mark *mark, *lmark; |
36 | struct hlist_node *pos, *n; | 36 | struct hlist_node *n; |
37 | struct mount *m = real_mount(mnt); | 37 | struct mount *m = real_mount(mnt); |
38 | LIST_HEAD(free_list); | 38 | LIST_HEAD(free_list); |
39 | 39 | ||
40 | spin_lock(&mnt->mnt_root->d_lock); | 40 | spin_lock(&mnt->mnt_root->d_lock); |
41 | hlist_for_each_entry_safe(mark, pos, n, &m->mnt_fsnotify_marks, m.m_list) { | 41 | hlist_for_each_entry_safe(mark, n, &m->mnt_fsnotify_marks, m.m_list) { |
42 | list_add(&mark->m.free_m_list, &free_list); | 42 | list_add(&mark->m.free_m_list, &free_list); |
43 | hlist_del_init_rcu(&mark->m.m_list); | 43 | hlist_del_init_rcu(&mark->m.m_list); |
44 | fsnotify_get_mark(mark); | 44 | fsnotify_get_mark(mark); |
@@ -71,12 +71,11 @@ static void fsnotify_recalc_vfsmount_mask_locked(struct vfsmount *mnt) | |||
71 | { | 71 | { |
72 | struct mount *m = real_mount(mnt); | 72 | struct mount *m = real_mount(mnt); |
73 | struct fsnotify_mark *mark; | 73 | struct fsnotify_mark *mark; |
74 | struct hlist_node *pos; | ||
75 | __u32 new_mask = 0; | 74 | __u32 new_mask = 0; |
76 | 75 | ||
77 | assert_spin_locked(&mnt->mnt_root->d_lock); | 76 | assert_spin_locked(&mnt->mnt_root->d_lock); |
78 | 77 | ||
79 | hlist_for_each_entry(mark, pos, &m->mnt_fsnotify_marks, m.m_list) | 78 | hlist_for_each_entry(mark, &m->mnt_fsnotify_marks, m.m_list) |
80 | new_mask |= mark->mask; | 79 | new_mask |= mark->mask; |
81 | m->mnt_fsnotify_mask = new_mask; | 80 | m->mnt_fsnotify_mask = new_mask; |
82 | } | 81 | } |
@@ -114,11 +113,10 @@ static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_ | |||
114 | { | 113 | { |
115 | struct mount *m = real_mount(mnt); | 114 | struct mount *m = real_mount(mnt); |
116 | struct fsnotify_mark *mark; | 115 | struct fsnotify_mark *mark; |
117 | struct hlist_node *pos; | ||
118 | 116 | ||
119 | assert_spin_locked(&mnt->mnt_root->d_lock); | 117 | assert_spin_locked(&mnt->mnt_root->d_lock); |
120 | 118 | ||
121 | hlist_for_each_entry(mark, pos, &m->mnt_fsnotify_marks, m.m_list) { | 119 | hlist_for_each_entry(mark, &m->mnt_fsnotify_marks, m.m_list) { |
122 | if (mark->group == group) { | 120 | if (mark->group == group) { |
123 | fsnotify_get_mark(mark); | 121 | fsnotify_get_mark(mark); |
124 | return mark; | 122 | return mark; |
@@ -153,8 +151,7 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
153 | int allow_dups) | 151 | int allow_dups) |
154 | { | 152 | { |
155 | struct mount *m = real_mount(mnt); | 153 | struct mount *m = real_mount(mnt); |
156 | struct fsnotify_mark *lmark; | 154 | struct fsnotify_mark *lmark, *last = NULL; |
157 | struct hlist_node *node, *last = NULL; | ||
158 | int ret = 0; | 155 | int ret = 0; |
159 | 156 | ||
160 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; | 157 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; |
@@ -173,8 +170,8 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
173 | } | 170 | } |
174 | 171 | ||
175 | /* should mark be in the middle of the current list? */ | 172 | /* should mark be in the middle of the current list? */ |
176 | hlist_for_each_entry(lmark, node, &m->mnt_fsnotify_marks, m.m_list) { | 173 | hlist_for_each_entry(lmark, &m->mnt_fsnotify_marks, m.m_list) { |
177 | last = node; | 174 | last = lmark; |
178 | 175 | ||
179 | if ((lmark->group == group) && !allow_dups) { | 176 | if ((lmark->group == group) && !allow_dups) { |
180 | ret = -EEXIST; | 177 | ret = -EEXIST; |
@@ -194,7 +191,7 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
194 | 191 | ||
195 | BUG_ON(last == NULL); | 192 | BUG_ON(last == NULL); |
196 | /* mark should be the last entry. last is the current last entry */ | 193 | /* mark should be the last entry. last is the current last entry */ |
197 | hlist_add_after_rcu(last, &mark->m.m_list); | 194 | hlist_add_after_rcu(&last->m.m_list, &mark->m.m_list); |
198 | out: | 195 | out: |
199 | fsnotify_recalc_vfsmount_mask_locked(mnt); | 196 | fsnotify_recalc_vfsmount_mask_locked(mnt); |
200 | spin_unlock(&mnt->mnt_root->d_lock); | 197 | spin_unlock(&mnt->mnt_root->d_lock); |
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 0d2bf566e39a..aa88bd8bcedc 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c | |||
@@ -304,28 +304,22 @@ static u8 o2net_num_from_nn(struct o2net_node *nn) | |||
304 | 304 | ||
305 | static int o2net_prep_nsw(struct o2net_node *nn, struct o2net_status_wait *nsw) | 305 | static int o2net_prep_nsw(struct o2net_node *nn, struct o2net_status_wait *nsw) |
306 | { | 306 | { |
307 | int ret = 0; | 307 | int ret; |
308 | |||
309 | do { | ||
310 | if (!idr_pre_get(&nn->nn_status_idr, GFP_ATOMIC)) { | ||
311 | ret = -EAGAIN; | ||
312 | break; | ||
313 | } | ||
314 | spin_lock(&nn->nn_lock); | ||
315 | ret = idr_get_new(&nn->nn_status_idr, nsw, &nsw->ns_id); | ||
316 | if (ret == 0) | ||
317 | list_add_tail(&nsw->ns_node_item, | ||
318 | &nn->nn_status_list); | ||
319 | spin_unlock(&nn->nn_lock); | ||
320 | } while (ret == -EAGAIN); | ||
321 | 308 | ||
322 | if (ret == 0) { | 309 | spin_lock(&nn->nn_lock); |
323 | init_waitqueue_head(&nsw->ns_wq); | 310 | ret = idr_alloc(&nn->nn_status_idr, nsw, 0, 0, GFP_ATOMIC); |
324 | nsw->ns_sys_status = O2NET_ERR_NONE; | 311 | if (ret >= 0) { |
325 | nsw->ns_status = 0; | 312 | nsw->ns_id = ret; |
313 | list_add_tail(&nsw->ns_node_item, &nn->nn_status_list); | ||
326 | } | 314 | } |
315 | spin_unlock(&nn->nn_lock); | ||
316 | if (ret < 0) | ||
317 | return ret; | ||
327 | 318 | ||
328 | return ret; | 319 | init_waitqueue_head(&nsw->ns_wq); |
320 | nsw->ns_sys_status = O2NET_ERR_NONE; | ||
321 | nsw->ns_status = 0; | ||
322 | return 0; | ||
329 | } | 323 | } |
330 | 324 | ||
331 | static void o2net_complete_nsw_locked(struct o2net_node *nn, | 325 | static void o2net_complete_nsw_locked(struct o2net_node *nn, |
diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index 8db4b58b2e4b..ef999729e274 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c | |||
@@ -169,11 +169,10 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode, | |||
169 | u64 parent_blkno, | 169 | u64 parent_blkno, |
170 | int skip_unhashed) | 170 | int skip_unhashed) |
171 | { | 171 | { |
172 | struct hlist_node *p; | ||
173 | struct dentry *dentry; | 172 | struct dentry *dentry; |
174 | 173 | ||
175 | spin_lock(&inode->i_lock); | 174 | spin_lock(&inode->i_lock); |
176 | hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) { | 175 | hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
177 | spin_lock(&dentry->d_lock); | 176 | spin_lock(&dentry->d_lock); |
178 | if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) { | 177 | if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) { |
179 | trace_ocfs2_find_local_alias(dentry->d_name.len, | 178 | trace_ocfs2_find_local_alias(dentry->d_name.len, |
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 01ebfd0bdad7..eeac97bb3bfa 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c | |||
@@ -2083,7 +2083,6 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm, | |||
2083 | u8 dead_node, u8 new_master) | 2083 | u8 dead_node, u8 new_master) |
2084 | { | 2084 | { |
2085 | int i; | 2085 | int i; |
2086 | struct hlist_node *hash_iter; | ||
2087 | struct hlist_head *bucket; | 2086 | struct hlist_head *bucket; |
2088 | struct dlm_lock_resource *res, *next; | 2087 | struct dlm_lock_resource *res, *next; |
2089 | 2088 | ||
@@ -2114,7 +2113,7 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm, | |||
2114 | * if necessary */ | 2113 | * if necessary */ |
2115 | for (i = 0; i < DLM_HASH_BUCKETS; i++) { | 2114 | for (i = 0; i < DLM_HASH_BUCKETS; i++) { |
2116 | bucket = dlm_lockres_hash(dlm, i); | 2115 | bucket = dlm_lockres_hash(dlm, i); |
2117 | hlist_for_each_entry(res, hash_iter, bucket, hash_node) { | 2116 | hlist_for_each_entry(res, bucket, hash_node) { |
2118 | if (!(res->state & DLM_LOCK_RES_RECOVERING)) | 2117 | if (!(res->state & DLM_LOCK_RES_RECOVERING)) |
2119 | continue; | 2118 | continue; |
2120 | 2119 | ||
@@ -2273,7 +2272,6 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm, | |||
2273 | 2272 | ||
2274 | static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) | 2273 | static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) |
2275 | { | 2274 | { |
2276 | struct hlist_node *iter; | ||
2277 | struct dlm_lock_resource *res; | 2275 | struct dlm_lock_resource *res; |
2278 | int i; | 2276 | int i; |
2279 | struct hlist_head *bucket; | 2277 | struct hlist_head *bucket; |
@@ -2299,7 +2297,7 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) | |||
2299 | */ | 2297 | */ |
2300 | for (i = 0; i < DLM_HASH_BUCKETS; i++) { | 2298 | for (i = 0; i < DLM_HASH_BUCKETS; i++) { |
2301 | bucket = dlm_lockres_hash(dlm, i); | 2299 | bucket = dlm_lockres_hash(dlm, i); |
2302 | hlist_for_each_entry(res, iter, bucket, hash_node) { | 2300 | hlist_for_each_entry(res, bucket, hash_node) { |
2303 | /* always prune any $RECOVERY entries for dead nodes, | 2301 | /* always prune any $RECOVERY entries for dead nodes, |
2304 | * otherwise hangs can occur during later recovery */ | 2302 | * otherwise hangs can occur during later recovery */ |
2305 | if (dlm_is_recovery_lock(res->lockname.name, | 2303 | if (dlm_is_recovery_lock(res->lockname.name, |
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index f169da4624fd..b7e74b580c0f 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -642,7 +642,7 @@ ocfs2_block_group_alloc_discontig(handle_t *handle, | |||
642 | * cluster groups will be staying in cache for the duration of | 642 | * cluster groups will be staying in cache for the duration of |
643 | * this operation. | 643 | * this operation. |
644 | */ | 644 | */ |
645 | ac->ac_allow_chain_relink = 0; | 645 | ac->ac_disable_chain_relink = 1; |
646 | 646 | ||
647 | /* Claim the first region */ | 647 | /* Claim the first region */ |
648 | status = ocfs2_block_group_claim_bits(osb, handle, ac, min_bits, | 648 | status = ocfs2_block_group_claim_bits(osb, handle, ac, min_bits, |
@@ -1823,7 +1823,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | |||
1823 | * Do this *after* figuring out how many bits we're taking out | 1823 | * Do this *after* figuring out how many bits we're taking out |
1824 | * of our target group. | 1824 | * of our target group. |
1825 | */ | 1825 | */ |
1826 | if (ac->ac_allow_chain_relink && | 1826 | if (!ac->ac_disable_chain_relink && |
1827 | (prev_group_bh) && | 1827 | (prev_group_bh) && |
1828 | (ocfs2_block_group_reasonably_empty(bg, res->sr_bits))) { | 1828 | (ocfs2_block_group_reasonably_empty(bg, res->sr_bits))) { |
1829 | status = ocfs2_relink_block_group(handle, alloc_inode, | 1829 | status = ocfs2_relink_block_group(handle, alloc_inode, |
@@ -1928,7 +1928,6 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, | |||
1928 | 1928 | ||
1929 | victim = ocfs2_find_victim_chain(cl); | 1929 | victim = ocfs2_find_victim_chain(cl); |
1930 | ac->ac_chain = victim; | 1930 | ac->ac_chain = victim; |
1931 | ac->ac_allow_chain_relink = 1; | ||
1932 | 1931 | ||
1933 | status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, | 1932 | status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, |
1934 | res, &bits_left); | 1933 | res, &bits_left); |
@@ -1947,7 +1946,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, | |||
1947 | * searching each chain in order. Don't allow chain relinking | 1946 | * searching each chain in order. Don't allow chain relinking |
1948 | * because we only calculate enough journal credits for one | 1947 | * because we only calculate enough journal credits for one |
1949 | * relink per alloc. */ | 1948 | * relink per alloc. */ |
1950 | ac->ac_allow_chain_relink = 0; | 1949 | ac->ac_disable_chain_relink = 1; |
1951 | for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i ++) { | 1950 | for (i = 0; i < le16_to_cpu(cl->cl_next_free_rec); i ++) { |
1952 | if (i == victim) | 1951 | if (i == victim) |
1953 | continue; | 1952 | continue; |
diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index b8afabfeede4..a36d0aa50911 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h | |||
@@ -49,7 +49,7 @@ struct ocfs2_alloc_context { | |||
49 | 49 | ||
50 | /* these are used by the chain search */ | 50 | /* these are used by the chain search */ |
51 | u16 ac_chain; | 51 | u16 ac_chain; |
52 | int ac_allow_chain_relink; | 52 | int ac_disable_chain_relink; |
53 | group_search_t *ac_group_search; | 53 | group_search_t *ac_group_search; |
54 | 54 | ||
55 | u64 ac_last_group; | 55 | u64 ac_last_group; |
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 0ba9ea1e7961..2e3ea308c144 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -7189,7 +7189,7 @@ int ocfs2_init_security_and_acl(struct inode *dir, | |||
7189 | struct buffer_head *dir_bh = NULL; | 7189 | struct buffer_head *dir_bh = NULL; |
7190 | 7190 | ||
7191 | ret = ocfs2_init_security_get(inode, dir, qstr, NULL); | 7191 | ret = ocfs2_init_security_get(inode, dir, qstr, NULL); |
7192 | if (!ret) { | 7192 | if (ret) { |
7193 | mlog_errno(ret); | 7193 | mlog_errno(ret); |
7194 | goto leave; | 7194 | goto leave; |
7195 | } | 7195 | } |
diff --git a/fs/proc/base.c b/fs/proc/base.c index f3b133d79914..69078c7cef1f 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -73,6 +73,7 @@ | |||
73 | #include <linux/security.h> | 73 | #include <linux/security.h> |
74 | #include <linux/ptrace.h> | 74 | #include <linux/ptrace.h> |
75 | #include <linux/tracehook.h> | 75 | #include <linux/tracehook.h> |
76 | #include <linux/printk.h> | ||
76 | #include <linux/cgroup.h> | 77 | #include <linux/cgroup.h> |
77 | #include <linux/cpuset.h> | 78 | #include <linux/cpuset.h> |
78 | #include <linux/audit.h> | 79 | #include <linux/audit.h> |
@@ -952,7 +953,7 @@ static ssize_t oom_adj_write(struct file *file, const char __user *buf, | |||
952 | * /proc/pid/oom_adj is provided for legacy purposes, ask users to use | 953 | * /proc/pid/oom_adj is provided for legacy purposes, ask users to use |
953 | * /proc/pid/oom_score_adj instead. | 954 | * /proc/pid/oom_score_adj instead. |
954 | */ | 955 | */ |
955 | printk_once(KERN_WARNING "%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n", | 956 | pr_warn_once("%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n", |
956 | current->comm, task_pid_nr(current), task_pid_nr(task), | 957 | current->comm, task_pid_nr(current), task_pid_nr(task), |
957 | task_pid_nr(task)); | 958 | task_pid_nr(task)); |
958 | 959 | ||
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 2983dc52ca25..4b3b3ffb52f1 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/printk.h> | ||
18 | #include <linux/mount.h> | 19 | #include <linux/mount.h> |
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
20 | #include <linux/idr.h> | 21 | #include <linux/idr.h> |
@@ -132,11 +133,8 @@ __proc_file_read(struct file *file, char __user *buf, size_t nbytes, | |||
132 | } | 133 | } |
133 | 134 | ||
134 | if (start == NULL) { | 135 | if (start == NULL) { |
135 | if (n > PAGE_SIZE) { | 136 | if (n > PAGE_SIZE) /* Apparent buffer overflow */ |
136 | printk(KERN_ERR | ||
137 | "proc_file_read: Apparent buffer overflow!\n"); | ||
138 | n = PAGE_SIZE; | 137 | n = PAGE_SIZE; |
139 | } | ||
140 | n -= *ppos; | 138 | n -= *ppos; |
141 | if (n <= 0) | 139 | if (n <= 0) |
142 | break; | 140 | break; |
@@ -144,26 +142,19 @@ __proc_file_read(struct file *file, char __user *buf, size_t nbytes, | |||
144 | n = count; | 142 | n = count; |
145 | start = page + *ppos; | 143 | start = page + *ppos; |
146 | } else if (start < page) { | 144 | } else if (start < page) { |
147 | if (n > PAGE_SIZE) { | 145 | if (n > PAGE_SIZE) /* Apparent buffer overflow */ |
148 | printk(KERN_ERR | ||
149 | "proc_file_read: Apparent buffer overflow!\n"); | ||
150 | n = PAGE_SIZE; | 146 | n = PAGE_SIZE; |
151 | } | ||
152 | if (n > count) { | 147 | if (n > count) { |
153 | /* | 148 | /* |
154 | * Don't reduce n because doing so might | 149 | * Don't reduce n because doing so might |
155 | * cut off part of a data block. | 150 | * cut off part of a data block. |
156 | */ | 151 | */ |
157 | printk(KERN_WARNING | 152 | pr_warn("proc_file_read: count exceeded\n"); |
158 | "proc_file_read: Read count exceeded\n"); | ||
159 | } | 153 | } |
160 | } else /* start >= page */ { | 154 | } else /* start >= page */ { |
161 | unsigned long startoff = (unsigned long)(start - page); | 155 | unsigned long startoff = (unsigned long)(start - page); |
162 | if (n > (PAGE_SIZE - startoff)) { | 156 | if (n > (PAGE_SIZE - startoff)) /* buffer overflow? */ |
163 | printk(KERN_ERR | ||
164 | "proc_file_read: Apparent buffer overflow!\n"); | ||
165 | n = PAGE_SIZE - startoff; | 157 | n = PAGE_SIZE - startoff; |
166 | } | ||
167 | if (n > count) | 158 | if (n > count) |
168 | n = count; | 159 | n = count; |
169 | } | 160 | } |
@@ -569,7 +560,7 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp | |||
569 | 560 | ||
570 | for (tmp = dir->subdir; tmp; tmp = tmp->next) | 561 | for (tmp = dir->subdir; tmp; tmp = tmp->next) |
571 | if (strcmp(tmp->name, dp->name) == 0) { | 562 | if (strcmp(tmp->name, dp->name) == 0) { |
572 | WARN(1, KERN_WARNING "proc_dir_entry '%s/%s' already registered\n", | 563 | WARN(1, "proc_dir_entry '%s/%s' already registered\n", |
573 | dir->name, dp->name); | 564 | dir->name, dp->name); |
574 | break; | 565 | break; |
575 | } | 566 | } |
@@ -830,9 +821,9 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
830 | if (S_ISDIR(de->mode)) | 821 | if (S_ISDIR(de->mode)) |
831 | parent->nlink--; | 822 | parent->nlink--; |
832 | de->nlink = 0; | 823 | de->nlink = 0; |
833 | WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " | 824 | WARN(de->subdir, "%s: removing non-empty directory " |
834 | "'%s/%s', leaking at least '%s'\n", __func__, | 825 | "'%s/%s', leaking at least '%s'\n", __func__, |
835 | de->parent->name, de->name, de->subdir->name); | 826 | de->parent->name, de->name, de->subdir->name); |
836 | pde_put(de); | 827 | pde_put(de); |
837 | } | 828 | } |
838 | EXPORT_SYMBOL(remove_proc_entry); | 829 | EXPORT_SYMBOL(remove_proc_entry); |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 70322e1a4f0f..a86aebc9ba7c 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/stat.h> | 13 | #include <linux/stat.h> |
14 | #include <linux/completion.h> | 14 | #include <linux/completion.h> |
15 | #include <linux/poll.h> | 15 | #include <linux/poll.h> |
16 | #include <linux/printk.h> | ||
16 | #include <linux/file.h> | 17 | #include <linux/file.h> |
17 | #include <linux/limits.h> | 18 | #include <linux/limits.h> |
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
@@ -495,13 +496,13 @@ int proc_fill_super(struct super_block *s) | |||
495 | pde_get(&proc_root); | 496 | pde_get(&proc_root); |
496 | root_inode = proc_get_inode(s, &proc_root); | 497 | root_inode = proc_get_inode(s, &proc_root); |
497 | if (!root_inode) { | 498 | if (!root_inode) { |
498 | printk(KERN_ERR "proc_fill_super: get root inode failed\n"); | 499 | pr_err("proc_fill_super: get root inode failed\n"); |
499 | return -ENOMEM; | 500 | return -ENOMEM; |
500 | } | 501 | } |
501 | 502 | ||
502 | s->s_root = d_make_root(root_inode); | 503 | s->s_root = d_make_root(root_inode); |
503 | if (!s->s_root) { | 504 | if (!s->s_root) { |
504 | printk(KERN_ERR "proc_fill_super: allocate dentry failed\n"); | 505 | pr_err("proc_fill_super: allocate dentry failed\n"); |
505 | return -ENOMEM; | 506 | return -ENOMEM; |
506 | } | 507 | } |
507 | 508 | ||
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 252544c05207..85ff3a4598b3 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/proc_fs.h> | 13 | #include <linux/proc_fs.h> |
14 | #include <linux/binfmts.h> | ||
14 | struct ctl_table_header; | 15 | struct ctl_table_header; |
15 | struct mempolicy; | 16 | struct mempolicy; |
16 | 17 | ||
@@ -108,7 +109,7 @@ static inline int task_dumpable(struct task_struct *task) | |||
108 | if (mm) | 109 | if (mm) |
109 | dumpable = get_dumpable(mm); | 110 | dumpable = get_dumpable(mm); |
110 | task_unlock(task); | 111 | task_unlock(task); |
111 | if (dumpable == SUID_DUMPABLE_ENABLED) | 112 | if (dumpable == SUID_DUMP_USER) |
112 | return 1; | 113 | return 1; |
113 | return 0; | 114 | return 0; |
114 | } | 115 | } |
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index e96d4f18ca3a..eda6f017f272 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/elfcore.h> | 17 | #include <linux/elfcore.h> |
18 | #include <linux/vmalloc.h> | 18 | #include <linux/vmalloc.h> |
19 | #include <linux/highmem.h> | 19 | #include <linux/highmem.h> |
20 | #include <linux/printk.h> | ||
20 | #include <linux/bootmem.h> | 21 | #include <linux/bootmem.h> |
21 | #include <linux/init.h> | 22 | #include <linux/init.h> |
22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
@@ -619,7 +620,7 @@ static int __init proc_kcore_init(void) | |||
619 | proc_root_kcore = proc_create("kcore", S_IRUSR, NULL, | 620 | proc_root_kcore = proc_create("kcore", S_IRUSR, NULL, |
620 | &proc_kcore_operations); | 621 | &proc_kcore_operations); |
621 | if (!proc_root_kcore) { | 622 | if (!proc_root_kcore) { |
622 | printk(KERN_ERR "couldn't create /proc/kcore\n"); | 623 | pr_err("couldn't create /proc/kcore\n"); |
623 | return 0; /* Always returns 0. */ | 624 | return 0; /* Always returns 0. */ |
624 | } | 625 | } |
625 | /* Store text area if it's special */ | 626 | /* Store text area if it's special */ |
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index de20ec480fa0..30b590f5bd35 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/time.h> | 8 | #include <linux/time.h> |
9 | #include <linux/proc_fs.h> | 9 | #include <linux/proc_fs.h> |
10 | #include <linux/seq_file.h> | 10 | #include <linux/seq_file.h> |
11 | #include <linux/printk.h> | ||
11 | #include <linux/stat.h> | 12 | #include <linux/stat.h> |
12 | #include <linux/string.h> | 13 | #include <linux/string.h> |
13 | #include <linux/of.h> | 14 | #include <linux/of.h> |
@@ -110,8 +111,8 @@ void proc_device_tree_update_prop(struct proc_dir_entry *pde, | |||
110 | if (ent->data == oldprop) | 111 | if (ent->data == oldprop) |
111 | break; | 112 | break; |
112 | if (ent == NULL) { | 113 | if (ent == NULL) { |
113 | printk(KERN_WARNING "device-tree: property \"%s\" " | 114 | pr_warn("device-tree: property \"%s\" does not exist\n", |
114 | " does not exist\n", oldprop->name); | 115 | oldprop->name); |
115 | } else { | 116 | } else { |
116 | ent->data = newprop; | 117 | ent->data = newprop; |
117 | ent->size = newprop->length; | 118 | ent->size = newprop->length; |
@@ -153,8 +154,8 @@ static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de, | |||
153 | realloc: | 154 | realloc: |
154 | fixed_name = kmalloc(fixup_len, GFP_KERNEL); | 155 | fixed_name = kmalloc(fixup_len, GFP_KERNEL); |
155 | if (fixed_name == NULL) { | 156 | if (fixed_name == NULL) { |
156 | printk(KERN_ERR "device-tree: Out of memory trying to fixup " | 157 | pr_err("device-tree: Out of memory trying to fixup " |
157 | "name \"%s\"\n", name); | 158 | "name \"%s\"\n", name); |
158 | return name; | 159 | return name; |
159 | } | 160 | } |
160 | 161 | ||
@@ -175,8 +176,8 @@ retry: | |||
175 | goto retry; | 176 | goto retry; |
176 | } | 177 | } |
177 | 178 | ||
178 | printk(KERN_WARNING "device-tree: Duplicate name in %s, " | 179 | pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n", |
179 | "renamed to \"%s\"\n", np->full_name, fixed_name); | 180 | np->full_name, fixed_name); |
180 | 181 | ||
181 | return fixed_name; | 182 | return fixed_name; |
182 | } | 183 | } |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 612df79cc6a1..ac05f33a0dde 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/sysctl.h> | 5 | #include <linux/sysctl.h> |
6 | #include <linux/poll.h> | 6 | #include <linux/poll.h> |
7 | #include <linux/proc_fs.h> | 7 | #include <linux/proc_fs.h> |
8 | #include <linux/printk.h> | ||
8 | #include <linux/security.h> | 9 | #include <linux/security.h> |
9 | #include <linux/sched.h> | 10 | #include <linux/sched.h> |
10 | #include <linux/namei.h> | 11 | #include <linux/namei.h> |
@@ -57,7 +58,7 @@ static void sysctl_print_dir(struct ctl_dir *dir) | |||
57 | { | 58 | { |
58 | if (dir->header.parent) | 59 | if (dir->header.parent) |
59 | sysctl_print_dir(dir->header.parent); | 60 | sysctl_print_dir(dir->header.parent); |
60 | printk(KERN_CONT "%s/", dir->header.ctl_table[0].procname); | 61 | pr_cont("%s/", dir->header.ctl_table[0].procname); |
61 | } | 62 | } |
62 | 63 | ||
63 | static int namecmp(const char *name1, int len1, const char *name2, int len2) | 64 | static int namecmp(const char *name1, int len1, const char *name2, int len2) |
@@ -134,9 +135,9 @@ static int insert_entry(struct ctl_table_header *head, struct ctl_table *entry) | |||
134 | else if (cmp > 0) | 135 | else if (cmp > 0) |
135 | p = &(*p)->rb_right; | 136 | p = &(*p)->rb_right; |
136 | else { | 137 | else { |
137 | printk(KERN_ERR "sysctl duplicate entry: "); | 138 | pr_err("sysctl duplicate entry: "); |
138 | sysctl_print_dir(head->parent); | 139 | sysctl_print_dir(head->parent); |
139 | printk(KERN_CONT "/%s\n", entry->procname); | 140 | pr_cont("/%s\n", entry->procname); |
140 | return -EEXIST; | 141 | return -EEXIST; |
141 | } | 142 | } |
142 | } | 143 | } |
@@ -927,9 +928,9 @@ found: | |||
927 | subdir->header.nreg++; | 928 | subdir->header.nreg++; |
928 | failed: | 929 | failed: |
929 | if (unlikely(IS_ERR(subdir))) { | 930 | if (unlikely(IS_ERR(subdir))) { |
930 | printk(KERN_ERR "sysctl could not get directory: "); | 931 | pr_err("sysctl could not get directory: "); |
931 | sysctl_print_dir(dir); | 932 | sysctl_print_dir(dir); |
932 | printk(KERN_CONT "/%*.*s %ld\n", | 933 | pr_cont("/%*.*s %ld\n", |
933 | namelen, namelen, name, PTR_ERR(subdir)); | 934 | namelen, namelen, name, PTR_ERR(subdir)); |
934 | } | 935 | } |
935 | drop_sysctl_table(&dir->header); | 936 | drop_sysctl_table(&dir->header); |
@@ -995,8 +996,8 @@ static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...) | |||
995 | vaf.fmt = fmt; | 996 | vaf.fmt = fmt; |
996 | vaf.va = &args; | 997 | vaf.va = &args; |
997 | 998 | ||
998 | printk(KERN_ERR "sysctl table check failed: %s/%s %pV\n", | 999 | pr_err("sysctl table check failed: %s/%s %pV\n", |
999 | path, table->procname, &vaf); | 1000 | path, table->procname, &vaf); |
1000 | 1001 | ||
1001 | va_end(args); | 1002 | va_end(args); |
1002 | return -EINVAL; | 1003 | return -EINVAL; |
@@ -1510,9 +1511,9 @@ static void put_links(struct ctl_table_header *header) | |||
1510 | drop_sysctl_table(link_head); | 1511 | drop_sysctl_table(link_head); |
1511 | } | 1512 | } |
1512 | else { | 1513 | else { |
1513 | printk(KERN_ERR "sysctl link missing during unregister: "); | 1514 | pr_err("sysctl link missing during unregister: "); |
1514 | sysctl_print_dir(parent); | 1515 | sysctl_print_dir(parent); |
1515 | printk(KERN_CONT "/%s\n", name); | 1516 | pr_cont("/%s\n", name); |
1516 | } | 1517 | } |
1517 | } | 1518 | } |
1518 | } | 1519 | } |
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 0d5071d29985..b870f740ab5a 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/export.h> | 15 | #include <linux/export.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/highmem.h> | 17 | #include <linux/highmem.h> |
18 | #include <linux/printk.h> | ||
18 | #include <linux/bootmem.h> | 19 | #include <linux/bootmem.h> |
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
20 | #include <linux/crash_dump.h> | 21 | #include <linux/crash_dump.h> |
@@ -175,15 +176,15 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer, | |||
175 | start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m); | 176 | start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m); |
176 | if (!curr_m) | 177 | if (!curr_m) |
177 | return -EINVAL; | 178 | return -EINVAL; |
178 | if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) | ||
179 | tsz = buflen; | ||
180 | |||
181 | /* Calculate left bytes in current memory segment. */ | ||
182 | nr_bytes = (curr_m->size - (start - curr_m->paddr)); | ||
183 | if (tsz > nr_bytes) | ||
184 | tsz = nr_bytes; | ||
185 | 179 | ||
186 | while (buflen) { | 180 | while (buflen) { |
181 | tsz = min_t(size_t, buflen, PAGE_SIZE - (start & ~PAGE_MASK)); | ||
182 | |||
183 | /* Calculate left bytes in current memory segment. */ | ||
184 | nr_bytes = (curr_m->size - (start - curr_m->paddr)); | ||
185 | if (tsz > nr_bytes) | ||
186 | tsz = nr_bytes; | ||
187 | |||
187 | tmp = read_from_oldmem(buffer, tsz, &start, 1); | 188 | tmp = read_from_oldmem(buffer, tsz, &start, 1); |
188 | if (tmp < 0) | 189 | if (tmp < 0) |
189 | return tmp; | 190 | return tmp; |
@@ -198,12 +199,6 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer, | |||
198 | struct vmcore, list); | 199 | struct vmcore, list); |
199 | start = curr_m->paddr; | 200 | start = curr_m->paddr; |
200 | } | 201 | } |
201 | if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) | ||
202 | tsz = buflen; | ||
203 | /* Calculate left bytes in current memory segment. */ | ||
204 | nr_bytes = (curr_m->size - (start - curr_m->paddr)); | ||
205 | if (tsz > nr_bytes) | ||
206 | tsz = nr_bytes; | ||
207 | } | 202 | } |
208 | return acc; | 203 | return acc; |
209 | } | 204 | } |
@@ -553,8 +548,7 @@ static int __init parse_crash_elf64_headers(void) | |||
553 | ehdr.e_ehsize != sizeof(Elf64_Ehdr) || | 548 | ehdr.e_ehsize != sizeof(Elf64_Ehdr) || |
554 | ehdr.e_phentsize != sizeof(Elf64_Phdr) || | 549 | ehdr.e_phentsize != sizeof(Elf64_Phdr) || |
555 | ehdr.e_phnum == 0) { | 550 | ehdr.e_phnum == 0) { |
556 | printk(KERN_WARNING "Warning: Core image elf header is not" | 551 | pr_warn("Warning: Core image elf header is not sane\n"); |
557 | "sane\n"); | ||
558 | return -EINVAL; | 552 | return -EINVAL; |
559 | } | 553 | } |
560 | 554 | ||
@@ -609,8 +603,7 @@ static int __init parse_crash_elf32_headers(void) | |||
609 | ehdr.e_ehsize != sizeof(Elf32_Ehdr) || | 603 | ehdr.e_ehsize != sizeof(Elf32_Ehdr) || |
610 | ehdr.e_phentsize != sizeof(Elf32_Phdr) || | 604 | ehdr.e_phentsize != sizeof(Elf32_Phdr) || |
611 | ehdr.e_phnum == 0) { | 605 | ehdr.e_phnum == 0) { |
612 | printk(KERN_WARNING "Warning: Core image elf header is not" | 606 | pr_warn("Warning: Core image elf header is not sane\n"); |
613 | "sane\n"); | ||
614 | return -EINVAL; | 607 | return -EINVAL; |
615 | } | 608 | } |
616 | 609 | ||
@@ -653,8 +646,7 @@ static int __init parse_crash_elf_headers(void) | |||
653 | if (rc < 0) | 646 | if (rc < 0) |
654 | return rc; | 647 | return rc; |
655 | if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) { | 648 | if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) { |
656 | printk(KERN_WARNING "Warning: Core image elf header" | 649 | pr_warn("Warning: Core image elf header not found\n"); |
657 | " not found\n"); | ||
658 | return -EINVAL; | 650 | return -EINVAL; |
659 | } | 651 | } |
660 | 652 | ||
@@ -673,8 +665,7 @@ static int __init parse_crash_elf_headers(void) | |||
673 | /* Determine vmcore size. */ | 665 | /* Determine vmcore size. */ |
674 | vmcore_size = get_vmcore_size_elf32(elfcorebuf); | 666 | vmcore_size = get_vmcore_size_elf32(elfcorebuf); |
675 | } else { | 667 | } else { |
676 | printk(KERN_WARNING "Warning: Core image elf header is not" | 668 | pr_warn("Warning: Core image elf header is not sane\n"); |
677 | " sane\n"); | ||
678 | return -EINVAL; | 669 | return -EINVAL; |
679 | } | 670 | } |
680 | return 0; | 671 | return 0; |
@@ -690,7 +681,7 @@ static int __init vmcore_init(void) | |||
690 | return rc; | 681 | return rc; |
691 | rc = parse_crash_elf_headers(); | 682 | rc = parse_crash_elf_headers(); |
692 | if (rc) { | 683 | if (rc) { |
693 | printk(KERN_WARNING "Kdump: vmcore not initialized\n"); | 684 | pr_warn("Kdump: vmcore not initialized\n"); |
694 | return rc; | 685 | return rc; |
695 | } | 686 | } |
696 | 687 | ||
diff --git a/fs/seq_file.c b/fs/seq_file.c index f2bc3dfd0b88..15c6304bab71 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
@@ -308,27 +308,27 @@ loff_t seq_lseek(struct file *file, loff_t offset, int whence) | |||
308 | mutex_lock(&m->lock); | 308 | mutex_lock(&m->lock); |
309 | m->version = file->f_version; | 309 | m->version = file->f_version; |
310 | switch (whence) { | 310 | switch (whence) { |
311 | case 1: | 311 | case SEEK_CUR: |
312 | offset += file->f_pos; | 312 | offset += file->f_pos; |
313 | case 0: | 313 | case SEEK_SET: |
314 | if (offset < 0) | 314 | if (offset < 0) |
315 | break; | 315 | break; |
316 | retval = offset; | 316 | retval = offset; |
317 | if (offset != m->read_pos) { | 317 | if (offset != m->read_pos) { |
318 | while ((retval=traverse(m, offset)) == -EAGAIN) | 318 | while ((retval = traverse(m, offset)) == -EAGAIN) |
319 | ; | 319 | ; |
320 | if (retval) { | 320 | if (retval) { |
321 | /* with extreme prejudice... */ | 321 | /* with extreme prejudice... */ |
322 | file->f_pos = 0; | 322 | file->f_pos = 0; |
323 | m->read_pos = 0; | 323 | m->read_pos = 0; |
324 | m->version = 0; | 324 | m->version = 0; |
325 | m->index = 0; | 325 | m->index = 0; |
326 | m->count = 0; | 326 | m->count = 0; |
327 | } else { | 327 | } else { |
328 | m->read_pos = offset; | 328 | m->read_pos = offset; |
329 | retval = file->f_pos = offset; | 329 | retval = file->f_pos = offset; |
330 | } | ||
331 | } | 330 | } |
331 | } | ||
332 | } | 332 | } |
333 | file->f_version = m->version; | 333 | file->f_version = m->version; |
334 | mutex_unlock(&m->lock); | 334 | mutex_unlock(&m->lock); |
diff --git a/fs/super.c b/fs/super.c index 12f123712161..7465d4364208 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -447,14 +447,13 @@ struct super_block *sget(struct file_system_type *type, | |||
447 | void *data) | 447 | void *data) |
448 | { | 448 | { |
449 | struct super_block *s = NULL; | 449 | struct super_block *s = NULL; |
450 | struct hlist_node *node; | ||
451 | struct super_block *old; | 450 | struct super_block *old; |
452 | int err; | 451 | int err; |
453 | 452 | ||
454 | retry: | 453 | retry: |
455 | spin_lock(&sb_lock); | 454 | spin_lock(&sb_lock); |
456 | if (test) { | 455 | if (test) { |
457 | hlist_for_each_entry(old, node, &type->fs_supers, s_instances) { | 456 | hlist_for_each_entry(old, &type->fs_supers, s_instances) { |
458 | if (!test(old, data)) | 457 | if (!test(old, data)) |
459 | continue; | 458 | continue; |
460 | if (!grab_super(old)) | 459 | if (!grab_super(old)) |
@@ -554,10 +553,9 @@ void iterate_supers_type(struct file_system_type *type, | |||
554 | void (*f)(struct super_block *, void *), void *arg) | 553 | void (*f)(struct super_block *, void *), void *arg) |
555 | { | 554 | { |
556 | struct super_block *sb, *p = NULL; | 555 | struct super_block *sb, *p = NULL; |
557 | struct hlist_node *node; | ||
558 | 556 | ||
559 | spin_lock(&sb_lock); | 557 | spin_lock(&sb_lock); |
560 | hlist_for_each_entry(sb, node, &type->fs_supers, s_instances) { | 558 | hlist_for_each_entry(sb, &type->fs_supers, s_instances) { |
561 | sb->s_count++; | 559 | sb->s_count++; |
562 | spin_unlock(&sb_lock); | 560 | spin_unlock(&sb_lock); |
563 | 561 | ||
@@ -842,7 +840,7 @@ int get_anon_bdev(dev_t *p) | |||
842 | else if (error) | 840 | else if (error) |
843 | return -EAGAIN; | 841 | return -EAGAIN; |
844 | 842 | ||
845 | if ((dev & MAX_IDR_MASK) == (1 << MINORBITS)) { | 843 | if (dev == (1 << MINORBITS)) { |
846 | spin_lock(&unnamed_dev_lock); | 844 | spin_lock(&unnamed_dev_lock); |
847 | ida_remove(&unnamed_dev_ida, dev); | 845 | ida_remove(&unnamed_dev_ida, dev); |
848 | if (unnamed_dev_start > dev) | 846 | if (unnamed_dev_start > dev) |
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 2ce9a5db6ab5..15c68f9489ae 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c | |||
@@ -461,14 +461,13 @@ const struct file_operations bin_fops = { | |||
461 | void unmap_bin_file(struct sysfs_dirent *attr_sd) | 461 | void unmap_bin_file(struct sysfs_dirent *attr_sd) |
462 | { | 462 | { |
463 | struct bin_buffer *bb; | 463 | struct bin_buffer *bb; |
464 | struct hlist_node *tmp; | ||
465 | 464 | ||
466 | if (sysfs_type(attr_sd) != SYSFS_KOBJ_BIN_ATTR) | 465 | if (sysfs_type(attr_sd) != SYSFS_KOBJ_BIN_ATTR) |
467 | return; | 466 | return; |
468 | 467 | ||
469 | mutex_lock(&sysfs_bin_lock); | 468 | mutex_lock(&sysfs_bin_lock); |
470 | 469 | ||
471 | hlist_for_each_entry(bb, tmp, &attr_sd->s_bin_attr.buffers, list) { | 470 | hlist_for_each_entry(bb, &attr_sd->s_bin_attr.buffers, list) { |
472 | struct inode *inode = file_inode(bb->file); | 471 | struct inode *inode = file_inode(bb->file); |
473 | 472 | ||
474 | unmap_mapping_range(inode->i_mapping, 0, 0, 1); | 473 | unmap_mapping_range(inode->i_mapping, 0, 0, 1); |
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 96fcbb85ff83..d1dba7ce75ae 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -1442,9 +1442,8 @@ xlog_recover_find_tid( | |||
1442 | xlog_tid_t tid) | 1442 | xlog_tid_t tid) |
1443 | { | 1443 | { |
1444 | xlog_recover_t *trans; | 1444 | xlog_recover_t *trans; |
1445 | struct hlist_node *n; | ||
1446 | 1445 | ||
1447 | hlist_for_each_entry(trans, n, head, r_list) { | 1446 | hlist_for_each_entry(trans, head, r_list) { |
1448 | if (trans->r_log_tid == tid) | 1447 | if (trans->r_log_tid == tid) |
1449 | return trans; | 1448 | return trans; |
1450 | } | 1449 | } |