aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-27 23:58:09 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-27 23:58:09 -0500
commit2a7d2b96d5cba7568139d9ab157a0e97ab32440f (patch)
treead029d8cc7b7068b7250e914360ec6315fdfa114 /fs
parente3c4877de8b9d93bd47b6ee88eb594b1c1e10da5 (diff)
parentb67bfe0d42cac56c512dd5da4b1b347a23f4b70a (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')
-rw-r--r--fs/affs/amigaffs.c3
-rw-r--r--fs/aio.c3
-rw-r--r--fs/cifs/inode.c3
-rw-r--r--fs/coredump.c2
-rw-r--r--fs/dcache.c9
-rw-r--r--fs/dlm/lock.c18
-rw-r--r--fs/dlm/lockspace.c1
-rw-r--r--fs/dlm/lowcomms.c11
-rw-r--r--fs/dlm/recover.c52
-rw-r--r--fs/ecryptfs/messaging.c6
-rw-r--r--fs/exec.c10
-rw-r--r--fs/exportfs/expfs.c3
-rw-r--r--fs/fat/fat.h2
-rw-r--r--fs/fat/inode.c77
-rw-r--r--fs/fat/nfs.c3
-rw-r--r--fs/fscache/cookie.c11
-rw-r--r--fs/hfsplus/Makefile4
-rw-r--r--fs/hfsplus/attributes.c399
-rw-r--r--fs/hfsplus/bfind.c93
-rw-r--r--fs/hfsplus/bnode.c8
-rw-r--r--fs/hfsplus/brec.c23
-rw-r--r--fs/hfsplus/btree.c8
-rw-r--r--fs/hfsplus/catalog.c36
-rw-r--r--fs/hfsplus/dir.c55
-rw-r--r--fs/hfsplus/extents.c4
-rw-r--r--fs/hfsplus/hfsplus_fs.h52
-rw-r--r--fs/hfsplus/hfsplus_raw.h68
-rw-r--r--fs/hfsplus/inode.c18
-rw-r--r--fs/hfsplus/ioctl.c108
-rw-r--r--fs/hfsplus/super.c56
-rw-r--r--fs/hfsplus/unicode.c7
-rw-r--r--fs/hfsplus/xattr.c709
-rw-r--r--fs/hfsplus/xattr.h60
-rw-r--r--fs/hfsplus/xattr_security.c104
-rw-r--r--fs/hfsplus/xattr_trusted.c63
-rw-r--r--fs/hfsplus/xattr_user.c63
-rw-r--r--fs/inode.c19
-rw-r--r--fs/lockd/host.c29
-rw-r--r--fs/lockd/svcsubs.c7
-rw-r--r--fs/nfs/client.c1
-rw-r--r--fs/nfs/nfs4client.c13
-rw-r--r--fs/nfs/pnfs_dev.c9
-rw-r--r--fs/nfsd/nfscache.c3
-rw-r--r--fs/notify/fsnotify.c3
-rw-r--r--fs/notify/inode_mark.c19
-rw-r--r--fs/notify/inotify/inotify_fsnotify.c1
-rw-r--r--fs/notify/inotify/inotify_user.c24
-rw-r--r--fs/notify/vfsmount_mark.c19
-rw-r--r--fs/ocfs2/cluster/tcp.c32
-rw-r--r--fs/ocfs2/dcache.c3
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c6
-rw-r--r--fs/ocfs2/suballoc.c7
-rw-r--r--fs/ocfs2/suballoc.h2
-rw-r--r--fs/ocfs2/xattr.c2
-rw-r--r--fs/proc/base.c3
-rw-r--r--fs/proc/generic.c27
-rw-r--r--fs/proc/inode.c5
-rw-r--r--fs/proc/internal.h3
-rw-r--r--fs/proc/kcore.c3
-rw-r--r--fs/proc/proc_devtree.c13
-rw-r--r--fs/proc/proc_sysctl.c19
-rw-r--r--fs/proc/vmcore.c35
-rw-r--r--fs/seq_file.c40
-rw-r--r--fs/super.c8
-rw-r--r--fs/sysfs/bin.c3
-rw-r--r--fs/xfs/xfs_log_recover.c3
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
125affs_fix_dcache(struct inode *inode, u32 entry_ino) 125affs_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;
diff --git a/fs/aio.c b/fs/aio.c
index 064bfbe37566..3f941f2a3059 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -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
816inode_has_hashed_dentries(struct inode *inode) 816inode_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);
675static struct dentry *__d_find_alias(struct inode *inode, int want_discon) 675static 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
680again: 679again:
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);
730void d_prune_aliases(struct inode *inode) 729void d_prune_aliases(struct inode *inode)
731{ 730{
732 struct dentry *dentry; 731 struct dentry *dentry;
733 struct hlist_node *p;
734restart: 732restart:
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)
1183static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) 1183static 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)
177static struct connection *__find_con(int nodeid) 177static 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)
232static void foreach_conn(void (*conn_func)(struct connection *c)) 231static 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)
257static struct connection *assoc2con(int assoc_id) 255static 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)
305static int recover_idr_add(struct dlm_rsb *r) 305static 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;
324out_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
331static void recover_idr_del(struct dlm_rsb *r) 330static 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
354static int recover_idr_clear_rsb(int id, void *p, void *data) 353static 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
367static 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 */
116int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon) 116int 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);
diff --git a/fs/exec.c b/fs/exec.c
index 864c50df660a..a96a4885bbbf 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -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);
1639void set_dumpable(struct mm_struct *mm, int value) 1639void 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
1668int get_dumpable(struct mm_struct *mm) 1668int 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
490static 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
491static void fat_put_super(struct super_block *sb) 537static 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
567static int fat_remount(struct super_block *sb, int *flags, char *data) 615static 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
1461out_invalid: 1526out_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);
435void __fscache_update_cookie(struct fscache_cookie *cookie) 433void __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 @@
5obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o 5obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o
6 6
7hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o btree.o \ 7hfsplus-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
12static struct kmem_cache *hfsplus_attr_tree_cachep;
13
14int 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
29void hfsplus_destroy_attr_tree_cache(void)
30{
31 kmem_cache_destroy(hfsplus_attr_tree_cachep);
32}
33
34int 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
49int 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
85void 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
110hfsplus_attr_entry *hfsplus_alloc_attr_entry(void)
111{
112 return kmem_cache_alloc(hfsplus_attr_tree_cachep, GFP_KERNEL);
113}
114
115void 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
123static 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
164int 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
192failed_find_attr:
193 return err;
194}
195
196int 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
216attr_not_found:
217 hfs_find_exit(&fd);
218 return 0;
219}
220
221int 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
280failed_create_attr:
281 hfs_find_exit(&fd);
282
283failed_init_create_attr:
284 hfsplus_destroy_attr_entry(entry_ptr);
285 return err;
286}
287
288static 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
325int 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
362out:
363 hfs_find_exit(&fd);
364 return err;
365}
366
367int 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
396end_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...)*/ 53int hfs_find_1st_rec_by_cnid(struct hfs_bnode *bnode,
42int __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
87int 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...)*/
109int __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
82done: 148done:
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
88fail: 155fail:
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 */
94int hfs_brec_find(struct hfs_find_data *fd) 161int 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
204int hfsplus_create_cat(u32 cnid, struct inode *dir, 206int 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
254err1: 256err1:
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);
258err2: 260err2:
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
340out: 348out:
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
19static inline void hfsplus_instantiate(struct dentry *dentry, 20static 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
479failed_mknod:
480 clear_nlink(inode);
481 hfsplus_delete_inode(inode);
482 iput(inode);
462out: 483out:
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
501const struct inode_operations hfsplus_dir_inode_operations = { 522const 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
513const struct file_operations hfsplus_dir_operations = { 538const 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 */
51enum 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 */
50struct hfs_btree { 58struct 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
336typedef 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 */
345int hfsplus_create_attr_tree_cache(void);
346void hfsplus_destroy_attr_tree_cache(void);
347hfsplus_attr_entry *hfsplus_alloc_attr_entry(void);
348void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry_p);
349int hfsplus_attr_bin_cmp_key(const hfsplus_btree_key *,
350 const hfsplus_btree_key *);
351int hfsplus_attr_build_key(struct super_block *, hfsplus_btree_key *,
352 u32, const char *);
353void hfsplus_attr_build_key_uni(hfsplus_btree_key *key,
354 u32 cnid,
355 struct hfsplus_attr_unistr *name);
356int hfsplus_find_attr(struct super_block *, u32,
357 const char *, struct hfs_find_data *);
358int hfsplus_attr_exists(struct inode *inode, const char *name);
359int hfsplus_create_attr(struct inode *, const char *, const void *, size_t);
360int hfsplus_delete_attr(struct inode *, const char *);
361int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid);
362
331/* bitmap.c */ 363/* bitmap.c */
332int hfsplus_block_allocate(struct super_block *, u32, u32, u32 *); 364int hfsplus_block_allocate(struct super_block *, u32, u32, u32 *);
333int hfsplus_block_free(struct super_block *, u32, u32); 365int 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 */
370int hfs_find_init(struct hfs_btree *, struct hfs_find_data *); 402int hfs_find_init(struct hfs_btree *, struct hfs_find_data *);
371void hfs_find_exit(struct hfs_find_data *); 403void hfs_find_exit(struct hfs_find_data *);
372int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *); 404int hfs_find_1st_rec_by_cnid(struct hfs_bnode *,
373int hfs_brec_find(struct hfs_find_data *); 405 struct hfs_find_data *,
406 int *, int *, int *);
407int hfs_find_rec_by_key(struct hfs_bnode *,
408 struct hfs_find_data *,
409 int *, int *, int *);
410int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *,
411 search_strategy_t);
412int hfs_brec_find(struct hfs_find_data *, search_strategy_t);
374int hfs_brec_read(struct hfs_find_data *, void *, int); 413int hfs_brec_read(struct hfs_find_data *, void *, int);
375int hfs_brec_goto(struct hfs_find_data *, int); 414int 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 */
419long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); 458long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
420int hfsplus_setxattr(struct dentry *dentry, const char *name,
421 const void *value, size_t size, int flags);
422ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
423 void *value, size_t size);
424ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
425 459
426/* options.c */ 460/* options.c */
427int hfsplus_parse_options(char *, struct hfsplus_sb_info *); 461int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
@@ -446,7 +480,7 @@ int hfsplus_strcmp(const struct hfsplus_unistr *,
446int hfsplus_uni2asc(struct super_block *, 480int hfsplus_uni2asc(struct super_block *,
447 const struct hfsplus_unistr *, char *, int *); 481 const struct hfsplus_unistr *, char *, int *);
448int hfsplus_asc2uni(struct super_block *, 482int hfsplus_asc2uni(struct super_block *,
449 struct hfsplus_unistr *, const char *, int); 483 struct hfsplus_unistr *, int, const char *, int);
450int hfsplus_hash_dentry(const struct dentry *dentry, 484int hfsplus_hash_dentry(const struct dentry *dentry,
451 const struct inode *inode, struct qstr *str); 485 const struct inode *inode, struct qstr *str);
452int hfsplus_compare_dentry(const struct dentry *parent, 486int 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 @@
52typedef __be32 hfsplus_cnid; 52typedef __be32 hfsplus_cnid;
53typedef __be16 hfsplus_unichr; 53typedef __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. */
56struct hfsplus_unistr { 59struct 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 */
68struct hfsplus_attr_unistr {
69 __be16 length;
70 hfsplus_unichr unicode[HFSPLUS_ATTR_MAX_STRLEN];
71} __packed;
62 72
63/* POSIX permissions */ 73/* POSIX permissions */
64struct hfsplus_perm { 74struct 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) */
296struct hfsplus_cat_thread { 308struct 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 */
350struct 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 */
361struct 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 */
368struct 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 */
377struct 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 */
386typedef 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 */
331typedef union { 394typedef 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
21static int hfsplus_readpage(struct file *file, struct page *page) 22static 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,
365static const struct inode_operations hfsplus_file_inode_operations = { 378static 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
373static const struct file_operations hfsplus_file_operations = { 387static 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
155int 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 }
194out:
195 hfs_find_exit(&fd);
196 return res;
197}
198
199ssize_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;
237out:
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
245ssize_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);
20static void hfsplus_destroy_inode(struct inode *inode); 20static 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
24static int hfsplus_system_read_inode(struct inode *inode) 25static 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;
563out_put_alloc_file: 597out_put_alloc_file:
564 iput(sbi->alloc_file); 598 iput(sbi->alloc_file);
599out_close_attr_tree:
600 hfs_btree_close(sbi->attr_tree);
565out_close_cat_tree: 601out_close_cat_tree:
566 hfs_btree_close(sbi->cat_tree); 602 hfs_btree_close(sbi->cat_tree);
567out_close_ext_tree: 603out_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
682destroy_attr_tree_cache:
683 hfsplus_destroy_attr_tree_cache();
684
685destroy_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
298int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, 298int 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
12const 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
20static 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
29static 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
38static 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
49static 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
78int __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
218end_setxattr:
219 hfs_find_exit(&cat_fd);
220 return err;
221}
222
223static inline int is_osx_xattr(const char *xattr_name)
224{
225 return !is_known_namespace(xattr_name);
226}
227
228static 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
238static 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
256static 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
301end_getxattr_finder_info:
302 if (size >= record_len)
303 hfs_find_exit(&fd);
304 return res;
305}
306
307ssize_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
398out:
399 hfs_find_exit(&fd);
400
401failed_getxattr_init:
402 hfsplus_destroy_attr_entry(entry);
403 return res;
404}
405
406static 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
416static 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
478end_listxattr_finder_info:
479 hfs_find_exit(&fd);
480
481 return res;
482}
483
484ssize_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
565end_listxattr:
566 hfs_find_exit(&fd);
567 return res;
568}
569
570int 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
651end_removexattr:
652 hfs_find_exit(&cat_fd);
653 return err;
654}
655
656static 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
675static 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
694static 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
704const 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
14extern const struct xattr_handler hfsplus_xattr_osx_handler;
15extern const struct xattr_handler hfsplus_xattr_user_handler;
16extern 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;*/
19extern const struct xattr_handler hfsplus_xattr_security_handler;
20
21extern const struct xattr_handler *hfsplus_xattr_handlers[];
22
23int __hfsplus_setxattr(struct inode *inode, const char *name,
24 const void *value, size_t size, int flags);
25
26static 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
32ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
33 void *value, size_t size);
34
35ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
36
37int hfsplus_removexattr(struct dentry *dentry, const char *name);
38
39int hfsplus_init_security(struct inode *inode, struct inode *dir,
40 const struct qstr *qstr);
41
42static inline int hfsplus_init_acl(struct inode *inode, struct inode *dir)
43{
44 /*TODO: implement*/
45 return 0;
46}
47
48static 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
13static 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
31static 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
49static 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
59static 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
92int 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
99const 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
12static 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
30static 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
48static 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
58const 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
12static 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
30static 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
48static 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
58const 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
804repeat: 803repeat:
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:
830static struct inode *find_inode_fast(struct super_block *sb, 829static 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
836repeat: 834repeat:
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);
1132static int test_inode_iunique(struct super_block *sb, unsigned long ino) 1130static 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 @@
32static struct hlist_head nlm_server_hosts[NLM_HOST_NRHASH]; 32static struct hlist_head nlm_server_hosts[NLM_HOST_NRHASH];
33static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH]; 33static 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
46static unsigned long nrhosts; 46static 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)
570static void nlm_complain_hosts(struct net *net) 567static 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
600nlm_shutdown_hosts_net(struct net *net) 596nlm_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
644nlm_gc_hosts(struct net *net) 639nlm_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
84nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, 84nlm_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
248nlm_traverse_files(void *data, nlm_host_match_fn_t match, 247nlm_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:
197EXPORT_SYMBOL_GPL(nfs_alloc_client); 197EXPORT_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 */
201void nfs_cleanup_cb_ident_idr(struct net *net) 200void 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;
32retry: 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
291nfs4_deviceid_mark_client_invalid(struct nfs_client *clp) 289nfs4_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)
120int 120int
121nfsd_cache_lookup(struct svc_rqst *rqstp) 121nfsd_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)
52void __fsnotify_update_child_dentry_flags(struct inode *inode) 52void __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 @@
36static void fsnotify_recalc_inode_mask_locked(struct inode *inode) 36static 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)
87void fsnotify_clear_marks_by_inode(struct inode *inode) 86void 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);
239out: 236out:
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
385static struct inotify_inode_mark *inotify_idr_find_locked(struct fsnotify_group *group, 383static 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 @@
33void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) 33void 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);
198out: 195out:
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
305static int o2net_prep_nsw(struct o2net_node *nn, struct o2net_status_wait *nsw) 305static 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
331static void o2net_complete_nsw_locked(struct o2net_node *nn, 325static 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
2274static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) 2273static 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}
838EXPORT_SYMBOL(remove_proc_entry); 829EXPORT_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>
14struct ctl_table_header; 15struct ctl_table_header;
15struct mempolicy; 16struct 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,
153realloc: 154realloc:
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
63static int namecmp(const char *name1, int len1, const char *name2, int len2) 64static 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++;
928failed: 929failed:
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
454retry: 453retry:
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 = {
461void unmap_bin_file(struct sysfs_dirent *attr_sd) 461void 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 }