diff options
Diffstat (limited to 'fs')
249 files changed, 8353 insertions, 4075 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 475769c25d64..8d50a610c0e0 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -50,6 +50,23 @@ config EXT2_FS_SECURITY | |||
50 | If you are not using a security module that requires using | 50 | If you are not using a security module that requires using |
51 | extended attributes for file security labels, say N. | 51 | extended attributes for file security labels, say N. |
52 | 52 | ||
53 | config EXT2_FS_XIP | ||
54 | bool "Ext2 execute in place support" | ||
55 | depends on EXT2_FS | ||
56 | help | ||
57 | Execute in place can be used on memory-backed block devices. If you | ||
58 | enable this option, you can select to mount block devices which are | ||
59 | capable of this feature without using the page cache. | ||
60 | |||
61 | If you do not use a block device that is capable of using this, | ||
62 | or if unsure, say N. | ||
63 | |||
64 | config FS_XIP | ||
65 | # execute in place | ||
66 | bool | ||
67 | depends on EXT2_FS_XIP | ||
68 | default y | ||
69 | |||
53 | config EXT3_FS | 70 | config EXT3_FS |
54 | tristate "Ext3 journalling file system support" | 71 | tristate "Ext3 journalling file system support" |
55 | help | 72 | help |
@@ -717,6 +734,12 @@ config PROC_KCORE | |||
717 | bool "/proc/kcore support" if !ARM | 734 | bool "/proc/kcore support" if !ARM |
718 | depends on PROC_FS && MMU | 735 | depends on PROC_FS && MMU |
719 | 736 | ||
737 | config PROC_VMCORE | ||
738 | bool "/proc/vmcore support (EXPERIMENTAL)" | ||
739 | depends on PROC_FS && EMBEDDED && EXPERIMENTAL && CRASH_DUMP | ||
740 | help | ||
741 | Exports the dump image of crashed kernel in ELF format. | ||
742 | |||
720 | config SYSFS | 743 | config SYSFS |
721 | bool "sysfs file system support" if EMBEDDED | 744 | bool "sysfs file system support" if EMBEDDED |
722 | default y | 745 | default y |
@@ -741,56 +764,6 @@ config SYSFS | |||
741 | 764 | ||
742 | Designers of embedded systems may wish to say N here to conserve space. | 765 | Designers of embedded systems may wish to say N here to conserve space. |
743 | 766 | ||
744 | config DEVFS_FS | ||
745 | bool "/dev file system support (OBSOLETE)" | ||
746 | depends on EXPERIMENTAL | ||
747 | help | ||
748 | This is support for devfs, a virtual file system (like /proc) which | ||
749 | provides the file system interface to device drivers, normally found | ||
750 | in /dev. Devfs does not depend on major and minor number | ||
751 | allocations. Device drivers register entries in /dev which then | ||
752 | appear automatically, which means that the system administrator does | ||
753 | not have to create character and block special device files in the | ||
754 | /dev directory using the mknod command (or MAKEDEV script) anymore. | ||
755 | |||
756 | This is work in progress. If you want to use this, you *must* read | ||
757 | the material in <file:Documentation/filesystems/devfs/>, especially | ||
758 | the file README there. | ||
759 | |||
760 | Note that devfs no longer manages /dev/pts! If you are using UNIX98 | ||
761 | ptys, you will also need to mount the /dev/pts filesystem (devpts). | ||
762 | |||
763 | Note that devfs has been obsoleted by udev, | ||
764 | <http://www.kernel.org/pub/linux/utils/kernel/hotplug/>. | ||
765 | It has been stripped down to a bare minimum and is only provided for | ||
766 | legacy installations that use its naming scheme which is | ||
767 | unfortunately different from the names normal Linux installations | ||
768 | use. | ||
769 | |||
770 | If unsure, say N. | ||
771 | |||
772 | config DEVFS_MOUNT | ||
773 | bool "Automatically mount at boot" | ||
774 | depends on DEVFS_FS | ||
775 | help | ||
776 | This option appears if you have CONFIG_DEVFS_FS enabled. Setting | ||
777 | this to 'Y' will make the kernel automatically mount devfs onto /dev | ||
778 | when the system is booted, before the init thread is started. | ||
779 | You can override this with the "devfs=nomount" boot option. | ||
780 | |||
781 | If unsure, say N. | ||
782 | |||
783 | config DEVFS_DEBUG | ||
784 | bool "Debug devfs" | ||
785 | depends on DEVFS_FS | ||
786 | help | ||
787 | If you say Y here, then the /dev file system code will generate | ||
788 | debugging messages. See the file | ||
789 | <file:Documentation/filesystems/devfs/boot-options> for more | ||
790 | details. | ||
791 | |||
792 | If unsure, say N. | ||
793 | |||
794 | config DEVPTS_FS_XATTR | 767 | config DEVPTS_FS_XATTR |
795 | bool "/dev/pts Extended Attributes" | 768 | bool "/dev/pts Extended Attributes" |
796 | depends on UNIX98_PTYS | 769 | depends on UNIX98_PTYS |
@@ -1310,6 +1283,7 @@ config NFS_FS | |||
1310 | depends on INET | 1283 | depends on INET |
1311 | select LOCKD | 1284 | select LOCKD |
1312 | select SUNRPC | 1285 | select SUNRPC |
1286 | select NFS_ACL_SUPPORT if NFS_V3_ACL | ||
1313 | help | 1287 | help |
1314 | If you are connected to some other (usually local) Unix computer | 1288 | If you are connected to some other (usually local) Unix computer |
1315 | (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing | 1289 | (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing |
@@ -1352,6 +1326,16 @@ config NFS_V3 | |||
1352 | 1326 | ||
1353 | If unsure, say Y. | 1327 | If unsure, say Y. |
1354 | 1328 | ||
1329 | config NFS_V3_ACL | ||
1330 | bool "Provide client support for the NFSv3 ACL protocol extension" | ||
1331 | depends on NFS_V3 | ||
1332 | help | ||
1333 | Implement the NFSv3 ACL protocol extension for manipulating POSIX | ||
1334 | Access Control Lists. The server should also be compiled with | ||
1335 | the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option. | ||
1336 | |||
1337 | If unsure, say N. | ||
1338 | |||
1355 | config NFS_V4 | 1339 | config NFS_V4 |
1356 | bool "Provide NFSv4 client support (EXPERIMENTAL)" | 1340 | bool "Provide NFSv4 client support (EXPERIMENTAL)" |
1357 | depends on NFS_FS && EXPERIMENTAL | 1341 | depends on NFS_FS && EXPERIMENTAL |
@@ -1395,6 +1379,7 @@ config NFSD | |||
1395 | select LOCKD | 1379 | select LOCKD |
1396 | select SUNRPC | 1380 | select SUNRPC |
1397 | select EXPORTFS | 1381 | select EXPORTFS |
1382 | select NFS_ACL_SUPPORT if NFSD_V3_ACL || NFSD_V2_ACL | ||
1398 | help | 1383 | help |
1399 | If you want your Linux box to act as an NFS *server*, so that other | 1384 | If you want your Linux box to act as an NFS *server*, so that other |
1400 | computers on your local network which support NFS can access certain | 1385 | computers on your local network which support NFS can access certain |
@@ -1418,6 +1403,10 @@ config NFSD | |||
1418 | To compile the NFS server support as a module, choose M here: the | 1403 | To compile the NFS server support as a module, choose M here: the |
1419 | module will be called nfsd. If unsure, say N. | 1404 | module will be called nfsd. If unsure, say N. |
1420 | 1405 | ||
1406 | config NFSD_V2_ACL | ||
1407 | bool | ||
1408 | depends on NFSD | ||
1409 | |||
1421 | config NFSD_V3 | 1410 | config NFSD_V3 |
1422 | bool "Provide NFSv3 server support" | 1411 | bool "Provide NFSv3 server support" |
1423 | depends on NFSD | 1412 | depends on NFSD |
@@ -1425,10 +1414,22 @@ config NFSD_V3 | |||
1425 | If you would like to include the NFSv3 server as well as the NFSv2 | 1414 | If you would like to include the NFSv3 server as well as the NFSv2 |
1426 | server, say Y here. If unsure, say Y. | 1415 | server, say Y here. If unsure, say Y. |
1427 | 1416 | ||
1417 | config NFSD_V3_ACL | ||
1418 | bool "Provide server support for the NFSv3 ACL protocol extension" | ||
1419 | depends on NFSD_V3 | ||
1420 | select NFSD_V2_ACL | ||
1421 | help | ||
1422 | Implement the NFSv3 ACL protocol extension for manipulating POSIX | ||
1423 | Access Control Lists on exported file systems. NFS clients should | ||
1424 | be compiled with the NFSv3 ACL protocol extension; see the | ||
1425 | CONFIG_NFS_V3_ACL option. If unsure, say N. | ||
1426 | |||
1428 | config NFSD_V4 | 1427 | config NFSD_V4 |
1429 | bool "Provide NFSv4 server support (EXPERIMENTAL)" | 1428 | bool "Provide NFSv4 server support (EXPERIMENTAL)" |
1430 | depends on NFSD_V3 && EXPERIMENTAL | 1429 | depends on NFSD_V3 && EXPERIMENTAL |
1431 | select NFSD_TCP | 1430 | select NFSD_TCP |
1431 | select CRYPTO_MD5 | ||
1432 | select CRYPTO | ||
1432 | help | 1433 | help |
1433 | If you would like to include the NFSv4 server as well as the NFSv2 | 1434 | If you would like to include the NFSv4 server as well as the NFSv2 |
1434 | and NFSv3 servers, say Y here. This feature is experimental, and | 1435 | and NFSv3 servers, say Y here. This feature is experimental, and |
@@ -1469,6 +1470,15 @@ config LOCKD_V4 | |||
1469 | config EXPORTFS | 1470 | config EXPORTFS |
1470 | tristate | 1471 | tristate |
1471 | 1472 | ||
1473 | config NFS_ACL_SUPPORT | ||
1474 | tristate | ||
1475 | select FS_POSIX_ACL | ||
1476 | |||
1477 | config NFS_COMMON | ||
1478 | bool | ||
1479 | depends on NFSD || NFS_FS | ||
1480 | default y | ||
1481 | |||
1472 | config SUNRPC | 1482 | config SUNRPC |
1473 | tristate | 1483 | tristate |
1474 | 1484 | ||
diff --git a/fs/Makefile b/fs/Makefile index 443f2bc56ccf..fc92e59e9faf 100644 --- a/fs/Makefile +++ b/fs/Makefile | |||
@@ -31,6 +31,7 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o | |||
31 | 31 | ||
32 | obj-$(CONFIG_FS_MBCACHE) += mbcache.o | 32 | obj-$(CONFIG_FS_MBCACHE) += mbcache.o |
33 | obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o | 33 | obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o |
34 | obj-$(CONFIG_NFS_COMMON) += nfs_common/ | ||
34 | 35 | ||
35 | obj-$(CONFIG_QUOTA) += dquot.o | 36 | obj-$(CONFIG_QUOTA) += dquot.o |
36 | obj-$(CONFIG_QFMT_V1) += quota_v1.o | 37 | obj-$(CONFIG_QFMT_V1) += quota_v1.o |
diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c index 6fc88ae8ad94..7ac07d0d47b9 100644 --- a/fs/afs/kafsasyncd.c +++ b/fs/afs/kafsasyncd.c | |||
@@ -116,7 +116,7 @@ static int kafsasyncd(void *arg) | |||
116 | remove_wait_queue(&kafsasyncd_sleepq, &myself); | 116 | remove_wait_queue(&kafsasyncd_sleepq, &myself); |
117 | set_current_state(TASK_RUNNING); | 117 | set_current_state(TASK_RUNNING); |
118 | 118 | ||
119 | try_to_freeze(PF_FREEZE); | 119 | try_to_freeze(); |
120 | 120 | ||
121 | /* discard pending signals */ | 121 | /* discard pending signals */ |
122 | afs_discard_my_signals(); | 122 | afs_discard_my_signals(); |
diff --git a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c index 86e710dd057e..65bc05ab8182 100644 --- a/fs/afs/kafstimod.c +++ b/fs/afs/kafstimod.c | |||
@@ -91,7 +91,7 @@ static int kafstimod(void *arg) | |||
91 | complete_and_exit(&kafstimod_dead, 0); | 91 | complete_and_exit(&kafstimod_dead, 0); |
92 | } | 92 | } |
93 | 93 | ||
94 | try_to_freeze(PF_FREEZE); | 94 | try_to_freeze(); |
95 | 95 | ||
96 | /* discard pending signals */ | 96 | /* discard pending signals */ |
97 | afs_discard_my_signals(); | 97 | afs_discard_my_signals(); |
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index c7b2b8890188..9c09641ce907 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -185,6 +185,19 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify); | |||
185 | int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); | 185 | int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); |
186 | void autofs4_catatonic_mode(struct autofs_sb_info *); | 186 | void autofs4_catatonic_mode(struct autofs_sb_info *); |
187 | 187 | ||
188 | static inline int autofs4_follow_mount(struct vfsmount **mnt, struct dentry **dentry) | ||
189 | { | ||
190 | int res = 0; | ||
191 | |||
192 | while (d_mountpoint(*dentry)) { | ||
193 | int followed = follow_down(mnt, dentry); | ||
194 | if (!followed) | ||
195 | break; | ||
196 | res = 1; | ||
197 | } | ||
198 | return res; | ||
199 | } | ||
200 | |||
188 | static inline int simple_positive(struct dentry *dentry) | 201 | static inline int simple_positive(struct dentry *dentry) |
189 | { | 202 | { |
190 | return dentry->d_inode && !d_unhashed(dentry); | 203 | return dentry->d_inode && !d_unhashed(dentry); |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 500425e24fba..feb6ac427d05 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -56,12 +56,9 @@ static int autofs4_check_mount(struct vfsmount *mnt, struct dentry *dentry) | |||
56 | mntget(mnt); | 56 | mntget(mnt); |
57 | dget(dentry); | 57 | dget(dentry); |
58 | 58 | ||
59 | if (!follow_down(&mnt, &dentry)) | 59 | if (!autofs4_follow_mount(&mnt, &dentry)) |
60 | goto done; | 60 | goto done; |
61 | 61 | ||
62 | while (d_mountpoint(dentry) && follow_down(&mnt, &dentry)) | ||
63 | ; | ||
64 | |||
65 | /* This is an autofs submount, we can't expire it */ | 62 | /* This is an autofs submount, we can't expire it */ |
66 | if (is_autofs4_dentry(dentry)) | 63 | if (is_autofs4_dentry(dentry)) |
67 | goto done; | 64 | goto done; |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 3765c047f157..2a771ec66956 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -205,7 +205,11 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
205 | struct vfsmount *fp_mnt = mntget(mnt); | 205 | struct vfsmount *fp_mnt = mntget(mnt); |
206 | struct dentry *fp_dentry = dget(dentry); | 206 | struct dentry *fp_dentry = dget(dentry); |
207 | 207 | ||
208 | while (follow_down(&fp_mnt, &fp_dentry) && d_mountpoint(fp_dentry)); | 208 | if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) { |
209 | dput(fp_dentry); | ||
210 | mntput(fp_mnt); | ||
211 | return -ENOENT; | ||
212 | } | ||
209 | 213 | ||
210 | fp = dentry_open(fp_dentry, fp_mnt, file->f_flags); | 214 | fp = dentry_open(fp_dentry, fp_mnt, file->f_flags); |
211 | status = PTR_ERR(fp); | 215 | status = PTR_ERR(fp); |
@@ -302,7 +306,14 @@ static int try_to_fill_dentry(struct dentry *dentry, | |||
302 | 306 | ||
303 | DPRINTK("expire done status=%d", status); | 307 | DPRINTK("expire done status=%d", status); |
304 | 308 | ||
305 | return 0; | 309 | /* |
310 | * If the directory still exists the mount request must | ||
311 | * continue otherwise it can't be followed at the right | ||
312 | * time during the walk. | ||
313 | */ | ||
314 | status = d_invalidate(dentry); | ||
315 | if (status != -EBUSY) | ||
316 | return 0; | ||
306 | } | 317 | } |
307 | 318 | ||
308 | DPRINTK("dentry=%p %.*s ino=%p", | 319 | DPRINTK("dentry=%p %.*s ino=%p", |
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 5a40d36e5a51..fa2348dcd671 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -191,6 +191,13 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
191 | } | 191 | } |
192 | 192 | ||
193 | if ( !wq ) { | 193 | if ( !wq ) { |
194 | /* Can't wait for an expire if there's no mount */ | ||
195 | if (notify == NFY_NONE && !d_mountpoint(dentry)) { | ||
196 | kfree(name); | ||
197 | up(&sbi->wq_sem); | ||
198 | return -ENOENT; | ||
199 | } | ||
200 | |||
194 | /* Create a new wait queue */ | 201 | /* Create a new wait queue */ |
195 | wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); | 202 | wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); |
196 | if ( !wq ) { | 203 | if ( !wq ) { |
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 009b8920c1ff..dd9baabaf016 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c | |||
@@ -316,6 +316,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
316 | current->mm->brk = ex.a_bss + | 316 | current->mm->brk = ex.a_bss + |
317 | (current->mm->start_brk = N_BSSADDR(ex)); | 317 | (current->mm->start_brk = N_BSSADDR(ex)); |
318 | current->mm->free_area_cache = current->mm->mmap_base; | 318 | current->mm->free_area_cache = current->mm->mmap_base; |
319 | current->mm->cached_hole_size = 0; | ||
319 | 320 | ||
320 | set_mm_counter(current->mm, rss, 0); | 321 | set_mm_counter(current->mm, rss, 0); |
321 | current->mm->mmap = NULL; | 322 | current->mm->mmap = NULL; |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index c374be51b041..7976a238f0a3 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -775,6 +775,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
775 | change some of these later */ | 775 | change some of these later */ |
776 | set_mm_counter(current->mm, rss, 0); | 776 | set_mm_counter(current->mm, rss, 0); |
777 | current->mm->free_area_cache = current->mm->mmap_base; | 777 | current->mm->free_area_cache = current->mm->mmap_base; |
778 | current->mm->cached_hole_size = 0; | ||
778 | retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), | 779 | retval = setup_arg_pages(bprm, randomize_stack_top(STACK_TOP), |
779 | executable_stack); | 780 | executable_stack); |
780 | if (retval < 0) { | 781 | if (retval < 0) { |
@@ -1125,7 +1126,7 @@ static int dump_write(struct file *file, const void *addr, int nr) | |||
1125 | return file->f_op->write(file, addr, nr, &file->f_pos) == nr; | 1126 | return file->f_op->write(file, addr, nr, &file->f_pos) == nr; |
1126 | } | 1127 | } |
1127 | 1128 | ||
1128 | static int dump_seek(struct file *file, off_t off) | 1129 | static int dump_seek(struct file *file, loff_t off) |
1129 | { | 1130 | { |
1130 | if (file->f_op->llseek) { | 1131 | if (file->f_op->llseek) { |
1131 | if (file->f_op->llseek(file, off, 0) != off) | 1132 | if (file->f_op->llseek(file, off, 0) != off) |
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index f0cd67d9d31b..c8998dc66882 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c | |||
@@ -520,7 +520,7 @@ static int load_flat_file(struct linux_binprm * bprm, | |||
520 | DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); | 520 | DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); |
521 | 521 | ||
522 | down_write(¤t->mm->mmap_sem); | 522 | down_write(¤t->mm->mmap_sem); |
523 | textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, 0, 0); | 523 | textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_SHARED, 0); |
524 | up_write(¤t->mm->mmap_sem); | 524 | up_write(¤t->mm->mmap_sem); |
525 | if (!textpos || textpos >= (unsigned long) -4096) { | 525 | if (!textpos || textpos >= (unsigned long) -4096) { |
526 | if (!textpos) | 526 | if (!textpos) |
@@ -532,7 +532,7 @@ static int load_flat_file(struct linux_binprm * bprm, | |||
532 | down_write(¤t->mm->mmap_sem); | 532 | down_write(¤t->mm->mmap_sem); |
533 | realdatastart = do_mmap(0, 0, data_len + extra + | 533 | realdatastart = do_mmap(0, 0, data_len + extra + |
534 | MAX_SHARED_LIBS * sizeof(unsigned long), | 534 | MAX_SHARED_LIBS * sizeof(unsigned long), |
535 | PROT_READ|PROT_WRITE|PROT_EXEC, 0, 0); | 535 | PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); |
536 | up_write(¤t->mm->mmap_sem); | 536 | up_write(¤t->mm->mmap_sem); |
537 | 537 | ||
538 | if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) { | 538 | if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) { |
@@ -574,7 +574,7 @@ static int load_flat_file(struct linux_binprm * bprm, | |||
574 | down_write(¤t->mm->mmap_sem); | 574 | down_write(¤t->mm->mmap_sem); |
575 | textpos = do_mmap(0, 0, text_len + data_len + extra + | 575 | textpos = do_mmap(0, 0, text_len + data_len + extra + |
576 | MAX_SHARED_LIBS * sizeof(unsigned long), | 576 | MAX_SHARED_LIBS * sizeof(unsigned long), |
577 | PROT_READ | PROT_EXEC | PROT_WRITE, 0, 0); | 577 | PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); |
578 | up_write(¤t->mm->mmap_sem); | 578 | up_write(¤t->mm->mmap_sem); |
579 | if (!textpos || textpos >= (unsigned long) -4096) { | 579 | if (!textpos || textpos >= (unsigned long) -4096) { |
580 | if (!textpos) | 580 | if (!textpos) |
diff --git a/fs/block_dev.c b/fs/block_dev.c index c0cbd1bc1a02..e0df94c37b7e 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -777,8 +777,7 @@ static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char __user *buf, | |||
777 | return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); | 777 | return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); |
778 | } | 778 | } |
779 | 779 | ||
780 | static int block_ioctl(struct inode *inode, struct file *file, unsigned cmd, | 780 | static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) |
781 | unsigned long arg) | ||
782 | { | 781 | { |
783 | return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); | 782 | return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); |
784 | } | 783 | } |
@@ -803,7 +802,7 @@ struct file_operations def_blk_fops = { | |||
803 | .aio_write = blkdev_file_aio_write, | 802 | .aio_write = blkdev_file_aio_write, |
804 | .mmap = generic_file_mmap, | 803 | .mmap = generic_file_mmap, |
805 | .fsync = block_fsync, | 804 | .fsync = block_fsync, |
806 | .ioctl = block_ioctl, | 805 | .unlocked_ioctl = block_ioctl, |
807 | #ifdef CONFIG_COMPAT | 806 | #ifdef CONFIG_COMPAT |
808 | .compat_ioctl = compat_blkdev_ioctl, | 807 | .compat_ioctl = compat_blkdev_ioctl, |
809 | #endif | 808 | #endif |
diff --git a/fs/buffer.c b/fs/buffer.c index 7e9e409feaa7..13e5938a64f6 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -331,7 +331,7 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) | |||
331 | return ret; | 331 | return ret; |
332 | } | 332 | } |
333 | 333 | ||
334 | asmlinkage long sys_fsync(unsigned int fd) | 334 | static long do_fsync(unsigned int fd, int datasync) |
335 | { | 335 | { |
336 | struct file * file; | 336 | struct file * file; |
337 | struct address_space *mapping; | 337 | struct address_space *mapping; |
@@ -342,14 +342,14 @@ asmlinkage long sys_fsync(unsigned int fd) | |||
342 | if (!file) | 342 | if (!file) |
343 | goto out; | 343 | goto out; |
344 | 344 | ||
345 | mapping = file->f_mapping; | ||
346 | |||
347 | ret = -EINVAL; | 345 | ret = -EINVAL; |
348 | if (!file->f_op || !file->f_op->fsync) { | 346 | if (!file->f_op || !file->f_op->fsync) { |
349 | /* Why? We can still call filemap_fdatawrite */ | 347 | /* Why? We can still call filemap_fdatawrite */ |
350 | goto out_putf; | 348 | goto out_putf; |
351 | } | 349 | } |
352 | 350 | ||
351 | mapping = file->f_mapping; | ||
352 | |||
353 | current->flags |= PF_SYNCWRITE; | 353 | current->flags |= PF_SYNCWRITE; |
354 | ret = filemap_fdatawrite(mapping); | 354 | ret = filemap_fdatawrite(mapping); |
355 | 355 | ||
@@ -358,7 +358,7 @@ asmlinkage long sys_fsync(unsigned int fd) | |||
358 | * which could cause livelocks in fsync_buffers_list | 358 | * which could cause livelocks in fsync_buffers_list |
359 | */ | 359 | */ |
360 | down(&mapping->host->i_sem); | 360 | down(&mapping->host->i_sem); |
361 | err = file->f_op->fsync(file, file->f_dentry, 0); | 361 | err = file->f_op->fsync(file, file->f_dentry, datasync); |
362 | if (!ret) | 362 | if (!ret) |
363 | ret = err; | 363 | ret = err; |
364 | up(&mapping->host->i_sem); | 364 | up(&mapping->host->i_sem); |
@@ -373,39 +373,14 @@ out: | |||
373 | return ret; | 373 | return ret; |
374 | } | 374 | } |
375 | 375 | ||
376 | asmlinkage long sys_fdatasync(unsigned int fd) | 376 | asmlinkage long sys_fsync(unsigned int fd) |
377 | { | 377 | { |
378 | struct file * file; | 378 | return do_fsync(fd, 0); |
379 | struct address_space *mapping; | 379 | } |
380 | int ret, err; | ||
381 | |||
382 | ret = -EBADF; | ||
383 | file = fget(fd); | ||
384 | if (!file) | ||
385 | goto out; | ||
386 | |||
387 | ret = -EINVAL; | ||
388 | if (!file->f_op || !file->f_op->fsync) | ||
389 | goto out_putf; | ||
390 | |||
391 | mapping = file->f_mapping; | ||
392 | |||
393 | current->flags |= PF_SYNCWRITE; | ||
394 | ret = filemap_fdatawrite(mapping); | ||
395 | down(&mapping->host->i_sem); | ||
396 | err = file->f_op->fsync(file, file->f_dentry, 1); | ||
397 | if (!ret) | ||
398 | ret = err; | ||
399 | up(&mapping->host->i_sem); | ||
400 | err = filemap_fdatawait(mapping); | ||
401 | if (!ret) | ||
402 | ret = err; | ||
403 | current->flags &= ~PF_SYNCWRITE; | ||
404 | 380 | ||
405 | out_putf: | 381 | asmlinkage long sys_fdatasync(unsigned int fd) |
406 | fput(file); | 382 | { |
407 | out: | 383 | return do_fsync(fd, 1); |
408 | return ret; | ||
409 | } | 384 | } |
410 | 385 | ||
411 | /* | 386 | /* |
@@ -528,7 +503,7 @@ static void free_more_memory(void) | |||
528 | for_each_pgdat(pgdat) { | 503 | for_each_pgdat(pgdat) { |
529 | zones = pgdat->node_zonelists[GFP_NOFS&GFP_ZONEMASK].zones; | 504 | zones = pgdat->node_zonelists[GFP_NOFS&GFP_ZONEMASK].zones; |
530 | if (*zones) | 505 | if (*zones) |
531 | try_to_free_pages(zones, GFP_NOFS, 0); | 506 | try_to_free_pages(zones, GFP_NOFS); |
532 | } | 507 | } |
533 | } | 508 | } |
534 | 509 | ||
@@ -1951,7 +1926,6 @@ static int __block_prepare_write(struct inode *inode, struct page *page, | |||
1951 | if (err) | 1926 | if (err) |
1952 | break; | 1927 | break; |
1953 | if (buffer_new(bh)) { | 1928 | if (buffer_new(bh)) { |
1954 | clear_buffer_new(bh); | ||
1955 | unmap_underlying_metadata(bh->b_bdev, | 1929 | unmap_underlying_metadata(bh->b_bdev, |
1956 | bh->b_blocknr); | 1930 | bh->b_blocknr); |
1957 | if (PageUptodate(page)) { | 1931 | if (PageUptodate(page)) { |
@@ -1993,9 +1967,14 @@ static int __block_prepare_write(struct inode *inode, struct page *page, | |||
1993 | if (!buffer_uptodate(*wait_bh)) | 1967 | if (!buffer_uptodate(*wait_bh)) |
1994 | err = -EIO; | 1968 | err = -EIO; |
1995 | } | 1969 | } |
1996 | if (!err) | 1970 | if (!err) { |
1997 | return err; | 1971 | bh = head; |
1998 | 1972 | do { | |
1973 | if (buffer_new(bh)) | ||
1974 | clear_buffer_new(bh); | ||
1975 | } while ((bh = bh->b_this_page) != head); | ||
1976 | return 0; | ||
1977 | } | ||
1999 | /* Error case: */ | 1978 | /* Error case: */ |
2000 | /* | 1979 | /* |
2001 | * Zero out any newly allocated blocks to avoid exposing stale | 1980 | * Zero out any newly allocated blocks to avoid exposing stale |
diff --git a/fs/char_dev.c b/fs/char_dev.c index c1e3537909fc..e82aac9cc2f5 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c | |||
@@ -56,10 +56,21 @@ int get_chrdev_list(char *page) | |||
56 | 56 | ||
57 | down(&chrdevs_lock); | 57 | down(&chrdevs_lock); |
58 | for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) { | 58 | for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) { |
59 | for (cd = chrdevs[i]; cd; cd = cd->next) | 59 | for (cd = chrdevs[i]; cd; cd = cd->next) { |
60 | /* | ||
61 | * if the current name, plus the 5 extra characters | ||
62 | * in the device line for this entry | ||
63 | * would run us off the page, we're done | ||
64 | */ | ||
65 | if ((len+strlen(cd->name) + 5) >= PAGE_SIZE) | ||
66 | goto page_full; | ||
67 | |||
68 | |||
60 | len += sprintf(page+len, "%3d %s\n", | 69 | len += sprintf(page+len, "%3d %s\n", |
61 | cd->major, cd->name); | 70 | cd->major, cd->name); |
71 | } | ||
62 | } | 72 | } |
73 | page_full: | ||
63 | up(&chrdevs_lock); | 74 | up(&chrdevs_lock); |
64 | 75 | ||
65 | return len; | 76 | return len; |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 95483baab706..dab4774ee7bb 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -6,7 +6,8 @@ kills the cifsd thread (NB: killing the cifs kernel threads is not | |||
6 | recommended, unmount and rmmod cifs will kill them when they are | 6 | recommended, unmount and rmmod cifs will kill them when they are |
7 | no longer needed). Fix readdir to ASCII servers (ie older servers | 7 | no longer needed). Fix readdir to ASCII servers (ie older servers |
8 | which do not support Unicode) and also require asterik. | 8 | which do not support Unicode) and also require asterik. |
9 | 9 | Fix out of memory case in which data could be written one page | |
10 | off in the page cache. | ||
10 | 11 | ||
11 | Version 1.33 | 12 | Version 1.33 |
12 | ------------ | 13 | ------------ |
diff --git a/fs/cifs/README b/fs/cifs/README index e74df0c73256..34b0cf7111f3 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -371,7 +371,7 @@ A partial list of the supported mount options follows: | |||
371 | on newly created files, directories, and devices (create, | 371 | on newly created files, directories, and devices (create, |
372 | mkdir, mknod) which will result in the server setting the | 372 | mkdir, mknod) which will result in the server setting the |
373 | uid and gid to the default (usually the server uid of the | 373 | uid and gid to the default (usually the server uid of the |
374 | usern who mounted the share). Letting the server (rather than | 374 | user who mounted the share). Letting the server (rather than |
375 | the client) set the uid and gid is the default. This | 375 | the client) set the uid and gid is the default. This |
376 | parameter has no effect if the CIFS Unix Extensions are not | 376 | parameter has no effect if the CIFS Unix Extensions are not |
377 | negotiated. | 377 | negotiated. |
@@ -384,7 +384,7 @@ A partial list of the supported mount options follows: | |||
384 | client (e.g. when the application is doing large sequential | 384 | client (e.g. when the application is doing large sequential |
385 | reads bigger than page size without rereading the same data) | 385 | reads bigger than page size without rereading the same data) |
386 | this can provide better performance than the default | 386 | this can provide better performance than the default |
387 | behavior which caches reads (reaadahead) and writes | 387 | behavior which caches reads (readahead) and writes |
388 | (writebehind) through the local Linux client pagecache | 388 | (writebehind) through the local Linux client pagecache |
389 | if oplock (caching token) is granted and held. Note that | 389 | if oplock (caching token) is granted and held. Note that |
390 | direct allows write operations larger than page size | 390 | direct allows write operations larger than page size |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index d00b3bfe1a52..78af5850c558 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -96,5 +96,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | |||
96 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 96 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
97 | extern int cifs_ioctl (struct inode * inode, struct file * filep, | 97 | extern int cifs_ioctl (struct inode * inode, struct file * filep, |
98 | unsigned int command, unsigned long arg); | 98 | unsigned int command, unsigned long arg); |
99 | #define CIFS_VERSION "1.34" | 99 | #define CIFS_VERSION "1.35" |
100 | #endif /* _CIFSFS_H */ | 100 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0010511083fc..ea239dea571e 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -228,7 +228,7 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | |||
228 | const struct nls_table *nls_codepage, | 228 | const struct nls_table *nls_codepage, |
229 | int remap_special_chars); | 229 | int remap_special_chars); |
230 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 230 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ |
231 | extern int cifs_convertUCSpath(char *target, const __u16 *source, int maxlen, | 231 | extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, |
232 | const struct nls_table * codepage); | 232 | const struct nls_table * codepage); |
233 | extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen, | 233 | extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen, |
234 | const struct nls_table * cp, int mapChars); | 234 | const struct nls_table * cp, int mapChars); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 741ff0c69f37..3c628bf667a5 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -567,7 +567,7 @@ DelFileRetry: | |||
567 | 567 | ||
568 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 568 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
569 | name_len = | 569 | name_len = |
570 | cifsConvertToUCS((__u16 *) pSMB->fileName, fileName, | 570 | cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, |
571 | PATH_MAX, nls_codepage, remap); | 571 | PATH_MAX, nls_codepage, remap); |
572 | name_len++; /* trailing null */ | 572 | name_len++; /* trailing null */ |
573 | name_len *= 2; | 573 | name_len *= 2; |
@@ -665,7 +665,7 @@ MkDirRetry: | |||
665 | return rc; | 665 | return rc; |
666 | 666 | ||
667 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 667 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
668 | name_len = cifsConvertToUCS((__u16 *) pSMB->DirName, name, | 668 | name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, |
669 | PATH_MAX, nls_codepage, remap); | 669 | PATH_MAX, nls_codepage, remap); |
670 | name_len++; /* trailing null */ | 670 | name_len++; /* trailing null */ |
671 | name_len *= 2; | 671 | name_len *= 2; |
@@ -719,7 +719,7 @@ openRetry: | |||
719 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 719 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
720 | count = 1; /* account for one byte pad to word boundary */ | 720 | count = 1; /* account for one byte pad to word boundary */ |
721 | name_len = | 721 | name_len = |
722 | cifsConvertToUCS((__u16 *) (pSMB->fileName + 1), | 722 | cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), |
723 | fileName, PATH_MAX, nls_codepage, remap); | 723 | fileName, PATH_MAX, nls_codepage, remap); |
724 | name_len++; /* trailing null */ | 724 | name_len++; /* trailing null */ |
725 | name_len *= 2; | 725 | name_len *= 2; |
@@ -1141,7 +1141,7 @@ renameRetry: | |||
1141 | 1141 | ||
1142 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 1142 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
1143 | name_len = | 1143 | name_len = |
1144 | cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName, | 1144 | cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, |
1145 | PATH_MAX, nls_codepage, remap); | 1145 | PATH_MAX, nls_codepage, remap); |
1146 | name_len++; /* trailing null */ | 1146 | name_len++; /* trailing null */ |
1147 | name_len *= 2; | 1147 | name_len *= 2; |
@@ -1149,7 +1149,7 @@ renameRetry: | |||
1149 | /* protocol requires ASCII signature byte on Unicode string */ | 1149 | /* protocol requires ASCII signature byte on Unicode string */ |
1150 | pSMB->OldFileName[name_len + 1] = 0x00; | 1150 | pSMB->OldFileName[name_len + 1] = 0x00; |
1151 | name_len2 = | 1151 | name_len2 = |
1152 | cifsConvertToUCS((__u16 *) &pSMB->OldFileName[name_len + 2], | 1152 | cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2], |
1153 | toName, PATH_MAX, nls_codepage, remap); | 1153 | toName, PATH_MAX, nls_codepage, remap); |
1154 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; | 1154 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; |
1155 | name_len2 *= 2; /* convert to bytes */ | 1155 | name_len2 *= 2; /* convert to bytes */ |
@@ -1236,10 +1236,10 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, | |||
1236 | /* unicode only call */ | 1236 | /* unicode only call */ |
1237 | if(target_name == NULL) { | 1237 | if(target_name == NULL) { |
1238 | sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); | 1238 | sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); |
1239 | len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name, | 1239 | len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, |
1240 | dummy_string, 24, nls_codepage, remap); | 1240 | dummy_string, 24, nls_codepage, remap); |
1241 | } else { | 1241 | } else { |
1242 | len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name, | 1242 | len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, |
1243 | target_name, PATH_MAX, nls_codepage, remap); | 1243 | target_name, PATH_MAX, nls_codepage, remap); |
1244 | } | 1244 | } |
1245 | rename_info->target_name_len = cpu_to_le32(2 * len_of_str); | 1245 | rename_info->target_name_len = cpu_to_le32(2 * len_of_str); |
@@ -1296,7 +1296,7 @@ copyRetry: | |||
1296 | pSMB->Flags = cpu_to_le16(flags & COPY_TREE); | 1296 | pSMB->Flags = cpu_to_le16(flags & COPY_TREE); |
1297 | 1297 | ||
1298 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 1298 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
1299 | name_len = cifsConvertToUCS((__u16 *) pSMB->OldFileName, | 1299 | name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, |
1300 | fromName, PATH_MAX, nls_codepage, | 1300 | fromName, PATH_MAX, nls_codepage, |
1301 | remap); | 1301 | remap); |
1302 | name_len++; /* trailing null */ | 1302 | name_len++; /* trailing null */ |
@@ -1304,7 +1304,7 @@ copyRetry: | |||
1304 | pSMB->OldFileName[name_len] = 0x04; /* pad */ | 1304 | pSMB->OldFileName[name_len] = 0x04; /* pad */ |
1305 | /* protocol requires ASCII signature byte on Unicode string */ | 1305 | /* protocol requires ASCII signature byte on Unicode string */ |
1306 | pSMB->OldFileName[name_len + 1] = 0x00; | 1306 | pSMB->OldFileName[name_len + 1] = 0x00; |
1307 | name_len2 = cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2], | 1307 | name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], |
1308 | toName, PATH_MAX, nls_codepage, remap); | 1308 | toName, PATH_MAX, nls_codepage, remap); |
1309 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; | 1309 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; |
1310 | name_len2 *= 2; /* convert to bytes */ | 1310 | name_len2 *= 2; /* convert to bytes */ |
@@ -1453,7 +1453,7 @@ createHardLinkRetry: | |||
1453 | return rc; | 1453 | return rc; |
1454 | 1454 | ||
1455 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 1455 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
1456 | name_len = cifsConvertToUCS((__u16 *) pSMB->FileName, toName, | 1456 | name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName, |
1457 | PATH_MAX, nls_codepage, remap); | 1457 | PATH_MAX, nls_codepage, remap); |
1458 | name_len++; /* trailing null */ | 1458 | name_len++; /* trailing null */ |
1459 | name_len *= 2; | 1459 | name_len *= 2; |
@@ -1476,7 +1476,7 @@ createHardLinkRetry: | |||
1476 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | 1476 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; |
1477 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 1477 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
1478 | name_len_target = | 1478 | name_len_target = |
1479 | cifsConvertToUCS((__u16 *) data_offset, fromName, PATH_MAX, | 1479 | cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX, |
1480 | nls_codepage, remap); | 1480 | nls_codepage, remap); |
1481 | name_len_target++; /* trailing null */ | 1481 | name_len_target++; /* trailing null */ |
1482 | name_len_target *= 2; | 1482 | name_len_target *= 2; |
@@ -1546,14 +1546,14 @@ winCreateHardLinkRetry: | |||
1546 | 1546 | ||
1547 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 1547 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
1548 | name_len = | 1548 | name_len = |
1549 | cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName, | 1549 | cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, |
1550 | PATH_MAX, nls_codepage, remap); | 1550 | PATH_MAX, nls_codepage, remap); |
1551 | name_len++; /* trailing null */ | 1551 | name_len++; /* trailing null */ |
1552 | name_len *= 2; | 1552 | name_len *= 2; |
1553 | pSMB->OldFileName[name_len] = 0; /* pad */ | 1553 | pSMB->OldFileName[name_len] = 0; /* pad */ |
1554 | pSMB->OldFileName[name_len + 1] = 0x04; | 1554 | pSMB->OldFileName[name_len + 1] = 0x04; |
1555 | name_len2 = | 1555 | name_len2 = |
1556 | cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2], | 1556 | cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], |
1557 | toName, PATH_MAX, nls_codepage, remap); | 1557 | toName, PATH_MAX, nls_codepage, remap); |
1558 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; | 1558 | name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; |
1559 | name_len2 *= 2; /* convert to bytes */ | 1559 | name_len2 *= 2; /* convert to bytes */ |
@@ -1939,7 +1939,7 @@ queryAclRetry: | |||
1939 | 1939 | ||
1940 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 1940 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
1941 | name_len = | 1941 | name_len = |
1942 | cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, | 1942 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, |
1943 | PATH_MAX, nls_codepage, remap); | 1943 | PATH_MAX, nls_codepage, remap); |
1944 | name_len++; /* trailing null */ | 1944 | name_len++; /* trailing null */ |
1945 | name_len *= 2; | 1945 | name_len *= 2; |
@@ -2024,7 +2024,7 @@ setAclRetry: | |||
2024 | return rc; | 2024 | return rc; |
2025 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2025 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
2026 | name_len = | 2026 | name_len = |
2027 | cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, | 2027 | cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, |
2028 | PATH_MAX, nls_codepage, remap); | 2028 | PATH_MAX, nls_codepage, remap); |
2029 | name_len++; /* trailing null */ | 2029 | name_len++; /* trailing null */ |
2030 | name_len *= 2; | 2030 | name_len *= 2; |
@@ -2188,7 +2188,7 @@ QPathInfoRetry: | |||
2188 | 2188 | ||
2189 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2189 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
2190 | name_len = | 2190 | name_len = |
2191 | cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, | 2191 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, |
2192 | PATH_MAX, nls_codepage, remap); | 2192 | PATH_MAX, nls_codepage, remap); |
2193 | name_len++; /* trailing null */ | 2193 | name_len++; /* trailing null */ |
2194 | name_len *= 2; | 2194 | name_len *= 2; |
@@ -2269,7 +2269,7 @@ UnixQPathInfoRetry: | |||
2269 | 2269 | ||
2270 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2270 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
2271 | name_len = | 2271 | name_len = |
2272 | cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, | 2272 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, |
2273 | PATH_MAX, nls_codepage, remap); | 2273 | PATH_MAX, nls_codepage, remap); |
2274 | name_len++; /* trailing null */ | 2274 | name_len++; /* trailing null */ |
2275 | name_len *= 2; | 2275 | name_len *= 2; |
@@ -2350,7 +2350,7 @@ findUniqueRetry: | |||
2350 | 2350 | ||
2351 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2351 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
2352 | name_len = | 2352 | name_len = |
2353 | cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX | 2353 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX |
2354 | /* find define for this maxpathcomponent */ | 2354 | /* find define for this maxpathcomponent */ |
2355 | , nls_codepage); | 2355 | , nls_codepage); |
2356 | name_len++; /* trailing null */ | 2356 | name_len++; /* trailing null */ |
@@ -2435,7 +2435,7 @@ findFirstRetry: | |||
2435 | 2435 | ||
2436 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2436 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
2437 | name_len = | 2437 | name_len = |
2438 | cifsConvertToUCS((__u16 *) pSMB->FileName,searchName, | 2438 | cifsConvertToUCS((__le16 *) pSMB->FileName,searchName, |
2439 | PATH_MAX, nls_codepage, remap); | 2439 | PATH_MAX, nls_codepage, remap); |
2440 | /* We can not add the asterik earlier in case | 2440 | /* We can not add the asterik earlier in case |
2441 | it got remapped to 0xF03A as if it were part of the | 2441 | it got remapped to 0xF03A as if it were part of the |
@@ -2726,7 +2726,7 @@ GetInodeNumberRetry: | |||
2726 | 2726 | ||
2727 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2727 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
2728 | name_len = | 2728 | name_len = |
2729 | cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, | 2729 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, |
2730 | PATH_MAX,nls_codepage, remap); | 2730 | PATH_MAX,nls_codepage, remap); |
2731 | name_len++; /* trailing null */ | 2731 | name_len++; /* trailing null */ |
2732 | name_len *= 2; | 2732 | name_len *= 2; |
@@ -2837,7 +2837,7 @@ getDFSRetry: | |||
2837 | if (ses->capabilities & CAP_UNICODE) { | 2837 | if (ses->capabilities & CAP_UNICODE) { |
2838 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 2838 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
2839 | name_len = | 2839 | name_len = |
2840 | cifsConvertToUCS((__u16 *) pSMB->RequestFileName, | 2840 | cifsConvertToUCS((__le16 *) pSMB->RequestFileName, |
2841 | searchName, PATH_MAX, nls_codepage, remap); | 2841 | searchName, PATH_MAX, nls_codepage, remap); |
2842 | name_len++; /* trailing null */ | 2842 | name_len++; /* trailing null */ |
2843 | name_len *= 2; | 2843 | name_len *= 2; |
@@ -3369,7 +3369,7 @@ SetEOFRetry: | |||
3369 | 3369 | ||
3370 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 3370 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
3371 | name_len = | 3371 | name_len = |
3372 | cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, | 3372 | cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, |
3373 | PATH_MAX, nls_codepage, remap); | 3373 | PATH_MAX, nls_codepage, remap); |
3374 | name_len++; /* trailing null */ | 3374 | name_len++; /* trailing null */ |
3375 | name_len *= 2; | 3375 | name_len *= 2; |
@@ -3627,7 +3627,7 @@ SetTimesRetry: | |||
3627 | 3627 | ||
3628 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 3628 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
3629 | name_len = | 3629 | name_len = |
3630 | cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, | 3630 | cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, |
3631 | PATH_MAX, nls_codepage, remap); | 3631 | PATH_MAX, nls_codepage, remap); |
3632 | name_len++; /* trailing null */ | 3632 | name_len++; /* trailing null */ |
3633 | name_len *= 2; | 3633 | name_len *= 2; |
@@ -3708,7 +3708,7 @@ SetAttrLgcyRetry: | |||
3708 | 3708 | ||
3709 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 3709 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
3710 | name_len = | 3710 | name_len = |
3711 | ConvertToUCS((wchar_t *) pSMB->fileName, fileName, | 3711 | ConvertToUCS((__le16 *) pSMB->fileName, fileName, |
3712 | PATH_MAX, nls_codepage); | 3712 | PATH_MAX, nls_codepage); |
3713 | name_len++; /* trailing null */ | 3713 | name_len++; /* trailing null */ |
3714 | name_len *= 2; | 3714 | name_len *= 2; |
@@ -3759,7 +3759,7 @@ setPermsRetry: | |||
3759 | 3759 | ||
3760 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 3760 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
3761 | name_len = | 3761 | name_len = |
3762 | cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, | 3762 | cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, |
3763 | PATH_MAX, nls_codepage, remap); | 3763 | PATH_MAX, nls_codepage, remap); |
3764 | name_len++; /* trailing null */ | 3764 | name_len++; /* trailing null */ |
3765 | name_len *= 2; | 3765 | name_len *= 2; |
@@ -3904,7 +3904,7 @@ QAllEAsRetry: | |||
3904 | 3904 | ||
3905 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 3905 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
3906 | name_len = | 3906 | name_len = |
3907 | cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, | 3907 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, |
3908 | PATH_MAX, nls_codepage, remap); | 3908 | PATH_MAX, nls_codepage, remap); |
3909 | name_len++; /* trailing null */ | 3909 | name_len++; /* trailing null */ |
3910 | name_len *= 2; | 3910 | name_len *= 2; |
@@ -4047,7 +4047,7 @@ QEARetry: | |||
4047 | 4047 | ||
4048 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 4048 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
4049 | name_len = | 4049 | name_len = |
4050 | cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, | 4050 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, |
4051 | PATH_MAX, nls_codepage, remap); | 4051 | PATH_MAX, nls_codepage, remap); |
4052 | name_len++; /* trailing null */ | 4052 | name_len++; /* trailing null */ |
4053 | name_len *= 2; | 4053 | name_len *= 2; |
@@ -4194,7 +4194,7 @@ SetEARetry: | |||
4194 | 4194 | ||
4195 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 4195 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
4196 | name_len = | 4196 | name_len = |
4197 | cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, | 4197 | cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, |
4198 | PATH_MAX, nls_codepage, remap); | 4198 | PATH_MAX, nls_codepage, remap); |
4199 | name_len++; /* trailing null */ | 4199 | name_len++; /* trailing null */ |
4200 | name_len *= 2; | 4200 | name_len *= 2; |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e3137aa48cdd..3f3538d4a1fa 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -392,7 +392,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name | |||
392 | rc = 0; | 392 | rc = 0; |
393 | d_add(direntry, NULL); | 393 | d_add(direntry, NULL); |
394 | } else { | 394 | } else { |
395 | cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc)); | 395 | cERROR(1,("Error 0x%x on cifs_get_inode_info in lookup of %s", |
396 | rc,full_path)); | ||
396 | /* BB special case check for Access Denied - watch security | 397 | /* BB special case check for Access Denied - watch security |
397 | exposure of returning dir info implicitly via different rc | 398 | exposure of returning dir info implicitly via different rc |
398 | if file exists or not but no access BB */ | 399 | if file exists or not but no access BB */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index dde2d251fc3d..30ab70ce5547 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1352,6 +1352,8 @@ static void cifs_copy_cache_pages(struct address_space *mapping, | |||
1352 | GFP_KERNEL)) { | 1352 | GFP_KERNEL)) { |
1353 | page_cache_release(page); | 1353 | page_cache_release(page); |
1354 | cFYI(1, ("Add page cache failed")); | 1354 | cFYI(1, ("Add page cache failed")); |
1355 | data += PAGE_CACHE_SIZE; | ||
1356 | bytes_read -= PAGE_CACHE_SIZE; | ||
1355 | continue; | 1357 | continue; |
1356 | } | 1358 | } |
1357 | 1359 | ||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 670947288262..8d336a900255 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -82,12 +82,12 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
82 | /* get new inode */ | 82 | /* get new inode */ |
83 | if (*pinode == NULL) { | 83 | if (*pinode == NULL) { |
84 | *pinode = new_inode(sb); | 84 | *pinode = new_inode(sb); |
85 | if(*pinode == NULL) | 85 | if (*pinode == NULL) |
86 | return -ENOMEM; | 86 | return -ENOMEM; |
87 | /* Is an i_ino of zero legal? */ | 87 | /* Is an i_ino of zero legal? */ |
88 | /* Are there sanity checks we can use to ensure that | 88 | /* Are there sanity checks we can use to ensure that |
89 | the server is really filling in that field? */ | 89 | the server is really filling in that field? */ |
90 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | 90 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { |
91 | (*pinode)->i_ino = | 91 | (*pinode)->i_ino = |
92 | (unsigned long)findData.UniqueId; | 92 | (unsigned long)findData.UniqueId; |
93 | } /* note ino incremented to unique num in new_inode */ | 93 | } /* note ino incremented to unique num in new_inode */ |
@@ -134,7 +134,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
134 | inode->i_gid = le64_to_cpu(findData.Gid); | 134 | inode->i_gid = le64_to_cpu(findData.Gid); |
135 | inode->i_nlink = le64_to_cpu(findData.Nlinks); | 135 | inode->i_nlink = le64_to_cpu(findData.Nlinks); |
136 | 136 | ||
137 | if(is_size_safe_to_change(cifsInfo)) { | 137 | if (is_size_safe_to_change(cifsInfo)) { |
138 | /* can not safely change the file size here if the | 138 | /* can not safely change the file size here if the |
139 | client is writing to it due to potential races */ | 139 | client is writing to it due to potential races */ |
140 | 140 | ||
@@ -162,7 +162,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
162 | if (S_ISREG(inode->i_mode)) { | 162 | if (S_ISREG(inode->i_mode)) { |
163 | cFYI(1, (" File inode ")); | 163 | cFYI(1, (" File inode ")); |
164 | inode->i_op = &cifs_file_inode_ops; | 164 | inode->i_op = &cifs_file_inode_ops; |
165 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | 165 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) |
166 | inode->i_fop = &cifs_file_direct_ops; | 166 | inode->i_fop = &cifs_file_direct_ops; |
167 | else | 167 | else |
168 | inode->i_fop = &cifs_file_ops; | 168 | inode->i_fop = &cifs_file_ops; |
@@ -198,17 +198,17 @@ int cifs_get_inode_info(struct inode **pinode, | |||
198 | pTcon = cifs_sb->tcon; | 198 | pTcon = cifs_sb->tcon; |
199 | cFYI(1,("Getting info on %s ", search_path)); | 199 | cFYI(1,("Getting info on %s ", search_path)); |
200 | 200 | ||
201 | if((pfindData == NULL) && (*pinode != NULL)) { | 201 | if ((pfindData == NULL) && (*pinode != NULL)) { |
202 | if(CIFS_I(*pinode)->clientCanCacheRead) { | 202 | if (CIFS_I(*pinode)->clientCanCacheRead) { |
203 | cFYI(1,("No need to revalidate cached inode sizes")); | 203 | cFYI(1,("No need to revalidate cached inode sizes")); |
204 | return rc; | 204 | return rc; |
205 | } | 205 | } |
206 | } | 206 | } |
207 | 207 | ||
208 | /* if file info not passed in then get it from server */ | 208 | /* if file info not passed in then get it from server */ |
209 | if(pfindData == NULL) { | 209 | if (pfindData == NULL) { |
210 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | 210 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
211 | if(buf == NULL) | 211 | if (buf == NULL) |
212 | return -ENOMEM; | 212 | return -ENOMEM; |
213 | pfindData = (FILE_ALL_INFO *)buf; | 213 | pfindData = (FILE_ALL_INFO *)buf; |
214 | /* could do find first instead but this returns more info */ | 214 | /* could do find first instead but this returns more info */ |
@@ -268,7 +268,7 @@ int cifs_get_inode_info(struct inode **pinode, | |||
268 | IndexNumber field is not guaranteed unique? */ | 268 | IndexNumber field is not guaranteed unique? */ |
269 | 269 | ||
270 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 270 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
271 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){ | 271 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){ |
272 | int rc1 = 0; | 272 | int rc1 = 0; |
273 | __u64 inode_num; | 273 | __u64 inode_num; |
274 | 274 | ||
@@ -277,7 +277,7 @@ int cifs_get_inode_info(struct inode **pinode, | |||
277 | cifs_sb->local_nls, | 277 | cifs_sb->local_nls, |
278 | cifs_sb->mnt_cifs_flags & | 278 | cifs_sb->mnt_cifs_flags & |
279 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 279 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
280 | if(rc1) { | 280 | if (rc1) { |
281 | cFYI(1,("GetSrvInodeNum rc %d", rc1)); | 281 | cFYI(1,("GetSrvInodeNum rc %d", rc1)); |
282 | /* BB EOPNOSUPP disable SERVER_INUM? */ | 282 | /* BB EOPNOSUPP disable SERVER_INUM? */ |
283 | } else /* do we need cast or hash to ino? */ | 283 | } else /* do we need cast or hash to ino? */ |
@@ -355,7 +355,7 @@ int cifs_get_inode_info(struct inode **pinode, | |||
355 | if (S_ISREG(inode->i_mode)) { | 355 | if (S_ISREG(inode->i_mode)) { |
356 | cFYI(1, (" File inode ")); | 356 | cFYI(1, (" File inode ")); |
357 | inode->i_op = &cifs_file_inode_ops; | 357 | inode->i_op = &cifs_file_inode_ops; |
358 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | 358 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) |
359 | inode->i_fop = &cifs_file_direct_ops; | 359 | inode->i_fop = &cifs_file_direct_ops; |
360 | else | 360 | else |
361 | inode->i_fop = &cifs_file_ops; | 361 | inode->i_fop = &cifs_file_ops; |
@@ -422,7 +422,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) | |||
422 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 422 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
423 | 423 | ||
424 | if (!rc) { | 424 | if (!rc) { |
425 | direntry->d_inode->i_nlink--; | 425 | if (direntry->d_inode) |
426 | direntry->d_inode->i_nlink--; | ||
426 | } else if (rc == -ENOENT) { | 427 | } else if (rc == -ENOENT) { |
427 | d_drop(direntry); | 428 | d_drop(direntry); |
428 | } else if (rc == -ETXTBSY) { | 429 | } else if (rc == -ETXTBSY) { |
@@ -440,7 +441,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) | |||
440 | cifs_sb->mnt_cifs_flags & | 441 | cifs_sb->mnt_cifs_flags & |
441 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 442 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
442 | CIFSSMBClose(xid, pTcon, netfid); | 443 | CIFSSMBClose(xid, pTcon, netfid); |
443 | direntry->d_inode->i_nlink--; | 444 | if (direntry->d_inode) |
445 | direntry->d_inode->i_nlink--; | ||
444 | } | 446 | } |
445 | } else if (rc == -EACCES) { | 447 | } else if (rc == -EACCES) { |
446 | /* try only if r/o attribute set in local lookup data? */ | 448 | /* try only if r/o attribute set in local lookup data? */ |
@@ -494,7 +496,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) | |||
494 | cifs_sb->mnt_cifs_flags & | 496 | cifs_sb->mnt_cifs_flags & |
495 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 497 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
496 | if (!rc) { | 498 | if (!rc) { |
497 | direntry->d_inode->i_nlink--; | 499 | if (direntry->d_inode) |
500 | direntry->d_inode->i_nlink--; | ||
498 | } else if (rc == -ETXTBSY) { | 501 | } else if (rc == -ETXTBSY) { |
499 | int oplock = FALSE; | 502 | int oplock = FALSE; |
500 | __u16 netfid; | 503 | __u16 netfid; |
@@ -514,17 +517,20 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) | |||
514 | cifs_sb->mnt_cifs_flags & | 517 | cifs_sb->mnt_cifs_flags & |
515 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 518 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
516 | CIFSSMBClose(xid, pTcon, netfid); | 519 | CIFSSMBClose(xid, pTcon, netfid); |
517 | direntry->d_inode->i_nlink--; | 520 | if (direntry->d_inode) |
521 | direntry->d_inode->i_nlink--; | ||
518 | } | 522 | } |
519 | /* BB if rc = -ETXTBUSY goto the rename logic BB */ | 523 | /* BB if rc = -ETXTBUSY goto the rename logic BB */ |
520 | } | 524 | } |
521 | } | 525 | } |
522 | } | 526 | } |
523 | cifsInode = CIFS_I(direntry->d_inode); | 527 | if (direntry->d_inode) { |
524 | cifsInode->time = 0; /* will force revalidate to get info when | 528 | cifsInode = CIFS_I(direntry->d_inode); |
525 | needed */ | 529 | cifsInode->time = 0; /* will force revalidate to get info |
526 | direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = | 530 | when needed */ |
527 | current_fs_time(inode->i_sb); | 531 | direntry->d_inode->i_ctime = current_fs_time(inode->i_sb); |
532 | } | ||
533 | inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); | ||
528 | cifsInode = CIFS_I(inode); | 534 | cifsInode = CIFS_I(inode); |
529 | cifsInode->time = 0; /* force revalidate of dir as well */ | 535 | cifsInode->time = 0; /* force revalidate of dir as well */ |
530 | 536 | ||
@@ -576,7 +582,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
576 | if (direntry->d_inode) | 582 | if (direntry->d_inode) |
577 | direntry->d_inode->i_nlink = 2; | 583 | direntry->d_inode->i_nlink = 2; |
578 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) | 584 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) |
579 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 585 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
580 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 586 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, |
581 | mode, | 587 | mode, |
582 | (__u64)current->euid, | 588 | (__u64)current->euid, |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index db14b503d89e..072b4ee8c53e 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -571,6 +571,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, | |||
571 | break; | 571 | break; |
572 | case UNI_LESSTHAN: | 572 | case UNI_LESSTHAN: |
573 | target[j] = '<'; | 573 | target[j] = '<'; |
574 | break; | ||
574 | default: | 575 | default: |
575 | len = cp->uni2char(src_char, &target[j], | 576 | len = cp->uni2char(src_char, &target[j], |
576 | NLS_MAX_CHARSET_SIZE); | 577 | NLS_MAX_CHARSET_SIZE); |
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index ef001a9313e6..3d1cce3653b8 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c | |||
@@ -61,7 +61,7 @@ unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */ | |||
61 | 61 | ||
62 | 62 | ||
63 | struct venus_comm coda_comms[MAX_CODADEVS]; | 63 | struct venus_comm coda_comms[MAX_CODADEVS]; |
64 | static struct class_simple *coda_psdev_class; | 64 | static struct class *coda_psdev_class; |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * Device operations | 67 | * Device operations |
@@ -363,14 +363,14 @@ static int init_coda_psdev(void) | |||
363 | CODA_PSDEV_MAJOR); | 363 | CODA_PSDEV_MAJOR); |
364 | return -EIO; | 364 | return -EIO; |
365 | } | 365 | } |
366 | coda_psdev_class = class_simple_create(THIS_MODULE, "coda"); | 366 | coda_psdev_class = class_create(THIS_MODULE, "coda"); |
367 | if (IS_ERR(coda_psdev_class)) { | 367 | if (IS_ERR(coda_psdev_class)) { |
368 | err = PTR_ERR(coda_psdev_class); | 368 | err = PTR_ERR(coda_psdev_class); |
369 | goto out_chrdev; | 369 | goto out_chrdev; |
370 | } | 370 | } |
371 | devfs_mk_dir ("coda"); | 371 | devfs_mk_dir ("coda"); |
372 | for (i = 0; i < MAX_CODADEVS; i++) { | 372 | for (i = 0; i < MAX_CODADEVS; i++) { |
373 | class_simple_device_add(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR,i), | 373 | class_device_create(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR,i), |
374 | NULL, "cfs%d", i); | 374 | NULL, "cfs%d", i); |
375 | err = devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i), | 375 | err = devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i), |
376 | S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i); | 376 | S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i); |
@@ -382,8 +382,8 @@ static int init_coda_psdev(void) | |||
382 | 382 | ||
383 | out_class: | 383 | out_class: |
384 | for (i = 0; i < MAX_CODADEVS; i++) | 384 | for (i = 0; i < MAX_CODADEVS; i++) |
385 | class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i)); | 385 | class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); |
386 | class_simple_destroy(coda_psdev_class); | 386 | class_destroy(coda_psdev_class); |
387 | out_chrdev: | 387 | out_chrdev: |
388 | unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); | 388 | unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); |
389 | out: | 389 | out: |
@@ -425,10 +425,10 @@ static int __init init_coda(void) | |||
425 | return 0; | 425 | return 0; |
426 | out: | 426 | out: |
427 | for (i = 0; i < MAX_CODADEVS; i++) { | 427 | for (i = 0; i < MAX_CODADEVS; i++) { |
428 | class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i)); | 428 | class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); |
429 | devfs_remove("coda/%d", i); | 429 | devfs_remove("coda/%d", i); |
430 | } | 430 | } |
431 | class_simple_destroy(coda_psdev_class); | 431 | class_destroy(coda_psdev_class); |
432 | devfs_remove("coda"); | 432 | devfs_remove("coda"); |
433 | unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); | 433 | unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); |
434 | coda_sysctl_clean(); | 434 | coda_sysctl_clean(); |
@@ -447,10 +447,10 @@ static void __exit exit_coda(void) | |||
447 | printk("coda: failed to unregister filesystem\n"); | 447 | printk("coda: failed to unregister filesystem\n"); |
448 | } | 448 | } |
449 | for (i = 0; i < MAX_CODADEVS; i++) { | 449 | for (i = 0; i < MAX_CODADEVS; i++) { |
450 | class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i)); | 450 | class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); |
451 | devfs_remove("coda/%d", i); | 451 | devfs_remove("coda/%d", i); |
452 | } | 452 | } |
453 | class_simple_destroy(coda_psdev_class); | 453 | class_destroy(coda_psdev_class); |
454 | devfs_remove("coda"); | 454 | devfs_remove("coda"); |
455 | unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); | 455 | unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); |
456 | coda_sysctl_clean(); | 456 | coda_sysctl_clean(); |
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 548556ff2506..efc97d9b7860 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
@@ -45,44 +45,15 @@ struct file_operations debugfs_file_operations = { | |||
45 | .open = default_open, | 45 | .open = default_open, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | #define simple_type(type, format, temptype, strtolfn) \ | 48 | static void debugfs_u8_set(void *data, u64 val) |
49 | static ssize_t read_file_##type(struct file *file, char __user *user_buf, \ | 49 | { |
50 | size_t count, loff_t *ppos) \ | 50 | *(u8 *)data = val; |
51 | { \ | 51 | } |
52 | char buf[32]; \ | 52 | static u64 debugfs_u8_get(void *data) |
53 | type *val = file->private_data; \ | 53 | { |
54 | \ | 54 | return *(u8 *)data; |
55 | snprintf(buf, sizeof(buf), format "\n", *val); \ | 55 | } |
56 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));\ | 56 | DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n"); |
57 | } \ | ||
58 | static ssize_t write_file_##type(struct file *file, const char __user *user_buf,\ | ||
59 | size_t count, loff_t *ppos) \ | ||
60 | { \ | ||
61 | char *endp; \ | ||
62 | char buf[32]; \ | ||
63 | int buf_size; \ | ||
64 | type *val = file->private_data; \ | ||
65 | temptype tmp; \ | ||
66 | \ | ||
67 | memset(buf, 0x00, sizeof(buf)); \ | ||
68 | buf_size = min(count, (sizeof(buf)-1)); \ | ||
69 | if (copy_from_user(buf, user_buf, buf_size)) \ | ||
70 | return -EFAULT; \ | ||
71 | \ | ||
72 | tmp = strtolfn(buf, &endp, 0); \ | ||
73 | if ((endp == buf) || ((type)tmp != tmp)) \ | ||
74 | return -EINVAL; \ | ||
75 | *val = tmp; \ | ||
76 | return count; \ | ||
77 | } \ | ||
78 | static struct file_operations fops_##type = { \ | ||
79 | .read = read_file_##type, \ | ||
80 | .write = write_file_##type, \ | ||
81 | .open = default_open, \ | ||
82 | }; | ||
83 | simple_type(u8, "%c", unsigned long, simple_strtoul); | ||
84 | simple_type(u16, "%hi", unsigned long, simple_strtoul); | ||
85 | simple_type(u32, "%i", unsigned long, simple_strtoul); | ||
86 | 57 | ||
87 | /** | 58 | /** |
88 | * debugfs_create_u8 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. | 59 | * debugfs_create_u8 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. |
@@ -116,6 +87,16 @@ struct dentry *debugfs_create_u8(const char *name, mode_t mode, | |||
116 | } | 87 | } |
117 | EXPORT_SYMBOL_GPL(debugfs_create_u8); | 88 | EXPORT_SYMBOL_GPL(debugfs_create_u8); |
118 | 89 | ||
90 | static void debugfs_u16_set(void *data, u64 val) | ||
91 | { | ||
92 | *(u16 *)data = val; | ||
93 | } | ||
94 | static u64 debugfs_u16_get(void *data) | ||
95 | { | ||
96 | return *(u16 *)data; | ||
97 | } | ||
98 | DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n"); | ||
99 | |||
119 | /** | 100 | /** |
120 | * debugfs_create_u16 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. | 101 | * debugfs_create_u16 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. |
121 | * | 102 | * |
@@ -148,6 +129,16 @@ struct dentry *debugfs_create_u16(const char *name, mode_t mode, | |||
148 | } | 129 | } |
149 | EXPORT_SYMBOL_GPL(debugfs_create_u16); | 130 | EXPORT_SYMBOL_GPL(debugfs_create_u16); |
150 | 131 | ||
132 | static void debugfs_u32_set(void *data, u64 val) | ||
133 | { | ||
134 | *(u32 *)data = val; | ||
135 | } | ||
136 | static u64 debugfs_u32_get(void *data) | ||
137 | { | ||
138 | return *(u32 *)data; | ||
139 | } | ||
140 | DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n"); | ||
141 | |||
151 | /** | 142 | /** |
152 | * debugfs_create_u32 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. | 143 | * debugfs_create_u32 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. |
153 | * | 144 | * |
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index b529786699e7..a86ac4aeaedb 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -110,16 +110,6 @@ static int debug_fill_super(struct super_block *sb, void *data, int silent) | |||
110 | return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); | 110 | return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); |
111 | } | 111 | } |
112 | 112 | ||
113 | static struct dentry * get_dentry(struct dentry *parent, const char *name) | ||
114 | { | ||
115 | struct qstr qstr; | ||
116 | |||
117 | qstr.name = name; | ||
118 | qstr.len = strlen(name); | ||
119 | qstr.hash = full_name_hash(name,qstr.len); | ||
120 | return lookup_hash(&qstr,parent); | ||
121 | } | ||
122 | |||
123 | static struct super_block *debug_get_sb(struct file_system_type *fs_type, | 113 | static struct super_block *debug_get_sb(struct file_system_type *fs_type, |
124 | int flags, const char *dev_name, | 114 | int flags, const char *dev_name, |
125 | void *data) | 115 | void *data) |
@@ -157,7 +147,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, | |||
157 | 147 | ||
158 | *dentry = NULL; | 148 | *dentry = NULL; |
159 | down(&parent->d_inode->i_sem); | 149 | down(&parent->d_inode->i_sem); |
160 | *dentry = get_dentry (parent, name); | 150 | *dentry = lookup_one_len(name, parent, strlen(name)); |
161 | if (!IS_ERR(dentry)) { | 151 | if (!IS_ERR(dentry)) { |
162 | if ((mode & S_IFMT) == S_IFDIR) | 152 | if ((mode & S_IFMT) == S_IFDIR) |
163 | error = debugfs_mkdir(parent->d_inode, *dentry, mode); | 153 | error = debugfs_mkdir(parent->d_inode, *dentry, mode); |
diff --git a/fs/direct-io.c b/fs/direct-io.c index 1d55e7e67342..0d06097bc995 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
@@ -215,7 +215,7 @@ static struct page *dio_get_page(struct dio *dio) | |||
215 | static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes) | 215 | static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes) |
216 | { | 216 | { |
217 | if (dio->end_io && dio->result) | 217 | if (dio->end_io && dio->result) |
218 | dio->end_io(dio->inode, offset, bytes, dio->map_bh.b_private); | 218 | dio->end_io(dio->iocb, offset, bytes, dio->map_bh.b_private); |
219 | if (dio->lock_type == DIO_LOCKING) | 219 | if (dio->lock_type == DIO_LOCKING) |
220 | up_read(&dio->inode->i_alloc_sem); | 220 | up_read(&dio->inode->i_alloc_sem); |
221 | } | 221 | } |
diff --git a/fs/dquot.c b/fs/dquot.c index 3995ce7907cc..b9732335bcdc 100644 --- a/fs/dquot.c +++ b/fs/dquot.c | |||
@@ -409,13 +409,10 @@ out_dqlock: | |||
409 | * for this sb+type at all. */ | 409 | * for this sb+type at all. */ |
410 | static void invalidate_dquots(struct super_block *sb, int type) | 410 | static void invalidate_dquots(struct super_block *sb, int type) |
411 | { | 411 | { |
412 | struct dquot *dquot; | 412 | struct dquot *dquot, *tmp; |
413 | struct list_head *head; | ||
414 | 413 | ||
415 | spin_lock(&dq_list_lock); | 414 | spin_lock(&dq_list_lock); |
416 | for (head = inuse_list.next; head != &inuse_list;) { | 415 | list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) { |
417 | dquot = list_entry(head, struct dquot, dq_inuse); | ||
418 | head = head->next; | ||
419 | if (dquot->dq_sb != sb) | 416 | if (dquot->dq_sb != sb) |
420 | continue; | 417 | continue; |
421 | if (dquot->dq_type != type) | 418 | if (dquot->dq_type != type) |
@@ -1519,14 +1516,22 @@ out_path: | |||
1519 | * This function is used when filesystem needs to initialize quotas | 1516 | * This function is used when filesystem needs to initialize quotas |
1520 | * during mount time. | 1517 | * during mount time. |
1521 | */ | 1518 | */ |
1522 | int vfs_quota_on_mount(int type, int format_id, struct dentry *dentry) | 1519 | int vfs_quota_on_mount(struct super_block *sb, char *qf_name, |
1520 | int format_id, int type) | ||
1523 | { | 1521 | { |
1522 | struct dentry *dentry; | ||
1524 | int error; | 1523 | int error; |
1525 | 1524 | ||
1525 | dentry = lookup_one_len(qf_name, sb->s_root, strlen(qf_name)); | ||
1526 | if (IS_ERR(dentry)) | ||
1527 | return PTR_ERR(dentry); | ||
1528 | |||
1526 | error = security_quota_on(dentry); | 1529 | error = security_quota_on(dentry); |
1527 | if (error) | 1530 | if (!error) |
1528 | return error; | 1531 | error = vfs_quota_on_inode(dentry->d_inode, type, format_id); |
1529 | return vfs_quota_on_inode(dentry->d_inode, type, format_id); | 1532 | |
1533 | dput(dentry); | ||
1534 | return error; | ||
1530 | } | 1535 | } |
1531 | 1536 | ||
1532 | /* Generic routine for getting common part of quota structure */ | 1537 | /* Generic routine for getting common part of quota structure */ |
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 9900e333655a..6ab1dd0ca904 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -101,57 +101,6 @@ | |||
101 | /* Maximum number of poll wake up nests we are allowing */ | 101 | /* Maximum number of poll wake up nests we are allowing */ |
102 | #define EP_MAX_POLLWAKE_NESTS 4 | 102 | #define EP_MAX_POLLWAKE_NESTS 4 |
103 | 103 | ||
104 | /* Macro to allocate a "struct epitem" from the slab cache */ | ||
105 | #define EPI_MEM_ALLOC() (struct epitem *) kmem_cache_alloc(epi_cache, SLAB_KERNEL) | ||
106 | |||
107 | /* Macro to free a "struct epitem" to the slab cache */ | ||
108 | #define EPI_MEM_FREE(p) kmem_cache_free(epi_cache, p) | ||
109 | |||
110 | /* Macro to allocate a "struct eppoll_entry" from the slab cache */ | ||
111 | #define PWQ_MEM_ALLOC() (struct eppoll_entry *) kmem_cache_alloc(pwq_cache, SLAB_KERNEL) | ||
112 | |||
113 | /* Macro to free a "struct eppoll_entry" to the slab cache */ | ||
114 | #define PWQ_MEM_FREE(p) kmem_cache_free(pwq_cache, p) | ||
115 | |||
116 | /* Fast test to see if the file is an evenpoll file */ | ||
117 | #define IS_FILE_EPOLL(f) ((f)->f_op == &eventpoll_fops) | ||
118 | |||
119 | /* Setup the structure that is used as key for the rb-tree */ | ||
120 | #define EP_SET_FFD(p, f, d) do { (p)->file = (f); (p)->fd = (d); } while (0) | ||
121 | |||
122 | /* Compare rb-tree keys */ | ||
123 | #define EP_CMP_FFD(p1, p2) ((p1)->file > (p2)->file ? +1: \ | ||
124 | ((p1)->file < (p2)->file ? -1: (p1)->fd - (p2)->fd)) | ||
125 | |||
126 | /* Special initialization for the rb-tree node to detect linkage */ | ||
127 | #define EP_RB_INITNODE(n) (n)->rb_parent = (n) | ||
128 | |||
129 | /* Removes a node from the rb-tree and marks it for a fast is-linked check */ | ||
130 | #define EP_RB_ERASE(n, r) do { rb_erase(n, r); (n)->rb_parent = (n); } while (0) | ||
131 | |||
132 | /* Fast check to verify that the item is linked to the main rb-tree */ | ||
133 | #define EP_RB_LINKED(n) ((n)->rb_parent != (n)) | ||
134 | |||
135 | /* | ||
136 | * Remove the item from the list and perform its initialization. | ||
137 | * This is useful for us because we can test if the item is linked | ||
138 | * using "EP_IS_LINKED(p)". | ||
139 | */ | ||
140 | #define EP_LIST_DEL(p) do { list_del(p); INIT_LIST_HEAD(p); } while (0) | ||
141 | |||
142 | /* Tells us if the item is currently linked */ | ||
143 | #define EP_IS_LINKED(p) (!list_empty(p)) | ||
144 | |||
145 | /* Get the "struct epitem" from a wait queue pointer */ | ||
146 | #define EP_ITEM_FROM_WAIT(p) ((struct epitem *) container_of(p, struct eppoll_entry, wait)->base) | ||
147 | |||
148 | /* Get the "struct epitem" from an epoll queue wrapper */ | ||
149 | #define EP_ITEM_FROM_EPQUEUE(p) (container_of(p, struct ep_pqueue, pt)->epi) | ||
150 | |||
151 | /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ | ||
152 | #define EP_OP_HASH_EVENT(op) ((op) != EPOLL_CTL_DEL) | ||
153 | |||
154 | |||
155 | struct epoll_filefd { | 104 | struct epoll_filefd { |
156 | struct file *file; | 105 | struct file *file; |
157 | int fd; | 106 | int fd; |
@@ -357,6 +306,82 @@ static struct dentry_operations eventpollfs_dentry_operations = { | |||
357 | 306 | ||
358 | 307 | ||
359 | 308 | ||
309 | /* Fast test to see if the file is an evenpoll file */ | ||
310 | static inline int is_file_epoll(struct file *f) | ||
311 | { | ||
312 | return f->f_op == &eventpoll_fops; | ||
313 | } | ||
314 | |||
315 | /* Setup the structure that is used as key for the rb-tree */ | ||
316 | static inline void ep_set_ffd(struct epoll_filefd *ffd, | ||
317 | struct file *file, int fd) | ||
318 | { | ||
319 | ffd->file = file; | ||
320 | ffd->fd = fd; | ||
321 | } | ||
322 | |||
323 | /* Compare rb-tree keys */ | ||
324 | static inline int ep_cmp_ffd(struct epoll_filefd *p1, | ||
325 | struct epoll_filefd *p2) | ||
326 | { | ||
327 | return (p1->file > p2->file ? +1: | ||
328 | (p1->file < p2->file ? -1 : p1->fd - p2->fd)); | ||
329 | } | ||
330 | |||
331 | /* Special initialization for the rb-tree node to detect linkage */ | ||
332 | static inline void ep_rb_initnode(struct rb_node *n) | ||
333 | { | ||
334 | n->rb_parent = n; | ||
335 | } | ||
336 | |||
337 | /* Removes a node from the rb-tree and marks it for a fast is-linked check */ | ||
338 | static inline void ep_rb_erase(struct rb_node *n, struct rb_root *r) | ||
339 | { | ||
340 | rb_erase(n, r); | ||
341 | n->rb_parent = n; | ||
342 | } | ||
343 | |||
344 | /* Fast check to verify that the item is linked to the main rb-tree */ | ||
345 | static inline int ep_rb_linked(struct rb_node *n) | ||
346 | { | ||
347 | return n->rb_parent != n; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * Remove the item from the list and perform its initialization. | ||
352 | * This is useful for us because we can test if the item is linked | ||
353 | * using "ep_is_linked(p)". | ||
354 | */ | ||
355 | static inline void ep_list_del(struct list_head *p) | ||
356 | { | ||
357 | list_del(p); | ||
358 | INIT_LIST_HEAD(p); | ||
359 | } | ||
360 | |||
361 | /* Tells us if the item is currently linked */ | ||
362 | static inline int ep_is_linked(struct list_head *p) | ||
363 | { | ||
364 | return !list_empty(p); | ||
365 | } | ||
366 | |||
367 | /* Get the "struct epitem" from a wait queue pointer */ | ||
368 | static inline struct epitem * ep_item_from_wait(wait_queue_t *p) | ||
369 | { | ||
370 | return container_of(p, struct eppoll_entry, wait)->base; | ||
371 | } | ||
372 | |||
373 | /* Get the "struct epitem" from an epoll queue wrapper */ | ||
374 | static inline struct epitem * ep_item_from_epqueue(poll_table *p) | ||
375 | { | ||
376 | return container_of(p, struct ep_pqueue, pt)->epi; | ||
377 | } | ||
378 | |||
379 | /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ | ||
380 | static inline int ep_op_hash_event(int op) | ||
381 | { | ||
382 | return op != EPOLL_CTL_DEL; | ||
383 | } | ||
384 | |||
360 | /* Initialize the poll safe wake up structure */ | 385 | /* Initialize the poll safe wake up structure */ |
361 | static void ep_poll_safewake_init(struct poll_safewake *psw) | 386 | static void ep_poll_safewake_init(struct poll_safewake *psw) |
362 | { | 387 | { |
@@ -456,7 +481,7 @@ void eventpoll_release_file(struct file *file) | |||
456 | epi = list_entry(lsthead->next, struct epitem, fllink); | 481 | epi = list_entry(lsthead->next, struct epitem, fllink); |
457 | 482 | ||
458 | ep = epi->ep; | 483 | ep = epi->ep; |
459 | EP_LIST_DEL(&epi->fllink); | 484 | ep_list_del(&epi->fllink); |
460 | down_write(&ep->sem); | 485 | down_write(&ep->sem); |
461 | ep_remove(ep, epi); | 486 | ep_remove(ep, epi); |
462 | up_write(&ep->sem); | 487 | up_write(&ep->sem); |
@@ -534,7 +559,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event) | |||
534 | current, epfd, op, fd, event)); | 559 | current, epfd, op, fd, event)); |
535 | 560 | ||
536 | error = -EFAULT; | 561 | error = -EFAULT; |
537 | if (EP_OP_HASH_EVENT(op) && | 562 | if (ep_op_hash_event(op) && |
538 | copy_from_user(&epds, event, sizeof(struct epoll_event))) | 563 | copy_from_user(&epds, event, sizeof(struct epoll_event))) |
539 | goto eexit_1; | 564 | goto eexit_1; |
540 | 565 | ||
@@ -560,7 +585,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event) | |||
560 | * adding an epoll file descriptor inside itself. | 585 | * adding an epoll file descriptor inside itself. |
561 | */ | 586 | */ |
562 | error = -EINVAL; | 587 | error = -EINVAL; |
563 | if (file == tfile || !IS_FILE_EPOLL(file)) | 588 | if (file == tfile || !is_file_epoll(file)) |
564 | goto eexit_3; | 589 | goto eexit_3; |
565 | 590 | ||
566 | /* | 591 | /* |
@@ -656,7 +681,7 @@ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, | |||
656 | * the user passed to us _is_ an eventpoll file. | 681 | * the user passed to us _is_ an eventpoll file. |
657 | */ | 682 | */ |
658 | error = -EINVAL; | 683 | error = -EINVAL; |
659 | if (!IS_FILE_EPOLL(file)) | 684 | if (!is_file_epoll(file)) |
660 | goto eexit_2; | 685 | goto eexit_2; |
661 | 686 | ||
662 | /* | 687 | /* |
@@ -831,11 +856,11 @@ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd) | |||
831 | struct epitem *epi, *epir = NULL; | 856 | struct epitem *epi, *epir = NULL; |
832 | struct epoll_filefd ffd; | 857 | struct epoll_filefd ffd; |
833 | 858 | ||
834 | EP_SET_FFD(&ffd, file, fd); | 859 | ep_set_ffd(&ffd, file, fd); |
835 | read_lock_irqsave(&ep->lock, flags); | 860 | read_lock_irqsave(&ep->lock, flags); |
836 | for (rbp = ep->rbr.rb_node; rbp; ) { | 861 | for (rbp = ep->rbr.rb_node; rbp; ) { |
837 | epi = rb_entry(rbp, struct epitem, rbn); | 862 | epi = rb_entry(rbp, struct epitem, rbn); |
838 | kcmp = EP_CMP_FFD(&ffd, &epi->ffd); | 863 | kcmp = ep_cmp_ffd(&ffd, &epi->ffd); |
839 | if (kcmp > 0) | 864 | if (kcmp > 0) |
840 | rbp = rbp->rb_right; | 865 | rbp = rbp->rb_right; |
841 | else if (kcmp < 0) | 866 | else if (kcmp < 0) |
@@ -875,7 +900,7 @@ static void ep_release_epitem(struct epitem *epi) | |||
875 | { | 900 | { |
876 | 901 | ||
877 | if (atomic_dec_and_test(&epi->usecnt)) | 902 | if (atomic_dec_and_test(&epi->usecnt)) |
878 | EPI_MEM_FREE(epi); | 903 | kmem_cache_free(epi_cache, epi); |
879 | } | 904 | } |
880 | 905 | ||
881 | 906 | ||
@@ -886,10 +911,10 @@ static void ep_release_epitem(struct epitem *epi) | |||
886 | static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, | 911 | static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, |
887 | poll_table *pt) | 912 | poll_table *pt) |
888 | { | 913 | { |
889 | struct epitem *epi = EP_ITEM_FROM_EPQUEUE(pt); | 914 | struct epitem *epi = ep_item_from_epqueue(pt); |
890 | struct eppoll_entry *pwq; | 915 | struct eppoll_entry *pwq; |
891 | 916 | ||
892 | if (epi->nwait >= 0 && (pwq = PWQ_MEM_ALLOC())) { | 917 | if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, SLAB_KERNEL))) { |
893 | init_waitqueue_func_entry(&pwq->wait, ep_poll_callback); | 918 | init_waitqueue_func_entry(&pwq->wait, ep_poll_callback); |
894 | pwq->whead = whead; | 919 | pwq->whead = whead; |
895 | pwq->base = epi; | 920 | pwq->base = epi; |
@@ -912,7 +937,7 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) | |||
912 | while (*p) { | 937 | while (*p) { |
913 | parent = *p; | 938 | parent = *p; |
914 | epic = rb_entry(parent, struct epitem, rbn); | 939 | epic = rb_entry(parent, struct epitem, rbn); |
915 | kcmp = EP_CMP_FFD(&epi->ffd, &epic->ffd); | 940 | kcmp = ep_cmp_ffd(&epi->ffd, &epic->ffd); |
916 | if (kcmp > 0) | 941 | if (kcmp > 0) |
917 | p = &parent->rb_right; | 942 | p = &parent->rb_right; |
918 | else | 943 | else |
@@ -932,17 +957,17 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, | |||
932 | struct ep_pqueue epq; | 957 | struct ep_pqueue epq; |
933 | 958 | ||
934 | error = -ENOMEM; | 959 | error = -ENOMEM; |
935 | if (!(epi = EPI_MEM_ALLOC())) | 960 | if (!(epi = kmem_cache_alloc(epi_cache, SLAB_KERNEL))) |
936 | goto eexit_1; | 961 | goto eexit_1; |
937 | 962 | ||
938 | /* Item initialization follow here ... */ | 963 | /* Item initialization follow here ... */ |
939 | EP_RB_INITNODE(&epi->rbn); | 964 | ep_rb_initnode(&epi->rbn); |
940 | INIT_LIST_HEAD(&epi->rdllink); | 965 | INIT_LIST_HEAD(&epi->rdllink); |
941 | INIT_LIST_HEAD(&epi->fllink); | 966 | INIT_LIST_HEAD(&epi->fllink); |
942 | INIT_LIST_HEAD(&epi->txlink); | 967 | INIT_LIST_HEAD(&epi->txlink); |
943 | INIT_LIST_HEAD(&epi->pwqlist); | 968 | INIT_LIST_HEAD(&epi->pwqlist); |
944 | epi->ep = ep; | 969 | epi->ep = ep; |
945 | EP_SET_FFD(&epi->ffd, tfile, fd); | 970 | ep_set_ffd(&epi->ffd, tfile, fd); |
946 | epi->event = *event; | 971 | epi->event = *event; |
947 | atomic_set(&epi->usecnt, 1); | 972 | atomic_set(&epi->usecnt, 1); |
948 | epi->nwait = 0; | 973 | epi->nwait = 0; |
@@ -978,7 +1003,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, | |||
978 | ep_rbtree_insert(ep, epi); | 1003 | ep_rbtree_insert(ep, epi); |
979 | 1004 | ||
980 | /* If the file is already "ready" we drop it inside the ready list */ | 1005 | /* If the file is already "ready" we drop it inside the ready list */ |
981 | if ((revents & event->events) && !EP_IS_LINKED(&epi->rdllink)) { | 1006 | if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) { |
982 | list_add_tail(&epi->rdllink, &ep->rdllist); | 1007 | list_add_tail(&epi->rdllink, &ep->rdllist); |
983 | 1008 | ||
984 | /* Notify waiting tasks that events are available */ | 1009 | /* Notify waiting tasks that events are available */ |
@@ -1007,11 +1032,11 @@ eexit_2: | |||
1007 | * allocated wait queue. | 1032 | * allocated wait queue. |
1008 | */ | 1033 | */ |
1009 | write_lock_irqsave(&ep->lock, flags); | 1034 | write_lock_irqsave(&ep->lock, flags); |
1010 | if (EP_IS_LINKED(&epi->rdllink)) | 1035 | if (ep_is_linked(&epi->rdllink)) |
1011 | EP_LIST_DEL(&epi->rdllink); | 1036 | ep_list_del(&epi->rdllink); |
1012 | write_unlock_irqrestore(&ep->lock, flags); | 1037 | write_unlock_irqrestore(&ep->lock, flags); |
1013 | 1038 | ||
1014 | EPI_MEM_FREE(epi); | 1039 | kmem_cache_free(epi_cache, epi); |
1015 | eexit_1: | 1040 | eexit_1: |
1016 | return error; | 1041 | return error; |
1017 | } | 1042 | } |
@@ -1050,14 +1075,14 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even | |||
1050 | * If the item is not linked to the hash it means that it's on its | 1075 | * If the item is not linked to the hash it means that it's on its |
1051 | * way toward the removal. Do nothing in this case. | 1076 | * way toward the removal. Do nothing in this case. |
1052 | */ | 1077 | */ |
1053 | if (EP_RB_LINKED(&epi->rbn)) { | 1078 | if (ep_rb_linked(&epi->rbn)) { |
1054 | /* | 1079 | /* |
1055 | * If the item is "hot" and it is not registered inside the ready | 1080 | * If the item is "hot" and it is not registered inside the ready |
1056 | * list, push it inside. If the item is not "hot" and it is currently | 1081 | * list, push it inside. If the item is not "hot" and it is currently |
1057 | * registered inside the ready list, unlink it. | 1082 | * registered inside the ready list, unlink it. |
1058 | */ | 1083 | */ |
1059 | if (revents & event->events) { | 1084 | if (revents & event->events) { |
1060 | if (!EP_IS_LINKED(&epi->rdllink)) { | 1085 | if (!ep_is_linked(&epi->rdllink)) { |
1061 | list_add_tail(&epi->rdllink, &ep->rdllist); | 1086 | list_add_tail(&epi->rdllink, &ep->rdllist); |
1062 | 1087 | ||
1063 | /* Notify waiting tasks that events are available */ | 1088 | /* Notify waiting tasks that events are available */ |
@@ -1097,9 +1122,9 @@ static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) | |||
1097 | while (!list_empty(lsthead)) { | 1122 | while (!list_empty(lsthead)) { |
1098 | pwq = list_entry(lsthead->next, struct eppoll_entry, llink); | 1123 | pwq = list_entry(lsthead->next, struct eppoll_entry, llink); |
1099 | 1124 | ||
1100 | EP_LIST_DEL(&pwq->llink); | 1125 | ep_list_del(&pwq->llink); |
1101 | remove_wait_queue(pwq->whead, &pwq->wait); | 1126 | remove_wait_queue(pwq->whead, &pwq->wait); |
1102 | PWQ_MEM_FREE(pwq); | 1127 | kmem_cache_free(pwq_cache, pwq); |
1103 | } | 1128 | } |
1104 | } | 1129 | } |
1105 | } | 1130 | } |
@@ -1118,7 +1143,7 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *epi) | |||
1118 | * The check protect us from doing a double unlink ( crash ). | 1143 | * The check protect us from doing a double unlink ( crash ). |
1119 | */ | 1144 | */ |
1120 | error = -ENOENT; | 1145 | error = -ENOENT; |
1121 | if (!EP_RB_LINKED(&epi->rbn)) | 1146 | if (!ep_rb_linked(&epi->rbn)) |
1122 | goto eexit_1; | 1147 | goto eexit_1; |
1123 | 1148 | ||
1124 | /* | 1149 | /* |
@@ -1133,14 +1158,14 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *epi) | |||
1133 | * This operation togheter with the above check closes the door to | 1158 | * This operation togheter with the above check closes the door to |
1134 | * double unlinks. | 1159 | * double unlinks. |
1135 | */ | 1160 | */ |
1136 | EP_RB_ERASE(&epi->rbn, &ep->rbr); | 1161 | ep_rb_erase(&epi->rbn, &ep->rbr); |
1137 | 1162 | ||
1138 | /* | 1163 | /* |
1139 | * If the item we are going to remove is inside the ready file descriptors | 1164 | * If the item we are going to remove is inside the ready file descriptors |
1140 | * we want to remove it from this list to avoid stale events. | 1165 | * we want to remove it from this list to avoid stale events. |
1141 | */ | 1166 | */ |
1142 | if (EP_IS_LINKED(&epi->rdllink)) | 1167 | if (ep_is_linked(&epi->rdllink)) |
1143 | EP_LIST_DEL(&epi->rdllink); | 1168 | ep_list_del(&epi->rdllink); |
1144 | 1169 | ||
1145 | error = 0; | 1170 | error = 0; |
1146 | eexit_1: | 1171 | eexit_1: |
@@ -1174,8 +1199,8 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) | |||
1174 | 1199 | ||
1175 | /* Remove the current item from the list of epoll hooks */ | 1200 | /* Remove the current item from the list of epoll hooks */ |
1176 | spin_lock(&file->f_ep_lock); | 1201 | spin_lock(&file->f_ep_lock); |
1177 | if (EP_IS_LINKED(&epi->fllink)) | 1202 | if (ep_is_linked(&epi->fllink)) |
1178 | EP_LIST_DEL(&epi->fllink); | 1203 | ep_list_del(&epi->fllink); |
1179 | spin_unlock(&file->f_ep_lock); | 1204 | spin_unlock(&file->f_ep_lock); |
1180 | 1205 | ||
1181 | /* We need to acquire the write IRQ lock before calling ep_unlink() */ | 1206 | /* We need to acquire the write IRQ lock before calling ep_unlink() */ |
@@ -1210,7 +1235,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k | |||
1210 | { | 1235 | { |
1211 | int pwake = 0; | 1236 | int pwake = 0; |
1212 | unsigned long flags; | 1237 | unsigned long flags; |
1213 | struct epitem *epi = EP_ITEM_FROM_WAIT(wait); | 1238 | struct epitem *epi = ep_item_from_wait(wait); |
1214 | struct eventpoll *ep = epi->ep; | 1239 | struct eventpoll *ep = epi->ep; |
1215 | 1240 | ||
1216 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n", | 1241 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n", |
@@ -1228,7 +1253,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k | |||
1228 | goto is_disabled; | 1253 | goto is_disabled; |
1229 | 1254 | ||
1230 | /* If this file is already in the ready list we exit soon */ | 1255 | /* If this file is already in the ready list we exit soon */ |
1231 | if (EP_IS_LINKED(&epi->rdllink)) | 1256 | if (ep_is_linked(&epi->rdllink)) |
1232 | goto is_linked; | 1257 | goto is_linked; |
1233 | 1258 | ||
1234 | list_add_tail(&epi->rdllink, &ep->rdllist); | 1259 | list_add_tail(&epi->rdllink, &ep->rdllist); |
@@ -1307,7 +1332,7 @@ static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist | |||
1307 | lnk = lnk->next; | 1332 | lnk = lnk->next; |
1308 | 1333 | ||
1309 | /* If this file is already in the ready list we exit soon */ | 1334 | /* If this file is already in the ready list we exit soon */ |
1310 | if (!EP_IS_LINKED(&epi->txlink)) { | 1335 | if (!ep_is_linked(&epi->txlink)) { |
1311 | /* | 1336 | /* |
1312 | * This is initialized in this way so that the default | 1337 | * This is initialized in this way so that the default |
1313 | * behaviour of the reinjecting code will be to push back | 1338 | * behaviour of the reinjecting code will be to push back |
@@ -1322,7 +1347,7 @@ static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist | |||
1322 | /* | 1347 | /* |
1323 | * Unlink the item from the ready list. | 1348 | * Unlink the item from the ready list. |
1324 | */ | 1349 | */ |
1325 | EP_LIST_DEL(&epi->rdllink); | 1350 | ep_list_del(&epi->rdllink); |
1326 | } | 1351 | } |
1327 | } | 1352 | } |
1328 | 1353 | ||
@@ -1401,7 +1426,7 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist) | |||
1401 | epi = list_entry(txlist->next, struct epitem, txlink); | 1426 | epi = list_entry(txlist->next, struct epitem, txlink); |
1402 | 1427 | ||
1403 | /* Unlink the current item from the transfer list */ | 1428 | /* Unlink the current item from the transfer list */ |
1404 | EP_LIST_DEL(&epi->txlink); | 1429 | ep_list_del(&epi->txlink); |
1405 | 1430 | ||
1406 | /* | 1431 | /* |
1407 | * If the item is no more linked to the interest set, we don't | 1432 | * If the item is no more linked to the interest set, we don't |
@@ -1410,8 +1435,8 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist) | |||
1410 | * item is set to have an Edge Triggered behaviour, we don't have | 1435 | * item is set to have an Edge Triggered behaviour, we don't have |
1411 | * to push it back either. | 1436 | * to push it back either. |
1412 | */ | 1437 | */ |
1413 | if (EP_RB_LINKED(&epi->rbn) && !(epi->event.events & EPOLLET) && | 1438 | if (ep_rb_linked(&epi->rbn) && !(epi->event.events & EPOLLET) && |
1414 | (epi->revents & epi->event.events) && !EP_IS_LINKED(&epi->rdllink)) { | 1439 | (epi->revents & epi->event.events) && !ep_is_linked(&epi->rdllink)) { |
1415 | list_add_tail(&epi->rdllink, &ep->rdllist); | 1440 | list_add_tail(&epi->rdllink, &ep->rdllist); |
1416 | ricnt++; | 1441 | ricnt++; |
1417 | } | 1442 | } |
@@ -58,6 +58,9 @@ | |||
58 | 58 | ||
59 | int core_uses_pid; | 59 | int core_uses_pid; |
60 | char core_pattern[65] = "core"; | 60 | char core_pattern[65] = "core"; |
61 | int suid_dumpable = 0; | ||
62 | |||
63 | EXPORT_SYMBOL(suid_dumpable); | ||
61 | /* The maximal length of core_pattern is also specified in sysctl.c */ | 64 | /* The maximal length of core_pattern is also specified in sysctl.c */ |
62 | 65 | ||
63 | static struct linux_binfmt *formats; | 66 | static struct linux_binfmt *formats; |
@@ -649,6 +652,7 @@ static inline int de_thread(struct task_struct *tsk) | |||
649 | } | 652 | } |
650 | sig->group_exit_task = NULL; | 653 | sig->group_exit_task = NULL; |
651 | sig->notify_count = 0; | 654 | sig->notify_count = 0; |
655 | sig->real_timer.data = (unsigned long)current; | ||
652 | spin_unlock_irq(lock); | 656 | spin_unlock_irq(lock); |
653 | 657 | ||
654 | /* | 658 | /* |
@@ -675,10 +679,8 @@ static inline int de_thread(struct task_struct *tsk) | |||
675 | proc_dentry2 = proc_pid_unhash(leader); | 679 | proc_dentry2 = proc_pid_unhash(leader); |
676 | write_lock_irq(&tasklist_lock); | 680 | write_lock_irq(&tasklist_lock); |
677 | 681 | ||
678 | if (leader->tgid != current->tgid) | 682 | BUG_ON(leader->tgid != current->tgid); |
679 | BUG(); | 683 | BUG_ON(current->pid == current->tgid); |
680 | if (current->pid == current->tgid) | ||
681 | BUG(); | ||
682 | /* | 684 | /* |
683 | * An exec() starts a new thread group with the | 685 | * An exec() starts a new thread group with the |
684 | * TGID of the previous thread group. Rehash the | 686 | * TGID of the previous thread group. Rehash the |
@@ -726,8 +728,7 @@ static inline int de_thread(struct task_struct *tsk) | |||
726 | proc_pid_flush(proc_dentry1); | 728 | proc_pid_flush(proc_dentry1); |
727 | proc_pid_flush(proc_dentry2); | 729 | proc_pid_flush(proc_dentry2); |
728 | 730 | ||
729 | if (exit_state != EXIT_ZOMBIE) | 731 | BUG_ON(exit_state != EXIT_ZOMBIE); |
730 | BUG(); | ||
731 | release_task(leader); | 732 | release_task(leader); |
732 | } | 733 | } |
733 | 734 | ||
@@ -772,10 +773,8 @@ no_thread_group: | |||
772 | kmem_cache_free(sighand_cachep, oldsighand); | 773 | kmem_cache_free(sighand_cachep, oldsighand); |
773 | } | 774 | } |
774 | 775 | ||
775 | if (!thread_group_empty(current)) | 776 | BUG_ON(!thread_group_empty(current)); |
776 | BUG(); | 777 | BUG_ON(!thread_group_leader(current)); |
777 | if (!thread_group_leader(current)) | ||
778 | BUG(); | ||
779 | return 0; | 778 | return 0; |
780 | } | 779 | } |
781 | 780 | ||
@@ -868,6 +867,9 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
868 | 867 | ||
869 | if (current->euid == current->uid && current->egid == current->gid) | 868 | if (current->euid == current->uid && current->egid == current->gid) |
870 | current->mm->dumpable = 1; | 869 | current->mm->dumpable = 1; |
870 | else | ||
871 | current->mm->dumpable = suid_dumpable; | ||
872 | |||
871 | name = bprm->filename; | 873 | name = bprm->filename; |
872 | 874 | ||
873 | /* Copies the binary name from after last slash */ | 875 | /* Copies the binary name from after last slash */ |
@@ -888,7 +890,7 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
888 | permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) || | 890 | permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) || |
889 | (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { | 891 | (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { |
890 | suid_keys(current); | 892 | suid_keys(current); |
891 | current->mm->dumpable = 0; | 893 | current->mm->dumpable = suid_dumpable; |
892 | } | 894 | } |
893 | 895 | ||
894 | /* An exec changes our domain. We are no longer part of the thread | 896 | /* An exec changes our domain. We are no longer part of the thread |
@@ -1436,6 +1438,8 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1436 | struct inode * inode; | 1438 | struct inode * inode; |
1437 | struct file * file; | 1439 | struct file * file; |
1438 | int retval = 0; | 1440 | int retval = 0; |
1441 | int fsuid = current->fsuid; | ||
1442 | int flag = 0; | ||
1439 | 1443 | ||
1440 | binfmt = current->binfmt; | 1444 | binfmt = current->binfmt; |
1441 | if (!binfmt || !binfmt->core_dump) | 1445 | if (!binfmt || !binfmt->core_dump) |
@@ -1445,6 +1449,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1445 | up_write(&mm->mmap_sem); | 1449 | up_write(&mm->mmap_sem); |
1446 | goto fail; | 1450 | goto fail; |
1447 | } | 1451 | } |
1452 | |||
1453 | /* | ||
1454 | * We cannot trust fsuid as being the "true" uid of the | ||
1455 | * process nor do we know its entire history. We only know it | ||
1456 | * was tainted so we dump it as root in mode 2. | ||
1457 | */ | ||
1458 | if (mm->dumpable == 2) { /* Setuid core dump mode */ | ||
1459 | flag = O_EXCL; /* Stop rewrite attacks */ | ||
1460 | current->fsuid = 0; /* Dump root private */ | ||
1461 | } | ||
1448 | mm->dumpable = 0; | 1462 | mm->dumpable = 0; |
1449 | init_completion(&mm->core_done); | 1463 | init_completion(&mm->core_done); |
1450 | spin_lock_irq(¤t->sighand->siglock); | 1464 | spin_lock_irq(¤t->sighand->siglock); |
@@ -1470,7 +1484,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1470 | lock_kernel(); | 1484 | lock_kernel(); |
1471 | format_corename(corename, core_pattern, signr); | 1485 | format_corename(corename, core_pattern, signr); |
1472 | unlock_kernel(); | 1486 | unlock_kernel(); |
1473 | file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE, 0600); | 1487 | file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600); |
1474 | if (IS_ERR(file)) | 1488 | if (IS_ERR(file)) |
1475 | goto fail_unlock; | 1489 | goto fail_unlock; |
1476 | inode = file->f_dentry->d_inode; | 1490 | inode = file->f_dentry->d_inode; |
@@ -1495,6 +1509,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
1495 | close_fail: | 1509 | close_fail: |
1496 | filp_close(file, NULL); | 1510 | filp_close(file, NULL); |
1497 | fail_unlock: | 1511 | fail_unlock: |
1512 | current->fsuid = fsuid; | ||
1498 | complete_all(&mm->core_done); | 1513 | complete_all(&mm->core_done); |
1499 | fail: | 1514 | fail: |
1500 | return retval; | 1515 | return retval; |
diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile index ee240a14e70f..c5d02da73bc3 100644 --- a/fs/ext2/Makefile +++ b/fs/ext2/Makefile | |||
@@ -10,3 +10,4 @@ ext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ | |||
10 | ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o | 10 | ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o |
11 | ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o | 11 | ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o |
12 | ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o | 12 | ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o |
13 | ext2-$(CONFIG_EXT2_FS_XIP) += xip.o | ||
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 25f4a64fd6bc..213148c36ebe 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c | |||
@@ -396,12 +396,12 @@ static size_t | |||
396 | ext2_xattr_list_acl_access(struct inode *inode, char *list, size_t list_size, | 396 | ext2_xattr_list_acl_access(struct inode *inode, char *list, size_t list_size, |
397 | const char *name, size_t name_len) | 397 | const char *name, size_t name_len) |
398 | { | 398 | { |
399 | const size_t size = sizeof(XATTR_NAME_ACL_ACCESS); | 399 | const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); |
400 | 400 | ||
401 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 401 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
402 | return 0; | 402 | return 0; |
403 | if (list && size <= list_size) | 403 | if (list && size <= list_size) |
404 | memcpy(list, XATTR_NAME_ACL_ACCESS, size); | 404 | memcpy(list, POSIX_ACL_XATTR_ACCESS, size); |
405 | return size; | 405 | return size; |
406 | } | 406 | } |
407 | 407 | ||
@@ -409,12 +409,12 @@ static size_t | |||
409 | ext2_xattr_list_acl_default(struct inode *inode, char *list, size_t list_size, | 409 | ext2_xattr_list_acl_default(struct inode *inode, char *list, size_t list_size, |
410 | const char *name, size_t name_len) | 410 | const char *name, size_t name_len) |
411 | { | 411 | { |
412 | const size_t size = sizeof(XATTR_NAME_ACL_DEFAULT); | 412 | const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); |
413 | 413 | ||
414 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 414 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
415 | return 0; | 415 | return 0; |
416 | if (list && size <= list_size) | 416 | if (list && size <= list_size) |
417 | memcpy(list, XATTR_NAME_ACL_DEFAULT, size); | 417 | memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); |
418 | return size; | 418 | return size; |
419 | } | 419 | } |
420 | 420 | ||
@@ -506,14 +506,14 @@ ext2_xattr_set_acl_default(struct inode *inode, const char *name, | |||
506 | } | 506 | } |
507 | 507 | ||
508 | struct xattr_handler ext2_xattr_acl_access_handler = { | 508 | struct xattr_handler ext2_xattr_acl_access_handler = { |
509 | .prefix = XATTR_NAME_ACL_ACCESS, | 509 | .prefix = POSIX_ACL_XATTR_ACCESS, |
510 | .list = ext2_xattr_list_acl_access, | 510 | .list = ext2_xattr_list_acl_access, |
511 | .get = ext2_xattr_get_acl_access, | 511 | .get = ext2_xattr_get_acl_access, |
512 | .set = ext2_xattr_set_acl_access, | 512 | .set = ext2_xattr_set_acl_access, |
513 | }; | 513 | }; |
514 | 514 | ||
515 | struct xattr_handler ext2_xattr_acl_default_handler = { | 515 | struct xattr_handler ext2_xattr_acl_default_handler = { |
516 | .prefix = XATTR_NAME_ACL_DEFAULT, | 516 | .prefix = POSIX_ACL_XATTR_DEFAULT, |
517 | .list = ext2_xattr_list_acl_default, | 517 | .list = ext2_xattr_list_acl_default, |
518 | .get = ext2_xattr_get_acl_default, | 518 | .get = ext2_xattr_get_acl_default, |
519 | .set = ext2_xattr_set_acl_default, | 519 | .set = ext2_xattr_set_acl_default, |
diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h index fed96ae81a7d..0bde85bafe38 100644 --- a/fs/ext2/acl.h +++ b/fs/ext2/acl.h | |||
@@ -4,7 +4,7 @@ | |||
4 | (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org> | 4 | (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/xattr_acl.h> | 7 | #include <linux/posix_acl_xattr.h> |
8 | 8 | ||
9 | #define EXT2_ACL_VERSION 0x0001 | 9 | #define EXT2_ACL_VERSION 0x0001 |
10 | 10 | ||
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 8f0fd726c3f1..eed521d22cf0 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -147,9 +147,11 @@ extern struct file_operations ext2_dir_operations; | |||
147 | /* file.c */ | 147 | /* file.c */ |
148 | extern struct inode_operations ext2_file_inode_operations; | 148 | extern struct inode_operations ext2_file_inode_operations; |
149 | extern struct file_operations ext2_file_operations; | 149 | extern struct file_operations ext2_file_operations; |
150 | extern struct file_operations ext2_xip_file_operations; | ||
150 | 151 | ||
151 | /* inode.c */ | 152 | /* inode.c */ |
152 | extern struct address_space_operations ext2_aops; | 153 | extern struct address_space_operations ext2_aops; |
154 | extern struct address_space_operations ext2_aops_xip; | ||
153 | extern struct address_space_operations ext2_nobh_aops; | 155 | extern struct address_space_operations ext2_nobh_aops; |
154 | 156 | ||
155 | /* namei.c */ | 157 | /* namei.c */ |
diff --git a/fs/ext2/file.c b/fs/ext2/file.c index f5e86141ec54..a484412fc782 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c | |||
@@ -55,6 +55,20 @@ struct file_operations ext2_file_operations = { | |||
55 | .sendfile = generic_file_sendfile, | 55 | .sendfile = generic_file_sendfile, |
56 | }; | 56 | }; |
57 | 57 | ||
58 | #ifdef CONFIG_EXT2_FS_XIP | ||
59 | struct file_operations ext2_xip_file_operations = { | ||
60 | .llseek = generic_file_llseek, | ||
61 | .read = xip_file_read, | ||
62 | .write = xip_file_write, | ||
63 | .ioctl = ext2_ioctl, | ||
64 | .mmap = xip_file_mmap, | ||
65 | .open = generic_file_open, | ||
66 | .release = ext2_release_file, | ||
67 | .fsync = ext2_sync_file, | ||
68 | .sendfile = xip_file_sendfile, | ||
69 | }; | ||
70 | #endif | ||
71 | |||
58 | struct inode_operations ext2_file_inode_operations = { | 72 | struct inode_operations ext2_file_inode_operations = { |
59 | .truncate = ext2_truncate, | 73 | .truncate = ext2_truncate, |
60 | #ifdef CONFIG_EXT2_FS_XATTR | 74 | #ifdef CONFIG_EXT2_FS_XATTR |
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index a50d9db4b6e4..53dceb0c6593 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/mpage.h> | 33 | #include <linux/mpage.h> |
34 | #include "ext2.h" | 34 | #include "ext2.h" |
35 | #include "acl.h" | 35 | #include "acl.h" |
36 | #include "xip.h" | ||
36 | 37 | ||
37 | MODULE_AUTHOR("Remy Card and others"); | 38 | MODULE_AUTHOR("Remy Card and others"); |
38 | MODULE_DESCRIPTION("Second Extended Filesystem"); | 39 | MODULE_DESCRIPTION("Second Extended Filesystem"); |
@@ -594,6 +595,16 @@ out: | |||
594 | if (err) | 595 | if (err) |
595 | goto cleanup; | 596 | goto cleanup; |
596 | 597 | ||
598 | if (ext2_use_xip(inode->i_sb)) { | ||
599 | /* | ||
600 | * we need to clear the block | ||
601 | */ | ||
602 | err = ext2_clear_xip_target (inode, | ||
603 | le32_to_cpu(chain[depth-1].key)); | ||
604 | if (err) | ||
605 | goto cleanup; | ||
606 | } | ||
607 | |||
597 | if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0) | 608 | if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0) |
598 | goto changed; | 609 | goto changed; |
599 | 610 | ||
@@ -691,6 +702,11 @@ struct address_space_operations ext2_aops = { | |||
691 | .writepages = ext2_writepages, | 702 | .writepages = ext2_writepages, |
692 | }; | 703 | }; |
693 | 704 | ||
705 | struct address_space_operations ext2_aops_xip = { | ||
706 | .bmap = ext2_bmap, | ||
707 | .get_xip_page = ext2_get_xip_page, | ||
708 | }; | ||
709 | |||
694 | struct address_space_operations ext2_nobh_aops = { | 710 | struct address_space_operations ext2_nobh_aops = { |
695 | .readpage = ext2_readpage, | 711 | .readpage = ext2_readpage, |
696 | .readpages = ext2_readpages, | 712 | .readpages = ext2_readpages, |
@@ -910,7 +926,9 @@ void ext2_truncate (struct inode * inode) | |||
910 | iblock = (inode->i_size + blocksize-1) | 926 | iblock = (inode->i_size + blocksize-1) |
911 | >> EXT2_BLOCK_SIZE_BITS(inode->i_sb); | 927 | >> EXT2_BLOCK_SIZE_BITS(inode->i_sb); |
912 | 928 | ||
913 | if (test_opt(inode->i_sb, NOBH)) | 929 | if (mapping_is_xip(inode->i_mapping)) |
930 | xip_truncate_page(inode->i_mapping, inode->i_size); | ||
931 | else if (test_opt(inode->i_sb, NOBH)) | ||
914 | nobh_truncate_page(inode->i_mapping, inode->i_size); | 932 | nobh_truncate_page(inode->i_mapping, inode->i_size); |
915 | else | 933 | else |
916 | block_truncate_page(inode->i_mapping, | 934 | block_truncate_page(inode->i_mapping, |
@@ -1110,11 +1128,16 @@ void ext2_read_inode (struct inode * inode) | |||
1110 | 1128 | ||
1111 | if (S_ISREG(inode->i_mode)) { | 1129 | if (S_ISREG(inode->i_mode)) { |
1112 | inode->i_op = &ext2_file_inode_operations; | 1130 | inode->i_op = &ext2_file_inode_operations; |
1113 | inode->i_fop = &ext2_file_operations; | 1131 | if (ext2_use_xip(inode->i_sb)) { |
1114 | if (test_opt(inode->i_sb, NOBH)) | 1132 | inode->i_mapping->a_ops = &ext2_aops_xip; |
1133 | inode->i_fop = &ext2_xip_file_operations; | ||
1134 | } else if (test_opt(inode->i_sb, NOBH)) { | ||
1115 | inode->i_mapping->a_ops = &ext2_nobh_aops; | 1135 | inode->i_mapping->a_ops = &ext2_nobh_aops; |
1116 | else | 1136 | inode->i_fop = &ext2_file_operations; |
1137 | } else { | ||
1117 | inode->i_mapping->a_ops = &ext2_aops; | 1138 | inode->i_mapping->a_ops = &ext2_aops; |
1139 | inode->i_fop = &ext2_file_operations; | ||
1140 | } | ||
1118 | } else if (S_ISDIR(inode->i_mode)) { | 1141 | } else if (S_ISDIR(inode->i_mode)) { |
1119 | inode->i_op = &ext2_dir_inode_operations; | 1142 | inode->i_op = &ext2_dir_inode_operations; |
1120 | inode->i_fop = &ext2_dir_operations; | 1143 | inode->i_fop = &ext2_dir_operations; |
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 3176b3d3ffa8..c5513953c825 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "ext2.h" | 34 | #include "ext2.h" |
35 | #include "xattr.h" | 35 | #include "xattr.h" |
36 | #include "acl.h" | 36 | #include "acl.h" |
37 | #include "xip.h" | ||
37 | 38 | ||
38 | /* | 39 | /* |
39 | * Couple of helper functions - make the code slightly cleaner. | 40 | * Couple of helper functions - make the code slightly cleaner. |
@@ -127,11 +128,16 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, st | |||
127 | int err = PTR_ERR(inode); | 128 | int err = PTR_ERR(inode); |
128 | if (!IS_ERR(inode)) { | 129 | if (!IS_ERR(inode)) { |
129 | inode->i_op = &ext2_file_inode_operations; | 130 | inode->i_op = &ext2_file_inode_operations; |
130 | inode->i_fop = &ext2_file_operations; | 131 | if (ext2_use_xip(inode->i_sb)) { |
131 | if (test_opt(inode->i_sb, NOBH)) | 132 | inode->i_mapping->a_ops = &ext2_aops_xip; |
133 | inode->i_fop = &ext2_xip_file_operations; | ||
134 | } else if (test_opt(inode->i_sb, NOBH)) { | ||
132 | inode->i_mapping->a_ops = &ext2_nobh_aops; | 135 | inode->i_mapping->a_ops = &ext2_nobh_aops; |
133 | else | 136 | inode->i_fop = &ext2_file_operations; |
137 | } else { | ||
134 | inode->i_mapping->a_ops = &ext2_aops; | 138 | inode->i_mapping->a_ops = &ext2_aops; |
139 | inode->i_fop = &ext2_file_operations; | ||
140 | } | ||
135 | mark_inode_dirty(inode); | 141 | mark_inode_dirty(inode); |
136 | err = ext2_add_nondir(dentry, inode); | 142 | err = ext2_add_nondir(dentry, inode); |
137 | } | 143 | } |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 661c3d98d946..876e391f2871 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "ext2.h" | 31 | #include "ext2.h" |
32 | #include "xattr.h" | 32 | #include "xattr.h" |
33 | #include "acl.h" | 33 | #include "acl.h" |
34 | #include "xip.h" | ||
34 | 35 | ||
35 | static void ext2_sync_super(struct super_block *sb, | 36 | static void ext2_sync_super(struct super_block *sb, |
36 | struct ext2_super_block *es); | 37 | struct ext2_super_block *es); |
@@ -257,7 +258,7 @@ enum { | |||
257 | Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, | 258 | Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, |
258 | Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, | 259 | Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, |
259 | Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, | 260 | Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, |
260 | Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, | 261 | Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip, |
261 | Opt_ignore, Opt_err, | 262 | Opt_ignore, Opt_err, |
262 | }; | 263 | }; |
263 | 264 | ||
@@ -286,6 +287,7 @@ static match_table_t tokens = { | |||
286 | {Opt_nouser_xattr, "nouser_xattr"}, | 287 | {Opt_nouser_xattr, "nouser_xattr"}, |
287 | {Opt_acl, "acl"}, | 288 | {Opt_acl, "acl"}, |
288 | {Opt_noacl, "noacl"}, | 289 | {Opt_noacl, "noacl"}, |
290 | {Opt_xip, "xip"}, | ||
289 | {Opt_ignore, "grpquota"}, | 291 | {Opt_ignore, "grpquota"}, |
290 | {Opt_ignore, "noquota"}, | 292 | {Opt_ignore, "noquota"}, |
291 | {Opt_ignore, "quota"}, | 293 | {Opt_ignore, "quota"}, |
@@ -397,6 +399,13 @@ static int parse_options (char * options, | |||
397 | printk("EXT2 (no)acl options not supported\n"); | 399 | printk("EXT2 (no)acl options not supported\n"); |
398 | break; | 400 | break; |
399 | #endif | 401 | #endif |
402 | case Opt_xip: | ||
403 | #ifdef CONFIG_EXT2_FS_XIP | ||
404 | set_opt (sbi->s_mount_opt, XIP); | ||
405 | #else | ||
406 | printk("EXT2 xip option not supported\n"); | ||
407 | #endif | ||
408 | break; | ||
400 | case Opt_ignore: | 409 | case Opt_ignore: |
401 | break; | 410 | break; |
402 | default: | 411 | default: |
@@ -640,6 +649,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) | |||
640 | ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? | 649 | ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? |
641 | MS_POSIXACL : 0); | 650 | MS_POSIXACL : 0); |
642 | 651 | ||
652 | ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset | ||
653 | EXT2_MOUNT_XIP if not */ | ||
654 | |||
643 | if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && | 655 | if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && |
644 | (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || | 656 | (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || |
645 | EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) || | 657 | EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) || |
@@ -668,6 +680,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) | |||
668 | 680 | ||
669 | blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); | 681 | blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); |
670 | 682 | ||
683 | if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) || | ||
684 | (sb->s_blocksize != blocksize))) { | ||
685 | if (!silent) | ||
686 | printk("XIP: Unsupported blocksize\n"); | ||
687 | goto failed_mount; | ||
688 | } | ||
689 | |||
671 | /* If the blocksize doesn't match, re-read the thing.. */ | 690 | /* If the blocksize doesn't match, re-read the thing.. */ |
672 | if (sb->s_blocksize != blocksize) { | 691 | if (sb->s_blocksize != blocksize) { |
673 | brelse(bh); | 692 | brelse(bh); |
@@ -916,6 +935,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
916 | { | 935 | { |
917 | struct ext2_sb_info * sbi = EXT2_SB(sb); | 936 | struct ext2_sb_info * sbi = EXT2_SB(sb); |
918 | struct ext2_super_block * es; | 937 | struct ext2_super_block * es; |
938 | unsigned long old_mount_opt = sbi->s_mount_opt; | ||
919 | 939 | ||
920 | /* | 940 | /* |
921 | * Allow the "check" option to be passed as a remount option. | 941 | * Allow the "check" option to be passed as a remount option. |
@@ -927,6 +947,11 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
927 | ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); | 947 | ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); |
928 | 948 | ||
929 | es = sbi->s_es; | 949 | es = sbi->s_es; |
950 | if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) != | ||
951 | (old_mount_opt & EXT2_MOUNT_XIP)) && | ||
952 | invalidate_inodes(sb)) | ||
953 | ext2_warning(sb, __FUNCTION__, "busy inodes while remounting "\ | ||
954 | "xip remain in cache (no functional problem)"); | ||
930 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) | 955 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) |
931 | return 0; | 956 | return 0; |
932 | if (*flags & MS_RDONLY) { | 957 | if (*flags & MS_RDONLY) { |
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c new file mode 100644 index 000000000000..d44431d1a338 --- /dev/null +++ b/fs/ext2/xip.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * linux/fs/ext2/xip.c | ||
3 | * | ||
4 | * Copyright (C) 2005 IBM Corporation | ||
5 | * Author: Carsten Otte (cotte@de.ibm.com) | ||
6 | */ | ||
7 | |||
8 | #include <linux/mm.h> | ||
9 | #include <linux/fs.h> | ||
10 | #include <linux/genhd.h> | ||
11 | #include <linux/buffer_head.h> | ||
12 | #include <linux/ext2_fs_sb.h> | ||
13 | #include <linux/ext2_fs.h> | ||
14 | #include "ext2.h" | ||
15 | #include "xip.h" | ||
16 | |||
17 | static inline int | ||
18 | __inode_direct_access(struct inode *inode, sector_t sector, unsigned long *data) { | ||
19 | BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access); | ||
20 | return inode->i_sb->s_bdev->bd_disk->fops | ||
21 | ->direct_access(inode->i_sb->s_bdev,sector,data); | ||
22 | } | ||
23 | |||
24 | int | ||
25 | ext2_clear_xip_target(struct inode *inode, int block) { | ||
26 | sector_t sector = block*(PAGE_SIZE/512); | ||
27 | unsigned long data; | ||
28 | int rc; | ||
29 | |||
30 | rc = __inode_direct_access(inode, sector, &data); | ||
31 | if (rc) | ||
32 | return rc; | ||
33 | clear_page((void*)data); | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | void ext2_xip_verify_sb(struct super_block *sb) | ||
38 | { | ||
39 | struct ext2_sb_info *sbi = EXT2_SB(sb); | ||
40 | |||
41 | if ((sbi->s_mount_opt & EXT2_MOUNT_XIP)) { | ||
42 | if ((sb->s_bdev == NULL) || | ||
43 | sb->s_bdev->bd_disk == NULL || | ||
44 | sb->s_bdev->bd_disk->fops == NULL || | ||
45 | sb->s_bdev->bd_disk->fops->direct_access == NULL) { | ||
46 | sbi->s_mount_opt &= (~EXT2_MOUNT_XIP); | ||
47 | ext2_warning(sb, __FUNCTION__, | ||
48 | "ignoring xip option - not supported by bdev"); | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | |||
53 | struct page* | ||
54 | ext2_get_xip_page(struct address_space *mapping, sector_t blockno, | ||
55 | int create) | ||
56 | { | ||
57 | int rc; | ||
58 | unsigned long data; | ||
59 | struct buffer_head tmp; | ||
60 | |||
61 | tmp.b_state = 0; | ||
62 | tmp.b_blocknr = 0; | ||
63 | rc = ext2_get_block(mapping->host, blockno/(PAGE_SIZE/512) , &tmp, | ||
64 | create); | ||
65 | if (rc) | ||
66 | return ERR_PTR(rc); | ||
67 | if (tmp.b_blocknr == 0) { | ||
68 | /* SPARSE block */ | ||
69 | BUG_ON(create); | ||
70 | return ERR_PTR(-ENODATA); | ||
71 | } | ||
72 | |||
73 | rc = __inode_direct_access | ||
74 | (mapping->host,tmp.b_blocknr*(PAGE_SIZE/512) ,&data); | ||
75 | if (rc) | ||
76 | return ERR_PTR(rc); | ||
77 | |||
78 | SetPageUptodate(virt_to_page(data)); | ||
79 | return virt_to_page(data); | ||
80 | } | ||
diff --git a/fs/ext2/xip.h b/fs/ext2/xip.h new file mode 100644 index 000000000000..aa85331d6c56 --- /dev/null +++ b/fs/ext2/xip.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * linux/fs/ext2/xip.h | ||
3 | * | ||
4 | * Copyright (C) 2005 IBM Corporation | ||
5 | * Author: Carsten Otte (cotte@de.ibm.com) | ||
6 | */ | ||
7 | |||
8 | #ifdef CONFIG_EXT2_FS_XIP | ||
9 | extern void ext2_xip_verify_sb (struct super_block *); | ||
10 | extern int ext2_clear_xip_target (struct inode *, int); | ||
11 | |||
12 | static inline int ext2_use_xip (struct super_block *sb) | ||
13 | { | ||
14 | struct ext2_sb_info *sbi = EXT2_SB(sb); | ||
15 | return (sbi->s_mount_opt & EXT2_MOUNT_XIP); | ||
16 | } | ||
17 | struct page* ext2_get_xip_page (struct address_space *, sector_t, int); | ||
18 | #define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page) | ||
19 | #else | ||
20 | #define mapping_is_xip(map) 0 | ||
21 | #define ext2_xip_verify_sb(sb) do { } while (0) | ||
22 | #define ext2_use_xip(sb) 0 | ||
23 | #define ext2_clear_xip_target(inode, chain) 0 | ||
24 | #define ext2_get_xip_page NULL | ||
25 | #endif | ||
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 638c13a26c03..3ac38266fc9e 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c | |||
@@ -393,7 +393,8 @@ ext3_acl_chmod(struct inode *inode) | |||
393 | int retries = 0; | 393 | int retries = 0; |
394 | 394 | ||
395 | retry: | 395 | retry: |
396 | handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); | 396 | handle = ext3_journal_start(inode, |
397 | EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); | ||
397 | if (IS_ERR(handle)) { | 398 | if (IS_ERR(handle)) { |
398 | error = PTR_ERR(handle); | 399 | error = PTR_ERR(handle); |
399 | ext3_std_error(inode->i_sb, error); | 400 | ext3_std_error(inode->i_sb, error); |
@@ -417,12 +418,12 @@ static size_t | |||
417 | ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len, | 418 | ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len, |
418 | const char *name, size_t name_len) | 419 | const char *name, size_t name_len) |
419 | { | 420 | { |
420 | const size_t size = sizeof(XATTR_NAME_ACL_ACCESS); | 421 | const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); |
421 | 422 | ||
422 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 423 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
423 | return 0; | 424 | return 0; |
424 | if (list && size <= list_len) | 425 | if (list && size <= list_len) |
425 | memcpy(list, XATTR_NAME_ACL_ACCESS, size); | 426 | memcpy(list, POSIX_ACL_XATTR_ACCESS, size); |
426 | return size; | 427 | return size; |
427 | } | 428 | } |
428 | 429 | ||
@@ -430,12 +431,12 @@ static size_t | |||
430 | ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len, | 431 | ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len, |
431 | const char *name, size_t name_len) | 432 | const char *name, size_t name_len) |
432 | { | 433 | { |
433 | const size_t size = sizeof(XATTR_NAME_ACL_DEFAULT); | 434 | const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); |
434 | 435 | ||
435 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 436 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
436 | return 0; | 437 | return 0; |
437 | if (list && size <= list_len) | 438 | if (list && size <= list_len) |
438 | memcpy(list, XATTR_NAME_ACL_DEFAULT, size); | 439 | memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); |
439 | return size; | 440 | return size; |
440 | } | 441 | } |
441 | 442 | ||
@@ -503,7 +504,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value, | |||
503 | acl = NULL; | 504 | acl = NULL; |
504 | 505 | ||
505 | retry: | 506 | retry: |
506 | handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); | 507 | handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); |
507 | if (IS_ERR(handle)) | 508 | if (IS_ERR(handle)) |
508 | return PTR_ERR(handle); | 509 | return PTR_ERR(handle); |
509 | error = ext3_set_acl(handle, inode, type, acl); | 510 | error = ext3_set_acl(handle, inode, type, acl); |
@@ -535,14 +536,14 @@ ext3_xattr_set_acl_default(struct inode *inode, const char *name, | |||
535 | } | 536 | } |
536 | 537 | ||
537 | struct xattr_handler ext3_xattr_acl_access_handler = { | 538 | struct xattr_handler ext3_xattr_acl_access_handler = { |
538 | .prefix = XATTR_NAME_ACL_ACCESS, | 539 | .prefix = POSIX_ACL_XATTR_ACCESS, |
539 | .list = ext3_xattr_list_acl_access, | 540 | .list = ext3_xattr_list_acl_access, |
540 | .get = ext3_xattr_get_acl_access, | 541 | .get = ext3_xattr_get_acl_access, |
541 | .set = ext3_xattr_set_acl_access, | 542 | .set = ext3_xattr_set_acl_access, |
542 | }; | 543 | }; |
543 | 544 | ||
544 | struct xattr_handler ext3_xattr_acl_default_handler = { | 545 | struct xattr_handler ext3_xattr_acl_default_handler = { |
545 | .prefix = XATTR_NAME_ACL_DEFAULT, | 546 | .prefix = POSIX_ACL_XATTR_DEFAULT, |
546 | .list = ext3_xattr_list_acl_default, | 547 | .list = ext3_xattr_list_acl_default, |
547 | .get = ext3_xattr_get_acl_default, | 548 | .get = ext3_xattr_get_acl_default, |
548 | .set = ext3_xattr_set_acl_default, | 549 | .set = ext3_xattr_set_acl_default, |
diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h index 98af0c0d0ba9..92d50b53a933 100644 --- a/fs/ext3/acl.h +++ b/fs/ext3/acl.h | |||
@@ -4,7 +4,7 @@ | |||
4 | (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org> | 4 | (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/xattr_acl.h> | 7 | #include <linux/posix_acl_xattr.h> |
8 | 8 | ||
9 | #define EXT3_ACL_VERSION 0x0001 | 9 | #define EXT3_ACL_VERSION 0x0001 |
10 | 10 | ||
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 0d5fa73b18dc..0b2db4f618cb 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -128,7 +128,7 @@ static unsigned long blocks_for_truncate(struct inode *inode) | |||
128 | if (needed > EXT3_MAX_TRANS_DATA) | 128 | if (needed > EXT3_MAX_TRANS_DATA) |
129 | needed = EXT3_MAX_TRANS_DATA; | 129 | needed = EXT3_MAX_TRANS_DATA; |
130 | 130 | ||
131 | return EXT3_DATA_TRANS_BLOCKS + needed; | 131 | return EXT3_DATA_TRANS_BLOCKS(inode->i_sb) + needed; |
132 | } | 132 | } |
133 | 133 | ||
134 | /* | 134 | /* |
@@ -2763,7 +2763,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) | |||
2763 | 2763 | ||
2764 | /* (user+group)*(old+new) structure, inode write (sb, | 2764 | /* (user+group)*(old+new) structure, inode write (sb, |
2765 | * inode block, ? - but truncate inode update has it) */ | 2765 | * inode block, ? - but truncate inode update has it) */ |
2766 | handle = ext3_journal_start(inode, 4*EXT3_QUOTA_INIT_BLOCKS+3); | 2766 | handle = ext3_journal_start(inode, 2*(EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)+ |
2767 | EXT3_QUOTA_DEL_BLOCKS(inode->i_sb))+3); | ||
2767 | if (IS_ERR(handle)) { | 2768 | if (IS_ERR(handle)) { |
2768 | error = PTR_ERR(handle); | 2769 | error = PTR_ERR(handle); |
2769 | goto err_out; | 2770 | goto err_out; |
@@ -2861,7 +2862,7 @@ static int ext3_writepage_trans_blocks(struct inode *inode) | |||
2861 | #ifdef CONFIG_QUOTA | 2862 | #ifdef CONFIG_QUOTA |
2862 | /* We know that structure was already allocated during DQUOT_INIT so | 2863 | /* We know that structure was already allocated during DQUOT_INIT so |
2863 | * we will be updating only the data blocks + inodes */ | 2864 | * we will be updating only the data blocks + inodes */ |
2864 | ret += 2*EXT3_QUOTA_TRANS_BLOCKS; | 2865 | ret += 2*EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb); |
2865 | #endif | 2866 | #endif |
2866 | 2867 | ||
2867 | return ret; | 2868 | return ret; |
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 79742d824a0a..50378d8ff84b 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
@@ -932,8 +932,16 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, | |||
932 | struct inode *dir = dentry->d_parent->d_inode; | 932 | struct inode *dir = dentry->d_parent->d_inode; |
933 | 933 | ||
934 | sb = dir->i_sb; | 934 | sb = dir->i_sb; |
935 | if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err))) | 935 | /* NFS may look up ".." - look at dx_root directory block */ |
936 | return NULL; | 936 | if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){ |
937 | if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err))) | ||
938 | return NULL; | ||
939 | } else { | ||
940 | frame = frames; | ||
941 | frame->bh = NULL; /* for dx_release() */ | ||
942 | frame->at = (struct dx_entry *)frames; /* hack for zero entry*/ | ||
943 | dx_set_block(frame->at, 0); /* dx_root block is 0 */ | ||
944 | } | ||
937 | hash = hinfo.hash; | 945 | hash = hinfo.hash; |
938 | do { | 946 | do { |
939 | block = dx_get_block(frame->at); | 947 | block = dx_get_block(frame->at); |
@@ -1637,9 +1645,9 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, | |||
1637 | int err, retries = 0; | 1645 | int err, retries = 0; |
1638 | 1646 | ||
1639 | retry: | 1647 | retry: |
1640 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + | 1648 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
1641 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 1649 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + |
1642 | 2*EXT3_QUOTA_INIT_BLOCKS); | 1650 | 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); |
1643 | if (IS_ERR(handle)) | 1651 | if (IS_ERR(handle)) |
1644 | return PTR_ERR(handle); | 1652 | return PTR_ERR(handle); |
1645 | 1653 | ||
@@ -1671,9 +1679,9 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry, | |||
1671 | return -EINVAL; | 1679 | return -EINVAL; |
1672 | 1680 | ||
1673 | retry: | 1681 | retry: |
1674 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + | 1682 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
1675 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 1683 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + |
1676 | 2*EXT3_QUOTA_INIT_BLOCKS); | 1684 | 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); |
1677 | if (IS_ERR(handle)) | 1685 | if (IS_ERR(handle)) |
1678 | return PTR_ERR(handle); | 1686 | return PTR_ERR(handle); |
1679 | 1687 | ||
@@ -1707,9 +1715,9 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) | |||
1707 | return -EMLINK; | 1715 | return -EMLINK; |
1708 | 1716 | ||
1709 | retry: | 1717 | retry: |
1710 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + | 1718 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
1711 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 1719 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + |
1712 | 2*EXT3_QUOTA_INIT_BLOCKS); | 1720 | 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); |
1713 | if (IS_ERR(handle)) | 1721 | if (IS_ERR(handle)) |
1714 | return PTR_ERR(handle); | 1722 | return PTR_ERR(handle); |
1715 | 1723 | ||
@@ -1998,7 +2006,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) | |||
1998 | /* Initialize quotas before so that eventual writes go in | 2006 | /* Initialize quotas before so that eventual writes go in |
1999 | * separate transaction */ | 2007 | * separate transaction */ |
2000 | DQUOT_INIT(dentry->d_inode); | 2008 | DQUOT_INIT(dentry->d_inode); |
2001 | handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS); | 2009 | handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); |
2002 | if (IS_ERR(handle)) | 2010 | if (IS_ERR(handle)) |
2003 | return PTR_ERR(handle); | 2011 | return PTR_ERR(handle); |
2004 | 2012 | ||
@@ -2057,7 +2065,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) | |||
2057 | /* Initialize quotas before so that eventual writes go | 2065 | /* Initialize quotas before so that eventual writes go |
2058 | * in separate transaction */ | 2066 | * in separate transaction */ |
2059 | DQUOT_INIT(dentry->d_inode); | 2067 | DQUOT_INIT(dentry->d_inode); |
2060 | handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS); | 2068 | handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); |
2061 | if (IS_ERR(handle)) | 2069 | if (IS_ERR(handle)) |
2062 | return PTR_ERR(handle); | 2070 | return PTR_ERR(handle); |
2063 | 2071 | ||
@@ -2112,9 +2120,9 @@ static int ext3_symlink (struct inode * dir, | |||
2112 | return -ENAMETOOLONG; | 2120 | return -ENAMETOOLONG; |
2113 | 2121 | ||
2114 | retry: | 2122 | retry: |
2115 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + | 2123 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
2116 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 + | 2124 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 + |
2117 | 2*EXT3_QUOTA_INIT_BLOCKS); | 2125 | 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); |
2118 | if (IS_ERR(handle)) | 2126 | if (IS_ERR(handle)) |
2119 | return PTR_ERR(handle); | 2127 | return PTR_ERR(handle); |
2120 | 2128 | ||
@@ -2166,7 +2174,7 @@ static int ext3_link (struct dentry * old_dentry, | |||
2166 | return -EMLINK; | 2174 | return -EMLINK; |
2167 | 2175 | ||
2168 | retry: | 2176 | retry: |
2169 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + | 2177 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
2170 | EXT3_INDEX_EXTRA_TRANS_BLOCKS); | 2178 | EXT3_INDEX_EXTRA_TRANS_BLOCKS); |
2171 | if (IS_ERR(handle)) | 2179 | if (IS_ERR(handle)) |
2172 | return PTR_ERR(handle); | 2180 | return PTR_ERR(handle); |
@@ -2208,7 +2216,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2208 | * in separate transaction */ | 2216 | * in separate transaction */ |
2209 | if (new_dentry->d_inode) | 2217 | if (new_dentry->d_inode) |
2210 | DQUOT_INIT(new_dentry->d_inode); | 2218 | DQUOT_INIT(new_dentry->d_inode); |
2211 | handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS + | 2219 | handle = ext3_journal_start(old_dir, 2 * |
2220 | EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) + | ||
2212 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); | 2221 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); |
2213 | if (IS_ERR(handle)) | 2222 | if (IS_ERR(handle)) |
2214 | return PTR_ERR(handle); | 2223 | return PTR_ERR(handle); |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 981ccb233ef5..b4b3e8a39131 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -589,7 +589,7 @@ enum { | |||
589 | Opt_commit, Opt_journal_update, Opt_journal_inum, | 589 | Opt_commit, Opt_journal_update, Opt_journal_inum, |
590 | Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, | 590 | Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, |
591 | Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, | 591 | Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, |
592 | Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, | 592 | Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, |
593 | Opt_ignore, Opt_barrier, Opt_err, Opt_resize, | 593 | Opt_ignore, Opt_barrier, Opt_err, Opt_resize, |
594 | }; | 594 | }; |
595 | 595 | ||
@@ -634,10 +634,10 @@ static match_table_t tokens = { | |||
634 | {Opt_grpjquota, "grpjquota=%s"}, | 634 | {Opt_grpjquota, "grpjquota=%s"}, |
635 | {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, | 635 | {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, |
636 | {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, | 636 | {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, |
637 | {Opt_ignore, "grpquota"}, | 637 | {Opt_quota, "grpquota"}, |
638 | {Opt_ignore, "noquota"}, | 638 | {Opt_noquota, "noquota"}, |
639 | {Opt_ignore, "quota"}, | 639 | {Opt_quota, "quota"}, |
640 | {Opt_ignore, "usrquota"}, | 640 | {Opt_quota, "usrquota"}, |
641 | {Opt_barrier, "barrier=%u"}, | 641 | {Opt_barrier, "barrier=%u"}, |
642 | {Opt_err, NULL}, | 642 | {Opt_err, NULL}, |
643 | {Opt_resize, "resize"}, | 643 | {Opt_resize, "resize"}, |
@@ -876,6 +876,7 @@ set_qf_name: | |||
876 | sbi->s_qf_names[qtype] = NULL; | 876 | sbi->s_qf_names[qtype] = NULL; |
877 | return 0; | 877 | return 0; |
878 | } | 878 | } |
879 | set_opt(sbi->s_mount_opt, QUOTA); | ||
879 | break; | 880 | break; |
880 | case Opt_offusrjquota: | 881 | case Opt_offusrjquota: |
881 | qtype = USRQUOTA; | 882 | qtype = USRQUOTA; |
@@ -898,6 +899,17 @@ clear_qf_name: | |||
898 | case Opt_jqfmt_vfsv0: | 899 | case Opt_jqfmt_vfsv0: |
899 | sbi->s_jquota_fmt = QFMT_VFS_V0; | 900 | sbi->s_jquota_fmt = QFMT_VFS_V0; |
900 | break; | 901 | break; |
902 | case Opt_quota: | ||
903 | set_opt(sbi->s_mount_opt, QUOTA); | ||
904 | break; | ||
905 | case Opt_noquota: | ||
906 | if (sb_any_quota_enabled(sb)) { | ||
907 | printk(KERN_ERR "EXT3-fs: Cannot change quota " | ||
908 | "options when quota turned on.\n"); | ||
909 | return 0; | ||
910 | } | ||
911 | clear_opt(sbi->s_mount_opt, QUOTA); | ||
912 | break; | ||
901 | #else | 913 | #else |
902 | case Opt_usrjquota: | 914 | case Opt_usrjquota: |
903 | case Opt_grpjquota: | 915 | case Opt_grpjquota: |
@@ -909,6 +921,9 @@ clear_qf_name: | |||
909 | "EXT3-fs: journalled quota options not " | 921 | "EXT3-fs: journalled quota options not " |
910 | "supported.\n"); | 922 | "supported.\n"); |
911 | break; | 923 | break; |
924 | case Opt_quota: | ||
925 | case Opt_noquota: | ||
926 | break; | ||
912 | #endif | 927 | #endif |
913 | case Opt_abort: | 928 | case Opt_abort: |
914 | set_opt(sbi->s_mount_opt, ABORT); | 929 | set_opt(sbi->s_mount_opt, ABORT); |
@@ -2238,7 +2253,7 @@ static int ext3_dquot_initialize(struct inode *inode, int type) | |||
2238 | int ret, err; | 2253 | int ret, err; |
2239 | 2254 | ||
2240 | /* We may create quota structure so we need to reserve enough blocks */ | 2255 | /* We may create quota structure so we need to reserve enough blocks */ |
2241 | handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS); | 2256 | handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)); |
2242 | if (IS_ERR(handle)) | 2257 | if (IS_ERR(handle)) |
2243 | return PTR_ERR(handle); | 2258 | return PTR_ERR(handle); |
2244 | ret = dquot_initialize(inode, type); | 2259 | ret = dquot_initialize(inode, type); |
@@ -2254,7 +2269,7 @@ static int ext3_dquot_drop(struct inode *inode) | |||
2254 | int ret, err; | 2269 | int ret, err; |
2255 | 2270 | ||
2256 | /* We may delete quota structure so we need to reserve enough blocks */ | 2271 | /* We may delete quota structure so we need to reserve enough blocks */ |
2257 | handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS); | 2272 | handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb)); |
2258 | if (IS_ERR(handle)) | 2273 | if (IS_ERR(handle)) |
2259 | return PTR_ERR(handle); | 2274 | return PTR_ERR(handle); |
2260 | ret = dquot_drop(inode); | 2275 | ret = dquot_drop(inode); |
@@ -2272,7 +2287,7 @@ static int ext3_write_dquot(struct dquot *dquot) | |||
2272 | 2287 | ||
2273 | inode = dquot_to_inode(dquot); | 2288 | inode = dquot_to_inode(dquot); |
2274 | handle = ext3_journal_start(inode, | 2289 | handle = ext3_journal_start(inode, |
2275 | EXT3_QUOTA_TRANS_BLOCKS); | 2290 | EXT3_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); |
2276 | if (IS_ERR(handle)) | 2291 | if (IS_ERR(handle)) |
2277 | return PTR_ERR(handle); | 2292 | return PTR_ERR(handle); |
2278 | ret = dquot_commit(dquot); | 2293 | ret = dquot_commit(dquot); |
@@ -2288,7 +2303,7 @@ static int ext3_acquire_dquot(struct dquot *dquot) | |||
2288 | handle_t *handle; | 2303 | handle_t *handle; |
2289 | 2304 | ||
2290 | handle = ext3_journal_start(dquot_to_inode(dquot), | 2305 | handle = ext3_journal_start(dquot_to_inode(dquot), |
2291 | EXT3_QUOTA_INIT_BLOCKS); | 2306 | EXT3_QUOTA_INIT_BLOCKS(dquot->dq_sb)); |
2292 | if (IS_ERR(handle)) | 2307 | if (IS_ERR(handle)) |
2293 | return PTR_ERR(handle); | 2308 | return PTR_ERR(handle); |
2294 | ret = dquot_acquire(dquot); | 2309 | ret = dquot_acquire(dquot); |
@@ -2304,7 +2319,7 @@ static int ext3_release_dquot(struct dquot *dquot) | |||
2304 | handle_t *handle; | 2319 | handle_t *handle; |
2305 | 2320 | ||
2306 | handle = ext3_journal_start(dquot_to_inode(dquot), | 2321 | handle = ext3_journal_start(dquot_to_inode(dquot), |
2307 | EXT3_QUOTA_INIT_BLOCKS); | 2322 | EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb)); |
2308 | if (IS_ERR(handle)) | 2323 | if (IS_ERR(handle)) |
2309 | return PTR_ERR(handle); | 2324 | return PTR_ERR(handle); |
2310 | ret = dquot_release(dquot); | 2325 | ret = dquot_release(dquot); |
@@ -2348,22 +2363,8 @@ static int ext3_write_info(struct super_block *sb, int type) | |||
2348 | */ | 2363 | */ |
2349 | static int ext3_quota_on_mount(struct super_block *sb, int type) | 2364 | static int ext3_quota_on_mount(struct super_block *sb, int type) |
2350 | { | 2365 | { |
2351 | int err; | 2366 | return vfs_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type], |
2352 | struct dentry *dentry; | 2367 | EXT3_SB(sb)->s_jquota_fmt, type); |
2353 | struct qstr name = { .name = EXT3_SB(sb)->s_qf_names[type], | ||
2354 | .hash = 0, | ||
2355 | .len = strlen(EXT3_SB(sb)->s_qf_names[type])}; | ||
2356 | |||
2357 | dentry = lookup_hash(&name, sb->s_root); | ||
2358 | if (IS_ERR(dentry)) | ||
2359 | return PTR_ERR(dentry); | ||
2360 | err = vfs_quota_on_mount(type, EXT3_SB(sb)->s_jquota_fmt, dentry); | ||
2361 | /* Now invalidate and put the dentry - quota got its own reference | ||
2362 | * to inode and dentry has at least wrong hash so we had better | ||
2363 | * throw it away */ | ||
2364 | d_invalidate(dentry); | ||
2365 | dput(dentry); | ||
2366 | return err; | ||
2367 | } | 2368 | } |
2368 | 2369 | ||
2369 | /* | 2370 | /* |
@@ -2375,6 +2376,8 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, | |||
2375 | int err; | 2376 | int err; |
2376 | struct nameidata nd; | 2377 | struct nameidata nd; |
2377 | 2378 | ||
2379 | if (!test_opt(sb, QUOTA)) | ||
2380 | return -EINVAL; | ||
2378 | /* Not journalling quota? */ | 2381 | /* Not journalling quota? */ |
2379 | if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] && | 2382 | if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] && |
2380 | !EXT3_SB(sb)->s_qf_names[GRPQUOTA]) | 2383 | !EXT3_SB(sb)->s_qf_names[GRPQUOTA]) |
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 4cbc6d0212d3..3f9dfa643b19 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c | |||
@@ -1044,7 +1044,7 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name, | |||
1044 | int error, retries = 0; | 1044 | int error, retries = 0; |
1045 | 1045 | ||
1046 | retry: | 1046 | retry: |
1047 | handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); | 1047 | handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); |
1048 | if (IS_ERR(handle)) { | 1048 | if (IS_ERR(handle)) { |
1049 | error = PTR_ERR(handle); | 1049 | error = PTR_ERR(handle); |
1050 | } else { | 1050 | } else { |
diff --git a/fs/file_table.c b/fs/file_table.c index 03d83cb686b1..fa7849fae134 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
@@ -63,42 +63,45 @@ static inline void file_free(struct file *f) | |||
63 | */ | 63 | */ |
64 | struct file *get_empty_filp(void) | 64 | struct file *get_empty_filp(void) |
65 | { | 65 | { |
66 | static int old_max; | 66 | static int old_max; |
67 | struct file * f; | 67 | struct file * f; |
68 | 68 | ||
69 | /* | 69 | /* |
70 | * Privileged users can go above max_files | 70 | * Privileged users can go above max_files |
71 | */ | 71 | */ |
72 | if (files_stat.nr_files < files_stat.max_files || | 72 | if (files_stat.nr_files >= files_stat.max_files && |
73 | capable(CAP_SYS_ADMIN)) { | 73 | !capable(CAP_SYS_ADMIN)) |
74 | f = kmem_cache_alloc(filp_cachep, GFP_KERNEL); | 74 | goto over; |
75 | if (f) { | 75 | |
76 | memset(f, 0, sizeof(*f)); | 76 | f = kmem_cache_alloc(filp_cachep, GFP_KERNEL); |
77 | if (security_file_alloc(f)) { | 77 | if (f == NULL) |
78 | file_free(f); | 78 | goto fail; |
79 | goto fail; | 79 | |
80 | } | 80 | memset(f, 0, sizeof(*f)); |
81 | eventpoll_init_file(f); | 81 | if (security_file_alloc(f)) |
82 | atomic_set(&f->f_count, 1); | 82 | goto fail_sec; |
83 | f->f_uid = current->fsuid; | 83 | |
84 | f->f_gid = current->fsgid; | 84 | eventpoll_init_file(f); |
85 | rwlock_init(&f->f_owner.lock); | 85 | atomic_set(&f->f_count, 1); |
86 | /* f->f_version: 0 */ | 86 | f->f_uid = current->fsuid; |
87 | INIT_LIST_HEAD(&f->f_list); | 87 | f->f_gid = current->fsgid; |
88 | f->f_maxcount = INT_MAX; | 88 | rwlock_init(&f->f_owner.lock); |
89 | return f; | 89 | /* f->f_version: 0 */ |
90 | } | 90 | INIT_LIST_HEAD(&f->f_list); |
91 | } | 91 | f->f_maxcount = INT_MAX; |
92 | 92 | return f; | |
93 | |||
94 | over: | ||
93 | /* Ran out of filps - report that */ | 95 | /* Ran out of filps - report that */ |
94 | if (files_stat.max_files >= old_max) { | 96 | if (files_stat.nr_files > old_max) { |
95 | printk(KERN_INFO "VFS: file-max limit %d reached\n", | 97 | printk(KERN_INFO "VFS: file-max limit %d reached\n", |
96 | files_stat.max_files); | 98 | files_stat.max_files); |
97 | old_max = files_stat.max_files; | 99 | old_max = files_stat.nr_files; |
98 | } else { | ||
99 | /* Big problems... */ | ||
100 | printk(KERN_WARNING "VFS: filp allocation failed\n"); | ||
101 | } | 100 | } |
101 | goto fail; | ||
102 | |||
103 | fail_sec: | ||
104 | file_free(f); | ||
102 | fail: | 105 | fail: |
103 | return NULL; | 106 | return NULL; |
104 | } | 107 | } |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 8e050fa58218..e94ab398b717 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -485,32 +485,6 @@ static void set_sb_syncing(int val) | |||
485 | spin_unlock(&sb_lock); | 485 | spin_unlock(&sb_lock); |
486 | } | 486 | } |
487 | 487 | ||
488 | /* | ||
489 | * Find a superblock with inodes that need to be synced | ||
490 | */ | ||
491 | static struct super_block *get_super_to_sync(void) | ||
492 | { | ||
493 | struct super_block *sb; | ||
494 | restart: | ||
495 | spin_lock(&sb_lock); | ||
496 | sb = sb_entry(super_blocks.prev); | ||
497 | for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) { | ||
498 | if (sb->s_syncing) | ||
499 | continue; | ||
500 | sb->s_syncing = 1; | ||
501 | sb->s_count++; | ||
502 | spin_unlock(&sb_lock); | ||
503 | down_read(&sb->s_umount); | ||
504 | if (!sb->s_root) { | ||
505 | drop_super(sb); | ||
506 | goto restart; | ||
507 | } | ||
508 | return sb; | ||
509 | } | ||
510 | spin_unlock(&sb_lock); | ||
511 | return NULL; | ||
512 | } | ||
513 | |||
514 | /** | 488 | /** |
515 | * sync_inodes - writes all inodes to disk | 489 | * sync_inodes - writes all inodes to disk |
516 | * @wait: wait for completion | 490 | * @wait: wait for completion |
@@ -530,23 +504,39 @@ restart: | |||
530 | * outstanding dirty inodes, the writeback goes block-at-a-time within the | 504 | * outstanding dirty inodes, the writeback goes block-at-a-time within the |
531 | * filesystem's write_inode(). This is extremely slow. | 505 | * filesystem's write_inode(). This is extremely slow. |
532 | */ | 506 | */ |
533 | void sync_inodes(int wait) | 507 | static void __sync_inodes(int wait) |
534 | { | 508 | { |
535 | struct super_block *sb; | 509 | struct super_block *sb; |
536 | 510 | ||
537 | set_sb_syncing(0); | 511 | spin_lock(&sb_lock); |
538 | while ((sb = get_super_to_sync()) != NULL) { | 512 | restart: |
539 | sync_inodes_sb(sb, 0); | 513 | list_for_each_entry(sb, &super_blocks, s_list) { |
540 | sync_blockdev(sb->s_bdev); | 514 | if (sb->s_syncing) |
541 | drop_super(sb); | 515 | continue; |
516 | sb->s_syncing = 1; | ||
517 | sb->s_count++; | ||
518 | spin_unlock(&sb_lock); | ||
519 | down_read(&sb->s_umount); | ||
520 | if (sb->s_root) { | ||
521 | sync_inodes_sb(sb, wait); | ||
522 | sync_blockdev(sb->s_bdev); | ||
523 | } | ||
524 | up_read(&sb->s_umount); | ||
525 | spin_lock(&sb_lock); | ||
526 | if (__put_super_and_need_restart(sb)) | ||
527 | goto restart; | ||
542 | } | 528 | } |
529 | spin_unlock(&sb_lock); | ||
530 | } | ||
531 | |||
532 | void sync_inodes(int wait) | ||
533 | { | ||
534 | set_sb_syncing(0); | ||
535 | __sync_inodes(0); | ||
536 | |||
543 | if (wait) { | 537 | if (wait) { |
544 | set_sb_syncing(0); | 538 | set_sb_syncing(0); |
545 | while ((sb = get_super_to_sync()) != NULL) { | 539 | __sync_inodes(1); |
546 | sync_inodes_sb(sb, 1); | ||
547 | sync_blockdev(sb->s_bdev); | ||
548 | drop_super(sb); | ||
549 | } | ||
550 | } | 540 | } |
551 | } | 541 | } |
552 | 542 | ||
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 14a0d339d036..4bf43ea87c46 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include "kern_util.h" | 23 | #include "kern_util.h" |
24 | #include "kern.h" | 24 | #include "kern.h" |
25 | #include "user_util.h" | 25 | #include "user_util.h" |
26 | #include "2_5compat.h" | ||
27 | #include "init.h" | 26 | #include "init.h" |
28 | 27 | ||
29 | struct hostfs_inode_info { | 28 | struct hostfs_inode_info { |
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 2af3338f891b..3a9b6d179cbd 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -122,6 +122,9 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
122 | 122 | ||
123 | start_addr = mm->free_area_cache; | 123 | start_addr = mm->free_area_cache; |
124 | 124 | ||
125 | if (len <= mm->cached_hole_size) | ||
126 | start_addr = TASK_UNMAPPED_BASE; | ||
127 | |||
125 | full_search: | 128 | full_search: |
126 | addr = ALIGN(start_addr, HPAGE_SIZE); | 129 | addr = ALIGN(start_addr, HPAGE_SIZE); |
127 | 130 | ||
diff --git a/fs/inode.c b/fs/inode.c index 801fe7f36280..1f9a3a2b89bc 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -500,7 +500,7 @@ repeat: | |||
500 | continue; | 500 | continue; |
501 | if (!test(inode, data)) | 501 | if (!test(inode, data)) |
502 | continue; | 502 | continue; |
503 | if (inode->i_state & (I_FREEING|I_CLEAR)) { | 503 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { |
504 | __wait_on_freeing_inode(inode); | 504 | __wait_on_freeing_inode(inode); |
505 | goto repeat; | 505 | goto repeat; |
506 | } | 506 | } |
@@ -525,7 +525,7 @@ repeat: | |||
525 | continue; | 525 | continue; |
526 | if (inode->i_sb != sb) | 526 | if (inode->i_sb != sb) |
527 | continue; | 527 | continue; |
528 | if (inode->i_state & (I_FREEING|I_CLEAR)) { | 528 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { |
529 | __wait_on_freeing_inode(inode); | 529 | __wait_on_freeing_inode(inode); |
530 | goto repeat; | 530 | goto repeat; |
531 | } | 531 | } |
@@ -727,7 +727,7 @@ EXPORT_SYMBOL(iunique); | |||
727 | struct inode *igrab(struct inode *inode) | 727 | struct inode *igrab(struct inode *inode) |
728 | { | 728 | { |
729 | spin_lock(&inode_lock); | 729 | spin_lock(&inode_lock); |
730 | if (!(inode->i_state & I_FREEING)) | 730 | if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) |
731 | __iget(inode); | 731 | __iget(inode); |
732 | else | 732 | else |
733 | /* | 733 | /* |
@@ -1024,17 +1024,21 @@ static void generic_forget_inode(struct inode *inode) | |||
1024 | if (!(inode->i_state & (I_DIRTY|I_LOCK))) | 1024 | if (!(inode->i_state & (I_DIRTY|I_LOCK))) |
1025 | list_move(&inode->i_list, &inode_unused); | 1025 | list_move(&inode->i_list, &inode_unused); |
1026 | inodes_stat.nr_unused++; | 1026 | inodes_stat.nr_unused++; |
1027 | spin_unlock(&inode_lock); | 1027 | if (!sb || (sb->s_flags & MS_ACTIVE)) { |
1028 | if (!sb || (sb->s_flags & MS_ACTIVE)) | 1028 | spin_unlock(&inode_lock); |
1029 | return; | 1029 | return; |
1030 | } | ||
1031 | inode->i_state |= I_WILL_FREE; | ||
1032 | spin_unlock(&inode_lock); | ||
1030 | write_inode_now(inode, 1); | 1033 | write_inode_now(inode, 1); |
1031 | spin_lock(&inode_lock); | 1034 | spin_lock(&inode_lock); |
1035 | inode->i_state &= ~I_WILL_FREE; | ||
1032 | inodes_stat.nr_unused--; | 1036 | inodes_stat.nr_unused--; |
1033 | hlist_del_init(&inode->i_hash); | 1037 | hlist_del_init(&inode->i_hash); |
1034 | } | 1038 | } |
1035 | list_del_init(&inode->i_list); | 1039 | list_del_init(&inode->i_list); |
1036 | list_del_init(&inode->i_sb_list); | 1040 | list_del_init(&inode->i_sb_list); |
1037 | inode->i_state|=I_FREEING; | 1041 | inode->i_state |= I_FREEING; |
1038 | inodes_stat.nr_inodes--; | 1042 | inodes_stat.nr_inodes--; |
1039 | spin_unlock(&inode_lock); | 1043 | spin_unlock(&inode_lock); |
1040 | if (inode->i_data.nrpages) | 1044 | if (inode->i_data.nrpages) |
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index 6030956b894b..7901ac9f97ab 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c | |||
@@ -193,12 +193,17 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, | |||
193 | 193 | ||
194 | /* Handle everything else. Do name translation if there | 194 | /* Handle everything else. Do name translation if there |
195 | is no Rock Ridge NM field. */ | 195 | is no Rock Ridge NM field. */ |
196 | if (sbi->s_unhide == 'n') { | 196 | |
197 | /* Do not report hidden or associated files */ | 197 | /* |
198 | if (de->flags[-sbi->s_high_sierra] & 5) { | 198 | * Do not report hidden files if so instructed, or associated |
199 | filp->f_pos += de_len; | 199 | * files unless instructed to do so |
200 | continue; | 200 | */ |
201 | } | 201 | if ((sbi->s_hide == 'y' && |
202 | (de->flags[-sbi->s_high_sierra] & 1)) || | ||
203 | (sbi->s_showassoc =='n' && | ||
204 | (de->flags[-sbi->s_high_sierra] & 4))) { | ||
205 | filp->f_pos += de_len; | ||
206 | continue; | ||
202 | } | 207 | } |
203 | 208 | ||
204 | map = 1; | 209 | map = 1; |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index abd7b12eeca7..1652de1b6cb9 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
@@ -28,11 +28,6 @@ | |||
28 | 28 | ||
29 | #define BEQUIET | 29 | #define BEQUIET |
30 | 30 | ||
31 | #ifdef LEAK_CHECK | ||
32 | static int check_malloc; | ||
33 | static int check_bread; | ||
34 | #endif | ||
35 | |||
36 | static int isofs_hashi(struct dentry *parent, struct qstr *qstr); | 31 | static int isofs_hashi(struct dentry *parent, struct qstr *qstr); |
37 | static int isofs_hash(struct dentry *parent, struct qstr *qstr); | 32 | static int isofs_hash(struct dentry *parent, struct qstr *qstr); |
38 | static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); | 33 | static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); |
@@ -55,11 +50,6 @@ static void isofs_put_super(struct super_block *sb) | |||
55 | } | 50 | } |
56 | #endif | 51 | #endif |
57 | 52 | ||
58 | #ifdef LEAK_CHECK | ||
59 | printk("Outstanding mallocs:%d, outstanding buffers: %d\n", | ||
60 | check_malloc, check_bread); | ||
61 | #endif | ||
62 | |||
63 | kfree(sbi); | 53 | kfree(sbi); |
64 | sb->s_fs_info = NULL; | 54 | sb->s_fs_info = NULL; |
65 | return; | 55 | return; |
@@ -73,7 +63,7 @@ static kmem_cache_t *isofs_inode_cachep; | |||
73 | static struct inode *isofs_alloc_inode(struct super_block *sb) | 63 | static struct inode *isofs_alloc_inode(struct super_block *sb) |
74 | { | 64 | { |
75 | struct iso_inode_info *ei; | 65 | struct iso_inode_info *ei; |
76 | ei = (struct iso_inode_info *)kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL); | 66 | ei = kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL); |
77 | if (!ei) | 67 | if (!ei) |
78 | return NULL; | 68 | return NULL; |
79 | return &ei->vfs_inode; | 69 | return &ei->vfs_inode; |
@@ -84,9 +74,9 @@ static void isofs_destroy_inode(struct inode *inode) | |||
84 | kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); | 74 | kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); |
85 | } | 75 | } |
86 | 76 | ||
87 | static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | 77 | static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) |
88 | { | 78 | { |
89 | struct iso_inode_info *ei = (struct iso_inode_info *) foo; | 79 | struct iso_inode_info *ei = foo; |
90 | 80 | ||
91 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | 81 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == |
92 | SLAB_CTOR_CONSTRUCTOR) | 82 | SLAB_CTOR_CONSTRUCTOR) |
@@ -107,7 +97,8 @@ static int init_inodecache(void) | |||
107 | static void destroy_inodecache(void) | 97 | static void destroy_inodecache(void) |
108 | { | 98 | { |
109 | if (kmem_cache_destroy(isofs_inode_cachep)) | 99 | if (kmem_cache_destroy(isofs_inode_cachep)) |
110 | printk(KERN_INFO "iso_inode_cache: not all structures were freed\n"); | 100 | printk(KERN_INFO "iso_inode_cache: not all structures were " |
101 | "freed\n"); | ||
111 | } | 102 | } |
112 | 103 | ||
113 | static int isofs_remount(struct super_block *sb, int *flags, char *data) | 104 | static int isofs_remount(struct super_block *sb, int *flags, char *data) |
@@ -144,7 +135,7 @@ static struct dentry_operations isofs_dentry_ops[] = { | |||
144 | { | 135 | { |
145 | .d_hash = isofs_hashi_ms, | 136 | .d_hash = isofs_hashi_ms, |
146 | .d_compare = isofs_dentry_cmpi_ms, | 137 | .d_compare = isofs_dentry_cmpi_ms, |
147 | } | 138 | }, |
148 | #endif | 139 | #endif |
149 | }; | 140 | }; |
150 | 141 | ||
@@ -153,7 +144,8 @@ struct iso9660_options{ | |||
153 | char rock; | 144 | char rock; |
154 | char joliet; | 145 | char joliet; |
155 | char cruft; | 146 | char cruft; |
156 | char unhide; | 147 | char hide; |
148 | char showassoc; | ||
157 | char nocompress; | 149 | char nocompress; |
158 | unsigned char check; | 150 | unsigned char check; |
159 | unsigned int blocksize; | 151 | unsigned int blocksize; |
@@ -219,8 +211,8 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms) | |||
219 | /* | 211 | /* |
220 | * Case insensitive compare of two isofs names. | 212 | * Case insensitive compare of two isofs names. |
221 | */ | 213 | */ |
222 | static int | 214 | static int isofs_dentry_cmpi_common(struct dentry *dentry, struct qstr *a, |
223 | isofs_dentry_cmpi_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms) | 215 | struct qstr *b, int ms) |
224 | { | 216 | { |
225 | int alen, blen; | 217 | int alen, blen; |
226 | 218 | ||
@@ -243,8 +235,8 @@ isofs_dentry_cmpi_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int | |||
243 | /* | 235 | /* |
244 | * Case sensitive compare of two isofs names. | 236 | * Case sensitive compare of two isofs names. |
245 | */ | 237 | */ |
246 | static int | 238 | static int isofs_dentry_cmp_common(struct dentry *dentry, struct qstr *a, |
247 | isofs_dentry_cmp_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms) | 239 | struct qstr *b, int ms) |
248 | { | 240 | { |
249 | int alen, blen; | 241 | int alen, blen; |
250 | 242 | ||
@@ -318,13 +310,15 @@ enum { | |||
318 | Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, | 310 | Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, |
319 | Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, | 311 | Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, |
320 | Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, | 312 | Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, |
321 | Opt_nocompress, | 313 | Opt_nocompress, Opt_hide, Opt_showassoc, |
322 | }; | 314 | }; |
323 | 315 | ||
324 | static match_table_t tokens = { | 316 | static match_table_t tokens = { |
325 | {Opt_norock, "norock"}, | 317 | {Opt_norock, "norock"}, |
326 | {Opt_nojoliet, "nojoliet"}, | 318 | {Opt_nojoliet, "nojoliet"}, |
327 | {Opt_unhide, "unhide"}, | 319 | {Opt_unhide, "unhide"}, |
320 | {Opt_hide, "hide"}, | ||
321 | {Opt_showassoc, "showassoc"}, | ||
328 | {Opt_cruft, "cruft"}, | 322 | {Opt_cruft, "cruft"}, |
329 | {Opt_utf8, "utf8"}, | 323 | {Opt_utf8, "utf8"}, |
330 | {Opt_iocharset, "iocharset=%s"}, | 324 | {Opt_iocharset, "iocharset=%s"}, |
@@ -356,7 +350,7 @@ static match_table_t tokens = { | |||
356 | {Opt_err, NULL} | 350 | {Opt_err, NULL} |
357 | }; | 351 | }; |
358 | 352 | ||
359 | static int parse_options(char *options, struct iso9660_options * popt) | 353 | static int parse_options(char *options, struct iso9660_options *popt) |
360 | { | 354 | { |
361 | char *p; | 355 | char *p; |
362 | int option; | 356 | int option; |
@@ -365,7 +359,8 @@ static int parse_options(char *options, struct iso9660_options * popt) | |||
365 | popt->rock = 'y'; | 359 | popt->rock = 'y'; |
366 | popt->joliet = 'y'; | 360 | popt->joliet = 'y'; |
367 | popt->cruft = 'n'; | 361 | popt->cruft = 'n'; |
368 | popt->unhide = 'n'; | 362 | popt->hide = 'n'; |
363 | popt->showassoc = 'n'; | ||
369 | popt->check = 'u'; /* unset */ | 364 | popt->check = 'u'; /* unset */ |
370 | popt->nocompress = 0; | 365 | popt->nocompress = 0; |
371 | popt->blocksize = 1024; | 366 | popt->blocksize = 1024; |
@@ -398,8 +393,12 @@ static int parse_options(char *options, struct iso9660_options * popt) | |||
398 | case Opt_nojoliet: | 393 | case Opt_nojoliet: |
399 | popt->joliet = 'n'; | 394 | popt->joliet = 'n'; |
400 | break; | 395 | break; |
396 | case Opt_hide: | ||
397 | popt->hide = 'y'; | ||
398 | break; | ||
401 | case Opt_unhide: | 399 | case Opt_unhide: |
402 | popt->unhide = 'y'; | 400 | case Opt_showassoc: |
401 | popt->showassoc = 'y'; | ||
403 | break; | 402 | break; |
404 | case Opt_cruft: | 403 | case Opt_cruft: |
405 | popt->cruft = 'y'; | 404 | popt->cruft = 'y'; |
@@ -493,7 +492,7 @@ static int parse_options(char *options, struct iso9660_options * popt) | |||
493 | */ | 492 | */ |
494 | #define WE_OBEY_THE_WRITTEN_STANDARDS 1 | 493 | #define WE_OBEY_THE_WRITTEN_STANDARDS 1 |
495 | 494 | ||
496 | static unsigned int isofs_get_last_session(struct super_block *sb,s32 session ) | 495 | static unsigned int isofs_get_last_session(struct super_block *sb, s32 session) |
497 | { | 496 | { |
498 | struct cdrom_multisession ms_info; | 497 | struct cdrom_multisession ms_info; |
499 | unsigned int vol_desc_start; | 498 | unsigned int vol_desc_start; |
@@ -518,7 +517,8 @@ static unsigned int isofs_get_last_session(struct super_block *sb,s32 session ) | |||
518 | printk(KERN_ERR "Invalid session number or type of track\n"); | 517 | printk(KERN_ERR "Invalid session number or type of track\n"); |
519 | } | 518 | } |
520 | i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info); | 519 | i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info); |
521 | if(session > 0) printk(KERN_ERR "Invalid session number\n"); | 520 | if (session > 0) |
521 | printk(KERN_ERR "Invalid session number\n"); | ||
522 | #if 0 | 522 | #if 0 |
523 | printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i); | 523 | printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i); |
524 | if (i==0) { | 524 | if (i==0) { |
@@ -557,13 +557,13 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) | |||
557 | struct iso9660_options opt; | 557 | struct iso9660_options opt; |
558 | struct isofs_sb_info * sbi; | 558 | struct isofs_sb_info * sbi; |
559 | 559 | ||
560 | sbi = kmalloc(sizeof(struct isofs_sb_info), GFP_KERNEL); | 560 | sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); |
561 | if (!sbi) | 561 | if (!sbi) |
562 | return -ENOMEM; | 562 | return -ENOMEM; |
563 | s->s_fs_info = sbi; | 563 | s->s_fs_info = sbi; |
564 | memset(sbi, 0, sizeof(struct isofs_sb_info)); | 564 | memset(sbi, 0, sizeof(*sbi)); |
565 | 565 | ||
566 | if (!parse_options((char *) data, &opt)) | 566 | if (!parse_options((char *)data, &opt)) |
567 | goto out_freesbi; | 567 | goto out_freesbi; |
568 | 568 | ||
569 | /* | 569 | /* |
@@ -792,7 +792,8 @@ root_found: | |||
792 | sbi->s_rock = (opt.rock == 'y' ? 2 : 0); | 792 | sbi->s_rock = (opt.rock == 'y' ? 2 : 0); |
793 | sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ | 793 | sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ |
794 | sbi->s_cruft = opt.cruft; | 794 | sbi->s_cruft = opt.cruft; |
795 | sbi->s_unhide = opt.unhide; | 795 | sbi->s_hide = opt.hide; |
796 | sbi->s_showassoc = opt.showassoc; | ||
796 | sbi->s_uid = opt.uid; | 797 | sbi->s_uid = opt.uid; |
797 | sbi->s_gid = opt.gid; | 798 | sbi->s_gid = opt.gid; |
798 | sbi->s_utf8 = opt.utf8; | 799 | sbi->s_utf8 = opt.utf8; |
@@ -1002,7 +1003,6 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s, | |||
1002 | rv++; | 1003 | rv++; |
1003 | } | 1004 | } |
1004 | 1005 | ||
1005 | |||
1006 | abort: | 1006 | abort: |
1007 | unlock_kernel(); | 1007 | unlock_kernel(); |
1008 | return rv; | 1008 | return rv; |
@@ -1014,7 +1014,7 @@ abort: | |||
1014 | static int isofs_get_block(struct inode *inode, sector_t iblock, | 1014 | static int isofs_get_block(struct inode *inode, sector_t iblock, |
1015 | struct buffer_head *bh_result, int create) | 1015 | struct buffer_head *bh_result, int create) |
1016 | { | 1016 | { |
1017 | if ( create ) { | 1017 | if (create) { |
1018 | printk("isofs_get_block: Kernel tries to allocate a block\n"); | 1018 | printk("isofs_get_block: Kernel tries to allocate a block\n"); |
1019 | return -EROFS; | 1019 | return -EROFS; |
1020 | } | 1020 | } |
@@ -1061,19 +1061,17 @@ static struct address_space_operations isofs_aops = { | |||
1061 | 1061 | ||
1062 | static inline void test_and_set_uid(uid_t *p, uid_t value) | 1062 | static inline void test_and_set_uid(uid_t *p, uid_t value) |
1063 | { | 1063 | { |
1064 | if(value) { | 1064 | if (value) |
1065 | *p = value; | 1065 | *p = value; |
1066 | } | ||
1067 | } | 1066 | } |
1068 | 1067 | ||
1069 | static inline void test_and_set_gid(gid_t *p, gid_t value) | 1068 | static inline void test_and_set_gid(gid_t *p, gid_t value) |
1070 | { | 1069 | { |
1071 | if(value) { | 1070 | if (value) |
1072 | *p = value; | 1071 | *p = value; |
1073 | } | ||
1074 | } | 1072 | } |
1075 | 1073 | ||
1076 | static int isofs_read_level3_size(struct inode * inode) | 1074 | static int isofs_read_level3_size(struct inode *inode) |
1077 | { | 1075 | { |
1078 | unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); | 1076 | unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); |
1079 | int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra; | 1077 | int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra; |
@@ -1136,7 +1134,7 @@ static int isofs_read_level3_size(struct inode * inode) | |||
1136 | bh = sb_bread(inode->i_sb, block); | 1134 | bh = sb_bread(inode->i_sb, block); |
1137 | if (!bh) | 1135 | if (!bh) |
1138 | goto out_noread; | 1136 | goto out_noread; |
1139 | memcpy((void *) tmpde + slop, bh->b_data, offset); | 1137 | memcpy((void *)tmpde+slop, bh->b_data, offset); |
1140 | } | 1138 | } |
1141 | de = tmpde; | 1139 | de = tmpde; |
1142 | } | 1140 | } |
@@ -1150,12 +1148,11 @@ static int isofs_read_level3_size(struct inode * inode) | |||
1150 | more_entries = de->flags[-high_sierra] & 0x80; | 1148 | more_entries = de->flags[-high_sierra] & 0x80; |
1151 | 1149 | ||
1152 | i++; | 1150 | i++; |
1153 | if(i > 100) | 1151 | if (i > 100) |
1154 | goto out_toomany; | 1152 | goto out_toomany; |
1155 | } while(more_entries); | 1153 | } while (more_entries); |
1156 | out: | 1154 | out: |
1157 | if (tmpde) | 1155 | kfree(tmpde); |
1158 | kfree(tmpde); | ||
1159 | if (bh) | 1156 | if (bh) |
1160 | brelse(bh); | 1157 | brelse(bh); |
1161 | return 0; | 1158 | return 0; |
@@ -1179,7 +1176,7 @@ out_toomany: | |||
1179 | goto out; | 1176 | goto out; |
1180 | } | 1177 | } |
1181 | 1178 | ||
1182 | static void isofs_read_inode(struct inode * inode) | 1179 | static void isofs_read_inode(struct inode *inode) |
1183 | { | 1180 | { |
1184 | struct super_block *sb = inode->i_sb; | 1181 | struct super_block *sb = inode->i_sb; |
1185 | struct isofs_sb_info *sbi = ISOFS_SB(sb); | 1182 | struct isofs_sb_info *sbi = ISOFS_SB(sb); |
@@ -1249,7 +1246,7 @@ static void isofs_read_inode(struct inode * inode) | |||
1249 | ei->i_format_parm[2] = 0; | 1246 | ei->i_format_parm[2] = 0; |
1250 | 1247 | ||
1251 | ei->i_section_size = isonum_733 (de->size); | 1248 | ei->i_section_size = isonum_733 (de->size); |
1252 | if(de->flags[-high_sierra] & 0x80) { | 1249 | if (de->flags[-high_sierra] & 0x80) { |
1253 | if(isofs_read_level3_size(inode)) goto fail; | 1250 | if(isofs_read_level3_size(inode)) goto fail; |
1254 | } else { | 1251 | } else { |
1255 | ei->i_next_section_block = 0; | 1252 | ei->i_next_section_block = 0; |
@@ -1336,16 +1333,16 @@ static void isofs_read_inode(struct inode * inode) | |||
1336 | /* XXX - parse_rock_ridge_inode() had already set i_rdev. */ | 1333 | /* XXX - parse_rock_ridge_inode() had already set i_rdev. */ |
1337 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | 1334 | init_special_inode(inode, inode->i_mode, inode->i_rdev); |
1338 | 1335 | ||
1339 | out: | 1336 | out: |
1340 | if (tmpde) | 1337 | if (tmpde) |
1341 | kfree(tmpde); | 1338 | kfree(tmpde); |
1342 | if (bh) | 1339 | if (bh) |
1343 | brelse(bh); | 1340 | brelse(bh); |
1344 | return; | 1341 | return; |
1345 | 1342 | ||
1346 | out_badread: | 1343 | out_badread: |
1347 | printk(KERN_WARNING "ISOFS: unable to read i-node block\n"); | 1344 | printk(KERN_WARNING "ISOFS: unable to read i-node block\n"); |
1348 | fail: | 1345 | fail: |
1349 | make_bad_inode(inode); | 1346 | make_bad_inode(inode); |
1350 | goto out; | 1347 | goto out; |
1351 | } | 1348 | } |
@@ -1394,11 +1391,8 @@ struct inode *isofs_iget(struct super_block *sb, | |||
1394 | 1391 | ||
1395 | hashval = (block << sb->s_blocksize_bits) | offset; | 1392 | hashval = (block << sb->s_blocksize_bits) | offset; |
1396 | 1393 | ||
1397 | inode = iget5_locked(sb, | 1394 | inode = iget5_locked(sb, hashval, &isofs_iget5_test, |
1398 | hashval, | 1395 | &isofs_iget5_set, &data); |
1399 | &isofs_iget5_test, | ||
1400 | &isofs_iget5_set, | ||
1401 | &data); | ||
1402 | 1396 | ||
1403 | if (inode && (inode->i_state & I_NEW)) { | 1397 | if (inode && (inode->i_state & I_NEW)) { |
1404 | sb->s_op->read_inode(inode); | 1398 | sb->s_op->read_inode(inode); |
@@ -1408,36 +1402,6 @@ struct inode *isofs_iget(struct super_block *sb, | |||
1408 | return inode; | 1402 | return inode; |
1409 | } | 1403 | } |
1410 | 1404 | ||
1411 | #ifdef LEAK_CHECK | ||
1412 | #undef malloc | ||
1413 | #undef free_s | ||
1414 | #undef sb_bread | ||
1415 | #undef brelse | ||
1416 | |||
1417 | void * leak_check_malloc(unsigned int size){ | ||
1418 | void * tmp; | ||
1419 | check_malloc++; | ||
1420 | tmp = kmalloc(size, GFP_KERNEL); | ||
1421 | return tmp; | ||
1422 | } | ||
1423 | |||
1424 | void leak_check_free_s(void * obj, int size){ | ||
1425 | check_malloc--; | ||
1426 | return kfree(obj); | ||
1427 | } | ||
1428 | |||
1429 | struct buffer_head * leak_check_bread(struct super_block *sb, int block){ | ||
1430 | check_bread++; | ||
1431 | return sb_bread(sb, block); | ||
1432 | } | ||
1433 | |||
1434 | void leak_check_brelse(struct buffer_head * bh){ | ||
1435 | check_bread--; | ||
1436 | return brelse(bh); | ||
1437 | } | ||
1438 | |||
1439 | #endif | ||
1440 | |||
1441 | static struct super_block *isofs_get_sb(struct file_system_type *fs_type, | 1405 | static struct super_block *isofs_get_sb(struct file_system_type *fs_type, |
1442 | int flags, const char *dev_name, void *data) | 1406 | int flags, const char *dev_name, void *data) |
1443 | { | 1407 | { |
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index 9ce7b51fb614..38c75151fc66 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h | |||
@@ -47,6 +47,8 @@ struct isofs_sb_info { | |||
47 | unsigned char s_nosuid; | 47 | unsigned char s_nosuid; |
48 | unsigned char s_nodev; | 48 | unsigned char s_nodev; |
49 | unsigned char s_nocompress; | 49 | unsigned char s_nocompress; |
50 | unsigned char s_hide; | ||
51 | unsigned char s_showassoc; | ||
50 | 52 | ||
51 | mode_t s_mode; | 53 | mode_t s_mode; |
52 | gid_t s_gid; | 54 | gid_t s_gid; |
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 690edf37173c..e37e82b7cbf0 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c | |||
@@ -131,14 +131,16 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, | |||
131 | } | 131 | } |
132 | 132 | ||
133 | /* | 133 | /* |
134 | * Skip hidden or associated files unless unhide is set | 134 | * Skip hidden or associated files unless hide or showassoc, |
135 | * respectively, is set | ||
135 | */ | 136 | */ |
136 | match = 0; | 137 | match = 0; |
137 | if (dlen > 0 && | 138 | if (dlen > 0 && |
138 | (!(de->flags[-sbi->s_high_sierra] & 5) | 139 | (sbi->s_hide =='n' || |
139 | || sbi->s_unhide == 'y')) | 140 | (!(de->flags[-sbi->s_high_sierra] & 1))) && |
140 | { | 141 | (sbi->s_showassoc =='y' || |
141 | match = (isofs_cmp(dentry,dpnt,dlen) == 0); | 142 | (!(de->flags[-sbi->s_high_sierra] & 4)))) { |
143 | match = (isofs_cmp(dentry, dpnt, dlen) == 0); | ||
142 | } | 144 | } |
143 | if (match) { | 145 | if (match) { |
144 | isofs_normalize_block_and_offset(de, | 146 | isofs_normalize_block_and_offset(de, |
@@ -146,11 +148,11 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, | |||
146 | &offset_saved); | 148 | &offset_saved); |
147 | *block_rv = block_saved; | 149 | *block_rv = block_saved; |
148 | *offset_rv = offset_saved; | 150 | *offset_rv = offset_saved; |
149 | if (bh) brelse(bh); | 151 | brelse(bh); |
150 | return 1; | 152 | return 1; |
151 | } | 153 | } |
152 | } | 154 | } |
153 | if (bh) brelse(bh); | 155 | brelse(bh); |
154 | return 0; | 156 | return 0; |
155 | } | 157 | } |
156 | 158 | ||
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 089e79c65585..4326cb47f8fa 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c | |||
@@ -13,352 +13,542 @@ | |||
13 | #include "isofs.h" | 13 | #include "isofs.h" |
14 | #include "rock.h" | 14 | #include "rock.h" |
15 | 15 | ||
16 | /* These functions are designed to read the system areas of a directory record | 16 | /* |
17 | * These functions are designed to read the system areas of a directory record | ||
17 | * and extract relevant information. There are different functions provided | 18 | * and extract relevant information. There are different functions provided |
18 | * depending upon what information we need at the time. One function fills | 19 | * depending upon what information we need at the time. One function fills |
19 | * out an inode structure, a second one extracts a filename, a third one | 20 | * out an inode structure, a second one extracts a filename, a third one |
20 | * returns a symbolic link name, and a fourth one returns the extent number | 21 | * returns a symbolic link name, and a fourth one returns the extent number |
21 | * for the file. */ | 22 | * for the file. |
22 | 23 | */ | |
23 | #define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ | 24 | |
24 | 25 | #define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ | |
25 | 26 | ||
26 | /* This is a way of ensuring that we have something in the system | 27 | struct rock_state { |
27 | use fields that is compatible with Rock Ridge */ | 28 | void *buffer; |
28 | #define CHECK_SP(FAIL) \ | 29 | unsigned char *chr; |
29 | if(rr->u.SP.magic[0] != 0xbe) FAIL; \ | 30 | int len; |
30 | if(rr->u.SP.magic[1] != 0xef) FAIL; \ | 31 | int cont_size; |
31 | ISOFS_SB(inode->i_sb)->s_rock_offset=rr->u.SP.skip; | 32 | int cont_extent; |
32 | /* We define a series of macros because each function must do exactly the | 33 | int cont_offset; |
33 | same thing in certain places. We use the macros to ensure that everything | 34 | struct inode *inode; |
34 | is done correctly */ | 35 | }; |
35 | 36 | ||
36 | #define CONTINUE_DECLS \ | 37 | /* |
37 | int cont_extent = 0, cont_offset = 0, cont_size = 0; \ | 38 | * This is a way of ensuring that we have something in the system |
38 | void *buffer = NULL | 39 | * use fields that is compatible with Rock Ridge. Return zero on success. |
39 | 40 | */ | |
40 | #define CHECK_CE \ | 41 | |
41 | {cont_extent = isonum_733(rr->u.CE.extent); \ | 42 | static int check_sp(struct rock_ridge *rr, struct inode *inode) |
42 | cont_offset = isonum_733(rr->u.CE.offset); \ | ||
43 | cont_size = isonum_733(rr->u.CE.size);} | ||
44 | |||
45 | #define SETUP_ROCK_RIDGE(DE,CHR,LEN) \ | ||
46 | {LEN= sizeof(struct iso_directory_record) + DE->name_len[0]; \ | ||
47 | if(LEN & 1) LEN++; \ | ||
48 | CHR = ((unsigned char *) DE) + LEN; \ | ||
49 | LEN = *((unsigned char *) DE) - LEN; \ | ||
50 | if (LEN<0) LEN=0; \ | ||
51 | if (ISOFS_SB(inode->i_sb)->s_rock_offset!=-1) \ | ||
52 | { \ | ||
53 | LEN-=ISOFS_SB(inode->i_sb)->s_rock_offset; \ | ||
54 | CHR+=ISOFS_SB(inode->i_sb)->s_rock_offset; \ | ||
55 | if (LEN<0) LEN=0; \ | ||
56 | } \ | ||
57 | } | ||
58 | |||
59 | #define MAYBE_CONTINUE(LABEL,DEV) \ | ||
60 | {if (buffer) { kfree(buffer); buffer = NULL; } \ | ||
61 | if (cont_extent){ \ | ||
62 | int block, offset, offset1; \ | ||
63 | struct buffer_head * pbh; \ | ||
64 | buffer = kmalloc(cont_size,GFP_KERNEL); \ | ||
65 | if (!buffer) goto out; \ | ||
66 | block = cont_extent; \ | ||
67 | offset = cont_offset; \ | ||
68 | offset1 = 0; \ | ||
69 | pbh = sb_bread(DEV->i_sb, block); \ | ||
70 | if(pbh){ \ | ||
71 | if (offset > pbh->b_size || offset + cont_size > pbh->b_size){ \ | ||
72 | brelse(pbh); \ | ||
73 | goto out; \ | ||
74 | } \ | ||
75 | memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \ | ||
76 | brelse(pbh); \ | ||
77 | chr = (unsigned char *) buffer; \ | ||
78 | len = cont_size; \ | ||
79 | cont_extent = 0; \ | ||
80 | cont_size = 0; \ | ||
81 | cont_offset = 0; \ | ||
82 | goto LABEL; \ | ||
83 | } \ | ||
84 | printk("Unable to read rock-ridge attributes\n"); \ | ||
85 | }} | ||
86 | |||
87 | /* return length of name field; 0: not found, -1: to be ignored */ | ||
88 | int get_rock_ridge_filename(struct iso_directory_record * de, | ||
89 | char * retname, struct inode * inode) | ||
90 | { | 43 | { |
91 | int len; | 44 | if (rr->u.SP.magic[0] != 0xbe) |
92 | unsigned char * chr; | 45 | return -1; |
93 | CONTINUE_DECLS; | 46 | if (rr->u.SP.magic[1] != 0xef) |
94 | int retnamlen = 0, truncate=0; | 47 | return -1; |
95 | 48 | ISOFS_SB(inode->i_sb)->s_rock_offset = rr->u.SP.skip; | |
96 | if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; | 49 | return 0; |
97 | *retname = 0; | 50 | } |
98 | 51 | ||
99 | SETUP_ROCK_RIDGE(de, chr, len); | 52 | static void setup_rock_ridge(struct iso_directory_record *de, |
100 | repeat: | 53 | struct inode *inode, struct rock_state *rs) |
101 | { | 54 | { |
102 | struct rock_ridge * rr; | 55 | rs->len = sizeof(struct iso_directory_record) + de->name_len[0]; |
103 | int sig; | 56 | if (rs->len & 1) |
104 | 57 | (rs->len)++; | |
105 | while (len > 2){ /* There may be one byte for padding somewhere */ | 58 | rs->chr = (unsigned char *)de + rs->len; |
106 | rr = (struct rock_ridge *) chr; | 59 | rs->len = *((unsigned char *)de) - rs->len; |
107 | if (rr->len < 3) goto out; /* Something got screwed up here */ | 60 | if (rs->len < 0) |
108 | sig = isonum_721(chr); | 61 | rs->len = 0; |
109 | chr += rr->len; | 62 | |
110 | len -= rr->len; | 63 | if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) { |
111 | if (len < 0) goto out; /* corrupted isofs */ | 64 | rs->len -= ISOFS_SB(inode->i_sb)->s_rock_offset; |
112 | 65 | rs->chr += ISOFS_SB(inode->i_sb)->s_rock_offset; | |
113 | switch(sig){ | 66 | if (rs->len < 0) |
114 | case SIG('R','R'): | 67 | rs->len = 0; |
115 | if((rr->u.RR.flags[0] & RR_NM) == 0) goto out; | 68 | } |
116 | break; | 69 | } |
117 | case SIG('S','P'): | 70 | |
118 | CHECK_SP(goto out); | 71 | static void init_rock_state(struct rock_state *rs, struct inode *inode) |
119 | break; | 72 | { |
120 | case SIG('C','E'): | 73 | memset(rs, 0, sizeof(*rs)); |
121 | CHECK_CE; | 74 | rs->inode = inode; |
122 | break; | 75 | } |
123 | case SIG('N','M'): | 76 | |
124 | if (truncate) break; | 77 | /* |
125 | if (rr->len < 5) break; | 78 | * Returns 0 if the caller should continue scanning, 1 if the scan must end |
126 | /* | 79 | * and -ve on error. |
127 | * If the flags are 2 or 4, this indicates '.' or '..'. | 80 | */ |
128 | * We don't want to do anything with this, because it | 81 | static int rock_continue(struct rock_state *rs) |
129 | * screws up the code that calls us. We don't really | 82 | { |
130 | * care anyways, since we can just use the non-RR | 83 | int ret = 1; |
131 | * name. | 84 | int blocksize = 1 << rs->inode->i_blkbits; |
132 | */ | 85 | const int min_de_size = offsetof(struct rock_ridge, u); |
133 | if (rr->u.NM.flags & 6) { | 86 | |
134 | break; | 87 | kfree(rs->buffer); |
88 | rs->buffer = NULL; | ||
89 | |||
90 | if ((unsigned)rs->cont_offset > blocksize - min_de_size || | ||
91 | (unsigned)rs->cont_size > blocksize || | ||
92 | (unsigned)(rs->cont_offset + rs->cont_size) > blocksize) { | ||
93 | printk(KERN_NOTICE "rock: corrupted directory entry. " | ||
94 | "extent=%d, offset=%d, size=%d\n", | ||
95 | rs->cont_extent, rs->cont_offset, rs->cont_size); | ||
96 | ret = -EIO; | ||
97 | goto out; | ||
135 | } | 98 | } |
136 | 99 | ||
137 | if (rr->u.NM.flags & ~1) { | 100 | if (rs->cont_extent) { |
138 | printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags); | 101 | struct buffer_head *bh; |
139 | break; | 102 | |
103 | rs->buffer = kmalloc(rs->cont_size, GFP_KERNEL); | ||
104 | if (!rs->buffer) { | ||
105 | ret = -ENOMEM; | ||
106 | goto out; | ||
107 | } | ||
108 | ret = -EIO; | ||
109 | bh = sb_bread(rs->inode->i_sb, rs->cont_extent); | ||
110 | if (bh) { | ||
111 | memcpy(rs->buffer, bh->b_data + rs->cont_offset, | ||
112 | rs->cont_size); | ||
113 | put_bh(bh); | ||
114 | rs->chr = rs->buffer; | ||
115 | rs->len = rs->cont_size; | ||
116 | rs->cont_extent = 0; | ||
117 | rs->cont_size = 0; | ||
118 | rs->cont_offset = 0; | ||
119 | return 0; | ||
120 | } | ||
121 | printk("Unable to read rock-ridge attributes\n"); | ||
122 | } | ||
123 | out: | ||
124 | kfree(rs->buffer); | ||
125 | rs->buffer = NULL; | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * We think there's a record of type `sig' at rs->chr. Parse the signature | ||
131 | * and make sure that there's really room for a record of that type. | ||
132 | */ | ||
133 | static int rock_check_overflow(struct rock_state *rs, int sig) | ||
134 | { | ||
135 | int len; | ||
136 | |||
137 | switch (sig) { | ||
138 | case SIG('S', 'P'): | ||
139 | len = sizeof(struct SU_SP_s); | ||
140 | break; | ||
141 | case SIG('C', 'E'): | ||
142 | len = sizeof(struct SU_CE_s); | ||
143 | break; | ||
144 | case SIG('E', 'R'): | ||
145 | len = sizeof(struct SU_ER_s); | ||
146 | break; | ||
147 | case SIG('R', 'R'): | ||
148 | len = sizeof(struct RR_RR_s); | ||
149 | break; | ||
150 | case SIG('P', 'X'): | ||
151 | len = sizeof(struct RR_PX_s); | ||
152 | break; | ||
153 | case SIG('P', 'N'): | ||
154 | len = sizeof(struct RR_PN_s); | ||
155 | break; | ||
156 | case SIG('S', 'L'): | ||
157 | len = sizeof(struct RR_SL_s); | ||
158 | break; | ||
159 | case SIG('N', 'M'): | ||
160 | len = sizeof(struct RR_NM_s); | ||
161 | break; | ||
162 | case SIG('C', 'L'): | ||
163 | len = sizeof(struct RR_CL_s); | ||
164 | break; | ||
165 | case SIG('P', 'L'): | ||
166 | len = sizeof(struct RR_PL_s); | ||
167 | break; | ||
168 | case SIG('T', 'F'): | ||
169 | len = sizeof(struct RR_TF_s); | ||
170 | break; | ||
171 | case SIG('Z', 'F'): | ||
172 | len = sizeof(struct RR_ZF_s); | ||
173 | break; | ||
174 | default: | ||
175 | len = 0; | ||
176 | break; | ||
140 | } | 177 | } |
141 | if((strlen(retname) + rr->len - 5) >= 254) { | 178 | len += offsetof(struct rock_ridge, u); |
142 | truncate = 1; | 179 | if (len > rs->len) { |
143 | break; | 180 | printk(KERN_NOTICE "rock: directory entry would overflow " |
181 | "storage\n"); | ||
182 | printk(KERN_NOTICE "rock: sig=0x%02x, size=%d, remaining=%d\n", | ||
183 | sig, len, rs->len); | ||
184 | return -EIO; | ||
185 | } | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * return length of name field; 0: not found, -1: to be ignored | ||
191 | */ | ||
192 | int get_rock_ridge_filename(struct iso_directory_record *de, | ||
193 | char *retname, struct inode *inode) | ||
194 | { | ||
195 | struct rock_state rs; | ||
196 | struct rock_ridge *rr; | ||
197 | int sig; | ||
198 | int retnamlen = 0; | ||
199 | int truncate = 0; | ||
200 | int ret = 0; | ||
201 | |||
202 | if (!ISOFS_SB(inode->i_sb)->s_rock) | ||
203 | return 0; | ||
204 | *retname = 0; | ||
205 | |||
206 | init_rock_state(&rs, inode); | ||
207 | setup_rock_ridge(de, inode, &rs); | ||
208 | repeat: | ||
209 | |||
210 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ | ||
211 | rr = (struct rock_ridge *)rs.chr; | ||
212 | if (rr->len < 3) | ||
213 | goto out; /* Something got screwed up here */ | ||
214 | sig = isonum_721(rs.chr); | ||
215 | if (rock_check_overflow(&rs, sig)) | ||
216 | goto eio; | ||
217 | rs.chr += rr->len; | ||
218 | rs.len -= rr->len; | ||
219 | if (rs.len < 0) | ||
220 | goto eio; /* corrupted isofs */ | ||
221 | |||
222 | switch (sig) { | ||
223 | case SIG('R', 'R'): | ||
224 | if ((rr->u.RR.flags[0] & RR_NM) == 0) | ||
225 | goto out; | ||
226 | break; | ||
227 | case SIG('S', 'P'): | ||
228 | if (check_sp(rr, inode)) | ||
229 | goto out; | ||
230 | break; | ||
231 | case SIG('C', 'E'): | ||
232 | rs.cont_extent = isonum_733(rr->u.CE.extent); | ||
233 | rs.cont_offset = isonum_733(rr->u.CE.offset); | ||
234 | rs.cont_size = isonum_733(rr->u.CE.size); | ||
235 | break; | ||
236 | case SIG('N', 'M'): | ||
237 | if (truncate) | ||
238 | break; | ||
239 | if (rr->len < 5) | ||
240 | break; | ||
241 | /* | ||
242 | * If the flags are 2 or 4, this indicates '.' or '..'. | ||
243 | * We don't want to do anything with this, because it | ||
244 | * screws up the code that calls us. We don't really | ||
245 | * care anyways, since we can just use the non-RR | ||
246 | * name. | ||
247 | */ | ||
248 | if (rr->u.NM.flags & 6) | ||
249 | break; | ||
250 | |||
251 | if (rr->u.NM.flags & ~1) { | ||
252 | printk("Unsupported NM flag settings (%d)\n", | ||
253 | rr->u.NM.flags); | ||
254 | break; | ||
255 | } | ||
256 | if ((strlen(retname) + rr->len - 5) >= 254) { | ||
257 | truncate = 1; | ||
258 | break; | ||
259 | } | ||
260 | strncat(retname, rr->u.NM.name, rr->len - 5); | ||
261 | retnamlen += rr->len - 5; | ||
262 | break; | ||
263 | case SIG('R', 'E'): | ||
264 | kfree(rs.buffer); | ||
265 | return -1; | ||
266 | default: | ||
267 | break; | ||
268 | } | ||
144 | } | 269 | } |
145 | strncat(retname, rr->u.NM.name, rr->len - 5); | 270 | ret = rock_continue(&rs); |
146 | retnamlen += rr->len - 5; | 271 | if (ret == 0) |
147 | break; | 272 | goto repeat; |
148 | case SIG('R','E'): | 273 | if (ret == 1) |
149 | if (buffer) kfree(buffer); | 274 | return retnamlen; /* If 0, this file did not have a NM field */ |
150 | return -1; | 275 | out: |
151 | default: | 276 | kfree(rs.buffer); |
152 | break; | 277 | return ret; |
153 | } | 278 | eio: |
154 | } | 279 | ret = -EIO; |
155 | } | 280 | goto out; |
156 | MAYBE_CONTINUE(repeat,inode); | ||
157 | if (buffer) kfree(buffer); | ||
158 | return retnamlen; /* If 0, this file did not have a NM field */ | ||
159 | out: | ||
160 | if(buffer) kfree(buffer); | ||
161 | return 0; | ||
162 | } | 281 | } |
163 | 282 | ||
164 | static int | 283 | static int |
165 | parse_rock_ridge_inode_internal(struct iso_directory_record *de, | 284 | parse_rock_ridge_inode_internal(struct iso_directory_record *de, |
166 | struct inode *inode, int regard_xa) | 285 | struct inode *inode, int regard_xa) |
167 | { | 286 | { |
168 | int len; | 287 | int symlink_len = 0; |
169 | unsigned char * chr; | 288 | int cnt, sig; |
170 | int symlink_len = 0; | 289 | struct inode *reloc; |
171 | CONTINUE_DECLS; | 290 | struct rock_ridge *rr; |
172 | 291 | int rootflag; | |
173 | if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; | 292 | struct rock_state rs; |
174 | 293 | int ret = 0; | |
175 | SETUP_ROCK_RIDGE(de, chr, len); | 294 | |
176 | if (regard_xa) | 295 | if (!ISOFS_SB(inode->i_sb)->s_rock) |
177 | { | 296 | return 0; |
178 | chr+=14; | 297 | |
179 | len-=14; | 298 | init_rock_state(&rs, inode); |
180 | if (len<0) len=0; | 299 | setup_rock_ridge(de, inode, &rs); |
181 | } | 300 | if (regard_xa) { |
182 | 301 | rs.chr += 14; | |
183 | repeat: | 302 | rs.len -= 14; |
184 | { | 303 | if (rs.len < 0) |
185 | int cnt, sig; | 304 | rs.len = 0; |
186 | struct inode * reloc; | 305 | } |
187 | struct rock_ridge * rr; | 306 | |
188 | int rootflag; | 307 | repeat: |
189 | 308 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ | |
190 | while (len > 2){ /* There may be one byte for padding somewhere */ | 309 | rr = (struct rock_ridge *)rs.chr; |
191 | rr = (struct rock_ridge *) chr; | 310 | if (rr->len < 3) |
192 | if (rr->len < 3) goto out; /* Something got screwed up here */ | 311 | goto out; /* Something got screwed up here */ |
193 | sig = isonum_721(chr); | 312 | sig = isonum_721(rs.chr); |
194 | chr += rr->len; | 313 | if (rock_check_overflow(&rs, sig)) |
195 | len -= rr->len; | 314 | goto eio; |
196 | if (len < 0) goto out; /* corrupted isofs */ | 315 | rs.chr += rr->len; |
197 | 316 | rs.len -= rr->len; | |
198 | switch(sig){ | 317 | if (rs.len < 0) |
318 | goto eio; /* corrupted isofs */ | ||
319 | |||
320 | switch (sig) { | ||
199 | #ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ | 321 | #ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ |
200 | case SIG('R','R'): | 322 | case SIG('R', 'R'): |
201 | if((rr->u.RR.flags[0] & | 323 | if ((rr->u.RR.flags[0] & |
202 | (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out; | 324 | (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) |
203 | break; | 325 | goto out; |
326 | break; | ||
204 | #endif | 327 | #endif |
205 | case SIG('S','P'): | 328 | case SIG('S', 'P'): |
206 | CHECK_SP(goto out); | 329 | if (check_sp(rr, inode)) |
207 | break; | 330 | goto out; |
208 | case SIG('C','E'): | 331 | break; |
209 | CHECK_CE; | 332 | case SIG('C', 'E'): |
210 | break; | 333 | rs.cont_extent = isonum_733(rr->u.CE.extent); |
211 | case SIG('E','R'): | 334 | rs.cont_offset = isonum_733(rr->u.CE.offset); |
212 | ISOFS_SB(inode->i_sb)->s_rock = 1; | 335 | rs.cont_size = isonum_733(rr->u.CE.size); |
213 | printk(KERN_DEBUG "ISO 9660 Extensions: "); | 336 | break; |
214 | { int p; | 337 | case SIG('E', 'R'): |
215 | for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]); | 338 | ISOFS_SB(inode->i_sb)->s_rock = 1; |
216 | } | 339 | printk(KERN_DEBUG "ISO 9660 Extensions: "); |
217 | printk("\n"); | 340 | { |
218 | break; | 341 | int p; |
219 | case SIG('P','X'): | 342 | for (p = 0; p < rr->u.ER.len_id; p++) |
220 | inode->i_mode = isonum_733(rr->u.PX.mode); | 343 | printk("%c", rr->u.ER.data[p]); |
221 | inode->i_nlink = isonum_733(rr->u.PX.n_links); | 344 | } |
222 | inode->i_uid = isonum_733(rr->u.PX.uid); | 345 | printk("\n"); |
223 | inode->i_gid = isonum_733(rr->u.PX.gid); | 346 | break; |
224 | break; | 347 | case SIG('P', 'X'): |
225 | case SIG('P','N'): | 348 | inode->i_mode = isonum_733(rr->u.PX.mode); |
226 | { int high, low; | 349 | inode->i_nlink = isonum_733(rr->u.PX.n_links); |
227 | high = isonum_733(rr->u.PN.dev_high); | 350 | inode->i_uid = isonum_733(rr->u.PX.uid); |
228 | low = isonum_733(rr->u.PN.dev_low); | 351 | inode->i_gid = isonum_733(rr->u.PX.gid); |
229 | /* | 352 | break; |
230 | * The Rock Ridge standard specifies that if sizeof(dev_t) <= 4, | 353 | case SIG('P', 'N'): |
231 | * then the high field is unused, and the device number is completely | 354 | { |
232 | * stored in the low field. Some writers may ignore this subtlety, | 355 | int high, low; |
233 | * and as a result we test to see if the entire device number is | 356 | high = isonum_733(rr->u.PN.dev_high); |
234 | * stored in the low field, and use that. | 357 | low = isonum_733(rr->u.PN.dev_low); |
235 | */ | 358 | /* |
236 | if((low & ~0xff) && high == 0) { | 359 | * The Rock Ridge standard specifies that if |
237 | inode->i_rdev = MKDEV(low >> 8, low & 0xff); | 360 | * sizeof(dev_t) <= 4, then the high field is |
238 | } else { | 361 | * unused, and the device number is completely |
239 | inode->i_rdev = MKDEV(high, low); | 362 | * stored in the low field. Some writers may |
240 | } | 363 | * ignore this subtlety, |
241 | } | 364 | * and as a result we test to see if the entire |
242 | break; | 365 | * device number is |
243 | case SIG('T','F'): | 366 | * stored in the low field, and use that. |
244 | /* Some RRIP writers incorrectly place ctime in the TF_CREATE field. | 367 | */ |
245 | Try to handle this correctly for either case. */ | 368 | if ((low & ~0xff) && high == 0) { |
246 | cnt = 0; /* Rock ridge never appears on a High Sierra disk */ | 369 | inode->i_rdev = |
247 | if(rr->u.TF.flags & TF_CREATE) { | 370 | MKDEV(low >> 8, low & 0xff); |
248 | inode->i_ctime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); | 371 | } else { |
249 | inode->i_ctime.tv_nsec = 0; | 372 | inode->i_rdev = |
250 | } | 373 | MKDEV(high, low); |
251 | if(rr->u.TF.flags & TF_MODIFY) { | 374 | } |
252 | inode->i_mtime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); | 375 | } |
253 | inode->i_mtime.tv_nsec = 0; | 376 | break; |
254 | } | 377 | case SIG('T', 'F'): |
255 | if(rr->u.TF.flags & TF_ACCESS) { | 378 | /* |
256 | inode->i_atime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); | 379 | * Some RRIP writers incorrectly place ctime in the |
257 | inode->i_atime.tv_nsec = 0; | 380 | * TF_CREATE field. Try to handle this correctly for |
258 | } | 381 | * either case. |
259 | if(rr->u.TF.flags & TF_ATTRIBUTES) { | 382 | */ |
260 | inode->i_ctime.tv_sec = iso_date(rr->u.TF.times[cnt++].time, 0); | 383 | /* Rock ridge never appears on a High Sierra disk */ |
261 | inode->i_ctime.tv_nsec = 0; | 384 | cnt = 0; |
262 | } | 385 | if (rr->u.TF.flags & TF_CREATE) { |
263 | break; | 386 | inode->i_ctime.tv_sec = |
264 | case SIG('S','L'): | 387 | iso_date(rr->u.TF.times[cnt++].time, |
265 | {int slen; | 388 | 0); |
266 | struct SL_component * slp; | 389 | inode->i_ctime.tv_nsec = 0; |
267 | struct SL_component * oldslp; | 390 | } |
268 | slen = rr->len - 5; | 391 | if (rr->u.TF.flags & TF_MODIFY) { |
269 | slp = &rr->u.SL.link; | 392 | inode->i_mtime.tv_sec = |
270 | inode->i_size = symlink_len; | 393 | iso_date(rr->u.TF.times[cnt++].time, |
271 | while (slen > 1){ | 394 | 0); |
272 | rootflag = 0; | 395 | inode->i_mtime.tv_nsec = 0; |
273 | switch(slp->flags &~1){ | 396 | } |
274 | case 0: | 397 | if (rr->u.TF.flags & TF_ACCESS) { |
275 | inode->i_size += slp->len; | 398 | inode->i_atime.tv_sec = |
276 | break; | 399 | iso_date(rr->u.TF.times[cnt++].time, |
277 | case 2: | 400 | 0); |
278 | inode->i_size += 1; | 401 | inode->i_atime.tv_nsec = 0; |
279 | break; | 402 | } |
280 | case 4: | 403 | if (rr->u.TF.flags & TF_ATTRIBUTES) { |
281 | inode->i_size += 2; | 404 | inode->i_ctime.tv_sec = |
282 | break; | 405 | iso_date(rr->u.TF.times[cnt++].time, |
283 | case 8: | 406 | 0); |
284 | rootflag = 1; | 407 | inode->i_ctime.tv_nsec = 0; |
285 | inode->i_size += 1; | 408 | } |
286 | break; | 409 | break; |
287 | default: | 410 | case SIG('S', 'L'): |
288 | printk("Symlink component flag not implemented\n"); | 411 | { |
289 | } | 412 | int slen; |
290 | slen -= slp->len + 2; | 413 | struct SL_component *slp; |
291 | oldslp = slp; | 414 | struct SL_component *oldslp; |
292 | slp = (struct SL_component *) (((char *) slp) + slp->len + 2); | 415 | slen = rr->len - 5; |
293 | 416 | slp = &rr->u.SL.link; | |
294 | if(slen < 2) { | 417 | inode->i_size = symlink_len; |
295 | if( ((rr->u.SL.flags & 1) != 0) | 418 | while (slen > 1) { |
296 | && ((oldslp->flags & 1) == 0) ) inode->i_size += 1; | 419 | rootflag = 0; |
297 | break; | 420 | switch (slp->flags & ~1) { |
298 | } | 421 | case 0: |
299 | 422 | inode->i_size += | |
300 | /* | 423 | slp->len; |
301 | * If this component record isn't continued, then append a '/'. | 424 | break; |
302 | */ | 425 | case 2: |
303 | if (!rootflag && (oldslp->flags & 1) == 0) | 426 | inode->i_size += 1; |
304 | inode->i_size += 1; | 427 | break; |
305 | } | 428 | case 4: |
306 | } | 429 | inode->i_size += 2; |
307 | symlink_len = inode->i_size; | 430 | break; |
308 | break; | 431 | case 8: |
309 | case SIG('R','E'): | 432 | rootflag = 1; |
310 | printk(KERN_WARNING "Attempt to read inode for relocated directory\n"); | 433 | inode->i_size += 1; |
311 | goto out; | 434 | break; |
312 | case SIG('C','L'): | 435 | default: |
313 | ISOFS_I(inode)->i_first_extent = isonum_733(rr->u.CL.location); | 436 | printk("Symlink component flag " |
314 | reloc = isofs_iget(inode->i_sb, ISOFS_I(inode)->i_first_extent, 0); | 437 | "not implemented\n"); |
315 | if (!reloc) | 438 | } |
316 | goto out; | 439 | slen -= slp->len + 2; |
317 | inode->i_mode = reloc->i_mode; | 440 | oldslp = slp; |
318 | inode->i_nlink = reloc->i_nlink; | 441 | slp = (struct SL_component *) |
319 | inode->i_uid = reloc->i_uid; | 442 | (((char *)slp) + slp->len + 2); |
320 | inode->i_gid = reloc->i_gid; | 443 | |
321 | inode->i_rdev = reloc->i_rdev; | 444 | if (slen < 2) { |
322 | inode->i_size = reloc->i_size; | 445 | if (((rr->u.SL. |
323 | inode->i_blocks = reloc->i_blocks; | 446 | flags & 1) != 0) |
324 | inode->i_atime = reloc->i_atime; | 447 | && |
325 | inode->i_ctime = reloc->i_ctime; | 448 | ((oldslp-> |
326 | inode->i_mtime = reloc->i_mtime; | 449 | flags & 1) == 0)) |
327 | iput(reloc); | 450 | inode->i_size += |
328 | break; | 451 | 1; |
452 | break; | ||
453 | } | ||
454 | |||
455 | /* | ||
456 | * If this component record isn't | ||
457 | * continued, then append a '/'. | ||
458 | */ | ||
459 | if (!rootflag | ||
460 | && (oldslp->flags & 1) == 0) | ||
461 | inode->i_size += 1; | ||
462 | } | ||
463 | } | ||
464 | symlink_len = inode->i_size; | ||
465 | break; | ||
466 | case SIG('R', 'E'): | ||
467 | printk(KERN_WARNING "Attempt to read inode for " | ||
468 | "relocated directory\n"); | ||
469 | goto out; | ||
470 | case SIG('C', 'L'): | ||
471 | ISOFS_I(inode)->i_first_extent = | ||
472 | isonum_733(rr->u.CL.location); | ||
473 | reloc = | ||
474 | isofs_iget(inode->i_sb, | ||
475 | ISOFS_I(inode)->i_first_extent, | ||
476 | 0); | ||
477 | if (!reloc) | ||
478 | goto out; | ||
479 | inode->i_mode = reloc->i_mode; | ||
480 | inode->i_nlink = reloc->i_nlink; | ||
481 | inode->i_uid = reloc->i_uid; | ||
482 | inode->i_gid = reloc->i_gid; | ||
483 | inode->i_rdev = reloc->i_rdev; | ||
484 | inode->i_size = reloc->i_size; | ||
485 | inode->i_blocks = reloc->i_blocks; | ||
486 | inode->i_atime = reloc->i_atime; | ||
487 | inode->i_ctime = reloc->i_ctime; | ||
488 | inode->i_mtime = reloc->i_mtime; | ||
489 | iput(reloc); | ||
490 | break; | ||
329 | #ifdef CONFIG_ZISOFS | 491 | #ifdef CONFIG_ZISOFS |
330 | case SIG('Z','F'): | 492 | case SIG('Z', 'F'): { |
331 | if ( !ISOFS_SB(inode->i_sb)->s_nocompress ) { | 493 | int algo; |
332 | int algo; | 494 | |
333 | algo = isonum_721(rr->u.ZF.algorithm); | 495 | if (ISOFS_SB(inode->i_sb)->s_nocompress) |
334 | if ( algo == SIG('p','z') ) { | 496 | break; |
335 | int block_shift = isonum_711(&rr->u.ZF.parms[1]); | 497 | algo = isonum_721(rr->u.ZF.algorithm); |
336 | if ( block_shift < PAGE_CACHE_SHIFT || block_shift > 17 ) { | 498 | if (algo == SIG('p', 'z')) { |
337 | printk(KERN_WARNING "isofs: Can't handle ZF block size of 2^%d\n", block_shift); | 499 | int block_shift = |
338 | } else { | 500 | isonum_711(&rr->u.ZF.parms[1]); |
339 | /* Note: we don't change i_blocks here */ | 501 | if (block_shift < PAGE_CACHE_SHIFT |
340 | ISOFS_I(inode)->i_file_format = isofs_file_compressed; | 502 | || block_shift > 17) { |
341 | /* Parameters to compression algorithm (header size, block size) */ | 503 | printk(KERN_WARNING "isofs: " |
342 | ISOFS_I(inode)->i_format_parm[0] = isonum_711(&rr->u.ZF.parms[0]); | 504 | "Can't handle ZF block " |
343 | ISOFS_I(inode)->i_format_parm[1] = isonum_711(&rr->u.ZF.parms[1]); | 505 | "size of 2^%d\n", |
344 | inode->i_size = isonum_733(rr->u.ZF.real_size); | 506 | block_shift); |
345 | } | 507 | } else { |
346 | } else { | 508 | /* |
347 | printk(KERN_WARNING "isofs: Unknown ZF compression algorithm: %c%c\n", | 509 | * Note: we don't change |
348 | rr->u.ZF.algorithm[0], rr->u.ZF.algorithm[1]); | 510 | * i_blocks here |
349 | } | 511 | */ |
350 | } | 512 | ISOFS_I(inode)->i_file_format = |
351 | break; | 513 | isofs_file_compressed; |
514 | /* | ||
515 | * Parameters to compression | ||
516 | * algorithm (header size, | ||
517 | * block size) | ||
518 | */ | ||
519 | ISOFS_I(inode)->i_format_parm[0] = | ||
520 | isonum_711(&rr->u.ZF.parms[0]); | ||
521 | ISOFS_I(inode)->i_format_parm[1] = | ||
522 | isonum_711(&rr->u.ZF.parms[1]); | ||
523 | inode->i_size = | ||
524 | isonum_733(rr->u.ZF. | ||
525 | real_size); | ||
526 | } | ||
527 | } else { | ||
528 | printk(KERN_WARNING | ||
529 | "isofs: Unknown ZF compression " | ||
530 | "algorithm: %c%c\n", | ||
531 | rr->u.ZF.algorithm[0], | ||
532 | rr->u.ZF.algorithm[1]); | ||
533 | } | ||
534 | break; | ||
535 | } | ||
352 | #endif | 536 | #endif |
353 | default: | 537 | default: |
354 | break; | 538 | break; |
355 | } | 539 | } |
356 | } | 540 | } |
357 | } | 541 | ret = rock_continue(&rs); |
358 | MAYBE_CONTINUE(repeat,inode); | 542 | if (ret == 0) |
359 | out: | 543 | goto repeat; |
360 | if(buffer) kfree(buffer); | 544 | if (ret == 1) |
361 | return 0; | 545 | ret = 0; |
546 | out: | ||
547 | kfree(rs.buffer); | ||
548 | return ret; | ||
549 | eio: | ||
550 | ret = -EIO; | ||
551 | goto out; | ||
362 | } | 552 | } |
363 | 553 | ||
364 | static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) | 554 | static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) |
@@ -376,32 +566,32 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) | |||
376 | if (slp->len > plimit - rpnt) | 566 | if (slp->len > plimit - rpnt) |
377 | return NULL; | 567 | return NULL; |
378 | memcpy(rpnt, slp->text, slp->len); | 568 | memcpy(rpnt, slp->text, slp->len); |
379 | rpnt+=slp->len; | 569 | rpnt += slp->len; |
380 | break; | 570 | break; |
381 | case 2: | 571 | case 2: |
382 | if (rpnt >= plimit) | 572 | if (rpnt >= plimit) |
383 | return NULL; | 573 | return NULL; |
384 | *rpnt++='.'; | 574 | *rpnt++ = '.'; |
385 | break; | 575 | break; |
386 | case 4: | 576 | case 4: |
387 | if (2 > plimit - rpnt) | 577 | if (2 > plimit - rpnt) |
388 | return NULL; | 578 | return NULL; |
389 | *rpnt++='.'; | 579 | *rpnt++ = '.'; |
390 | *rpnt++='.'; | 580 | *rpnt++ = '.'; |
391 | break; | 581 | break; |
392 | case 8: | 582 | case 8: |
393 | if (rpnt >= plimit) | 583 | if (rpnt >= plimit) |
394 | return NULL; | 584 | return NULL; |
395 | rootflag = 1; | 585 | rootflag = 1; |
396 | *rpnt++='/'; | 586 | *rpnt++ = '/'; |
397 | break; | 587 | break; |
398 | default: | 588 | default: |
399 | printk("Symlink component flag not implemented (%d)\n", | 589 | printk("Symlink component flag not implemented (%d)\n", |
400 | slp->flags); | 590 | slp->flags); |
401 | } | 591 | } |
402 | slen -= slp->len + 2; | 592 | slen -= slp->len + 2; |
403 | oldslp = slp; | 593 | oldslp = slp; |
404 | slp = (struct SL_component *) ((char *) slp + slp->len + 2); | 594 | slp = (struct SL_component *)((char *)slp + slp->len + 2); |
405 | 595 | ||
406 | if (slen < 2) { | 596 | if (slen < 2) { |
407 | /* | 597 | /* |
@@ -412,7 +602,7 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) | |||
412 | !(oldslp->flags & 1)) { | 602 | !(oldslp->flags & 1)) { |
413 | if (rpnt >= plimit) | 603 | if (rpnt >= plimit) |
414 | return NULL; | 604 | return NULL; |
415 | *rpnt++='/'; | 605 | *rpnt++ = '/'; |
416 | } | 606 | } |
417 | break; | 607 | break; |
418 | } | 608 | } |
@@ -423,59 +613,61 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) | |||
423 | if (!rootflag && !(oldslp->flags & 1)) { | 613 | if (!rootflag && !(oldslp->flags & 1)) { |
424 | if (rpnt >= plimit) | 614 | if (rpnt >= plimit) |
425 | return NULL; | 615 | return NULL; |
426 | *rpnt++='/'; | 616 | *rpnt++ = '/'; |
427 | } | 617 | } |
428 | } | 618 | } |
429 | return rpnt; | 619 | return rpnt; |
430 | } | 620 | } |
431 | 621 | ||
432 | int parse_rock_ridge_inode(struct iso_directory_record * de, | 622 | int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode) |
433 | struct inode * inode) | ||
434 | { | 623 | { |
435 | int result=parse_rock_ridge_inode_internal(de,inode,0); | 624 | int result = parse_rock_ridge_inode_internal(de, inode, 0); |
436 | /* if rockridge flag was reset and we didn't look for attributes | ||
437 | * behind eventual XA attributes, have a look there */ | ||
438 | if ((ISOFS_SB(inode->i_sb)->s_rock_offset==-1) | ||
439 | &&(ISOFS_SB(inode->i_sb)->s_rock==2)) | ||
440 | { | ||
441 | result=parse_rock_ridge_inode_internal(de,inode,14); | ||
442 | } | ||
443 | return result; | ||
444 | } | ||
445 | 625 | ||
446 | /* readpage() for symlinks: reads symlink contents into the page and either | 626 | /* |
447 | makes it uptodate and returns 0 or returns error (-EIO) */ | 627 | * if rockridge flag was reset and we didn't look for attributes |
628 | * behind eventual XA attributes, have a look there | ||
629 | */ | ||
630 | if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1) | ||
631 | && (ISOFS_SB(inode->i_sb)->s_rock == 2)) { | ||
632 | result = parse_rock_ridge_inode_internal(de, inode, 14); | ||
633 | } | ||
634 | return result; | ||
635 | } | ||
448 | 636 | ||
637 | /* | ||
638 | * readpage() for symlinks: reads symlink contents into the page and either | ||
639 | * makes it uptodate and returns 0 or returns error (-EIO) | ||
640 | */ | ||
449 | static int rock_ridge_symlink_readpage(struct file *file, struct page *page) | 641 | static int rock_ridge_symlink_readpage(struct file *file, struct page *page) |
450 | { | 642 | { |
451 | struct inode *inode = page->mapping->host; | 643 | struct inode *inode = page->mapping->host; |
452 | struct iso_inode_info *ei = ISOFS_I(inode); | 644 | struct iso_inode_info *ei = ISOFS_I(inode); |
453 | char *link = kmap(page); | 645 | char *link = kmap(page); |
454 | unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); | 646 | unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); |
455 | struct buffer_head *bh; | 647 | struct buffer_head *bh; |
456 | char *rpnt = link; | 648 | char *rpnt = link; |
457 | unsigned char *pnt; | 649 | unsigned char *pnt; |
458 | struct iso_directory_record *raw_inode; | 650 | struct iso_directory_record *raw_de; |
459 | CONTINUE_DECLS; | ||
460 | unsigned long block, offset; | 651 | unsigned long block, offset; |
461 | int sig; | 652 | int sig; |
462 | int len; | ||
463 | unsigned char *chr; | ||
464 | struct rock_ridge *rr; | 653 | struct rock_ridge *rr; |
654 | struct rock_state rs; | ||
655 | int ret; | ||
465 | 656 | ||
466 | if (!ISOFS_SB(inode->i_sb)->s_rock) | 657 | if (!ISOFS_SB(inode->i_sb)->s_rock) |
467 | goto error; | 658 | goto error; |
468 | 659 | ||
660 | init_rock_state(&rs, inode); | ||
469 | block = ei->i_iget5_block; | 661 | block = ei->i_iget5_block; |
470 | lock_kernel(); | 662 | lock_kernel(); |
471 | bh = sb_bread(inode->i_sb, block); | 663 | bh = sb_bread(inode->i_sb, block); |
472 | if (!bh) | 664 | if (!bh) |
473 | goto out_noread; | 665 | goto out_noread; |
474 | 666 | ||
475 | offset = ei->i_iget5_offset; | 667 | offset = ei->i_iget5_offset; |
476 | pnt = (unsigned char *) bh->b_data + offset; | 668 | pnt = (unsigned char *)bh->b_data + offset; |
477 | 669 | ||
478 | raw_inode = (struct iso_directory_record *) pnt; | 670 | raw_de = (struct iso_directory_record *)pnt; |
479 | 671 | ||
480 | /* | 672 | /* |
481 | * If we go past the end of the buffer, there is some sort of error. | 673 | * If we go past the end of the buffer, there is some sort of error. |
@@ -483,20 +675,24 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) | |||
483 | if (offset + *pnt > bufsize) | 675 | if (offset + *pnt > bufsize) |
484 | goto out_bad_span; | 676 | goto out_bad_span; |
485 | 677 | ||
486 | /* Now test for possible Rock Ridge extensions which will override | 678 | /* |
487 | some of these numbers in the inode structure. */ | 679 | * Now test for possible Rock Ridge extensions which will override |
680 | * some of these numbers in the inode structure. | ||
681 | */ | ||
488 | 682 | ||
489 | SETUP_ROCK_RIDGE(raw_inode, chr, len); | 683 | setup_rock_ridge(raw_de, inode, &rs); |
490 | 684 | ||
491 | repeat: | 685 | repeat: |
492 | while (len > 2) { /* There may be one byte for padding somewhere */ | 686 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ |
493 | rr = (struct rock_ridge *) chr; | 687 | rr = (struct rock_ridge *)rs.chr; |
494 | if (rr->len < 3) | 688 | if (rr->len < 3) |
495 | goto out; /* Something got screwed up here */ | 689 | goto out; /* Something got screwed up here */ |
496 | sig = isonum_721(chr); | 690 | sig = isonum_721(rs.chr); |
497 | chr += rr->len; | 691 | if (rock_check_overflow(&rs, sig)) |
498 | len -= rr->len; | 692 | goto out; |
499 | if (len < 0) | 693 | rs.chr += rr->len; |
694 | rs.len -= rr->len; | ||
695 | if (rs.len < 0) | ||
500 | goto out; /* corrupted isofs */ | 696 | goto out; /* corrupted isofs */ |
501 | 697 | ||
502 | switch (sig) { | 698 | switch (sig) { |
@@ -505,7 +701,8 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) | |||
505 | goto out; | 701 | goto out; |
506 | break; | 702 | break; |
507 | case SIG('S', 'P'): | 703 | case SIG('S', 'P'): |
508 | CHECK_SP(goto out); | 704 | if (check_sp(rr, inode)) |
705 | goto out; | ||
509 | break; | 706 | break; |
510 | case SIG('S', 'L'): | 707 | case SIG('S', 'L'): |
511 | rpnt = get_symlink_chunk(rpnt, rr, | 708 | rpnt = get_symlink_chunk(rpnt, rr, |
@@ -515,14 +712,18 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) | |||
515 | break; | 712 | break; |
516 | case SIG('C', 'E'): | 713 | case SIG('C', 'E'): |
517 | /* This tells is if there is a continuation record */ | 714 | /* This tells is if there is a continuation record */ |
518 | CHECK_CE; | 715 | rs.cont_extent = isonum_733(rr->u.CE.extent); |
716 | rs.cont_offset = isonum_733(rr->u.CE.offset); | ||
717 | rs.cont_size = isonum_733(rr->u.CE.size); | ||
519 | default: | 718 | default: |
520 | break; | 719 | break; |
521 | } | 720 | } |
522 | } | 721 | } |
523 | MAYBE_CONTINUE(repeat, inode); | 722 | ret = rock_continue(&rs); |
524 | if (buffer) | 723 | if (ret == 0) |
525 | kfree(buffer); | 724 | goto repeat; |
725 | if (ret < 0) | ||
726 | goto fail; | ||
526 | 727 | ||
527 | if (rpnt == link) | 728 | if (rpnt == link) |
528 | goto fail; | 729 | goto fail; |
@@ -535,19 +736,18 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) | |||
535 | return 0; | 736 | return 0; |
536 | 737 | ||
537 | /* error exit from macro */ | 738 | /* error exit from macro */ |
538 | out: | 739 | out: |
539 | if (buffer) | 740 | kfree(rs.buffer); |
540 | kfree(buffer); | ||
541 | goto fail; | 741 | goto fail; |
542 | out_noread: | 742 | out_noread: |
543 | printk("unable to read i-node block"); | 743 | printk("unable to read i-node block"); |
544 | goto fail; | 744 | goto fail; |
545 | out_bad_span: | 745 | out_bad_span: |
546 | printk("symlink spans iso9660 blocks\n"); | 746 | printk("symlink spans iso9660 blocks\n"); |
547 | fail: | 747 | fail: |
548 | brelse(bh); | 748 | brelse(bh); |
549 | unlock_kernel(); | 749 | unlock_kernel(); |
550 | error: | 750 | error: |
551 | SetPageError(page); | 751 | SetPageError(page); |
552 | kunmap(page); | 752 | kunmap(page); |
553 | unlock_page(page); | 753 | unlock_page(page); |
@@ -555,5 +755,5 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) | |||
555 | } | 755 | } |
556 | 756 | ||
557 | struct address_space_operations isofs_symlink_aops = { | 757 | struct address_space_operations isofs_symlink_aops = { |
558 | .readpage = rock_ridge_symlink_readpage | 758 | .readpage = rock_ridge_symlink_readpage |
559 | }; | 759 | }; |
diff --git a/fs/isofs/rock.h b/fs/isofs/rock.h index deaf5c8e8b4a..ed09e2b08637 100644 --- a/fs/isofs/rock.h +++ b/fs/isofs/rock.h | |||
@@ -1,85 +1,88 @@ | |||
1 | /* These structs are used by the system-use-sharing protocol, in which the | 1 | /* |
2 | Rock Ridge extensions are embedded. It is quite possible that other | 2 | * These structs are used by the system-use-sharing protocol, in which the |
3 | extensions are present on the disk, and this is fine as long as they | 3 | * Rock Ridge extensions are embedded. It is quite possible that other |
4 | all use SUSP */ | 4 | * extensions are present on the disk, and this is fine as long as they |
5 | 5 | * all use SUSP | |
6 | struct SU_SP{ | 6 | */ |
7 | unsigned char magic[2]; | 7 | |
8 | unsigned char skip; | 8 | struct SU_SP_s { |
9 | } __attribute__((packed)); | 9 | unsigned char magic[2]; |
10 | 10 | unsigned char skip; | |
11 | struct SU_CE{ | 11 | } __attribute__ ((packed)); |
12 | char extent[8]; | 12 | |
13 | char offset[8]; | 13 | struct SU_CE_s { |
14 | char size[8]; | 14 | char extent[8]; |
15 | char offset[8]; | ||
16 | char size[8]; | ||
15 | }; | 17 | }; |
16 | 18 | ||
17 | struct SU_ER{ | 19 | struct SU_ER_s { |
18 | unsigned char len_id; | 20 | unsigned char len_id; |
19 | unsigned char len_des; | 21 | unsigned char len_des; |
20 | unsigned char len_src; | 22 | unsigned char len_src; |
21 | unsigned char ext_ver; | 23 | unsigned char ext_ver; |
22 | char data[0]; | 24 | char data[0]; |
23 | } __attribute__((packed)); | 25 | } __attribute__ ((packed)); |
24 | 26 | ||
25 | struct RR_RR{ | 27 | struct RR_RR_s { |
26 | char flags[1]; | 28 | char flags[1]; |
27 | } __attribute__((packed)); | 29 | } __attribute__ ((packed)); |
28 | 30 | ||
29 | struct RR_PX{ | 31 | struct RR_PX_s { |
30 | char mode[8]; | 32 | char mode[8]; |
31 | char n_links[8]; | 33 | char n_links[8]; |
32 | char uid[8]; | 34 | char uid[8]; |
33 | char gid[8]; | 35 | char gid[8]; |
34 | }; | 36 | }; |
35 | 37 | ||
36 | struct RR_PN{ | 38 | struct RR_PN_s { |
37 | char dev_high[8]; | 39 | char dev_high[8]; |
38 | char dev_low[8]; | 40 | char dev_low[8]; |
39 | }; | 41 | }; |
40 | 42 | ||
43 | struct SL_component { | ||
44 | unsigned char flags; | ||
45 | unsigned char len; | ||
46 | char text[0]; | ||
47 | } __attribute__ ((packed)); | ||
41 | 48 | ||
42 | struct SL_component{ | 49 | struct RR_SL_s { |
43 | unsigned char flags; | 50 | unsigned char flags; |
44 | unsigned char len; | 51 | struct SL_component link; |
45 | char text[0]; | 52 | } __attribute__ ((packed)); |
46 | } __attribute__((packed)); | ||
47 | 53 | ||
48 | struct RR_SL{ | 54 | struct RR_NM_s { |
49 | unsigned char flags; | 55 | unsigned char flags; |
50 | struct SL_component link; | 56 | char name[0]; |
51 | } __attribute__((packed)); | 57 | } __attribute__ ((packed)); |
52 | 58 | ||
53 | struct RR_NM{ | 59 | struct RR_CL_s { |
54 | unsigned char flags; | 60 | char location[8]; |
55 | char name[0]; | ||
56 | } __attribute__((packed)); | ||
57 | |||
58 | struct RR_CL{ | ||
59 | char location[8]; | ||
60 | }; | 61 | }; |
61 | 62 | ||
62 | struct RR_PL{ | 63 | struct RR_PL_s { |
63 | char location[8]; | 64 | char location[8]; |
64 | }; | 65 | }; |
65 | 66 | ||
66 | struct stamp{ | 67 | struct stamp { |
67 | char time[7]; | 68 | char time[7]; |
68 | } __attribute__((packed)); | 69 | } __attribute__ ((packed)); |
69 | 70 | ||
70 | struct RR_TF{ | 71 | struct RR_TF_s { |
71 | char flags; | 72 | char flags; |
72 | struct stamp times[0]; /* Variable number of these beasts */ | 73 | struct stamp times[0]; /* Variable number of these beasts */ |
73 | } __attribute__((packed)); | 74 | } __attribute__ ((packed)); |
74 | 75 | ||
75 | /* Linux-specific extension for transparent decompression */ | 76 | /* Linux-specific extension for transparent decompression */ |
76 | struct RR_ZF{ | 77 | struct RR_ZF_s { |
77 | char algorithm[2]; | 78 | char algorithm[2]; |
78 | char parms[2]; | 79 | char parms[2]; |
79 | char real_size[8]; | 80 | char real_size[8]; |
80 | }; | 81 | }; |
81 | 82 | ||
82 | /* These are the bits and their meanings for flags in the TF structure. */ | 83 | /* |
84 | * These are the bits and their meanings for flags in the TF structure. | ||
85 | */ | ||
83 | #define TF_CREATE 1 | 86 | #define TF_CREATE 1 |
84 | #define TF_MODIFY 2 | 87 | #define TF_MODIFY 2 |
85 | #define TF_ACCESS 4 | 88 | #define TF_ACCESS 4 |
@@ -89,31 +92,31 @@ struct RR_ZF{ | |||
89 | #define TF_EFFECTIVE 64 | 92 | #define TF_EFFECTIVE 64 |
90 | #define TF_LONG_FORM 128 | 93 | #define TF_LONG_FORM 128 |
91 | 94 | ||
92 | struct rock_ridge{ | 95 | struct rock_ridge { |
93 | char signature[2]; | 96 | char signature[2]; |
94 | unsigned char len; | 97 | unsigned char len; |
95 | unsigned char version; | 98 | unsigned char version; |
96 | union{ | 99 | union { |
97 | struct SU_SP SP; | 100 | struct SU_SP_s SP; |
98 | struct SU_CE CE; | 101 | struct SU_CE_s CE; |
99 | struct SU_ER ER; | 102 | struct SU_ER_s ER; |
100 | struct RR_RR RR; | 103 | struct RR_RR_s RR; |
101 | struct RR_PX PX; | 104 | struct RR_PX_s PX; |
102 | struct RR_PN PN; | 105 | struct RR_PN_s PN; |
103 | struct RR_SL SL; | 106 | struct RR_SL_s SL; |
104 | struct RR_NM NM; | 107 | struct RR_NM_s NM; |
105 | struct RR_CL CL; | 108 | struct RR_CL_s CL; |
106 | struct RR_PL PL; | 109 | struct RR_PL_s PL; |
107 | struct RR_TF TF; | 110 | struct RR_TF_s TF; |
108 | struct RR_ZF ZF; | 111 | struct RR_ZF_s ZF; |
109 | } u; | 112 | } u; |
110 | }; | 113 | }; |
111 | 114 | ||
112 | #define RR_PX 1 /* POSIX attributes */ | 115 | #define RR_PX 1 /* POSIX attributes */ |
113 | #define RR_PN 2 /* POSIX devices */ | 116 | #define RR_PN 2 /* POSIX devices */ |
114 | #define RR_SL 4 /* Symbolic link */ | 117 | #define RR_SL 4 /* Symbolic link */ |
115 | #define RR_NM 8 /* Alternate Name */ | 118 | #define RR_NM 8 /* Alternate Name */ |
116 | #define RR_CL 16 /* Child link */ | 119 | #define RR_CL 16 /* Child link */ |
117 | #define RR_PL 32 /* Parent link */ | 120 | #define RR_PL 32 /* Parent link */ |
118 | #define RR_RE 64 /* Relocation directory */ | 121 | #define RR_RE 64 /* Relocation directory */ |
119 | #define RR_TF 128 /* Timestamps */ | 122 | #define RR_TF 128 /* Timestamps */ |
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 98d830401c56..5a97e346bd95 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c | |||
@@ -188,7 +188,6 @@ static int __cleanup_transaction(journal_t *journal, transaction_t *transaction) | |||
188 | } else { | 188 | } else { |
189 | jbd_unlock_bh_state(bh); | 189 | jbd_unlock_bh_state(bh); |
190 | } | 190 | } |
191 | jh = next_jh; | ||
192 | } while (jh != last_jh); | 191 | } while (jh != last_jh); |
193 | 192 | ||
194 | return ret; | 193 | return ret; |
@@ -339,8 +338,10 @@ int log_do_checkpoint(journal_t *journal) | |||
339 | } | 338 | } |
340 | } while (jh != last_jh && !retry); | 339 | } while (jh != last_jh && !retry); |
341 | 340 | ||
342 | if (batch_count) | 341 | if (batch_count) { |
343 | __flush_batch(journal, bhs, &batch_count); | 342 | __flush_batch(journal, bhs, &batch_count); |
343 | retry = 1; | ||
344 | } | ||
344 | 345 | ||
345 | /* | 346 | /* |
346 | * If someone cleaned up this transaction while we slept, we're | 347 | * If someone cleaned up this transaction while we slept, we're |
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 1e6f2e2ad4a3..5e7b43949517 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c | |||
@@ -167,7 +167,7 @@ loop: | |||
167 | } | 167 | } |
168 | 168 | ||
169 | wake_up(&journal->j_wait_done_commit); | 169 | wake_up(&journal->j_wait_done_commit); |
170 | if (current->flags & PF_FREEZE) { | 170 | if (freezing(current)) { |
171 | /* | 171 | /* |
172 | * The simpler the better. Flushing journal isn't a | 172 | * The simpler the better. Flushing journal isn't a |
173 | * good idea, because that depends on threads that may | 173 | * good idea, because that depends on threads that may |
@@ -175,7 +175,7 @@ loop: | |||
175 | */ | 175 | */ |
176 | jbd_debug(1, "Now suspending kjournald\n"); | 176 | jbd_debug(1, "Now suspending kjournald\n"); |
177 | spin_unlock(&journal->j_state_lock); | 177 | spin_unlock(&journal->j_state_lock); |
178 | refrigerator(PF_FREEZE); | 178 | refrigerator(); |
179 | spin_lock(&journal->j_state_lock); | 179 | spin_lock(&journal->j_state_lock); |
180 | } else { | 180 | } else { |
181 | /* | 181 | /* |
diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c index 8cc6893fc56c..fc589ddd0762 100644 --- a/fs/jffs/intrep.c +++ b/fs/jffs/intrep.c | |||
@@ -175,8 +175,64 @@ jffs_hexdump(struct mtd_info *mtd, loff_t pos, int size) | |||
175 | } | 175 | } |
176 | } | 176 | } |
177 | 177 | ||
178 | /* Print the contents of a node. */ | ||
179 | static void | ||
180 | jffs_print_node(struct jffs_node *n) | ||
181 | { | ||
182 | D(printk("jffs_node: 0x%p\n", n)); | ||
183 | D(printk("{\n")); | ||
184 | D(printk(" 0x%08x, /* version */\n", n->version)); | ||
185 | D(printk(" 0x%08x, /* data_offset */\n", n->data_offset)); | ||
186 | D(printk(" 0x%08x, /* data_size */\n", n->data_size)); | ||
187 | D(printk(" 0x%08x, /* removed_size */\n", n->removed_size)); | ||
188 | D(printk(" 0x%08x, /* fm_offset */\n", n->fm_offset)); | ||
189 | D(printk(" 0x%02x, /* name_size */\n", n->name_size)); | ||
190 | D(printk(" 0x%p, /* fm, fm->offset: %u */\n", | ||
191 | n->fm, (n->fm ? n->fm->offset : 0))); | ||
192 | D(printk(" 0x%p, /* version_prev */\n", n->version_prev)); | ||
193 | D(printk(" 0x%p, /* version_next */\n", n->version_next)); | ||
194 | D(printk(" 0x%p, /* range_prev */\n", n->range_prev)); | ||
195 | D(printk(" 0x%p, /* range_next */\n", n->range_next)); | ||
196 | D(printk("}\n")); | ||
197 | } | ||
198 | |||
178 | #endif | 199 | #endif |
179 | 200 | ||
201 | /* Print the contents of a raw inode. */ | ||
202 | static void | ||
203 | jffs_print_raw_inode(struct jffs_raw_inode *raw_inode) | ||
204 | { | ||
205 | D(printk("jffs_raw_inode: inode number: %u\n", raw_inode->ino)); | ||
206 | D(printk("{\n")); | ||
207 | D(printk(" 0x%08x, /* magic */\n", raw_inode->magic)); | ||
208 | D(printk(" 0x%08x, /* ino */\n", raw_inode->ino)); | ||
209 | D(printk(" 0x%08x, /* pino */\n", raw_inode->pino)); | ||
210 | D(printk(" 0x%08x, /* version */\n", raw_inode->version)); | ||
211 | D(printk(" 0x%08x, /* mode */\n", raw_inode->mode)); | ||
212 | D(printk(" 0x%04x, /* uid */\n", raw_inode->uid)); | ||
213 | D(printk(" 0x%04x, /* gid */\n", raw_inode->gid)); | ||
214 | D(printk(" 0x%08x, /* atime */\n", raw_inode->atime)); | ||
215 | D(printk(" 0x%08x, /* mtime */\n", raw_inode->mtime)); | ||
216 | D(printk(" 0x%08x, /* ctime */\n", raw_inode->ctime)); | ||
217 | D(printk(" 0x%08x, /* offset */\n", raw_inode->offset)); | ||
218 | D(printk(" 0x%08x, /* dsize */\n", raw_inode->dsize)); | ||
219 | D(printk(" 0x%08x, /* rsize */\n", raw_inode->rsize)); | ||
220 | D(printk(" 0x%02x, /* nsize */\n", raw_inode->nsize)); | ||
221 | D(printk(" 0x%02x, /* nlink */\n", raw_inode->nlink)); | ||
222 | D(printk(" 0x%02x, /* spare */\n", | ||
223 | raw_inode->spare)); | ||
224 | D(printk(" %u, /* rename */\n", | ||
225 | raw_inode->rename)); | ||
226 | D(printk(" %u, /* deleted */\n", | ||
227 | raw_inode->deleted)); | ||
228 | D(printk(" 0x%02x, /* accurate */\n", | ||
229 | raw_inode->accurate)); | ||
230 | D(printk(" 0x%08x, /* dchksum */\n", raw_inode->dchksum)); | ||
231 | D(printk(" 0x%04x, /* nchksum */\n", raw_inode->nchksum)); | ||
232 | D(printk(" 0x%04x, /* chksum */\n", raw_inode->chksum)); | ||
233 | D(printk("}\n")); | ||
234 | } | ||
235 | |||
180 | #define flash_safe_acquire(arg) | 236 | #define flash_safe_acquire(arg) |
181 | #define flash_safe_release(arg) | 237 | #define flash_safe_release(arg) |
182 | 238 | ||
@@ -2507,64 +2563,6 @@ jffs_update_file(struct jffs_file *f, struct jffs_node *node) | |||
2507 | return 0; | 2563 | return 0; |
2508 | } | 2564 | } |
2509 | 2565 | ||
2510 | /* Print the contents of a node. */ | ||
2511 | void | ||
2512 | jffs_print_node(struct jffs_node *n) | ||
2513 | { | ||
2514 | D(printk("jffs_node: 0x%p\n", n)); | ||
2515 | D(printk("{\n")); | ||
2516 | D(printk(" 0x%08x, /* version */\n", n->version)); | ||
2517 | D(printk(" 0x%08x, /* data_offset */\n", n->data_offset)); | ||
2518 | D(printk(" 0x%08x, /* data_size */\n", n->data_size)); | ||
2519 | D(printk(" 0x%08x, /* removed_size */\n", n->removed_size)); | ||
2520 | D(printk(" 0x%08x, /* fm_offset */\n", n->fm_offset)); | ||
2521 | D(printk(" 0x%02x, /* name_size */\n", n->name_size)); | ||
2522 | D(printk(" 0x%p, /* fm, fm->offset: %u */\n", | ||
2523 | n->fm, (n->fm ? n->fm->offset : 0))); | ||
2524 | D(printk(" 0x%p, /* version_prev */\n", n->version_prev)); | ||
2525 | D(printk(" 0x%p, /* version_next */\n", n->version_next)); | ||
2526 | D(printk(" 0x%p, /* range_prev */\n", n->range_prev)); | ||
2527 | D(printk(" 0x%p, /* range_next */\n", n->range_next)); | ||
2528 | D(printk("}\n")); | ||
2529 | } | ||
2530 | |||
2531 | |||
2532 | /* Print the contents of a raw inode. */ | ||
2533 | void | ||
2534 | jffs_print_raw_inode(struct jffs_raw_inode *raw_inode) | ||
2535 | { | ||
2536 | D(printk("jffs_raw_inode: inode number: %u\n", raw_inode->ino)); | ||
2537 | D(printk("{\n")); | ||
2538 | D(printk(" 0x%08x, /* magic */\n", raw_inode->magic)); | ||
2539 | D(printk(" 0x%08x, /* ino */\n", raw_inode->ino)); | ||
2540 | D(printk(" 0x%08x, /* pino */\n", raw_inode->pino)); | ||
2541 | D(printk(" 0x%08x, /* version */\n", raw_inode->version)); | ||
2542 | D(printk(" 0x%08x, /* mode */\n", raw_inode->mode)); | ||
2543 | D(printk(" 0x%04x, /* uid */\n", raw_inode->uid)); | ||
2544 | D(printk(" 0x%04x, /* gid */\n", raw_inode->gid)); | ||
2545 | D(printk(" 0x%08x, /* atime */\n", raw_inode->atime)); | ||
2546 | D(printk(" 0x%08x, /* mtime */\n", raw_inode->mtime)); | ||
2547 | D(printk(" 0x%08x, /* ctime */\n", raw_inode->ctime)); | ||
2548 | D(printk(" 0x%08x, /* offset */\n", raw_inode->offset)); | ||
2549 | D(printk(" 0x%08x, /* dsize */\n", raw_inode->dsize)); | ||
2550 | D(printk(" 0x%08x, /* rsize */\n", raw_inode->rsize)); | ||
2551 | D(printk(" 0x%02x, /* nsize */\n", raw_inode->nsize)); | ||
2552 | D(printk(" 0x%02x, /* nlink */\n", raw_inode->nlink)); | ||
2553 | D(printk(" 0x%02x, /* spare */\n", | ||
2554 | raw_inode->spare)); | ||
2555 | D(printk(" %u, /* rename */\n", | ||
2556 | raw_inode->rename)); | ||
2557 | D(printk(" %u, /* deleted */\n", | ||
2558 | raw_inode->deleted)); | ||
2559 | D(printk(" 0x%02x, /* accurate */\n", | ||
2560 | raw_inode->accurate)); | ||
2561 | D(printk(" 0x%08x, /* dchksum */\n", raw_inode->dchksum)); | ||
2562 | D(printk(" 0x%04x, /* nchksum */\n", raw_inode->nchksum)); | ||
2563 | D(printk(" 0x%04x, /* chksum */\n", raw_inode->chksum)); | ||
2564 | D(printk("}\n")); | ||
2565 | } | ||
2566 | |||
2567 | |||
2568 | /* Print the contents of a file. */ | 2566 | /* Print the contents of a file. */ |
2569 | #if 0 | 2567 | #if 0 |
2570 | int | 2568 | int |
diff --git a/fs/jffs/intrep.h b/fs/jffs/intrep.h index 4ae97b17911c..5c7abe0e2695 100644 --- a/fs/jffs/intrep.h +++ b/fs/jffs/intrep.h | |||
@@ -49,8 +49,6 @@ int jffs_garbage_collect_thread(void *c); | |||
49 | void jffs_garbage_collect_trigger(struct jffs_control *c); | 49 | void jffs_garbage_collect_trigger(struct jffs_control *c); |
50 | 50 | ||
51 | /* For debugging purposes. */ | 51 | /* For debugging purposes. */ |
52 | void jffs_print_node(struct jffs_node *n); | ||
53 | void jffs_print_raw_inode(struct jffs_raw_inode *raw_inode); | ||
54 | #if 0 | 52 | #if 0 |
55 | int jffs_print_file(struct jffs_file *f); | 53 | int jffs_print_file(struct jffs_file *f); |
56 | #endif /* 0 */ | 54 | #endif /* 0 */ |
diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c index 0cab8da49d3c..053e3a98a276 100644 --- a/fs/jffs/jffs_fm.c +++ b/fs/jffs/jffs_fm.c | |||
@@ -31,6 +31,60 @@ static void jffs_free_fm(struct jffs_fm *n); | |||
31 | extern kmem_cache_t *fm_cache; | 31 | extern kmem_cache_t *fm_cache; |
32 | extern kmem_cache_t *node_cache; | 32 | extern kmem_cache_t *node_cache; |
33 | 33 | ||
34 | #if CONFIG_JFFS_FS_VERBOSE > 0 | ||
35 | void | ||
36 | jffs_print_fmcontrol(struct jffs_fmcontrol *fmc) | ||
37 | { | ||
38 | D(printk("struct jffs_fmcontrol: 0x%p\n", fmc)); | ||
39 | D(printk("{\n")); | ||
40 | D(printk(" %u, /* flash_size */\n", fmc->flash_size)); | ||
41 | D(printk(" %u, /* used_size */\n", fmc->used_size)); | ||
42 | D(printk(" %u, /* dirty_size */\n", fmc->dirty_size)); | ||
43 | D(printk(" %u, /* free_size */\n", fmc->free_size)); | ||
44 | D(printk(" %u, /* sector_size */\n", fmc->sector_size)); | ||
45 | D(printk(" %u, /* min_free_size */\n", fmc->min_free_size)); | ||
46 | D(printk(" %u, /* max_chunk_size */\n", fmc->max_chunk_size)); | ||
47 | D(printk(" 0x%p, /* mtd */\n", fmc->mtd)); | ||
48 | D(printk(" 0x%p, /* head */ " | ||
49 | "(head->offset = 0x%08x)\n", | ||
50 | fmc->head, (fmc->head ? fmc->head->offset : 0))); | ||
51 | D(printk(" 0x%p, /* tail */ " | ||
52 | "(tail->offset + tail->size = 0x%08x)\n", | ||
53 | fmc->tail, | ||
54 | (fmc->tail ? fmc->tail->offset + fmc->tail->size : 0))); | ||
55 | D(printk(" 0x%p, /* head_extra */\n", fmc->head_extra)); | ||
56 | D(printk(" 0x%p, /* tail_extra */\n", fmc->tail_extra)); | ||
57 | D(printk("}\n")); | ||
58 | } | ||
59 | #endif /* CONFIG_JFFS_FS_VERBOSE > 0 */ | ||
60 | |||
61 | #if CONFIG_JFFS_FS_VERBOSE > 2 | ||
62 | static void | ||
63 | jffs_print_fm(struct jffs_fm *fm) | ||
64 | { | ||
65 | D(printk("struct jffs_fm: 0x%p\n", fm)); | ||
66 | D(printk("{\n")); | ||
67 | D(printk(" 0x%08x, /* offset */\n", fm->offset)); | ||
68 | D(printk(" %u, /* size */\n", fm->size)); | ||
69 | D(printk(" 0x%p, /* prev */\n", fm->prev)); | ||
70 | D(printk(" 0x%p, /* next */\n", fm->next)); | ||
71 | D(printk(" 0x%p, /* nodes */\n", fm->nodes)); | ||
72 | D(printk("}\n")); | ||
73 | } | ||
74 | #endif /* CONFIG_JFFS_FS_VERBOSE > 2 */ | ||
75 | |||
76 | #if 0 | ||
77 | void | ||
78 | jffs_print_node_ref(struct jffs_node_ref *ref) | ||
79 | { | ||
80 | D(printk("struct jffs_node_ref: 0x%p\n", ref)); | ||
81 | D(printk("{\n")); | ||
82 | D(printk(" 0x%p, /* node */\n", ref->node)); | ||
83 | D(printk(" 0x%p, /* next */\n", ref->next)); | ||
84 | D(printk("}\n")); | ||
85 | } | ||
86 | #endif /* 0 */ | ||
87 | |||
34 | /* This function creates a new shiny flash memory control structure. */ | 88 | /* This function creates a new shiny flash memory control structure. */ |
35 | struct jffs_fmcontrol * | 89 | struct jffs_fmcontrol * |
36 | jffs_build_begin(struct jffs_control *c, int unit) | 90 | jffs_build_begin(struct jffs_control *c, int unit) |
@@ -742,54 +796,3 @@ int jffs_get_node_inuse(void) | |||
742 | { | 796 | { |
743 | return no_jffs_node; | 797 | return no_jffs_node; |
744 | } | 798 | } |
745 | |||
746 | void | ||
747 | jffs_print_fmcontrol(struct jffs_fmcontrol *fmc) | ||
748 | { | ||
749 | D(printk("struct jffs_fmcontrol: 0x%p\n", fmc)); | ||
750 | D(printk("{\n")); | ||
751 | D(printk(" %u, /* flash_size */\n", fmc->flash_size)); | ||
752 | D(printk(" %u, /* used_size */\n", fmc->used_size)); | ||
753 | D(printk(" %u, /* dirty_size */\n", fmc->dirty_size)); | ||
754 | D(printk(" %u, /* free_size */\n", fmc->free_size)); | ||
755 | D(printk(" %u, /* sector_size */\n", fmc->sector_size)); | ||
756 | D(printk(" %u, /* min_free_size */\n", fmc->min_free_size)); | ||
757 | D(printk(" %u, /* max_chunk_size */\n", fmc->max_chunk_size)); | ||
758 | D(printk(" 0x%p, /* mtd */\n", fmc->mtd)); | ||
759 | D(printk(" 0x%p, /* head */ " | ||
760 | "(head->offset = 0x%08x)\n", | ||
761 | fmc->head, (fmc->head ? fmc->head->offset : 0))); | ||
762 | D(printk(" 0x%p, /* tail */ " | ||
763 | "(tail->offset + tail->size = 0x%08x)\n", | ||
764 | fmc->tail, | ||
765 | (fmc->tail ? fmc->tail->offset + fmc->tail->size : 0))); | ||
766 | D(printk(" 0x%p, /* head_extra */\n", fmc->head_extra)); | ||
767 | D(printk(" 0x%p, /* tail_extra */\n", fmc->tail_extra)); | ||
768 | D(printk("}\n")); | ||
769 | } | ||
770 | |||
771 | void | ||
772 | jffs_print_fm(struct jffs_fm *fm) | ||
773 | { | ||
774 | D(printk("struct jffs_fm: 0x%p\n", fm)); | ||
775 | D(printk("{\n")); | ||
776 | D(printk(" 0x%08x, /* offset */\n", fm->offset)); | ||
777 | D(printk(" %u, /* size */\n", fm->size)); | ||
778 | D(printk(" 0x%p, /* prev */\n", fm->prev)); | ||
779 | D(printk(" 0x%p, /* next */\n", fm->next)); | ||
780 | D(printk(" 0x%p, /* nodes */\n", fm->nodes)); | ||
781 | D(printk("}\n")); | ||
782 | } | ||
783 | |||
784 | #if 0 | ||
785 | void | ||
786 | jffs_print_node_ref(struct jffs_node_ref *ref) | ||
787 | { | ||
788 | D(printk("struct jffs_node_ref: 0x%p\n", ref)); | ||
789 | D(printk("{\n")); | ||
790 | D(printk(" 0x%p, /* node */\n", ref->node)); | ||
791 | D(printk(" 0x%p, /* next */\n", ref->next)); | ||
792 | D(printk("}\n")); | ||
793 | } | ||
794 | #endif /* 0 */ | ||
795 | |||
diff --git a/fs/jffs/jffs_fm.h b/fs/jffs/jffs_fm.h index bc291c431822..f64151e74122 100644 --- a/fs/jffs/jffs_fm.h +++ b/fs/jffs/jffs_fm.h | |||
@@ -139,8 +139,9 @@ int jffs_add_node(struct jffs_node *node); | |||
139 | void jffs_fmfree_partly(struct jffs_fmcontrol *fmc, struct jffs_fm *fm, | 139 | void jffs_fmfree_partly(struct jffs_fmcontrol *fmc, struct jffs_fm *fm, |
140 | __u32 size); | 140 | __u32 size); |
141 | 141 | ||
142 | #if CONFIG_JFFS_FS_VERBOSE > 0 | ||
142 | void jffs_print_fmcontrol(struct jffs_fmcontrol *fmc); | 143 | void jffs_print_fmcontrol(struct jffs_fmcontrol *fmc); |
143 | void jffs_print_fm(struct jffs_fm *fm); | 144 | #endif |
144 | #if 0 | 145 | #if 0 |
145 | void jffs_print_node_ref(struct jffs_node_ref *ref); | 146 | void jffs_print_node_ref(struct jffs_node_ref *ref); |
146 | #endif /* 0 */ | 147 | #endif /* 0 */ |
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 65119d72cce0..0f224384f176 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c | |||
@@ -95,7 +95,7 @@ static int jffs2_garbage_collect_thread(void *_c) | |||
95 | schedule(); | 95 | schedule(); |
96 | } | 96 | } |
97 | 97 | ||
98 | if (try_to_freeze(0)) | 98 | if (try_to_freeze()) |
99 | continue; | 99 | continue; |
100 | 100 | ||
101 | cond_resched(); | 101 | cond_resched(); |
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 8d2a9ab981d4..e892dab40c26 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
23 | #include <linux/quotaops.h> | 23 | #include <linux/quotaops.h> |
24 | #include <linux/posix_acl_xattr.h> | ||
24 | #include "jfs_incore.h" | 25 | #include "jfs_incore.h" |
25 | #include "jfs_xattr.h" | 26 | #include "jfs_xattr.h" |
26 | #include "jfs_acl.h" | 27 | #include "jfs_acl.h" |
@@ -36,11 +37,11 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type) | |||
36 | 37 | ||
37 | switch(type) { | 38 | switch(type) { |
38 | case ACL_TYPE_ACCESS: | 39 | case ACL_TYPE_ACCESS: |
39 | ea_name = XATTR_NAME_ACL_ACCESS; | 40 | ea_name = POSIX_ACL_XATTR_ACCESS; |
40 | p_acl = &ji->i_acl; | 41 | p_acl = &ji->i_acl; |
41 | break; | 42 | break; |
42 | case ACL_TYPE_DEFAULT: | 43 | case ACL_TYPE_DEFAULT: |
43 | ea_name = XATTR_NAME_ACL_DEFAULT; | 44 | ea_name = POSIX_ACL_XATTR_DEFAULT; |
44 | p_acl = &ji->i_default_acl; | 45 | p_acl = &ji->i_default_acl; |
45 | break; | 46 | break; |
46 | default: | 47 | default: |
@@ -70,8 +71,7 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type) | |||
70 | if (!IS_ERR(acl)) | 71 | if (!IS_ERR(acl)) |
71 | *p_acl = posix_acl_dup(acl); | 72 | *p_acl = posix_acl_dup(acl); |
72 | } | 73 | } |
73 | if (value) | 74 | kfree(value); |
74 | kfree(value); | ||
75 | return acl; | 75 | return acl; |
76 | } | 76 | } |
77 | 77 | ||
@@ -89,11 +89,11 @@ static int jfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
89 | 89 | ||
90 | switch(type) { | 90 | switch(type) { |
91 | case ACL_TYPE_ACCESS: | 91 | case ACL_TYPE_ACCESS: |
92 | ea_name = XATTR_NAME_ACL_ACCESS; | 92 | ea_name = POSIX_ACL_XATTR_ACCESS; |
93 | p_acl = &ji->i_acl; | 93 | p_acl = &ji->i_acl; |
94 | break; | 94 | break; |
95 | case ACL_TYPE_DEFAULT: | 95 | case ACL_TYPE_DEFAULT: |
96 | ea_name = XATTR_NAME_ACL_DEFAULT; | 96 | ea_name = POSIX_ACL_XATTR_DEFAULT; |
97 | p_acl = &ji->i_default_acl; | 97 | p_acl = &ji->i_default_acl; |
98 | if (!S_ISDIR(inode->i_mode)) | 98 | if (!S_ISDIR(inode->i_mode)) |
99 | return acl ? -EACCES : 0; | 99 | return acl ? -EACCES : 0; |
@@ -102,7 +102,7 @@ static int jfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
102 | return -EINVAL; | 102 | return -EINVAL; |
103 | } | 103 | } |
104 | if (acl) { | 104 | if (acl) { |
105 | size = xattr_acl_size(acl->a_count); | 105 | size = posix_acl_xattr_size(acl->a_count); |
106 | value = kmalloc(size, GFP_KERNEL); | 106 | value = kmalloc(size, GFP_KERNEL); |
107 | if (!value) | 107 | if (!value) |
108 | return -ENOMEM; | 108 | return -ENOMEM; |
@@ -112,8 +112,7 @@ static int jfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
112 | } | 112 | } |
113 | rc = __jfs_setxattr(inode, ea_name, value, size, 0); | 113 | rc = __jfs_setxattr(inode, ea_name, value, size, 0); |
114 | out: | 114 | out: |
115 | if (value) | 115 | kfree(value); |
116 | kfree(value); | ||
117 | 116 | ||
118 | if (!rc) { | 117 | if (!rc) { |
119 | if (*p_acl && (*p_acl != JFS_ACL_NOT_CACHED)) | 118 | if (*p_acl && (*p_acl != JFS_ACL_NOT_CACHED)) |
diff --git a/fs/jfs/file.c b/fs/jfs/file.c index a87b06fa8ff8..c2c19c9ed9a4 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) International Business Machines Corp., 2000-2002 | 2 | * Copyright (C) International Business Machines Corp., 2000-2002 |
3 | * Portions Copyright (c) Christoph Hellwig, 2001-2002 | 3 | * Portions Copyright (C) Christoph Hellwig, 2001-2002 |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -19,16 +19,13 @@ | |||
19 | 19 | ||
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include "jfs_incore.h" | 21 | #include "jfs_incore.h" |
22 | #include "jfs_inode.h" | ||
22 | #include "jfs_dmap.h" | 23 | #include "jfs_dmap.h" |
23 | #include "jfs_txnmgr.h" | 24 | #include "jfs_txnmgr.h" |
24 | #include "jfs_xattr.h" | 25 | #include "jfs_xattr.h" |
25 | #include "jfs_acl.h" | 26 | #include "jfs_acl.h" |
26 | #include "jfs_debug.h" | 27 | #include "jfs_debug.h" |
27 | 28 | ||
28 | |||
29 | extern int jfs_commit_inode(struct inode *, int); | ||
30 | extern void jfs_truncate(struct inode *); | ||
31 | |||
32 | int jfs_fsync(struct file *file, struct dentry *dentry, int datasync) | 29 | int jfs_fsync(struct file *file, struct dentry *dentry, int datasync) |
33 | { | 30 | { |
34 | struct inode *inode = dentry->d_inode; | 31 | struct inode *inode = dentry->d_inode; |
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 24a689179af2..2137138c59b0 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/pagemap.h> | 23 | #include <linux/pagemap.h> |
24 | #include <linux/quotaops.h> | 24 | #include <linux/quotaops.h> |
25 | #include "jfs_incore.h" | 25 | #include "jfs_incore.h" |
26 | #include "jfs_inode.h" | ||
26 | #include "jfs_filsys.h" | 27 | #include "jfs_filsys.h" |
27 | #include "jfs_imap.h" | 28 | #include "jfs_imap.h" |
28 | #include "jfs_extent.h" | 29 | #include "jfs_extent.h" |
@@ -30,14 +31,6 @@ | |||
30 | #include "jfs_debug.h" | 31 | #include "jfs_debug.h" |
31 | 32 | ||
32 | 33 | ||
33 | extern struct inode_operations jfs_dir_inode_operations; | ||
34 | extern struct inode_operations jfs_file_inode_operations; | ||
35 | extern struct inode_operations jfs_symlink_inode_operations; | ||
36 | extern struct file_operations jfs_dir_operations; | ||
37 | extern struct file_operations jfs_file_operations; | ||
38 | struct address_space_operations jfs_aops; | ||
39 | extern int freeZeroLink(struct inode *); | ||
40 | |||
41 | void jfs_read_inode(struct inode *inode) | 34 | void jfs_read_inode(struct inode *inode) |
42 | { | 35 | { |
43 | if (diRead(inode)) { | 36 | if (diRead(inode)) { |
@@ -136,7 +129,7 @@ void jfs_delete_inode(struct inode *inode) | |||
136 | jfs_info("In jfs_delete_inode, inode = 0x%p", inode); | 129 | jfs_info("In jfs_delete_inode, inode = 0x%p", inode); |
137 | 130 | ||
138 | if (test_cflag(COMMIT_Freewmap, inode)) | 131 | if (test_cflag(COMMIT_Freewmap, inode)) |
139 | freeZeroLink(inode); | 132 | jfs_free_zero_link(inode); |
140 | 133 | ||
141 | diFree(inode); | 134 | diFree(inode); |
142 | 135 | ||
diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h index d2ae430adecf..a3acd3eec059 100644 --- a/fs/jfs/jfs_acl.h +++ b/fs/jfs/jfs_acl.h | |||
@@ -20,8 +20,6 @@ | |||
20 | 20 | ||
21 | #ifdef CONFIG_JFS_POSIX_ACL | 21 | #ifdef CONFIG_JFS_POSIX_ACL |
22 | 22 | ||
23 | #include <linux/xattr_acl.h> | ||
24 | |||
25 | int jfs_permission(struct inode *, int, struct nameidata *); | 23 | int jfs_permission(struct inode *, int, struct nameidata *); |
26 | int jfs_init_acl(struct inode *, struct inode *); | 24 | int jfs_init_acl(struct inode *, struct inode *); |
27 | int jfs_setattr(struct dentry *, struct iattr *); | 25 | int jfs_setattr(struct dentry *, struct iattr *); |
diff --git a/fs/jfs/jfs_debug.c b/fs/jfs/jfs_debug.c index 91a0a889ebc5..4caea6b43b92 100644 --- a/fs/jfs/jfs_debug.c +++ b/fs/jfs/jfs_debug.c | |||
@@ -58,8 +58,6 @@ void dump_mem(char *label, void *data, int length) | |||
58 | 58 | ||
59 | static struct proc_dir_entry *base; | 59 | static struct proc_dir_entry *base; |
60 | #ifdef CONFIG_JFS_DEBUG | 60 | #ifdef CONFIG_JFS_DEBUG |
61 | extern read_proc_t jfs_txanchor_read; | ||
62 | |||
63 | static int loglevel_read(char *page, char **start, off_t off, | 61 | static int loglevel_read(char *page, char **start, off_t off, |
64 | int count, int *eof, void *data) | 62 | int count, int *eof, void *data) |
65 | { | 63 | { |
@@ -97,14 +95,6 @@ static int loglevel_write(struct file *file, const char __user *buffer, | |||
97 | } | 95 | } |
98 | #endif | 96 | #endif |
99 | 97 | ||
100 | |||
101 | #ifdef CONFIG_JFS_STATISTICS | ||
102 | extern read_proc_t jfs_lmstats_read; | ||
103 | extern read_proc_t jfs_txstats_read; | ||
104 | extern read_proc_t jfs_xtstat_read; | ||
105 | extern read_proc_t jfs_mpstat_read; | ||
106 | #endif | ||
107 | |||
108 | static struct { | 98 | static struct { |
109 | const char *name; | 99 | const char *name; |
110 | read_proc_t *read_fn; | 100 | read_proc_t *read_fn; |
diff --git a/fs/jfs/jfs_debug.h b/fs/jfs/jfs_debug.h index a38079ae1e00..ddffbbd4d955 100644 --- a/fs/jfs/jfs_debug.h +++ b/fs/jfs/jfs_debug.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) International Business Machines Corp., 2000-2002 | 2 | * Copyright (C) International Business Machines Corp., 2000-2002 |
3 | * Portions Copyright (c) Christoph Hellwig, 2001-2002 | 3 | * Portions Copyright (C) Christoph Hellwig, 2001-2002 |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -31,7 +31,9 @@ | |||
31 | * CONFIG_JFS_DEBUG or CONFIG_JFS_STATISTICS is defined | 31 | * CONFIG_JFS_DEBUG or CONFIG_JFS_STATISTICS is defined |
32 | */ | 32 | */ |
33 | #if defined(CONFIG_PROC_FS) && (defined(CONFIG_JFS_DEBUG) || defined(CONFIG_JFS_STATISTICS)) | 33 | #if defined(CONFIG_PROC_FS) && (defined(CONFIG_JFS_DEBUG) || defined(CONFIG_JFS_STATISTICS)) |
34 | #define PROC_FS_JFS | 34 | #define PROC_FS_JFS |
35 | extern void jfs_proc_init(void); | ||
36 | extern void jfs_proc_clean(void); | ||
35 | #endif | 37 | #endif |
36 | 38 | ||
37 | /* | 39 | /* |
@@ -65,8 +67,8 @@ | |||
65 | 67 | ||
66 | extern int jfsloglevel; | 68 | extern int jfsloglevel; |
67 | 69 | ||
68 | /* dump memory contents */ | ||
69 | extern void dump_mem(char *label, void *data, int length); | 70 | extern void dump_mem(char *label, void *data, int length); |
71 | extern int jfs_txanchor_read(char *, char **, off_t, int, int *, void *); | ||
70 | 72 | ||
71 | /* information message: e.g., configuration, major event */ | 73 | /* information message: e.g., configuration, major event */ |
72 | #define jfs_info(fmt, arg...) do { \ | 74 | #define jfs_info(fmt, arg...) do { \ |
@@ -110,6 +112,11 @@ extern void dump_mem(char *label, void *data, int length); | |||
110 | * ---------- | 112 | * ---------- |
111 | */ | 113 | */ |
112 | #ifdef CONFIG_JFS_STATISTICS | 114 | #ifdef CONFIG_JFS_STATISTICS |
115 | extern int jfs_lmstats_read(char *, char **, off_t, int, int *, void *); | ||
116 | extern int jfs_txstats_read(char *, char **, off_t, int, int *, void *); | ||
117 | extern int jfs_mpstat_read(char *, char **, off_t, int, int *, void *); | ||
118 | extern int jfs_xtstat_read(char *, char **, off_t, int, int *, void *); | ||
119 | |||
113 | #define INCREMENT(x) ((x)++) | 120 | #define INCREMENT(x) ((x)++) |
114 | #define DECREMENT(x) ((x)--) | 121 | #define DECREMENT(x) ((x)--) |
115 | #define HIGHWATERMARK(x,y) ((x) = max((x), (y))) | 122 | #define HIGHWATERMARK(x,y) ((x) = max((x), (y))) |
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 69007fd546ef..cced2fed9d0f 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c | |||
@@ -272,7 +272,6 @@ int dbMount(struct inode *ipbmap) | |||
272 | int dbUnmount(struct inode *ipbmap, int mounterror) | 272 | int dbUnmount(struct inode *ipbmap, int mounterror) |
273 | { | 273 | { |
274 | struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap; | 274 | struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap; |
275 | int i; | ||
276 | 275 | ||
277 | if (!(mounterror || isReadOnly(ipbmap))) | 276 | if (!(mounterror || isReadOnly(ipbmap))) |
278 | dbSync(ipbmap); | 277 | dbSync(ipbmap); |
@@ -282,14 +281,6 @@ int dbUnmount(struct inode *ipbmap, int mounterror) | |||
282 | */ | 281 | */ |
283 | truncate_inode_pages(ipbmap->i_mapping, 0); | 282 | truncate_inode_pages(ipbmap->i_mapping, 0); |
284 | 283 | ||
285 | /* | ||
286 | * Sanity Check | ||
287 | */ | ||
288 | for (i = 0; i < bmp->db_numag; i++) | ||
289 | if (atomic_read(&bmp->db_active[i])) | ||
290 | printk(KERN_ERR "dbUnmount: db_active[%d] = %d\n", | ||
291 | i, atomic_read(&bmp->db_active[i])); | ||
292 | |||
293 | /* free the memory for the in-memory bmap. */ | 284 | /* free the memory for the in-memory bmap. */ |
294 | kfree(bmp); | 285 | kfree(bmp); |
295 | 286 | ||
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index ac41f72d6d50..8676aee3ae48 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c | |||
@@ -2931,6 +2931,9 @@ static void add_missing_indices(struct inode *inode, s64 bn) | |||
2931 | ASSERT(p->header.flag & BT_LEAF); | 2931 | ASSERT(p->header.flag & BT_LEAF); |
2932 | 2932 | ||
2933 | tlck = txLock(tid, inode, mp, tlckDTREE | tlckENTRY); | 2933 | tlck = txLock(tid, inode, mp, tlckDTREE | tlckENTRY); |
2934 | if (BT_IS_ROOT(mp)) | ||
2935 | tlck->type |= tlckBTROOT; | ||
2936 | |||
2934 | dtlck = (struct dt_lock *) &tlck->lock; | 2937 | dtlck = (struct dt_lock *) &tlck->lock; |
2935 | 2938 | ||
2936 | stbl = DT_GETSTBL(p); | 2939 | stbl = DT_GETSTBL(p); |
diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index 1953acb79266..4879603daa1c 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/quotaops.h> | 20 | #include <linux/quotaops.h> |
21 | #include "jfs_incore.h" | 21 | #include "jfs_incore.h" |
22 | #include "jfs_inode.h" | ||
22 | #include "jfs_superblock.h" | 23 | #include "jfs_superblock.h" |
23 | #include "jfs_dmap.h" | 24 | #include "jfs_dmap.h" |
24 | #include "jfs_extent.h" | 25 | #include "jfs_extent.h" |
@@ -33,12 +34,6 @@ static int extBrealloc(struct inode *, s64, s64, s64 *, s64 *); | |||
33 | #endif | 34 | #endif |
34 | static s64 extRoundDown(s64 nb); | 35 | static s64 extRoundDown(s64 nb); |
35 | 36 | ||
36 | /* | ||
37 | * external references | ||
38 | */ | ||
39 | extern int jfs_commit_inode(struct inode *, int); | ||
40 | |||
41 | |||
42 | #define DPD(a) (printk("(a): %d\n",(a))) | 37 | #define DPD(a) (printk("(a): %d\n",(a))) |
43 | #define DPC(a) (printk("(a): %c\n",(a))) | 38 | #define DPC(a) (printk("(a): %c\n",(a))) |
44 | #define DPL1(a) \ | 39 | #define DPL1(a) \ |
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 7acff2ce3c80..971af2977eff 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/quotaops.h> | 47 | #include <linux/quotaops.h> |
48 | 48 | ||
49 | #include "jfs_incore.h" | 49 | #include "jfs_incore.h" |
50 | #include "jfs_inode.h" | ||
50 | #include "jfs_filsys.h" | 51 | #include "jfs_filsys.h" |
51 | #include "jfs_dinode.h" | 52 | #include "jfs_dinode.h" |
52 | #include "jfs_dmap.h" | 53 | #include "jfs_dmap.h" |
@@ -69,11 +70,6 @@ | |||
69 | #define AG_UNLOCK(imap,agno) up(&imap->im_aglock[agno]) | 70 | #define AG_UNLOCK(imap,agno) up(&imap->im_aglock[agno]) |
70 | 71 | ||
71 | /* | 72 | /* |
72 | * external references | ||
73 | */ | ||
74 | extern struct address_space_operations jfs_aops; | ||
75 | |||
76 | /* | ||
77 | * forward references | 73 | * forward references |
78 | */ | 74 | */ |
79 | static int diAllocAG(struct inomap *, int, boolean_t, struct inode *); | 75 | static int diAllocAG(struct inomap *, int, boolean_t, struct inode *); |
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c index 84f2459b2191..2af5efbfd06f 100644 --- a/fs/jfs/jfs_inode.c +++ b/fs/jfs/jfs_inode.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/quotaops.h> | 20 | #include <linux/quotaops.h> |
21 | #include "jfs_incore.h" | 21 | #include "jfs_incore.h" |
22 | #include "jfs_inode.h" | ||
22 | #include "jfs_filsys.h" | 23 | #include "jfs_filsys.h" |
23 | #include "jfs_imap.h" | 24 | #include "jfs_imap.h" |
24 | #include "jfs_dinode.h" | 25 | #include "jfs_dinode.h" |
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index 3df91fbfe781..b54bac576cb3 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) International Business Machines Corp., 2000-2001 | 2 | * Copyright (C) International Business Machines Corp., 2000-2001 |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
@@ -19,5 +19,22 @@ | |||
19 | #define _H_JFS_INODE | 19 | #define _H_JFS_INODE |
20 | 20 | ||
21 | extern struct inode *ialloc(struct inode *, umode_t); | 21 | extern struct inode *ialloc(struct inode *, umode_t); |
22 | extern int jfs_fsync(struct file *, struct dentry *, int); | ||
23 | extern void jfs_read_inode(struct inode *); | ||
24 | extern int jfs_commit_inode(struct inode *, int); | ||
25 | extern int jfs_write_inode(struct inode*, int); | ||
26 | extern void jfs_delete_inode(struct inode *); | ||
27 | extern void jfs_dirty_inode(struct inode *); | ||
28 | extern void jfs_truncate(struct inode *); | ||
29 | extern void jfs_truncate_nolock(struct inode *, loff_t); | ||
30 | extern void jfs_free_zero_link(struct inode *); | ||
31 | extern struct dentry *jfs_get_parent(struct dentry *dentry); | ||
22 | 32 | ||
33 | extern struct address_space_operations jfs_aops; | ||
34 | extern struct inode_operations jfs_dir_inode_operations; | ||
35 | extern struct file_operations jfs_dir_operations; | ||
36 | extern struct inode_operations jfs_file_inode_operations; | ||
37 | extern struct file_operations jfs_file_operations; | ||
38 | extern struct inode_operations jfs_symlink_inode_operations; | ||
39 | extern struct dentry_operations jfs_ci_dentry_operations; | ||
23 | #endif /* _H_JFS_INODE */ | 40 | #endif /* _H_JFS_INODE */ |
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index dfa1200daa61..79d07624bfe1 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c | |||
@@ -71,6 +71,7 @@ | |||
71 | #include "jfs_incore.h" | 71 | #include "jfs_incore.h" |
72 | #include "jfs_filsys.h" | 72 | #include "jfs_filsys.h" |
73 | #include "jfs_metapage.h" | 73 | #include "jfs_metapage.h" |
74 | #include "jfs_superblock.h" | ||
74 | #include "jfs_txnmgr.h" | 75 | #include "jfs_txnmgr.h" |
75 | #include "jfs_debug.h" | 76 | #include "jfs_debug.h" |
76 | 77 | ||
@@ -167,14 +168,6 @@ static struct jfs_log *dummy_log = NULL; | |||
167 | static DECLARE_MUTEX(jfs_log_sem); | 168 | static DECLARE_MUTEX(jfs_log_sem); |
168 | 169 | ||
169 | /* | 170 | /* |
170 | * external references | ||
171 | */ | ||
172 | extern void txLazyUnlock(struct tblock * tblk); | ||
173 | extern int jfs_stop_threads; | ||
174 | extern struct completion jfsIOwait; | ||
175 | extern int jfs_tlocks_low; | ||
176 | |||
177 | /* | ||
178 | * forward references | 171 | * forward references |
179 | */ | 172 | */ |
180 | static int lmWriteRecord(struct jfs_log * log, struct tblock * tblk, | 173 | static int lmWriteRecord(struct jfs_log * log, struct tblock * tblk, |
@@ -1624,6 +1617,8 @@ void jfs_flush_journal(struct jfs_log *log, int wait) | |||
1624 | } | 1617 | } |
1625 | } | 1618 | } |
1626 | assert(list_empty(&log->cqueue)); | 1619 | assert(list_empty(&log->cqueue)); |
1620 | |||
1621 | #ifdef CONFIG_JFS_DEBUG | ||
1627 | if (!list_empty(&log->synclist)) { | 1622 | if (!list_empty(&log->synclist)) { |
1628 | struct logsyncblk *lp; | 1623 | struct logsyncblk *lp; |
1629 | 1624 | ||
@@ -1638,9 +1633,8 @@ void jfs_flush_journal(struct jfs_log *log, int wait) | |||
1638 | dump_mem("orphan tblock", lp, | 1633 | dump_mem("orphan tblock", lp, |
1639 | sizeof(struct tblock)); | 1634 | sizeof(struct tblock)); |
1640 | } | 1635 | } |
1641 | // current->state = TASK_INTERRUPTIBLE; | ||
1642 | // schedule(); | ||
1643 | } | 1636 | } |
1637 | #endif | ||
1644 | //assert(list_empty(&log->synclist)); | 1638 | //assert(list_empty(&log->synclist)); |
1645 | clear_bit(log_FLUSH, &log->flag); | 1639 | clear_bit(log_FLUSH, &log->flag); |
1646 | } | 1640 | } |
@@ -2365,9 +2359,9 @@ int jfsIOWait(void *arg) | |||
2365 | lbmStartIO(bp); | 2359 | lbmStartIO(bp); |
2366 | spin_lock_irq(&log_redrive_lock); | 2360 | spin_lock_irq(&log_redrive_lock); |
2367 | } | 2361 | } |
2368 | if (current->flags & PF_FREEZE) { | 2362 | if (freezing(current)) { |
2369 | spin_unlock_irq(&log_redrive_lock); | 2363 | spin_unlock_irq(&log_redrive_lock); |
2370 | refrigerator(PF_FREEZE); | 2364 | refrigerator(); |
2371 | } else { | 2365 | } else { |
2372 | add_wait_queue(&jfs_IO_thread_wait, &wq); | 2366 | add_wait_queue(&jfs_IO_thread_wait, &wq); |
2373 | set_current_state(TASK_INTERRUPTIBLE); | 2367 | set_current_state(TASK_INTERRUPTIBLE); |
diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h index 51291fbc420c..747114cd38b8 100644 --- a/fs/jfs/jfs_logmgr.h +++ b/fs/jfs/jfs_logmgr.h | |||
@@ -507,6 +507,8 @@ extern int lmLogClose(struct super_block *sb); | |||
507 | extern int lmLogShutdown(struct jfs_log * log); | 507 | extern int lmLogShutdown(struct jfs_log * log); |
508 | extern int lmLogInit(struct jfs_log * log); | 508 | extern int lmLogInit(struct jfs_log * log); |
509 | extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize); | 509 | extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize); |
510 | extern int lmGroupCommit(struct jfs_log *, struct tblock *); | ||
511 | extern int jfsIOWait(void *); | ||
510 | extern void jfs_flush_journal(struct jfs_log * log, int wait); | 512 | extern void jfs_flush_journal(struct jfs_log * log, int wait); |
511 | extern void jfs_syncpt(struct jfs_log *log); | 513 | extern void jfs_syncpt(struct jfs_log *log); |
512 | 514 | ||
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 41bf078dce05..6c5485d16c39 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c | |||
@@ -198,7 +198,7 @@ static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) | |||
198 | } | 198 | } |
199 | } | 199 | } |
200 | 200 | ||
201 | static inline struct metapage *alloc_metapage(int gfp_mask) | 201 | static inline struct metapage *alloc_metapage(unsigned int gfp_mask) |
202 | { | 202 | { |
203 | return mempool_alloc(metapage_mempool, gfp_mask); | 203 | return mempool_alloc(metapage_mempool, gfp_mask); |
204 | } | 204 | } |
@@ -726,12 +726,12 @@ void force_metapage(struct metapage *mp) | |||
726 | page_cache_release(page); | 726 | page_cache_release(page); |
727 | } | 727 | } |
728 | 728 | ||
729 | extern void hold_metapage(struct metapage *mp) | 729 | void hold_metapage(struct metapage *mp) |
730 | { | 730 | { |
731 | lock_page(mp->page); | 731 | lock_page(mp->page); |
732 | } | 732 | } |
733 | 733 | ||
734 | extern void put_metapage(struct metapage *mp) | 734 | void put_metapage(struct metapage *mp) |
735 | { | 735 | { |
736 | if (mp->count || mp->nohomeok) { | 736 | if (mp->count || mp->nohomeok) { |
737 | /* Someone else will release this */ | 737 | /* Someone else will release this */ |
diff --git a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h index 991e9fb84c75..f0b7d3282b07 100644 --- a/fs/jfs/jfs_metapage.h +++ b/fs/jfs/jfs_metapage.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) International Business Machines Corp., 2000-2002 | 2 | * Copyright (C) International Business Machines Corp., 2000-2002 |
3 | * Portions Copyright (c) Christoph Hellwig, 2001-2002 | 3 | * Portions Copyright (C) Christoph Hellwig, 2001-2002 |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -58,6 +58,8 @@ struct metapage { | |||
58 | #define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag) | 58 | #define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag) |
59 | 59 | ||
60 | /* function prototypes */ | 60 | /* function prototypes */ |
61 | extern int metapage_init(void); | ||
62 | extern void metapage_exit(void); | ||
61 | extern struct metapage *__get_metapage(struct inode *inode, | 63 | extern struct metapage *__get_metapage(struct inode *inode, |
62 | unsigned long lblock, unsigned int size, | 64 | unsigned long lblock, unsigned int size, |
63 | int absolute, unsigned long new); | 65 | int absolute, unsigned long new); |
diff --git a/fs/jfs/jfs_superblock.h b/fs/jfs/jfs_superblock.h index ab0566f70cfa..fcf781bf31cb 100644 --- a/fs/jfs/jfs_superblock.h +++ b/fs/jfs/jfs_superblock.h | |||
@@ -109,5 +109,16 @@ struct jfs_superblock { | |||
109 | extern int readSuper(struct super_block *, struct buffer_head **); | 109 | extern int readSuper(struct super_block *, struct buffer_head **); |
110 | extern int updateSuper(struct super_block *, uint); | 110 | extern int updateSuper(struct super_block *, uint); |
111 | extern void jfs_error(struct super_block *, const char *, ...); | 111 | extern void jfs_error(struct super_block *, const char *, ...); |
112 | extern int jfs_mount(struct super_block *); | ||
113 | extern int jfs_mount_rw(struct super_block *, int); | ||
114 | extern int jfs_umount(struct super_block *); | ||
115 | extern int jfs_umount_rw(struct super_block *); | ||
116 | |||
117 | extern int jfs_stop_threads; | ||
118 | extern struct completion jfsIOwait; | ||
119 | extern wait_queue_head_t jfs_IO_thread_wait; | ||
120 | extern wait_queue_head_t jfs_commit_thread_wait; | ||
121 | extern wait_queue_head_t jfs_sync_thread_wait; | ||
122 | extern int jfs_extendfs(struct super_block *, s64, int); | ||
112 | 123 | ||
113 | #endif /*_H_JFS_SUPERBLOCK */ | 124 | #endif /*_H_JFS_SUPERBLOCK */ |
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index e93d01aa12c4..121c981ff453 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c | |||
@@ -42,7 +42,6 @@ | |||
42 | * hold on to mp+lock thru update of maps | 42 | * hold on to mp+lock thru update of maps |
43 | */ | 43 | */ |
44 | 44 | ||
45 | |||
46 | #include <linux/fs.h> | 45 | #include <linux/fs.h> |
47 | #include <linux/vmalloc.h> | 46 | #include <linux/vmalloc.h> |
48 | #include <linux/smp_lock.h> | 47 | #include <linux/smp_lock.h> |
@@ -51,6 +50,7 @@ | |||
51 | #include <linux/module.h> | 50 | #include <linux/module.h> |
52 | #include <linux/moduleparam.h> | 51 | #include <linux/moduleparam.h> |
53 | #include "jfs_incore.h" | 52 | #include "jfs_incore.h" |
53 | #include "jfs_inode.h" | ||
54 | #include "jfs_filsys.h" | 54 | #include "jfs_filsys.h" |
55 | #include "jfs_metapage.h" | 55 | #include "jfs_metapage.h" |
56 | #include "jfs_dinode.h" | 56 | #include "jfs_dinode.h" |
@@ -109,7 +109,6 @@ static int TxLockHWM; /* High water mark for number of txLocks used */ | |||
109 | static int TxLockVHWM; /* Very High water mark */ | 109 | static int TxLockVHWM; /* Very High water mark */ |
110 | struct tlock *TxLock; /* transaction lock table */ | 110 | struct tlock *TxLock; /* transaction lock table */ |
111 | 111 | ||
112 | |||
113 | /* | 112 | /* |
114 | * transaction management lock | 113 | * transaction management lock |
115 | */ | 114 | */ |
@@ -149,7 +148,6 @@ static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event) | |||
149 | 148 | ||
150 | #define TXN_WAKEUP(event) wake_up_all(event) | 149 | #define TXN_WAKEUP(event) wake_up_all(event) |
151 | 150 | ||
152 | |||
153 | /* | 151 | /* |
154 | * statistics | 152 | * statistics |
155 | */ | 153 | */ |
@@ -161,16 +159,6 @@ static struct { | |||
161 | int waitlock; /* 4: # of tlock wait */ | 159 | int waitlock; /* 4: # of tlock wait */ |
162 | } stattx; | 160 | } stattx; |
163 | 161 | ||
164 | |||
165 | /* | ||
166 | * external references | ||
167 | */ | ||
168 | extern int lmGroupCommit(struct jfs_log *, struct tblock *); | ||
169 | extern int jfs_commit_inode(struct inode *, int); | ||
170 | extern int jfs_stop_threads; | ||
171 | |||
172 | extern struct completion jfsIOwait; | ||
173 | |||
174 | /* | 162 | /* |
175 | * forward references | 163 | * forward references |
176 | */ | 164 | */ |
@@ -358,7 +346,6 @@ void txExit(void) | |||
358 | TxBlock = NULL; | 346 | TxBlock = NULL; |
359 | } | 347 | } |
360 | 348 | ||
361 | |||
362 | /* | 349 | /* |
363 | * NAME: txBegin() | 350 | * NAME: txBegin() |
364 | * | 351 | * |
@@ -460,7 +447,6 @@ tid_t txBegin(struct super_block *sb, int flag) | |||
460 | return t; | 447 | return t; |
461 | } | 448 | } |
462 | 449 | ||
463 | |||
464 | /* | 450 | /* |
465 | * NAME: txBeginAnon() | 451 | * NAME: txBeginAnon() |
466 | * | 452 | * |
@@ -503,7 +489,6 @@ void txBeginAnon(struct super_block *sb) | |||
503 | TXN_UNLOCK(); | 489 | TXN_UNLOCK(); |
504 | } | 490 | } |
505 | 491 | ||
506 | |||
507 | /* | 492 | /* |
508 | * txEnd() | 493 | * txEnd() |
509 | * | 494 | * |
@@ -592,7 +577,6 @@ wakeup: | |||
592 | TXN_WAKEUP(&TxAnchor.freewait); | 577 | TXN_WAKEUP(&TxAnchor.freewait); |
593 | } | 578 | } |
594 | 579 | ||
595 | |||
596 | /* | 580 | /* |
597 | * txLock() | 581 | * txLock() |
598 | * | 582 | * |
@@ -868,7 +852,6 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp, | |||
868 | return NULL; | 852 | return NULL; |
869 | } | 853 | } |
870 | 854 | ||
871 | |||
872 | /* | 855 | /* |
873 | * NAME: txRelease() | 856 | * NAME: txRelease() |
874 | * | 857 | * |
@@ -908,7 +891,6 @@ static void txRelease(struct tblock * tblk) | |||
908 | TXN_UNLOCK(); | 891 | TXN_UNLOCK(); |
909 | } | 892 | } |
910 | 893 | ||
911 | |||
912 | /* | 894 | /* |
913 | * NAME: txUnlock() | 895 | * NAME: txUnlock() |
914 | * | 896 | * |
@@ -996,7 +978,6 @@ static void txUnlock(struct tblock * tblk) | |||
996 | } | 978 | } |
997 | } | 979 | } |
998 | 980 | ||
999 | |||
1000 | /* | 981 | /* |
1001 | * txMaplock() | 982 | * txMaplock() |
1002 | * | 983 | * |
@@ -1069,7 +1050,6 @@ struct tlock *txMaplock(tid_t tid, struct inode *ip, int type) | |||
1069 | return tlck; | 1050 | return tlck; |
1070 | } | 1051 | } |
1071 | 1052 | ||
1072 | |||
1073 | /* | 1053 | /* |
1074 | * txLinelock() | 1054 | * txLinelock() |
1075 | * | 1055 | * |
@@ -1103,8 +1083,6 @@ struct linelock *txLinelock(struct linelock * tlock) | |||
1103 | return linelock; | 1083 | return linelock; |
1104 | } | 1084 | } |
1105 | 1085 | ||
1106 | |||
1107 | |||
1108 | /* | 1086 | /* |
1109 | * transaction commit management | 1087 | * transaction commit management |
1110 | * ----------------------------- | 1088 | * ----------------------------- |
@@ -1373,7 +1351,6 @@ int txCommit(tid_t tid, /* transaction identifier */ | |||
1373 | return rc; | 1351 | return rc; |
1374 | } | 1352 | } |
1375 | 1353 | ||
1376 | |||
1377 | /* | 1354 | /* |
1378 | * NAME: txLog() | 1355 | * NAME: txLog() |
1379 | * | 1356 | * |
@@ -1437,7 +1414,6 @@ static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd) | |||
1437 | return rc; | 1414 | return rc; |
1438 | } | 1415 | } |
1439 | 1416 | ||
1440 | |||
1441 | /* | 1417 | /* |
1442 | * diLog() | 1418 | * diLog() |
1443 | * | 1419 | * |
@@ -1465,7 +1441,6 @@ static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
1465 | if (tlck->type & tlckENTRY) { | 1441 | if (tlck->type & tlckENTRY) { |
1466 | /* log after-image for logredo(): */ | 1442 | /* log after-image for logredo(): */ |
1467 | lrd->type = cpu_to_le16(LOG_REDOPAGE); | 1443 | lrd->type = cpu_to_le16(LOG_REDOPAGE); |
1468 | // *pxd = mp->cm_pxd; | ||
1469 | PXDaddress(pxd, mp->index); | 1444 | PXDaddress(pxd, mp->index); |
1470 | PXDlength(pxd, | 1445 | PXDlength(pxd, |
1471 | mp->logical_size >> tblk->sb->s_blocksize_bits); | 1446 | mp->logical_size >> tblk->sb->s_blocksize_bits); |
@@ -1552,7 +1527,6 @@ static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
1552 | return rc; | 1527 | return rc; |
1553 | } | 1528 | } |
1554 | 1529 | ||
1555 | |||
1556 | /* | 1530 | /* |
1557 | * dataLog() | 1531 | * dataLog() |
1558 | * | 1532 | * |
@@ -1599,7 +1573,6 @@ static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
1599 | return 0; | 1573 | return 0; |
1600 | } | 1574 | } |
1601 | 1575 | ||
1602 | |||
1603 | /* | 1576 | /* |
1604 | * dtLog() | 1577 | * dtLog() |
1605 | * | 1578 | * |
@@ -1639,7 +1612,6 @@ static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
1639 | lrd->log.redopage.type |= cpu_to_le16(LOG_EXTEND); | 1612 | lrd->log.redopage.type |= cpu_to_le16(LOG_EXTEND); |
1640 | else | 1613 | else |
1641 | lrd->log.redopage.type |= cpu_to_le16(LOG_NEW); | 1614 | lrd->log.redopage.type |= cpu_to_le16(LOG_NEW); |
1642 | // *pxd = mp->cm_pxd; | ||
1643 | PXDaddress(pxd, mp->index); | 1615 | PXDaddress(pxd, mp->index); |
1644 | PXDlength(pxd, | 1616 | PXDlength(pxd, |
1645 | mp->logical_size >> tblk->sb->s_blocksize_bits); | 1617 | mp->logical_size >> tblk->sb->s_blocksize_bits); |
@@ -1704,7 +1676,6 @@ static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
1704 | return; | 1676 | return; |
1705 | } | 1677 | } |
1706 | 1678 | ||
1707 | |||
1708 | /* | 1679 | /* |
1709 | * xtLog() | 1680 | * xtLog() |
1710 | * | 1681 | * |
@@ -1760,7 +1731,6 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
1760 | * applying the after-image to the meta-data page. | 1731 | * applying the after-image to the meta-data page. |
1761 | */ | 1732 | */ |
1762 | lrd->type = cpu_to_le16(LOG_REDOPAGE); | 1733 | lrd->type = cpu_to_le16(LOG_REDOPAGE); |
1763 | // *page_pxd = mp->cm_pxd; | ||
1764 | PXDaddress(page_pxd, mp->index); | 1734 | PXDaddress(page_pxd, mp->index); |
1765 | PXDlength(page_pxd, | 1735 | PXDlength(page_pxd, |
1766 | mp->logical_size >> tblk->sb->s_blocksize_bits); | 1736 | mp->logical_size >> tblk->sb->s_blocksize_bits); |
@@ -2093,7 +2063,6 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
2093 | return; | 2063 | return; |
2094 | } | 2064 | } |
2095 | 2065 | ||
2096 | |||
2097 | /* | 2066 | /* |
2098 | * mapLog() | 2067 | * mapLog() |
2099 | * | 2068 | * |
@@ -2180,7 +2149,6 @@ void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
2180 | } | 2149 | } |
2181 | } | 2150 | } |
2182 | 2151 | ||
2183 | |||
2184 | /* | 2152 | /* |
2185 | * txEA() | 2153 | * txEA() |
2186 | * | 2154 | * |
@@ -2233,7 +2201,6 @@ void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea) | |||
2233 | } | 2201 | } |
2234 | } | 2202 | } |
2235 | 2203 | ||
2236 | |||
2237 | /* | 2204 | /* |
2238 | * txForce() | 2205 | * txForce() |
2239 | * | 2206 | * |
@@ -2300,7 +2267,6 @@ void txForce(struct tblock * tblk) | |||
2300 | } | 2267 | } |
2301 | } | 2268 | } |
2302 | 2269 | ||
2303 | |||
2304 | /* | 2270 | /* |
2305 | * txUpdateMap() | 2271 | * txUpdateMap() |
2306 | * | 2272 | * |
@@ -2437,7 +2403,6 @@ static void txUpdateMap(struct tblock * tblk) | |||
2437 | } | 2403 | } |
2438 | } | 2404 | } |
2439 | 2405 | ||
2440 | |||
2441 | /* | 2406 | /* |
2442 | * txAllocPMap() | 2407 | * txAllocPMap() |
2443 | * | 2408 | * |
@@ -2509,7 +2474,6 @@ static void txAllocPMap(struct inode *ip, struct maplock * maplock, | |||
2509 | } | 2474 | } |
2510 | } | 2475 | } |
2511 | 2476 | ||
2512 | |||
2513 | /* | 2477 | /* |
2514 | * txFreeMap() | 2478 | * txFreeMap() |
2515 | * | 2479 | * |
@@ -2611,7 +2575,6 @@ void txFreeMap(struct inode *ip, | |||
2611 | } | 2575 | } |
2612 | } | 2576 | } |
2613 | 2577 | ||
2614 | |||
2615 | /* | 2578 | /* |
2616 | * txFreelock() | 2579 | * txFreelock() |
2617 | * | 2580 | * |
@@ -2652,7 +2615,6 @@ void txFreelock(struct inode *ip) | |||
2652 | TXN_UNLOCK(); | 2615 | TXN_UNLOCK(); |
2653 | } | 2616 | } |
2654 | 2617 | ||
2655 | |||
2656 | /* | 2618 | /* |
2657 | * txAbort() | 2619 | * txAbort() |
2658 | * | 2620 | * |
@@ -2826,9 +2788,9 @@ int jfs_lazycommit(void *arg) | |||
2826 | /* In case a wakeup came while all threads were active */ | 2788 | /* In case a wakeup came while all threads were active */ |
2827 | jfs_commit_thread_waking = 0; | 2789 | jfs_commit_thread_waking = 0; |
2828 | 2790 | ||
2829 | if (current->flags & PF_FREEZE) { | 2791 | if (freezing(current)) { |
2830 | LAZY_UNLOCK(flags); | 2792 | LAZY_UNLOCK(flags); |
2831 | refrigerator(PF_FREEZE); | 2793 | refrigerator(); |
2832 | } else { | 2794 | } else { |
2833 | DECLARE_WAITQUEUE(wq, current); | 2795 | DECLARE_WAITQUEUE(wq, current); |
2834 | 2796 | ||
@@ -3025,9 +2987,9 @@ int jfs_sync(void *arg) | |||
3025 | /* Add anon_list2 back to anon_list */ | 2987 | /* Add anon_list2 back to anon_list */ |
3026 | list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list); | 2988 | list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list); |
3027 | 2989 | ||
3028 | if (current->flags & PF_FREEZE) { | 2990 | if (freezing(current)) { |
3029 | TXN_UNLOCK(); | 2991 | TXN_UNLOCK(); |
3030 | refrigerator(PF_FREEZE); | 2992 | refrigerator(); |
3031 | } else { | 2993 | } else { |
3032 | DECLARE_WAITQUEUE(wq, current); | 2994 | DECLARE_WAITQUEUE(wq, current); |
3033 | 2995 | ||
diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h index b71b82c2df04..59ad0f6b7231 100644 --- a/fs/jfs/jfs_txnmgr.h +++ b/fs/jfs/jfs_txnmgr.h | |||
@@ -285,34 +285,26 @@ struct commit { | |||
285 | /* | 285 | /* |
286 | * external declarations | 286 | * external declarations |
287 | */ | 287 | */ |
288 | extern struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage *mp, | 288 | extern int jfs_tlocks_low; |
289 | int flag); | 289 | |
290 | 290 | extern int txInit(void); | |
291 | extern struct tlock *txMaplock(tid_t tid, struct inode *ip, int flag); | 291 | extern void txExit(void); |
292 | 292 | extern struct tlock *txLock(tid_t, struct inode *, struct metapage *, int); | |
293 | extern int txCommit(tid_t tid, int nip, struct inode **iplist, int flag); | 293 | extern struct tlock *txMaplock(tid_t, struct inode *, int); |
294 | 294 | extern int txCommit(tid_t, int, struct inode **, int); | |
295 | extern tid_t txBegin(struct super_block *sb, int flag); | 295 | extern tid_t txBegin(struct super_block *, int); |
296 | 296 | extern void txBeginAnon(struct super_block *); | |
297 | extern void txBeginAnon(struct super_block *sb); | 297 | extern void txEnd(tid_t); |
298 | 298 | extern void txAbort(tid_t, int); | |
299 | extern void txEnd(tid_t tid); | 299 | extern struct linelock *txLinelock(struct linelock *); |
300 | 300 | extern void txFreeMap(struct inode *, struct maplock *, struct tblock *, int); | |
301 | extern void txAbort(tid_t tid, int dirty); | 301 | extern void txEA(tid_t, struct inode *, dxd_t *, dxd_t *); |
302 | 302 | extern void txFreelock(struct inode *); | |
303 | extern struct linelock *txLinelock(struct linelock * tlock); | 303 | extern int lmLog(struct jfs_log *, struct tblock *, struct lrd *, |
304 | 304 | struct tlock *); | |
305 | extern void txFreeMap(struct inode *ip, struct maplock * maplock, | 305 | extern void txQuiesce(struct super_block *); |
306 | struct tblock * tblk, int maptype); | 306 | extern void txResume(struct super_block *); |
307 | 307 | extern void txLazyUnlock(struct tblock *); | |
308 | extern void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea); | 308 | extern int jfs_lazycommit(void *); |
309 | 309 | extern int jfs_sync(void *); | |
310 | extern void txFreelock(struct inode *ip); | ||
311 | |||
312 | extern int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | ||
313 | struct tlock * tlck); | ||
314 | |||
315 | extern void txQuiesce(struct super_block *sb); | ||
316 | |||
317 | extern void txResume(struct super_block *sb); | ||
318 | #endif /* _H_JFS_TXNMGR */ | 310 | #endif /* _H_JFS_TXNMGR */ |
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 8413a368f449..1cae14e741eb 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c | |||
@@ -31,20 +31,9 @@ | |||
31 | #include "jfs_acl.h" | 31 | #include "jfs_acl.h" |
32 | #include "jfs_debug.h" | 32 | #include "jfs_debug.h" |
33 | 33 | ||
34 | extern struct inode_operations jfs_file_inode_operations; | ||
35 | extern struct inode_operations jfs_symlink_inode_operations; | ||
36 | extern struct file_operations jfs_file_operations; | ||
37 | extern struct address_space_operations jfs_aops; | ||
38 | |||
39 | extern int jfs_fsync(struct file *, struct dentry *, int); | ||
40 | extern void jfs_truncate_nolock(struct inode *, loff_t); | ||
41 | extern int jfs_init_acl(struct inode *, struct inode *); | ||
42 | |||
43 | /* | 34 | /* |
44 | * forward references | 35 | * forward references |
45 | */ | 36 | */ |
46 | struct inode_operations jfs_dir_inode_operations; | ||
47 | struct file_operations jfs_dir_operations; | ||
48 | struct dentry_operations jfs_ci_dentry_operations; | 37 | struct dentry_operations jfs_ci_dentry_operations; |
49 | 38 | ||
50 | static s64 commitZeroLink(tid_t, struct inode *); | 39 | static s64 commitZeroLink(tid_t, struct inode *); |
@@ -655,7 +644,7 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip) | |||
655 | 644 | ||
656 | 645 | ||
657 | /* | 646 | /* |
658 | * NAME: freeZeroLink() | 647 | * NAME: jfs_free_zero_link() |
659 | * | 648 | * |
660 | * FUNCTION: for non-directory, called by iClose(), | 649 | * FUNCTION: for non-directory, called by iClose(), |
661 | * free resources of a file from cache and WORKING map | 650 | * free resources of a file from cache and WORKING map |
@@ -663,15 +652,12 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip) | |||
663 | * while associated with a pager object, | 652 | * while associated with a pager object, |
664 | * | 653 | * |
665 | * PARAMETER: ip - pointer to inode of file. | 654 | * PARAMETER: ip - pointer to inode of file. |
666 | * | ||
667 | * RETURN: 0 -ok | ||
668 | */ | 655 | */ |
669 | int freeZeroLink(struct inode *ip) | 656 | void jfs_free_zero_link(struct inode *ip) |
670 | { | 657 | { |
671 | int rc = 0; | ||
672 | int type; | 658 | int type; |
673 | 659 | ||
674 | jfs_info("freeZeroLink: ip = 0x%p", ip); | 660 | jfs_info("jfs_free_zero_link: ip = 0x%p", ip); |
675 | 661 | ||
676 | /* return if not reg or symbolic link or if size is | 662 | /* return if not reg or symbolic link or if size is |
677 | * already ok. | 663 | * already ok. |
@@ -684,10 +670,10 @@ int freeZeroLink(struct inode *ip) | |||
684 | case S_IFLNK: | 670 | case S_IFLNK: |
685 | /* if its contained in inode nothing to do */ | 671 | /* if its contained in inode nothing to do */ |
686 | if (ip->i_size < IDATASIZE) | 672 | if (ip->i_size < IDATASIZE) |
687 | return 0; | 673 | return; |
688 | break; | 674 | break; |
689 | default: | 675 | default: |
690 | return 0; | 676 | return; |
691 | } | 677 | } |
692 | 678 | ||
693 | /* | 679 | /* |
@@ -737,9 +723,7 @@ int freeZeroLink(struct inode *ip) | |||
737 | * free xtree/data blocks from working block map; | 723 | * free xtree/data blocks from working block map; |
738 | */ | 724 | */ |
739 | if (ip->i_size) | 725 | if (ip->i_size) |
740 | rc = xtTruncate(0, ip, 0, COMMIT_WMAP); | 726 | xtTruncate(0, ip, 0, COMMIT_WMAP); |
741 | |||
742 | return rc; | ||
743 | } | 727 | } |
744 | 728 | ||
745 | /* | 729 | /* |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 5e774ed7fb64..ee32211288ce 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
@@ -24,10 +24,12 @@ | |||
24 | #include <linux/completion.h> | 24 | #include <linux/completion.h> |
25 | #include <linux/vfs.h> | 25 | #include <linux/vfs.h> |
26 | #include <linux/moduleparam.h> | 26 | #include <linux/moduleparam.h> |
27 | #include <linux/posix_acl.h> | ||
27 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
28 | 29 | ||
29 | #include "jfs_incore.h" | 30 | #include "jfs_incore.h" |
30 | #include "jfs_filsys.h" | 31 | #include "jfs_filsys.h" |
32 | #include "jfs_inode.h" | ||
31 | #include "jfs_metapage.h" | 33 | #include "jfs_metapage.h" |
32 | #include "jfs_superblock.h" | 34 | #include "jfs_superblock.h" |
33 | #include "jfs_dmap.h" | 35 | #include "jfs_dmap.h" |
@@ -62,37 +64,6 @@ module_param(jfsloglevel, int, 0644); | |||
62 | MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)"); | 64 | MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)"); |
63 | #endif | 65 | #endif |
64 | 66 | ||
65 | /* | ||
66 | * External declarations | ||
67 | */ | ||
68 | extern int jfs_mount(struct super_block *); | ||
69 | extern int jfs_mount_rw(struct super_block *, int); | ||
70 | extern int jfs_umount(struct super_block *); | ||
71 | extern int jfs_umount_rw(struct super_block *); | ||
72 | |||
73 | extern int jfsIOWait(void *); | ||
74 | extern int jfs_lazycommit(void *); | ||
75 | extern int jfs_sync(void *); | ||
76 | |||
77 | extern void jfs_read_inode(struct inode *inode); | ||
78 | extern void jfs_dirty_inode(struct inode *inode); | ||
79 | extern void jfs_delete_inode(struct inode *inode); | ||
80 | extern int jfs_write_inode(struct inode *inode, int wait); | ||
81 | |||
82 | extern struct dentry *jfs_get_parent(struct dentry *dentry); | ||
83 | extern int jfs_extendfs(struct super_block *, s64, int); | ||
84 | |||
85 | extern struct dentry_operations jfs_ci_dentry_operations; | ||
86 | |||
87 | #ifdef PROC_FS_JFS /* see jfs_debug.h */ | ||
88 | extern void jfs_proc_init(void); | ||
89 | extern void jfs_proc_clean(void); | ||
90 | #endif | ||
91 | |||
92 | extern wait_queue_head_t jfs_IO_thread_wait; | ||
93 | extern wait_queue_head_t jfs_commit_thread_wait; | ||
94 | extern wait_queue_head_t jfs_sync_thread_wait; | ||
95 | |||
96 | static void jfs_handle_error(struct super_block *sb) | 67 | static void jfs_handle_error(struct super_block *sb) |
97 | { | 68 | { |
98 | struct jfs_sb_info *sbi = JFS_SBI(sb); | 69 | struct jfs_sb_info *sbi = JFS_SBI(sb); |
@@ -593,11 +564,6 @@ static struct file_system_type jfs_fs_type = { | |||
593 | .fs_flags = FS_REQUIRES_DEV, | 564 | .fs_flags = FS_REQUIRES_DEV, |
594 | }; | 565 | }; |
595 | 566 | ||
596 | extern int metapage_init(void); | ||
597 | extern int txInit(void); | ||
598 | extern void txExit(void); | ||
599 | extern void metapage_exit(void); | ||
600 | |||
601 | static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) | 567 | static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) |
602 | { | 568 | { |
603 | struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo; | 569 | struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo; |
diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c index ef4c07ee92b2..287d8d6c3cfd 100644 --- a/fs/jfs/symlink.c +++ b/fs/jfs/symlink.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Christoph Hellwig, 2001-2002 | 2 | * Copyright (C) Christoph Hellwig, 2001-2002 |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/namei.h> | 20 | #include <linux/namei.h> |
21 | #include "jfs_incore.h" | 21 | #include "jfs_incore.h" |
22 | #include "jfs_inode.h" | ||
22 | #include "jfs_xattr.h" | 23 | #include "jfs_xattr.h" |
23 | 24 | ||
24 | static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd) | 25 | static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd) |
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 7a9ffd5d03dc..ee438d429d45 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/xattr.h> | 21 | #include <linux/xattr.h> |
22 | #include <linux/posix_acl_xattr.h> | ||
22 | #include <linux/quotaops.h> | 23 | #include <linux/quotaops.h> |
23 | #include "jfs_incore.h" | 24 | #include "jfs_incore.h" |
24 | #include "jfs_superblock.h" | 25 | #include "jfs_superblock.h" |
@@ -718,9 +719,9 @@ static int can_set_system_xattr(struct inode *inode, const char *name, | |||
718 | return -EPERM; | 719 | return -EPERM; |
719 | 720 | ||
720 | /* | 721 | /* |
721 | * XATTR_NAME_ACL_ACCESS is tied to i_mode | 722 | * POSIX_ACL_XATTR_ACCESS is tied to i_mode |
722 | */ | 723 | */ |
723 | if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) { | 724 | if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) { |
724 | acl = posix_acl_from_xattr(value, value_len); | 725 | acl = posix_acl_from_xattr(value, value_len); |
725 | if (IS_ERR(acl)) { | 726 | if (IS_ERR(acl)) { |
726 | rc = PTR_ERR(acl); | 727 | rc = PTR_ERR(acl); |
@@ -750,7 +751,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name, | |||
750 | JFS_IP(inode)->i_acl = JFS_ACL_NOT_CACHED; | 751 | JFS_IP(inode)->i_acl = JFS_ACL_NOT_CACHED; |
751 | 752 | ||
752 | return 0; | 753 | return 0; |
753 | } else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) { | 754 | } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { |
754 | acl = posix_acl_from_xattr(value, value_len); | 755 | acl = posix_acl_from_xattr(value, value_len); |
755 | if (IS_ERR(acl)) { | 756 | if (IS_ERR(acl)) { |
756 | rc = PTR_ERR(acl); | 757 | rc = PTR_ERR(acl); |
@@ -946,8 +947,7 @@ int __jfs_setxattr(struct inode *inode, const char *name, const void *value, | |||
946 | out: | 947 | out: |
947 | up_write(&JFS_IP(inode)->xattr_sem); | 948 | up_write(&JFS_IP(inode)->xattr_sem); |
948 | 949 | ||
949 | if (os2name) | 950 | kfree(os2name); |
950 | kfree(os2name); | ||
951 | 951 | ||
952 | return rc; | 952 | return rc; |
953 | } | 953 | } |
@@ -1042,8 +1042,7 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, | |||
1042 | out: | 1042 | out: |
1043 | up_read(&JFS_IP(inode)->xattr_sem); | 1043 | up_read(&JFS_IP(inode)->xattr_sem); |
1044 | 1044 | ||
1045 | if (os2name) | 1045 | kfree(os2name); |
1046 | kfree(os2name); | ||
1047 | 1046 | ||
1048 | return size; | 1047 | return size; |
1049 | } | 1048 | } |
diff --git a/fs/libfs.c b/fs/libfs.c index f90b29595927..58101dff2c66 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -183,6 +183,7 @@ struct file_operations simple_dir_operations = { | |||
183 | .llseek = dcache_dir_lseek, | 183 | .llseek = dcache_dir_lseek, |
184 | .read = generic_read_dir, | 184 | .read = generic_read_dir, |
185 | .readdir = dcache_readdir, | 185 | .readdir = dcache_readdir, |
186 | .fsync = simple_sync_file, | ||
186 | }; | 187 | }; |
187 | 188 | ||
188 | struct inode_operations simple_dir_inode_operations = { | 189 | struct inode_operations simple_dir_inode_operations = { |
@@ -519,6 +520,102 @@ int simple_transaction_release(struct inode *inode, struct file *file) | |||
519 | return 0; | 520 | return 0; |
520 | } | 521 | } |
521 | 522 | ||
523 | /* Simple attribute files */ | ||
524 | |||
525 | struct simple_attr { | ||
526 | u64 (*get)(void *); | ||
527 | void (*set)(void *, u64); | ||
528 | char get_buf[24]; /* enough to store a u64 and "\n\0" */ | ||
529 | char set_buf[24]; | ||
530 | void *data; | ||
531 | const char *fmt; /* format for read operation */ | ||
532 | struct semaphore sem; /* protects access to these buffers */ | ||
533 | }; | ||
534 | |||
535 | /* simple_attr_open is called by an actual attribute open file operation | ||
536 | * to set the attribute specific access operations. */ | ||
537 | int simple_attr_open(struct inode *inode, struct file *file, | ||
538 | u64 (*get)(void *), void (*set)(void *, u64), | ||
539 | const char *fmt) | ||
540 | { | ||
541 | struct simple_attr *attr; | ||
542 | |||
543 | attr = kmalloc(sizeof(*attr), GFP_KERNEL); | ||
544 | if (!attr) | ||
545 | return -ENOMEM; | ||
546 | |||
547 | attr->get = get; | ||
548 | attr->set = set; | ||
549 | attr->data = inode->u.generic_ip; | ||
550 | attr->fmt = fmt; | ||
551 | init_MUTEX(&attr->sem); | ||
552 | |||
553 | file->private_data = attr; | ||
554 | |||
555 | return nonseekable_open(inode, file); | ||
556 | } | ||
557 | |||
558 | int simple_attr_close(struct inode *inode, struct file *file) | ||
559 | { | ||
560 | kfree(file->private_data); | ||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | /* read from the buffer that is filled with the get function */ | ||
565 | ssize_t simple_attr_read(struct file *file, char __user *buf, | ||
566 | size_t len, loff_t *ppos) | ||
567 | { | ||
568 | struct simple_attr *attr; | ||
569 | size_t size; | ||
570 | ssize_t ret; | ||
571 | |||
572 | attr = file->private_data; | ||
573 | |||
574 | if (!attr->get) | ||
575 | return -EACCES; | ||
576 | |||
577 | down(&attr->sem); | ||
578 | if (*ppos) /* continued read */ | ||
579 | size = strlen(attr->get_buf); | ||
580 | else /* first read */ | ||
581 | size = scnprintf(attr->get_buf, sizeof(attr->get_buf), | ||
582 | attr->fmt, | ||
583 | (unsigned long long)attr->get(attr->data)); | ||
584 | |||
585 | ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); | ||
586 | up(&attr->sem); | ||
587 | return ret; | ||
588 | } | ||
589 | |||
590 | /* interpret the buffer as a number to call the set function with */ | ||
591 | ssize_t simple_attr_write(struct file *file, const char __user *buf, | ||
592 | size_t len, loff_t *ppos) | ||
593 | { | ||
594 | struct simple_attr *attr; | ||
595 | u64 val; | ||
596 | size_t size; | ||
597 | ssize_t ret; | ||
598 | |||
599 | attr = file->private_data; | ||
600 | |||
601 | if (!attr->set) | ||
602 | return -EACCES; | ||
603 | |||
604 | down(&attr->sem); | ||
605 | ret = -EFAULT; | ||
606 | size = min(sizeof(attr->set_buf) - 1, len); | ||
607 | if (copy_from_user(attr->set_buf, buf, size)) | ||
608 | goto out; | ||
609 | |||
610 | ret = len; /* claim we got the whole input */ | ||
611 | attr->set_buf[size] = '\0'; | ||
612 | val = simple_strtol(attr->set_buf, NULL, 0); | ||
613 | attr->set(attr->data, val); | ||
614 | out: | ||
615 | up(&attr->sem); | ||
616 | return ret; | ||
617 | } | ||
618 | |||
522 | EXPORT_SYMBOL(dcache_dir_close); | 619 | EXPORT_SYMBOL(dcache_dir_close); |
523 | EXPORT_SYMBOL(dcache_dir_lseek); | 620 | EXPORT_SYMBOL(dcache_dir_lseek); |
524 | EXPORT_SYMBOL(dcache_dir_open); | 621 | EXPORT_SYMBOL(dcache_dir_open); |
@@ -547,3 +644,7 @@ EXPORT_SYMBOL(simple_read_from_buffer); | |||
547 | EXPORT_SYMBOL(simple_transaction_get); | 644 | EXPORT_SYMBOL(simple_transaction_get); |
548 | EXPORT_SYMBOL(simple_transaction_read); | 645 | EXPORT_SYMBOL(simple_transaction_read); |
549 | EXPORT_SYMBOL(simple_transaction_release); | 646 | EXPORT_SYMBOL(simple_transaction_release); |
647 | EXPORT_SYMBOL_GPL(simple_attr_open); | ||
648 | EXPORT_SYMBOL_GPL(simple_attr_close); | ||
649 | EXPORT_SYMBOL_GPL(simple_attr_read); | ||
650 | EXPORT_SYMBOL_GPL(simple_attr_write); | ||
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index ef7103b8c5bd..006bb9e14579 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -31,7 +31,7 @@ static int reclaimer(void *ptr); | |||
31 | * This is the representation of a blocked client lock. | 31 | * This is the representation of a blocked client lock. |
32 | */ | 32 | */ |
33 | struct nlm_wait { | 33 | struct nlm_wait { |
34 | struct nlm_wait * b_next; /* linked list */ | 34 | struct list_head b_list; /* linked list */ |
35 | wait_queue_head_t b_wait; /* where to wait on */ | 35 | wait_queue_head_t b_wait; /* where to wait on */ |
36 | struct nlm_host * b_host; | 36 | struct nlm_host * b_host; |
37 | struct file_lock * b_lock; /* local file lock */ | 37 | struct file_lock * b_lock; /* local file lock */ |
@@ -39,27 +39,54 @@ struct nlm_wait { | |||
39 | u32 b_status; /* grant callback status */ | 39 | u32 b_status; /* grant callback status */ |
40 | }; | 40 | }; |
41 | 41 | ||
42 | static struct nlm_wait * nlm_blocked; | 42 | static LIST_HEAD(nlm_blocked); |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Block on a lock | 45 | * Queue up a lock for blocking so that the GRANTED request can see it |
46 | */ | 46 | */ |
47 | int | 47 | int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl) |
48 | nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) | 48 | { |
49 | struct nlm_wait *block; | ||
50 | |||
51 | BUG_ON(req->a_block != NULL); | ||
52 | block = kmalloc(sizeof(*block), GFP_KERNEL); | ||
53 | if (block == NULL) | ||
54 | return -ENOMEM; | ||
55 | block->b_host = host; | ||
56 | block->b_lock = fl; | ||
57 | init_waitqueue_head(&block->b_wait); | ||
58 | block->b_status = NLM_LCK_BLOCKED; | ||
59 | |||
60 | list_add(&block->b_list, &nlm_blocked); | ||
61 | req->a_block = block; | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | void nlmclnt_finish_block(struct nlm_rqst *req) | ||
49 | { | 67 | { |
50 | struct nlm_wait block, **head; | 68 | struct nlm_wait *block = req->a_block; |
51 | int err; | ||
52 | u32 pstate; | ||
53 | 69 | ||
54 | block.b_host = host; | 70 | if (block == NULL) |
55 | block.b_lock = fl; | 71 | return; |
56 | init_waitqueue_head(&block.b_wait); | 72 | req->a_block = NULL; |
57 | block.b_status = NLM_LCK_BLOCKED; | 73 | list_del(&block->b_list); |
58 | block.b_next = nlm_blocked; | 74 | kfree(block); |
59 | nlm_blocked = █ | 75 | } |
76 | |||
77 | /* | ||
78 | * Block on a lock | ||
79 | */ | ||
80 | long nlmclnt_block(struct nlm_rqst *req, long timeout) | ||
81 | { | ||
82 | struct nlm_wait *block = req->a_block; | ||
83 | long ret; | ||
60 | 84 | ||
61 | /* Remember pseudo nsm state */ | 85 | /* A borken server might ask us to block even if we didn't |
62 | pstate = host->h_state; | 86 | * request it. Just say no! |
87 | */ | ||
88 | if (!req->a_args.block) | ||
89 | return -EAGAIN; | ||
63 | 90 | ||
64 | /* Go to sleep waiting for GRANT callback. Some servers seem | 91 | /* Go to sleep waiting for GRANT callback. Some servers seem |
65 | * to lose callbacks, however, so we're going to poll from | 92 | * to lose callbacks, however, so we're going to poll from |
@@ -69,28 +96,16 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp) | |||
69 | * a 1 minute timeout would do. See the comment before | 96 | * a 1 minute timeout would do. See the comment before |
70 | * nlmclnt_lock for an explanation. | 97 | * nlmclnt_lock for an explanation. |
71 | */ | 98 | */ |
72 | sleep_on_timeout(&block.b_wait, 30*HZ); | 99 | ret = wait_event_interruptible_timeout(block->b_wait, |
73 | 100 | block->b_status != NLM_LCK_BLOCKED, | |
74 | for (head = &nlm_blocked; *head; head = &(*head)->b_next) { | 101 | timeout); |
75 | if (*head == &block) { | ||
76 | *head = block.b_next; | ||
77 | break; | ||
78 | } | ||
79 | } | ||
80 | 102 | ||
81 | if (!signalled()) { | 103 | if (block->b_status != NLM_LCK_BLOCKED) { |
82 | *statp = block.b_status; | 104 | req->a_res.status = block->b_status; |
83 | return 0; | 105 | block->b_status = NLM_LCK_BLOCKED; |
84 | } | 106 | } |
85 | 107 | ||
86 | /* Okay, we were interrupted. Cancel the pending request | 108 | return ret; |
87 | * unless the server has rebooted. | ||
88 | */ | ||
89 | if (pstate == host->h_state && (err = nlmclnt_cancel(host, fl)) < 0) | ||
90 | printk(KERN_NOTICE | ||
91 | "lockd: CANCEL call failed (errno %d)\n", -err); | ||
92 | |||
93 | return -ERESTARTSYS; | ||
94 | } | 109 | } |
95 | 110 | ||
96 | /* | 111 | /* |
@@ -100,27 +115,23 @@ u32 | |||
100 | nlmclnt_grant(struct nlm_lock *lock) | 115 | nlmclnt_grant(struct nlm_lock *lock) |
101 | { | 116 | { |
102 | struct nlm_wait *block; | 117 | struct nlm_wait *block; |
118 | u32 res = nlm_lck_denied; | ||
103 | 119 | ||
104 | /* | 120 | /* |
105 | * Look up blocked request based on arguments. | 121 | * Look up blocked request based on arguments. |
106 | * Warning: must not use cookie to match it! | 122 | * Warning: must not use cookie to match it! |
107 | */ | 123 | */ |
108 | for (block = nlm_blocked; block; block = block->b_next) { | 124 | list_for_each_entry(block, &nlm_blocked, b_list) { |
109 | if (nlm_compare_locks(block->b_lock, &lock->fl)) | 125 | if (nlm_compare_locks(block->b_lock, &lock->fl)) { |
110 | break; | 126 | /* Alright, we found a lock. Set the return status |
127 | * and wake up the caller | ||
128 | */ | ||
129 | block->b_status = NLM_LCK_GRANTED; | ||
130 | wake_up(&block->b_wait); | ||
131 | res = nlm_granted; | ||
132 | } | ||
111 | } | 133 | } |
112 | 134 | return res; | |
113 | /* Ooops, no blocked request found. */ | ||
114 | if (block == NULL) | ||
115 | return nlm_lck_denied; | ||
116 | |||
117 | /* Alright, we found the lock. Set the return status and | ||
118 | * wake up the caller. | ||
119 | */ | ||
120 | block->b_status = NLM_LCK_GRANTED; | ||
121 | wake_up(&block->b_wait); | ||
122 | |||
123 | return nlm_granted; | ||
124 | } | 135 | } |
125 | 136 | ||
126 | /* | 137 | /* |
@@ -230,7 +241,7 @@ restart: | |||
230 | host->h_reclaiming = 0; | 241 | host->h_reclaiming = 0; |
231 | 242 | ||
232 | /* Now, wake up all processes that sleep on a blocked lock */ | 243 | /* Now, wake up all processes that sleep on a blocked lock */ |
233 | for (block = nlm_blocked; block; block = block->b_next) { | 244 | list_for_each_entry(block, &nlm_blocked, b_list) { |
234 | if (block->b_host == host) { | 245 | if (block->b_host == host) { |
235 | block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; | 246 | block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; |
236 | wake_up(&block->b_wait); | 247 | wake_up(&block->b_wait); |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index a4407619b1f1..14b3ce87fa29 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #define NLMDBG_FACILITY NLMDBG_CLIENT | 22 | #define NLMDBG_FACILITY NLMDBG_CLIENT |
23 | #define NLMCLNT_GRACE_WAIT (5*HZ) | 23 | #define NLMCLNT_GRACE_WAIT (5*HZ) |
24 | #define NLMCLNT_POLL_TIMEOUT (30*HZ) | ||
24 | 25 | ||
25 | static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); | 26 | static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); |
26 | static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); | 27 | static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); |
@@ -312,7 +313,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue) | |||
312 | prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE); | 313 | prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE); |
313 | if (!signalled ()) { | 314 | if (!signalled ()) { |
314 | schedule_timeout(NLMCLNT_GRACE_WAIT); | 315 | schedule_timeout(NLMCLNT_GRACE_WAIT); |
315 | try_to_freeze(PF_FREEZE); | 316 | try_to_freeze(); |
316 | if (!signalled ()) | 317 | if (!signalled ()) |
317 | status = 0; | 318 | status = 0; |
318 | } | 319 | } |
@@ -553,7 +554,8 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
553 | { | 554 | { |
554 | struct nlm_host *host = req->a_host; | 555 | struct nlm_host *host = req->a_host; |
555 | struct nlm_res *resp = &req->a_res; | 556 | struct nlm_res *resp = &req->a_res; |
556 | int status; | 557 | long timeout; |
558 | int status; | ||
557 | 559 | ||
558 | if (!host->h_monitored && nsm_monitor(host) < 0) { | 560 | if (!host->h_monitored && nsm_monitor(host) < 0) { |
559 | printk(KERN_NOTICE "lockd: failed to monitor %s\n", | 561 | printk(KERN_NOTICE "lockd: failed to monitor %s\n", |
@@ -562,15 +564,32 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
562 | goto out; | 564 | goto out; |
563 | } | 565 | } |
564 | 566 | ||
565 | do { | 567 | if (req->a_args.block) { |
566 | if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) { | 568 | status = nlmclnt_prepare_block(req, host, fl); |
567 | if (resp->status != NLM_LCK_BLOCKED) | ||
568 | break; | ||
569 | status = nlmclnt_block(host, fl, &resp->status); | ||
570 | } | ||
571 | if (status < 0) | 569 | if (status < 0) |
572 | goto out; | 570 | goto out; |
573 | } while (resp->status == NLM_LCK_BLOCKED && req->a_args.block); | 571 | } |
572 | for(;;) { | ||
573 | status = nlmclnt_call(req, NLMPROC_LOCK); | ||
574 | if (status < 0) | ||
575 | goto out_unblock; | ||
576 | if (resp->status != NLM_LCK_BLOCKED) | ||
577 | break; | ||
578 | /* Wait on an NLM blocking lock */ | ||
579 | timeout = nlmclnt_block(req, NLMCLNT_POLL_TIMEOUT); | ||
580 | /* Did a reclaimer thread notify us of a server reboot? */ | ||
581 | if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) | ||
582 | continue; | ||
583 | if (resp->status != NLM_LCK_BLOCKED) | ||
584 | break; | ||
585 | if (timeout >= 0) | ||
586 | continue; | ||
587 | /* We were interrupted. Send a CANCEL request to the server | ||
588 | * and exit | ||
589 | */ | ||
590 | status = (int)timeout; | ||
591 | goto out_unblock; | ||
592 | } | ||
574 | 593 | ||
575 | if (resp->status == NLM_LCK_GRANTED) { | 594 | if (resp->status == NLM_LCK_GRANTED) { |
576 | fl->fl_u.nfs_fl.state = host->h_state; | 595 | fl->fl_u.nfs_fl.state = host->h_state; |
@@ -579,6 +598,11 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
579 | do_vfs_lock(fl); | 598 | do_vfs_lock(fl); |
580 | } | 599 | } |
581 | status = nlm_stat_to_errno(resp->status); | 600 | status = nlm_stat_to_errno(resp->status); |
601 | out_unblock: | ||
602 | nlmclnt_finish_block(req); | ||
603 | /* Cancel the blocked request if it is still pending */ | ||
604 | if (resp->status == NLM_LCK_BLOCKED) | ||
605 | nlmclnt_cancel(host, fl); | ||
582 | out: | 606 | out: |
583 | nlmclnt_release_lockargs(req); | 607 | nlmclnt_release_lockargs(req); |
584 | return status; | 608 | return status; |
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 52707c5ad6ea..82c77df81c5f 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -189,17 +189,15 @@ nlm_bind_host(struct nlm_host *host) | |||
189 | goto forgetit; | 189 | goto forgetit; |
190 | 190 | ||
191 | xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); | 191 | xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); |
192 | xprt->nocong = 1; /* No congestion control for NLM */ | ||
193 | xprt->resvport = 1; /* NLM requires a reserved port */ | ||
192 | 194 | ||
193 | /* Existing NLM servers accept AUTH_UNIX only */ | 195 | /* Existing NLM servers accept AUTH_UNIX only */ |
194 | clnt = rpc_create_client(xprt, host->h_name, &nlm_program, | 196 | clnt = rpc_create_client(xprt, host->h_name, &nlm_program, |
195 | host->h_version, RPC_AUTH_UNIX); | 197 | host->h_version, RPC_AUTH_UNIX); |
196 | if (IS_ERR(clnt)) { | 198 | if (IS_ERR(clnt)) |
197 | xprt_destroy(xprt); | ||
198 | goto forgetit; | 199 | goto forgetit; |
199 | } | ||
200 | clnt->cl_autobind = 1; /* turn on pmap queries */ | 200 | clnt->cl_autobind = 1; /* turn on pmap queries */ |
201 | xprt->nocong = 1; /* No congestion control for NLM */ | ||
202 | xprt->resvport = 1; /* NLM requires a reserved port */ | ||
203 | 201 | ||
204 | host->h_rpcclnt = clnt; | 202 | host->h_rpcclnt = clnt; |
205 | } | 203 | } |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 6fc1bebeec1d..2d144abe84ad 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -115,20 +115,19 @@ nsm_create(void) | |||
115 | xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); | 115 | xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); |
116 | if (IS_ERR(xprt)) | 116 | if (IS_ERR(xprt)) |
117 | return (struct rpc_clnt *)xprt; | 117 | return (struct rpc_clnt *)xprt; |
118 | xprt->resvport = 1; /* NSM requires a reserved port */ | ||
118 | 119 | ||
119 | clnt = rpc_create_client(xprt, "localhost", | 120 | clnt = rpc_create_client(xprt, "localhost", |
120 | &nsm_program, SM_VERSION, | 121 | &nsm_program, SM_VERSION, |
121 | RPC_AUTH_NULL); | 122 | RPC_AUTH_NULL); |
122 | if (IS_ERR(clnt)) | 123 | if (IS_ERR(clnt)) |
123 | goto out_destroy; | 124 | goto out_err; |
124 | clnt->cl_softrtry = 1; | 125 | clnt->cl_softrtry = 1; |
125 | clnt->cl_chatty = 1; | 126 | clnt->cl_chatty = 1; |
126 | clnt->cl_oneshot = 1; | 127 | clnt->cl_oneshot = 1; |
127 | xprt->resvport = 1; /* NSM requires a reserved port */ | ||
128 | return clnt; | 128 | return clnt; |
129 | 129 | ||
130 | out_destroy: | 130 | out_err: |
131 | xprt_destroy(xprt); | ||
132 | return clnt; | 131 | return clnt; |
133 | } | 132 | } |
134 | 133 | ||
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index b82e470912e8..6e242556b903 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -191,7 +191,9 @@ lockd(struct svc_rqst *rqstp) | |||
191 | printk(KERN_DEBUG | 191 | printk(KERN_DEBUG |
192 | "lockd: new process, skipping host shutdown\n"); | 192 | "lockd: new process, skipping host shutdown\n"); |
193 | wake_up(&lockd_exit); | 193 | wake_up(&lockd_exit); |
194 | 194 | ||
195 | flush_signals(current); | ||
196 | |||
195 | /* Exit the RPC thread */ | 197 | /* Exit the RPC thread */ |
196 | svc_exit_thread(rqstp); | 198 | svc_exit_thread(rqstp); |
197 | 199 | ||
diff --git a/fs/locks.c b/fs/locks.c index 3fa6a7ce57a7..a0bc03495bd4 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1548,6 +1548,8 @@ int fcntl_getlk(struct file *filp, struct flock __user *l) | |||
1548 | 1548 | ||
1549 | if (filp->f_op && filp->f_op->lock) { | 1549 | if (filp->f_op && filp->f_op->lock) { |
1550 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); | 1550 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); |
1551 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | ||
1552 | file_lock.fl_ops->fl_release_private(&file_lock); | ||
1551 | if (error < 0) | 1553 | if (error < 0) |
1552 | goto out; | 1554 | goto out; |
1553 | else | 1555 | else |
@@ -1690,6 +1692,8 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l) | |||
1690 | 1692 | ||
1691 | if (filp->f_op && filp->f_op->lock) { | 1693 | if (filp->f_op && filp->f_op->lock) { |
1692 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); | 1694 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); |
1695 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | ||
1696 | file_lock.fl_ops->fl_release_private(&file_lock); | ||
1693 | if (error < 0) | 1697 | if (error < 0) |
1694 | goto out; | 1698 | goto out; |
1695 | else | 1699 | else |
@@ -1873,6 +1877,8 @@ void locks_remove_flock(struct file *filp) | |||
1873 | .fl_end = OFFSET_MAX, | 1877 | .fl_end = OFFSET_MAX, |
1874 | }; | 1878 | }; |
1875 | filp->f_op->flock(filp, F_SETLKW, &fl); | 1879 | filp->f_op->flock(filp, F_SETLKW, &fl); |
1880 | if (fl.fl_ops && fl.fl_ops->fl_release_private) | ||
1881 | fl.fl_ops->fl_release_private(&fl); | ||
1876 | } | 1882 | } |
1877 | 1883 | ||
1878 | lock_kernel(); | 1884 | lock_kernel(); |
diff --git a/fs/mpage.c b/fs/mpage.c index b92c0e64aefa..bb9aebe93862 100644 --- a/fs/mpage.c +++ b/fs/mpage.c | |||
@@ -79,8 +79,11 @@ static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err) | |||
79 | if (--bvec >= bio->bi_io_vec) | 79 | if (--bvec >= bio->bi_io_vec) |
80 | prefetchw(&bvec->bv_page->flags); | 80 | prefetchw(&bvec->bv_page->flags); |
81 | 81 | ||
82 | if (!uptodate) | 82 | if (!uptodate){ |
83 | SetPageError(page); | 83 | SetPageError(page); |
84 | if (page->mapping) | ||
85 | set_bit(AS_EIO, &page->mapping->flags); | ||
86 | } | ||
84 | end_page_writeback(page); | 87 | end_page_writeback(page); |
85 | } while (bvec >= bio->bi_io_vec); | 88 | } while (bvec >= bio->bi_io_vec); |
86 | bio_put(bio); | 89 | bio_put(bio); |
diff --git a/fs/namei.c b/fs/namei.c index dd78f01b6de8..fa8df81ce8ca 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -493,12 +493,21 @@ fail: | |||
493 | return PTR_ERR(link); | 493 | return PTR_ERR(link); |
494 | } | 494 | } |
495 | 495 | ||
496 | static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) | 496 | struct path { |
497 | struct vfsmount *mnt; | ||
498 | struct dentry *dentry; | ||
499 | }; | ||
500 | |||
501 | static inline int __do_follow_link(struct path *path, struct nameidata *nd) | ||
497 | { | 502 | { |
498 | int error; | 503 | int error; |
504 | struct dentry *dentry = path->dentry; | ||
499 | 505 | ||
500 | touch_atime(nd->mnt, dentry); | 506 | touch_atime(path->mnt, dentry); |
501 | nd_set_link(nd, NULL); | 507 | nd_set_link(nd, NULL); |
508 | |||
509 | if (path->mnt == nd->mnt) | ||
510 | mntget(path->mnt); | ||
502 | error = dentry->d_inode->i_op->follow_link(dentry, nd); | 511 | error = dentry->d_inode->i_op->follow_link(dentry, nd); |
503 | if (!error) { | 512 | if (!error) { |
504 | char *s = nd_get_link(nd); | 513 | char *s = nd_get_link(nd); |
@@ -507,6 +516,8 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
507 | if (dentry->d_inode->i_op->put_link) | 516 | if (dentry->d_inode->i_op->put_link) |
508 | dentry->d_inode->i_op->put_link(dentry, nd); | 517 | dentry->d_inode->i_op->put_link(dentry, nd); |
509 | } | 518 | } |
519 | dput(dentry); | ||
520 | mntput(path->mnt); | ||
510 | 521 | ||
511 | return error; | 522 | return error; |
512 | } | 523 | } |
@@ -518,7 +529,7 @@ static inline int __do_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
518 | * Without that kind of total limit, nasty chains of consecutive | 529 | * Without that kind of total limit, nasty chains of consecutive |
519 | * symlinks can cause almost arbitrarily long lookups. | 530 | * symlinks can cause almost arbitrarily long lookups. |
520 | */ | 531 | */ |
521 | static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) | 532 | static inline int do_follow_link(struct path *path, struct nameidata *nd) |
522 | { | 533 | { |
523 | int err = -ELOOP; | 534 | int err = -ELOOP; |
524 | if (current->link_count >= MAX_NESTED_LINKS) | 535 | if (current->link_count >= MAX_NESTED_LINKS) |
@@ -527,17 +538,20 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
527 | goto loop; | 538 | goto loop; |
528 | BUG_ON(nd->depth >= MAX_NESTED_LINKS); | 539 | BUG_ON(nd->depth >= MAX_NESTED_LINKS); |
529 | cond_resched(); | 540 | cond_resched(); |
530 | err = security_inode_follow_link(dentry, nd); | 541 | err = security_inode_follow_link(path->dentry, nd); |
531 | if (err) | 542 | if (err) |
532 | goto loop; | 543 | goto loop; |
533 | current->link_count++; | 544 | current->link_count++; |
534 | current->total_link_count++; | 545 | current->total_link_count++; |
535 | nd->depth++; | 546 | nd->depth++; |
536 | err = __do_follow_link(dentry, nd); | 547 | err = __do_follow_link(path, nd); |
537 | current->link_count--; | 548 | current->link_count--; |
538 | nd->depth--; | 549 | nd->depth--; |
539 | return err; | 550 | return err; |
540 | loop: | 551 | loop: |
552 | dput(path->dentry); | ||
553 | if (path->mnt != nd->mnt) | ||
554 | mntput(path->mnt); | ||
541 | path_release(nd); | 555 | path_release(nd); |
542 | return err; | 556 | return err; |
543 | } | 557 | } |
@@ -565,87 +579,91 @@ int follow_up(struct vfsmount **mnt, struct dentry **dentry) | |||
565 | /* no need for dcache_lock, as serialization is taken care in | 579 | /* no need for dcache_lock, as serialization is taken care in |
566 | * namespace.c | 580 | * namespace.c |
567 | */ | 581 | */ |
568 | static int follow_mount(struct vfsmount **mnt, struct dentry **dentry) | 582 | static int __follow_mount(struct path *path) |
569 | { | 583 | { |
570 | int res = 0; | 584 | int res = 0; |
585 | while (d_mountpoint(path->dentry)) { | ||
586 | struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry); | ||
587 | if (!mounted) | ||
588 | break; | ||
589 | dput(path->dentry); | ||
590 | if (res) | ||
591 | mntput(path->mnt); | ||
592 | path->mnt = mounted; | ||
593 | path->dentry = dget(mounted->mnt_root); | ||
594 | res = 1; | ||
595 | } | ||
596 | return res; | ||
597 | } | ||
598 | |||
599 | static void follow_mount(struct vfsmount **mnt, struct dentry **dentry) | ||
600 | { | ||
571 | while (d_mountpoint(*dentry)) { | 601 | while (d_mountpoint(*dentry)) { |
572 | struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); | 602 | struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); |
573 | if (!mounted) | 603 | if (!mounted) |
574 | break; | 604 | break; |
605 | dput(*dentry); | ||
575 | mntput(*mnt); | 606 | mntput(*mnt); |
576 | *mnt = mounted; | 607 | *mnt = mounted; |
577 | dput(*dentry); | ||
578 | *dentry = dget(mounted->mnt_root); | 608 | *dentry = dget(mounted->mnt_root); |
579 | res = 1; | ||
580 | } | 609 | } |
581 | return res; | ||
582 | } | 610 | } |
583 | 611 | ||
584 | /* no need for dcache_lock, as serialization is taken care in | 612 | /* no need for dcache_lock, as serialization is taken care in |
585 | * namespace.c | 613 | * namespace.c |
586 | */ | 614 | */ |
587 | static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry) | 615 | int follow_down(struct vfsmount **mnt, struct dentry **dentry) |
588 | { | 616 | { |
589 | struct vfsmount *mounted; | 617 | struct vfsmount *mounted; |
590 | 618 | ||
591 | mounted = lookup_mnt(*mnt, *dentry); | 619 | mounted = lookup_mnt(*mnt, *dentry); |
592 | if (mounted) { | 620 | if (mounted) { |
621 | dput(*dentry); | ||
593 | mntput(*mnt); | 622 | mntput(*mnt); |
594 | *mnt = mounted; | 623 | *mnt = mounted; |
595 | dput(*dentry); | ||
596 | *dentry = dget(mounted->mnt_root); | 624 | *dentry = dget(mounted->mnt_root); |
597 | return 1; | 625 | return 1; |
598 | } | 626 | } |
599 | return 0; | 627 | return 0; |
600 | } | 628 | } |
601 | 629 | ||
602 | int follow_down(struct vfsmount **mnt, struct dentry **dentry) | 630 | static inline void follow_dotdot(struct nameidata *nd) |
603 | { | ||
604 | return __follow_down(mnt,dentry); | ||
605 | } | ||
606 | |||
607 | static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) | ||
608 | { | 631 | { |
609 | while(1) { | 632 | while(1) { |
610 | struct vfsmount *parent; | 633 | struct vfsmount *parent; |
611 | struct dentry *old = *dentry; | 634 | struct dentry *old = nd->dentry; |
612 | 635 | ||
613 | read_lock(¤t->fs->lock); | 636 | read_lock(¤t->fs->lock); |
614 | if (*dentry == current->fs->root && | 637 | if (nd->dentry == current->fs->root && |
615 | *mnt == current->fs->rootmnt) { | 638 | nd->mnt == current->fs->rootmnt) { |
616 | read_unlock(¤t->fs->lock); | 639 | read_unlock(¤t->fs->lock); |
617 | break; | 640 | break; |
618 | } | 641 | } |
619 | read_unlock(¤t->fs->lock); | 642 | read_unlock(¤t->fs->lock); |
620 | spin_lock(&dcache_lock); | 643 | spin_lock(&dcache_lock); |
621 | if (*dentry != (*mnt)->mnt_root) { | 644 | if (nd->dentry != nd->mnt->mnt_root) { |
622 | *dentry = dget((*dentry)->d_parent); | 645 | nd->dentry = dget(nd->dentry->d_parent); |
623 | spin_unlock(&dcache_lock); | 646 | spin_unlock(&dcache_lock); |
624 | dput(old); | 647 | dput(old); |
625 | break; | 648 | break; |
626 | } | 649 | } |
627 | spin_unlock(&dcache_lock); | 650 | spin_unlock(&dcache_lock); |
628 | spin_lock(&vfsmount_lock); | 651 | spin_lock(&vfsmount_lock); |
629 | parent = (*mnt)->mnt_parent; | 652 | parent = nd->mnt->mnt_parent; |
630 | if (parent == *mnt) { | 653 | if (parent == nd->mnt) { |
631 | spin_unlock(&vfsmount_lock); | 654 | spin_unlock(&vfsmount_lock); |
632 | break; | 655 | break; |
633 | } | 656 | } |
634 | mntget(parent); | 657 | mntget(parent); |
635 | *dentry = dget((*mnt)->mnt_mountpoint); | 658 | nd->dentry = dget(nd->mnt->mnt_mountpoint); |
636 | spin_unlock(&vfsmount_lock); | 659 | spin_unlock(&vfsmount_lock); |
637 | dput(old); | 660 | dput(old); |
638 | mntput(*mnt); | 661 | mntput(nd->mnt); |
639 | *mnt = parent; | 662 | nd->mnt = parent; |
640 | } | 663 | } |
641 | follow_mount(mnt, dentry); | 664 | follow_mount(&nd->mnt, &nd->dentry); |
642 | } | 665 | } |
643 | 666 | ||
644 | struct path { | ||
645 | struct vfsmount *mnt; | ||
646 | struct dentry *dentry; | ||
647 | }; | ||
648 | |||
649 | /* | 667 | /* |
650 | * It's more convoluted than I'd like it to be, but... it's still fairly | 668 | * It's more convoluted than I'd like it to be, but... it's still fairly |
651 | * small and for now I'd prefer to have fast path as straight as possible. | 669 | * small and for now I'd prefer to have fast path as straight as possible. |
@@ -664,6 +682,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, | |||
664 | done: | 682 | done: |
665 | path->mnt = mnt; | 683 | path->mnt = mnt; |
666 | path->dentry = dentry; | 684 | path->dentry = dentry; |
685 | __follow_mount(path); | ||
667 | return 0; | 686 | return 0; |
668 | 687 | ||
669 | need_lookup: | 688 | need_lookup: |
@@ -751,7 +770,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
751 | case 2: | 770 | case 2: |
752 | if (this.name[1] != '.') | 771 | if (this.name[1] != '.') |
753 | break; | 772 | break; |
754 | follow_dotdot(&nd->mnt, &nd->dentry); | 773 | follow_dotdot(nd); |
755 | inode = nd->dentry->d_inode; | 774 | inode = nd->dentry->d_inode; |
756 | /* fallthrough */ | 775 | /* fallthrough */ |
757 | case 1: | 776 | case 1: |
@@ -771,8 +790,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
771 | err = do_lookup(nd, &this, &next); | 790 | err = do_lookup(nd, &this, &next); |
772 | if (err) | 791 | if (err) |
773 | break; | 792 | break; |
774 | /* Check mountpoints.. */ | ||
775 | follow_mount(&next.mnt, &next.dentry); | ||
776 | 793 | ||
777 | err = -ENOENT; | 794 | err = -ENOENT; |
778 | inode = next.dentry->d_inode; | 795 | inode = next.dentry->d_inode; |
@@ -783,10 +800,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
783 | goto out_dput; | 800 | goto out_dput; |
784 | 801 | ||
785 | if (inode->i_op->follow_link) { | 802 | if (inode->i_op->follow_link) { |
786 | mntget(next.mnt); | 803 | err = do_follow_link(&next, nd); |
787 | err = do_follow_link(next.dentry, nd); | ||
788 | dput(next.dentry); | ||
789 | mntput(next.mnt); | ||
790 | if (err) | 804 | if (err) |
791 | goto return_err; | 805 | goto return_err; |
792 | err = -ENOENT; | 806 | err = -ENOENT; |
@@ -798,6 +812,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
798 | break; | 812 | break; |
799 | } else { | 813 | } else { |
800 | dput(nd->dentry); | 814 | dput(nd->dentry); |
815 | if (nd->mnt != next.mnt) | ||
816 | mntput(nd->mnt); | ||
801 | nd->mnt = next.mnt; | 817 | nd->mnt = next.mnt; |
802 | nd->dentry = next.dentry; | 818 | nd->dentry = next.dentry; |
803 | } | 819 | } |
@@ -819,7 +835,7 @@ last_component: | |||
819 | case 2: | 835 | case 2: |
820 | if (this.name[1] != '.') | 836 | if (this.name[1] != '.') |
821 | break; | 837 | break; |
822 | follow_dotdot(&nd->mnt, &nd->dentry); | 838 | follow_dotdot(nd); |
823 | inode = nd->dentry->d_inode; | 839 | inode = nd->dentry->d_inode; |
824 | /* fallthrough */ | 840 | /* fallthrough */ |
825 | case 1: | 841 | case 1: |
@@ -833,19 +849,17 @@ last_component: | |||
833 | err = do_lookup(nd, &this, &next); | 849 | err = do_lookup(nd, &this, &next); |
834 | if (err) | 850 | if (err) |
835 | break; | 851 | break; |
836 | follow_mount(&next.mnt, &next.dentry); | ||
837 | inode = next.dentry->d_inode; | 852 | inode = next.dentry->d_inode; |
838 | if ((lookup_flags & LOOKUP_FOLLOW) | 853 | if ((lookup_flags & LOOKUP_FOLLOW) |
839 | && inode && inode->i_op && inode->i_op->follow_link) { | 854 | && inode && inode->i_op && inode->i_op->follow_link) { |
840 | mntget(next.mnt); | 855 | err = do_follow_link(&next, nd); |
841 | err = do_follow_link(next.dentry, nd); | ||
842 | dput(next.dentry); | ||
843 | mntput(next.mnt); | ||
844 | if (err) | 856 | if (err) |
845 | goto return_err; | 857 | goto return_err; |
846 | inode = nd->dentry->d_inode; | 858 | inode = nd->dentry->d_inode; |
847 | } else { | 859 | } else { |
848 | dput(nd->dentry); | 860 | dput(nd->dentry); |
861 | if (nd->mnt != next.mnt) | ||
862 | mntput(nd->mnt); | ||
849 | nd->mnt = next.mnt; | 863 | nd->mnt = next.mnt; |
850 | nd->dentry = next.dentry; | 864 | nd->dentry = next.dentry; |
851 | } | 865 | } |
@@ -885,6 +899,8 @@ return_base: | |||
885 | return 0; | 899 | return 0; |
886 | out_dput: | 900 | out_dput: |
887 | dput(next.dentry); | 901 | dput(next.dentry); |
902 | if (nd->mnt != next.mnt) | ||
903 | mntput(next.mnt); | ||
888 | break; | 904 | break; |
889 | } | 905 | } |
890 | path_release(nd); | 906 | path_release(nd); |
@@ -1398,7 +1414,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
1398 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | 1414 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) |
1399 | { | 1415 | { |
1400 | int acc_mode, error = 0; | 1416 | int acc_mode, error = 0; |
1401 | struct dentry *dentry; | 1417 | struct path path; |
1402 | struct dentry *dir; | 1418 | struct dentry *dir; |
1403 | int count = 0; | 1419 | int count = 0; |
1404 | 1420 | ||
@@ -1442,23 +1458,24 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
1442 | dir = nd->dentry; | 1458 | dir = nd->dentry; |
1443 | nd->flags &= ~LOOKUP_PARENT; | 1459 | nd->flags &= ~LOOKUP_PARENT; |
1444 | down(&dir->d_inode->i_sem); | 1460 | down(&dir->d_inode->i_sem); |
1445 | dentry = __lookup_hash(&nd->last, nd->dentry, nd); | 1461 | path.dentry = __lookup_hash(&nd->last, nd->dentry, nd); |
1462 | path.mnt = nd->mnt; | ||
1446 | 1463 | ||
1447 | do_last: | 1464 | do_last: |
1448 | error = PTR_ERR(dentry); | 1465 | error = PTR_ERR(path.dentry); |
1449 | if (IS_ERR(dentry)) { | 1466 | if (IS_ERR(path.dentry)) { |
1450 | up(&dir->d_inode->i_sem); | 1467 | up(&dir->d_inode->i_sem); |
1451 | goto exit; | 1468 | goto exit; |
1452 | } | 1469 | } |
1453 | 1470 | ||
1454 | /* Negative dentry, just create the file */ | 1471 | /* Negative dentry, just create the file */ |
1455 | if (!dentry->d_inode) { | 1472 | if (!path.dentry->d_inode) { |
1456 | if (!IS_POSIXACL(dir->d_inode)) | 1473 | if (!IS_POSIXACL(dir->d_inode)) |
1457 | mode &= ~current->fs->umask; | 1474 | mode &= ~current->fs->umask; |
1458 | error = vfs_create(dir->d_inode, dentry, mode, nd); | 1475 | error = vfs_create(dir->d_inode, path.dentry, mode, nd); |
1459 | up(&dir->d_inode->i_sem); | 1476 | up(&dir->d_inode->i_sem); |
1460 | dput(nd->dentry); | 1477 | dput(nd->dentry); |
1461 | nd->dentry = dentry; | 1478 | nd->dentry = path.dentry; |
1462 | if (error) | 1479 | if (error) |
1463 | goto exit; | 1480 | goto exit; |
1464 | /* Don't check for write permission, don't truncate */ | 1481 | /* Don't check for write permission, don't truncate */ |
@@ -1476,22 +1493,24 @@ do_last: | |||
1476 | if (flag & O_EXCL) | 1493 | if (flag & O_EXCL) |
1477 | goto exit_dput; | 1494 | goto exit_dput; |
1478 | 1495 | ||
1479 | if (d_mountpoint(dentry)) { | 1496 | if (__follow_mount(&path)) { |
1480 | error = -ELOOP; | 1497 | error = -ELOOP; |
1481 | if (flag & O_NOFOLLOW) | 1498 | if (flag & O_NOFOLLOW) |
1482 | goto exit_dput; | 1499 | goto exit_dput; |
1483 | while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry)); | ||
1484 | } | 1500 | } |
1485 | error = -ENOENT; | 1501 | error = -ENOENT; |
1486 | if (!dentry->d_inode) | 1502 | if (!path.dentry->d_inode) |
1487 | goto exit_dput; | 1503 | goto exit_dput; |
1488 | if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link) | 1504 | if (path.dentry->d_inode->i_op && path.dentry->d_inode->i_op->follow_link) |
1489 | goto do_link; | 1505 | goto do_link; |
1490 | 1506 | ||
1491 | dput(nd->dentry); | 1507 | dput(nd->dentry); |
1492 | nd->dentry = dentry; | 1508 | nd->dentry = path.dentry; |
1509 | if (nd->mnt != path.mnt) | ||
1510 | mntput(nd->mnt); | ||
1511 | nd->mnt = path.mnt; | ||
1493 | error = -EISDIR; | 1512 | error = -EISDIR; |
1494 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) | 1513 | if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode)) |
1495 | goto exit; | 1514 | goto exit; |
1496 | ok: | 1515 | ok: |
1497 | error = may_open(nd, acc_mode, flag); | 1516 | error = may_open(nd, acc_mode, flag); |
@@ -1500,7 +1519,9 @@ ok: | |||
1500 | return 0; | 1519 | return 0; |
1501 | 1520 | ||
1502 | exit_dput: | 1521 | exit_dput: |
1503 | dput(dentry); | 1522 | dput(path.dentry); |
1523 | if (nd->mnt != path.mnt) | ||
1524 | mntput(path.mnt); | ||
1504 | exit: | 1525 | exit: |
1505 | path_release(nd); | 1526 | path_release(nd); |
1506 | return error; | 1527 | return error; |
@@ -1520,18 +1541,15 @@ do_link: | |||
1520 | * are done. Procfs-like symlinks just set LAST_BIND. | 1541 | * are done. Procfs-like symlinks just set LAST_BIND. |
1521 | */ | 1542 | */ |
1522 | nd->flags |= LOOKUP_PARENT; | 1543 | nd->flags |= LOOKUP_PARENT; |
1523 | error = security_inode_follow_link(dentry, nd); | 1544 | error = security_inode_follow_link(path.dentry, nd); |
1524 | if (error) | 1545 | if (error) |
1525 | goto exit_dput; | 1546 | goto exit_dput; |
1526 | error = __do_follow_link(dentry, nd); | 1547 | error = __do_follow_link(&path, nd); |
1527 | dput(dentry); | ||
1528 | if (error) | 1548 | if (error) |
1529 | return error; | 1549 | return error; |
1530 | nd->flags &= ~LOOKUP_PARENT; | 1550 | nd->flags &= ~LOOKUP_PARENT; |
1531 | if (nd->last_type == LAST_BIND) { | 1551 | if (nd->last_type == LAST_BIND) |
1532 | dentry = nd->dentry; | ||
1533 | goto ok; | 1552 | goto ok; |
1534 | } | ||
1535 | error = -EISDIR; | 1553 | error = -EISDIR; |
1536 | if (nd->last_type != LAST_NORM) | 1554 | if (nd->last_type != LAST_NORM) |
1537 | goto exit; | 1555 | goto exit; |
@@ -1546,7 +1564,8 @@ do_link: | |||
1546 | } | 1564 | } |
1547 | dir = nd->dentry; | 1565 | dir = nd->dentry; |
1548 | down(&dir->d_inode->i_sem); | 1566 | down(&dir->d_inode->i_sem); |
1549 | dentry = __lookup_hash(&nd->last, nd->dentry, nd); | 1567 | path.dentry = __lookup_hash(&nd->last, nd->dentry, nd); |
1568 | path.mnt = nd->mnt; | ||
1550 | putname(nd->last.name); | 1569 | putname(nd->last.name); |
1551 | goto do_last; | 1570 | goto do_last; |
1552 | } | 1571 | } |
@@ -1558,19 +1577,35 @@ do_link: | |||
1558 | * | 1577 | * |
1559 | * Simple function to lookup and return a dentry and create it | 1578 | * Simple function to lookup and return a dentry and create it |
1560 | * if it doesn't exist. Is SMP-safe. | 1579 | * if it doesn't exist. Is SMP-safe. |
1580 | * | ||
1581 | * Returns with nd->dentry->d_inode->i_sem locked. | ||
1561 | */ | 1582 | */ |
1562 | struct dentry *lookup_create(struct nameidata *nd, int is_dir) | 1583 | struct dentry *lookup_create(struct nameidata *nd, int is_dir) |
1563 | { | 1584 | { |
1564 | struct dentry *dentry; | 1585 | struct dentry *dentry = ERR_PTR(-EEXIST); |
1565 | 1586 | ||
1566 | down(&nd->dentry->d_inode->i_sem); | 1587 | down(&nd->dentry->d_inode->i_sem); |
1567 | dentry = ERR_PTR(-EEXIST); | 1588 | /* |
1589 | * Yucky last component or no last component at all? | ||
1590 | * (foo/., foo/.., /////) | ||
1591 | */ | ||
1568 | if (nd->last_type != LAST_NORM) | 1592 | if (nd->last_type != LAST_NORM) |
1569 | goto fail; | 1593 | goto fail; |
1570 | nd->flags &= ~LOOKUP_PARENT; | 1594 | nd->flags &= ~LOOKUP_PARENT; |
1595 | |||
1596 | /* | ||
1597 | * Do the final lookup. | ||
1598 | */ | ||
1571 | dentry = lookup_hash(&nd->last, nd->dentry); | 1599 | dentry = lookup_hash(&nd->last, nd->dentry); |
1572 | if (IS_ERR(dentry)) | 1600 | if (IS_ERR(dentry)) |
1573 | goto fail; | 1601 | goto fail; |
1602 | |||
1603 | /* | ||
1604 | * Special case - lookup gave negative, but... we had foo/bar/ | ||
1605 | * From the vfs_mknod() POV we just have a negative dentry - | ||
1606 | * all is fine. Let's be bastards - you had / on the end, you've | ||
1607 | * been asking for (non-existent) directory. -ENOENT for you. | ||
1608 | */ | ||
1574 | if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode) | 1609 | if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode) |
1575 | goto enoent; | 1610 | goto enoent; |
1576 | return dentry; | 1611 | return dentry; |
diff --git a/fs/namespace.c b/fs/namespace.c index 3b93e5d750eb..208c079e9fdb 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -337,7 +337,7 @@ int may_umount(struct vfsmount *mnt) | |||
337 | 337 | ||
338 | EXPORT_SYMBOL(may_umount); | 338 | EXPORT_SYMBOL(may_umount); |
339 | 339 | ||
340 | void umount_tree(struct vfsmount *mnt) | 340 | static void umount_tree(struct vfsmount *mnt) |
341 | { | 341 | { |
342 | struct vfsmount *p; | 342 | struct vfsmount *p; |
343 | LIST_HEAD(kill); | 343 | LIST_HEAD(kill); |
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 2dc2d8693968..a9f7a8ab1d59 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c | |||
@@ -705,18 +705,6 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, | |||
705 | DPRINTK("ncp_do_readdir: init failed, err=%d\n", err); | 705 | DPRINTK("ncp_do_readdir: init failed, err=%d\n", err); |
706 | return; | 706 | return; |
707 | } | 707 | } |
708 | #ifdef USE_OLD_SLOW_DIRECTORY_LISTING | ||
709 | for (;;) { | ||
710 | err = ncp_search_for_file_or_subdir(server, &seq, &entry.i); | ||
711 | if (err) { | ||
712 | DPRINTK("ncp_do_readdir: search failed, err=%d\n", err); | ||
713 | break; | ||
714 | } | ||
715 | entry.volume = entry.i.volNumber; | ||
716 | if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) | ||
717 | break; | ||
718 | } | ||
719 | #else | ||
720 | /* We MUST NOT use server->buffer_size handshaked with server if we are | 708 | /* We MUST NOT use server->buffer_size handshaked with server if we are |
721 | using UDP, as for UDP server uses max. buffer size determined by | 709 | using UDP, as for UDP server uses max. buffer size determined by |
722 | MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). | 710 | MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). |
@@ -754,7 +742,6 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, | |||
754 | } | 742 | } |
755 | } while (more); | 743 | } while (more); |
756 | vfree(buf); | 744 | vfree(buf); |
757 | #endif | ||
758 | return; | 745 | return; |
759 | } | 746 | } |
760 | 747 | ||
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index e4eb5ed4bee4..c755e1848a42 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c | |||
@@ -845,46 +845,6 @@ out: | |||
845 | return result; | 845 | return result; |
846 | } | 846 | } |
847 | 847 | ||
848 | /* Search for everything */ | ||
849 | int ncp_search_for_file_or_subdir(struct ncp_server *server, | ||
850 | struct nw_search_sequence *seq, | ||
851 | struct nw_info_struct *target) | ||
852 | { | ||
853 | int result; | ||
854 | |||
855 | ncp_init_request(server); | ||
856 | ncp_add_byte(server, 3); /* subfunction */ | ||
857 | ncp_add_byte(server, server->name_space[seq->volNumber]); | ||
858 | ncp_add_byte(server, 0); /* data stream (???) */ | ||
859 | ncp_add_word(server, cpu_to_le16(0x8006)); /* Search attribs */ | ||
860 | ncp_add_dword(server, RIM_ALL); /* return info mask */ | ||
861 | ncp_add_mem(server, seq, 9); | ||
862 | #ifdef CONFIG_NCPFS_NFS_NS | ||
863 | if (server->name_space[seq->volNumber] == NW_NS_NFS) { | ||
864 | ncp_add_byte(server, 0); /* 0 byte pattern */ | ||
865 | } else | ||
866 | #endif | ||
867 | { | ||
868 | ncp_add_byte(server, 2); /* 2 byte pattern */ | ||
869 | ncp_add_byte(server, 0xff); /* following is a wildcard */ | ||
870 | ncp_add_byte(server, '*'); | ||
871 | } | ||
872 | |||
873 | if ((result = ncp_request(server, 87)) != 0) | ||
874 | goto out; | ||
875 | memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq)); | ||
876 | ncp_extract_file_info(ncp_reply_data(server, 10), target); | ||
877 | |||
878 | ncp_unlock_server(server); | ||
879 | |||
880 | result = ncp_obtain_nfs_info(server, target); | ||
881 | return result; | ||
882 | |||
883 | out: | ||
884 | ncp_unlock_server(server); | ||
885 | return result; | ||
886 | } | ||
887 | |||
888 | int ncp_search_for_fileset(struct ncp_server *server, | 848 | int ncp_search_for_fileset(struct ncp_server *server, |
889 | struct nw_search_sequence *seq, | 849 | struct nw_search_sequence *seq, |
890 | int* more, | 850 | int* more, |
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 05ec2e9d90c6..9e4dc30c2435 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h | |||
@@ -87,9 +87,6 @@ int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, char *, | |||
87 | 87 | ||
88 | int ncp_initialize_search(struct ncp_server *, struct inode *, | 88 | int ncp_initialize_search(struct ncp_server *, struct inode *, |
89 | struct nw_search_sequence *target); | 89 | struct nw_search_sequence *target); |
90 | int ncp_search_for_file_or_subdir(struct ncp_server *server, | ||
91 | struct nw_search_sequence *seq, | ||
92 | struct nw_info_struct *target); | ||
93 | int ncp_search_for_fileset(struct ncp_server *server, | 90 | int ncp_search_for_fileset(struct ncp_server *server, |
94 | struct nw_search_sequence *seq, | 91 | struct nw_search_sequence *seq, |
95 | int* more, int* cnt, | 92 | int* more, int* cnt, |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index b4baa031edf4..8b3bb715d177 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -8,6 +8,7 @@ nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \ | |||
8 | proc.o read.o symlink.o unlink.o write.o | 8 | proc.o read.o symlink.o unlink.o write.o |
9 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o | 9 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o |
10 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 10 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o |
11 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | ||
11 | nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | 12 | nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ |
12 | delegation.o idmap.o \ | 13 | delegation.o idmap.o \ |
13 | callback.o callback_xdr.o callback_proc.o | 14 | callback.o callback_xdr.o callback_proc.o |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 560d6175dd58..f2ca782aba33 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/sunrpc/svc.h> | 14 | #include <linux/sunrpc/svc.h> |
15 | #include <linux/sunrpc/svcsock.h> | 15 | #include <linux/sunrpc/svcsock.h> |
16 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
17 | #include "nfs4_fs.h" | ||
17 | #include "callback.h" | 18 | #include "callback.h" |
18 | 19 | ||
19 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 20 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index ece27e42b93b..65f1e19e4d19 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <linux/nfs4.h> | 9 | #include <linux/nfs4.h> |
10 | #include <linux/nfs_fs.h> | 10 | #include <linux/nfs_fs.h> |
11 | #include "nfs4_fs.h" | ||
11 | #include "callback.h" | 12 | #include "callback.h" |
12 | #include "delegation.h" | 13 | #include "delegation.h" |
13 | 14 | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index d271df9df2b2..7c33b9a81a94 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/sunrpc/svc.h> | 10 | #include <linux/sunrpc/svc.h> |
11 | #include <linux/nfs4.h> | 11 | #include <linux/nfs4.h> |
12 | #include <linux/nfs_fs.h> | 12 | #include <linux/nfs_fs.h> |
13 | #include "nfs4_fs.h" | ||
13 | #include "callback.h" | 14 | #include "callback.h" |
14 | 15 | ||
15 | #define CB_OP_TAGLEN_MAXSZ (512) | 16 | #define CB_OP_TAGLEN_MAXSZ (512) |
@@ -410,7 +411,6 @@ static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp | |||
410 | xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); | 411 | xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); |
411 | 412 | ||
412 | p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); | 413 | p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); |
413 | rqstp->rq_res.head[0].iov_len = PAGE_SIZE; | ||
414 | xdr_init_encode(&xdr_out, &rqstp->rq_res, p); | 414 | xdr_init_encode(&xdr_out, &rqstp->rq_res, p); |
415 | 415 | ||
416 | decode_compound_hdr_arg(&xdr_in, &hdr_arg); | 416 | decode_compound_hdr_arg(&xdr_in, &hdr_arg); |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 5b9c60f97791..d7f7eb669d03 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
17 | #include <linux/nfs_xdr.h> | 17 | #include <linux/nfs_xdr.h> |
18 | 18 | ||
19 | #include "nfs4_fs.h" | ||
19 | #include "delegation.h" | 20 | #include "delegation.h" |
20 | 21 | ||
21 | static struct nfs_delegation *nfs_alloc_delegation(void) | 22 | static struct nfs_delegation *nfs_alloc_delegation(void) |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 73f96acd5d37..b38a57e78a63 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/smp_lock.h> | 32 | #include <linux/smp_lock.h> |
33 | #include <linux/namei.h> | 33 | #include <linux/namei.h> |
34 | 34 | ||
35 | #include "nfs4_fs.h" | ||
35 | #include "delegation.h" | 36 | #include "delegation.h" |
36 | 37 | ||
37 | #define NFS_PARANOIA 1 | 38 | #define NFS_PARANOIA 1 |
@@ -50,8 +51,10 @@ static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); | |||
50 | static int nfs_rename(struct inode *, struct dentry *, | 51 | static int nfs_rename(struct inode *, struct dentry *, |
51 | struct inode *, struct dentry *); | 52 | struct inode *, struct dentry *); |
52 | static int nfs_fsync_dir(struct file *, struct dentry *, int); | 53 | static int nfs_fsync_dir(struct file *, struct dentry *, int); |
54 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | ||
53 | 55 | ||
54 | struct file_operations nfs_dir_operations = { | 56 | struct file_operations nfs_dir_operations = { |
57 | .llseek = nfs_llseek_dir, | ||
55 | .read = generic_read_dir, | 58 | .read = generic_read_dir, |
56 | .readdir = nfs_readdir, | 59 | .readdir = nfs_readdir, |
57 | .open = nfs_opendir, | 60 | .open = nfs_opendir, |
@@ -74,6 +77,27 @@ struct inode_operations nfs_dir_inode_operations = { | |||
74 | .setattr = nfs_setattr, | 77 | .setattr = nfs_setattr, |
75 | }; | 78 | }; |
76 | 79 | ||
80 | #ifdef CONFIG_NFS_V3 | ||
81 | struct inode_operations nfs3_dir_inode_operations = { | ||
82 | .create = nfs_create, | ||
83 | .lookup = nfs_lookup, | ||
84 | .link = nfs_link, | ||
85 | .unlink = nfs_unlink, | ||
86 | .symlink = nfs_symlink, | ||
87 | .mkdir = nfs_mkdir, | ||
88 | .rmdir = nfs_rmdir, | ||
89 | .mknod = nfs_mknod, | ||
90 | .rename = nfs_rename, | ||
91 | .permission = nfs_permission, | ||
92 | .getattr = nfs_getattr, | ||
93 | .setattr = nfs_setattr, | ||
94 | .listxattr = nfs3_listxattr, | ||
95 | .getxattr = nfs3_getxattr, | ||
96 | .setxattr = nfs3_setxattr, | ||
97 | .removexattr = nfs3_removexattr, | ||
98 | }; | ||
99 | #endif /* CONFIG_NFS_V3 */ | ||
100 | |||
77 | #ifdef CONFIG_NFS_V4 | 101 | #ifdef CONFIG_NFS_V4 |
78 | 102 | ||
79 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); | 103 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); |
@@ -90,6 +114,9 @@ struct inode_operations nfs4_dir_inode_operations = { | |||
90 | .permission = nfs_permission, | 114 | .permission = nfs_permission, |
91 | .getattr = nfs_getattr, | 115 | .getattr = nfs_getattr, |
92 | .setattr = nfs_setattr, | 116 | .setattr = nfs_setattr, |
117 | .getxattr = nfs4_getxattr, | ||
118 | .setxattr = nfs4_setxattr, | ||
119 | .listxattr = nfs4_listxattr, | ||
93 | }; | 120 | }; |
94 | 121 | ||
95 | #endif /* CONFIG_NFS_V4 */ | 122 | #endif /* CONFIG_NFS_V4 */ |
@@ -116,7 +143,8 @@ typedef struct { | |||
116 | struct page *page; | 143 | struct page *page; |
117 | unsigned long page_index; | 144 | unsigned long page_index; |
118 | u32 *ptr; | 145 | u32 *ptr; |
119 | u64 target; | 146 | u64 *dir_cookie; |
147 | loff_t current_index; | ||
120 | struct nfs_entry *entry; | 148 | struct nfs_entry *entry; |
121 | decode_dirent_t decode; | 149 | decode_dirent_t decode; |
122 | int plus; | 150 | int plus; |
@@ -164,12 +192,10 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) | |||
164 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; | 192 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; |
165 | /* Ensure consistent page alignment of the data. | 193 | /* Ensure consistent page alignment of the data. |
166 | * Note: assumes we have exclusive access to this mapping either | 194 | * Note: assumes we have exclusive access to this mapping either |
167 | * throught inode->i_sem or some other mechanism. | 195 | * through inode->i_sem or some other mechanism. |
168 | */ | 196 | */ |
169 | if (page->index == 0) { | 197 | if (page->index == 0) |
170 | invalidate_inode_pages(inode->i_mapping); | 198 | invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1); |
171 | NFS_I(inode)->readdir_timestamp = timestamp; | ||
172 | } | ||
173 | unlock_page(page); | 199 | unlock_page(page); |
174 | return 0; | 200 | return 0; |
175 | error: | 201 | error: |
@@ -202,22 +228,22 @@ void dir_page_release(nfs_readdir_descriptor_t *desc) | |||
202 | 228 | ||
203 | /* | 229 | /* |
204 | * Given a pointer to a buffer that has already been filled by a call | 230 | * Given a pointer to a buffer that has already been filled by a call |
205 | * to readdir, find the next entry. | 231 | * to readdir, find the next entry with cookie '*desc->dir_cookie'. |
206 | * | 232 | * |
207 | * If the end of the buffer has been reached, return -EAGAIN, if not, | 233 | * If the end of the buffer has been reached, return -EAGAIN, if not, |
208 | * return the offset within the buffer of the next entry to be | 234 | * return the offset within the buffer of the next entry to be |
209 | * read. | 235 | * read. |
210 | */ | 236 | */ |
211 | static inline | 237 | static inline |
212 | int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page) | 238 | int find_dirent(nfs_readdir_descriptor_t *desc) |
213 | { | 239 | { |
214 | struct nfs_entry *entry = desc->entry; | 240 | struct nfs_entry *entry = desc->entry; |
215 | int loop_count = 0, | 241 | int loop_count = 0, |
216 | status; | 242 | status; |
217 | 243 | ||
218 | while((status = dir_decode(desc)) == 0) { | 244 | while((status = dir_decode(desc)) == 0) { |
219 | dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie); | 245 | dfprintk(VFS, "NFS: found cookie %Lu\n", (unsigned long long)entry->cookie); |
220 | if (entry->prev_cookie == desc->target) | 246 | if (entry->prev_cookie == *desc->dir_cookie) |
221 | break; | 247 | break; |
222 | if (loop_count++ > 200) { | 248 | if (loop_count++ > 200) { |
223 | loop_count = 0; | 249 | loop_count = 0; |
@@ -229,8 +255,44 @@ int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page) | |||
229 | } | 255 | } |
230 | 256 | ||
231 | /* | 257 | /* |
232 | * Find the given page, and call find_dirent() in order to try to | 258 | * Given a pointer to a buffer that has already been filled by a call |
233 | * return the next entry. | 259 | * to readdir, find the entry at offset 'desc->file->f_pos'. |
260 | * | ||
261 | * If the end of the buffer has been reached, return -EAGAIN, if not, | ||
262 | * return the offset within the buffer of the next entry to be | ||
263 | * read. | ||
264 | */ | ||
265 | static inline | ||
266 | int find_dirent_index(nfs_readdir_descriptor_t *desc) | ||
267 | { | ||
268 | struct nfs_entry *entry = desc->entry; | ||
269 | int loop_count = 0, | ||
270 | status; | ||
271 | |||
272 | for(;;) { | ||
273 | status = dir_decode(desc); | ||
274 | if (status) | ||
275 | break; | ||
276 | |||
277 | dfprintk(VFS, "NFS: found cookie %Lu at index %Ld\n", (unsigned long long)entry->cookie, desc->current_index); | ||
278 | |||
279 | if (desc->file->f_pos == desc->current_index) { | ||
280 | *desc->dir_cookie = entry->cookie; | ||
281 | break; | ||
282 | } | ||
283 | desc->current_index++; | ||
284 | if (loop_count++ > 200) { | ||
285 | loop_count = 0; | ||
286 | schedule(); | ||
287 | } | ||
288 | } | ||
289 | dfprintk(VFS, "NFS: find_dirent_index() returns %d\n", status); | ||
290 | return status; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Find the given page, and call find_dirent() or find_dirent_index in | ||
295 | * order to try to return the next entry. | ||
234 | */ | 296 | */ |
235 | static inline | 297 | static inline |
236 | int find_dirent_page(nfs_readdir_descriptor_t *desc) | 298 | int find_dirent_page(nfs_readdir_descriptor_t *desc) |
@@ -253,7 +315,10 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
253 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ | 315 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ |
254 | desc->page = page; | 316 | desc->page = page; |
255 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | 317 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ |
256 | status = find_dirent(desc, page); | 318 | if (*desc->dir_cookie != 0) |
319 | status = find_dirent(desc); | ||
320 | else | ||
321 | status = find_dirent_index(desc); | ||
257 | if (status < 0) | 322 | if (status < 0) |
258 | dir_page_release(desc); | 323 | dir_page_release(desc); |
259 | out: | 324 | out: |
@@ -268,7 +333,8 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
268 | * Recurse through the page cache pages, and return a | 333 | * Recurse through the page cache pages, and return a |
269 | * filled nfs_entry structure of the next directory entry if possible. | 334 | * filled nfs_entry structure of the next directory entry if possible. |
270 | * | 335 | * |
271 | * The target for the search is 'desc->target'. | 336 | * The target for the search is '*desc->dir_cookie' if non-0, |
337 | * 'desc->file->f_pos' otherwise | ||
272 | */ | 338 | */ |
273 | static inline | 339 | static inline |
274 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | 340 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) |
@@ -276,7 +342,16 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | |||
276 | int loop_count = 0; | 342 | int loop_count = 0; |
277 | int res; | 343 | int res; |
278 | 344 | ||
279 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target); | 345 | /* Always search-by-index from the beginning of the cache */ |
346 | if (*desc->dir_cookie == 0) { | ||
347 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for offset %Ld\n", (long long)desc->file->f_pos); | ||
348 | desc->page_index = 0; | ||
349 | desc->entry->cookie = desc->entry->prev_cookie = 0; | ||
350 | desc->entry->eof = 0; | ||
351 | desc->current_index = 0; | ||
352 | } else | ||
353 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); | ||
354 | |||
280 | for (;;) { | 355 | for (;;) { |
281 | res = find_dirent_page(desc); | 356 | res = find_dirent_page(desc); |
282 | if (res != -EAGAIN) | 357 | if (res != -EAGAIN) |
@@ -313,7 +388,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
313 | int loop_count = 0, | 388 | int loop_count = 0, |
314 | res; | 389 | res; |
315 | 390 | ||
316 | dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)desc->target); | 391 | dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)entry->cookie); |
317 | 392 | ||
318 | for(;;) { | 393 | for(;;) { |
319 | unsigned d_type = DT_UNKNOWN; | 394 | unsigned d_type = DT_UNKNOWN; |
@@ -333,10 +408,11 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
333 | } | 408 | } |
334 | 409 | ||
335 | res = filldir(dirent, entry->name, entry->len, | 410 | res = filldir(dirent, entry->name, entry->len, |
336 | entry->prev_cookie, fileid, d_type); | 411 | file->f_pos, fileid, d_type); |
337 | if (res < 0) | 412 | if (res < 0) |
338 | break; | 413 | break; |
339 | file->f_pos = desc->target = entry->cookie; | 414 | file->f_pos++; |
415 | *desc->dir_cookie = entry->cookie; | ||
340 | if (dir_decode(desc) != 0) { | 416 | if (dir_decode(desc) != 0) { |
341 | desc->page_index ++; | 417 | desc->page_index ++; |
342 | break; | 418 | break; |
@@ -349,7 +425,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
349 | dir_page_release(desc); | 425 | dir_page_release(desc); |
350 | if (dentry != NULL) | 426 | if (dentry != NULL) |
351 | dput(dentry); | 427 | dput(dentry); |
352 | dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target, res); | 428 | dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res); |
353 | return res; | 429 | return res; |
354 | } | 430 | } |
355 | 431 | ||
@@ -375,14 +451,14 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
375 | struct page *page = NULL; | 451 | struct page *page = NULL; |
376 | int status; | 452 | int status; |
377 | 453 | ||
378 | dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target); | 454 | dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); |
379 | 455 | ||
380 | page = alloc_page(GFP_HIGHUSER); | 456 | page = alloc_page(GFP_HIGHUSER); |
381 | if (!page) { | 457 | if (!page) { |
382 | status = -ENOMEM; | 458 | status = -ENOMEM; |
383 | goto out; | 459 | goto out; |
384 | } | 460 | } |
385 | desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->target, | 461 | desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, *desc->dir_cookie, |
386 | page, | 462 | page, |
387 | NFS_SERVER(inode)->dtsize, | 463 | NFS_SERVER(inode)->dtsize, |
388 | desc->plus); | 464 | desc->plus); |
@@ -391,7 +467,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
391 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | 467 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ |
392 | if (desc->error >= 0) { | 468 | if (desc->error >= 0) { |
393 | if ((status = dir_decode(desc)) == 0) | 469 | if ((status = dir_decode(desc)) == 0) |
394 | desc->entry->prev_cookie = desc->target; | 470 | desc->entry->prev_cookie = *desc->dir_cookie; |
395 | } else | 471 | } else |
396 | status = -EIO; | 472 | status = -EIO; |
397 | if (status < 0) | 473 | if (status < 0) |
@@ -412,8 +488,9 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
412 | goto out; | 488 | goto out; |
413 | } | 489 | } |
414 | 490 | ||
415 | /* The file offset position is now represented as a true offset into the | 491 | /* The file offset position represents the dirent entry number. A |
416 | * page cache as is the case in most of the other filesystems. | 492 | last cookie cache takes care of the common case of reading the |
493 | whole directory. | ||
417 | */ | 494 | */ |
418 | static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | 495 | static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) |
419 | { | 496 | { |
@@ -435,15 +512,15 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
435 | } | 512 | } |
436 | 513 | ||
437 | /* | 514 | /* |
438 | * filp->f_pos points to the file offset in the page cache. | 515 | * filp->f_pos points to the dirent entry number. |
439 | * but if the cache has meanwhile been zapped, we need to | 516 | * *desc->dir_cookie has the cookie for the next entry. We have |
440 | * read from the last dirent to revalidate f_pos | 517 | * to either find the entry with the appropriate number or |
441 | * itself. | 518 | * revalidate the cookie. |
442 | */ | 519 | */ |
443 | memset(desc, 0, sizeof(*desc)); | 520 | memset(desc, 0, sizeof(*desc)); |
444 | 521 | ||
445 | desc->file = filp; | 522 | desc->file = filp; |
446 | desc->target = filp->f_pos; | 523 | desc->dir_cookie = &((struct nfs_open_context *)filp->private_data)->dir_cookie; |
447 | desc->decode = NFS_PROTO(inode)->decode_dirent; | 524 | desc->decode = NFS_PROTO(inode)->decode_dirent; |
448 | desc->plus = NFS_USE_READDIRPLUS(inode); | 525 | desc->plus = NFS_USE_READDIRPLUS(inode); |
449 | 526 | ||
@@ -455,9 +532,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
455 | 532 | ||
456 | while(!desc->entry->eof) { | 533 | while(!desc->entry->eof) { |
457 | res = readdir_search_pagecache(desc); | 534 | res = readdir_search_pagecache(desc); |
535 | |||
458 | if (res == -EBADCOOKIE) { | 536 | if (res == -EBADCOOKIE) { |
459 | /* This means either end of directory */ | 537 | /* This means either end of directory */ |
460 | if (desc->entry->cookie != desc->target) { | 538 | if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) { |
461 | /* Or that the server has 'lost' a cookie */ | 539 | /* Or that the server has 'lost' a cookie */ |
462 | res = uncached_readdir(desc, dirent, filldir); | 540 | res = uncached_readdir(desc, dirent, filldir); |
463 | if (res >= 0) | 541 | if (res >= 0) |
@@ -490,6 +568,28 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
490 | return 0; | 568 | return 0; |
491 | } | 569 | } |
492 | 570 | ||
571 | loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) | ||
572 | { | ||
573 | down(&filp->f_dentry->d_inode->i_sem); | ||
574 | switch (origin) { | ||
575 | case 1: | ||
576 | offset += filp->f_pos; | ||
577 | case 0: | ||
578 | if (offset >= 0) | ||
579 | break; | ||
580 | default: | ||
581 | offset = -EINVAL; | ||
582 | goto out; | ||
583 | } | ||
584 | if (offset != filp->f_pos) { | ||
585 | filp->f_pos = offset; | ||
586 | ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0; | ||
587 | } | ||
588 | out: | ||
589 | up(&filp->f_dentry->d_inode->i_sem); | ||
590 | return offset; | ||
591 | } | ||
592 | |||
493 | /* | 593 | /* |
494 | * All directory operations under NFS are synchronous, so fsync() | 594 | * All directory operations under NFS are synchronous, so fsync() |
495 | * is a dummy operation. | 595 | * is a dummy operation. |
@@ -528,19 +628,39 @@ static inline void nfs_renew_times(struct dentry * dentry) | |||
528 | dentry->d_time = jiffies; | 628 | dentry->d_time = jiffies; |
529 | } | 629 | } |
530 | 630 | ||
631 | /* | ||
632 | * Return the intent data that applies to this particular path component | ||
633 | * | ||
634 | * Note that the current set of intents only apply to the very last | ||
635 | * component of the path. | ||
636 | * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT. | ||
637 | */ | ||
638 | static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask) | ||
639 | { | ||
640 | if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT)) | ||
641 | return 0; | ||
642 | return nd->flags & mask; | ||
643 | } | ||
644 | |||
645 | /* | ||
646 | * Inode and filehandle revalidation for lookups. | ||
647 | * | ||
648 | * We force revalidation in the cases where the VFS sets LOOKUP_REVAL, | ||
649 | * or if the intent information indicates that we're about to open this | ||
650 | * particular file and the "nocto" mount flag is not set. | ||
651 | * | ||
652 | */ | ||
531 | static inline | 653 | static inline |
532 | int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) | 654 | int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) |
533 | { | 655 | { |
534 | struct nfs_server *server = NFS_SERVER(inode); | 656 | struct nfs_server *server = NFS_SERVER(inode); |
535 | 657 | ||
536 | if (nd != NULL) { | 658 | if (nd != NULL) { |
537 | int ndflags = nd->flags; | ||
538 | /* VFS wants an on-the-wire revalidation */ | 659 | /* VFS wants an on-the-wire revalidation */ |
539 | if (ndflags & LOOKUP_REVAL) | 660 | if (nd->flags & LOOKUP_REVAL) |
540 | goto out_force; | 661 | goto out_force; |
541 | /* This is an open(2) */ | 662 | /* This is an open(2) */ |
542 | if ((ndflags & LOOKUP_OPEN) && | 663 | if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 && |
543 | !(ndflags & LOOKUP_CONTINUE) && | ||
544 | !(server->flags & NFS_MOUNT_NOCTO)) | 664 | !(server->flags & NFS_MOUNT_NOCTO)) |
545 | goto out_force; | 665 | goto out_force; |
546 | } | 666 | } |
@@ -560,12 +680,8 @@ static inline | |||
560 | int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, | 680 | int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, |
561 | struct nameidata *nd) | 681 | struct nameidata *nd) |
562 | { | 682 | { |
563 | int ndflags = 0; | ||
564 | |||
565 | if (nd) | ||
566 | ndflags = nd->flags; | ||
567 | /* Don't revalidate a negative dentry if we're creating a new file */ | 683 | /* Don't revalidate a negative dentry if we're creating a new file */ |
568 | if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE)) | 684 | if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0) |
569 | return 0; | 685 | return 0; |
570 | return !nfs_check_verifier(dir, dentry); | 686 | return !nfs_check_verifier(dir, dentry); |
571 | } | 687 | } |
@@ -700,12 +816,16 @@ struct dentry_operations nfs_dentry_operations = { | |||
700 | .d_iput = nfs_dentry_iput, | 816 | .d_iput = nfs_dentry_iput, |
701 | }; | 817 | }; |
702 | 818 | ||
819 | /* | ||
820 | * Use intent information to check whether or not we're going to do | ||
821 | * an O_EXCL create using this path component. | ||
822 | */ | ||
703 | static inline | 823 | static inline |
704 | int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) | 824 | int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) |
705 | { | 825 | { |
706 | if (NFS_PROTO(dir)->version == 2) | 826 | if (NFS_PROTO(dir)->version == 2) |
707 | return 0; | 827 | return 0; |
708 | if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE)) | 828 | if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0) |
709 | return 0; | 829 | return 0; |
710 | return (nd->intent.open.flags & O_EXCL) != 0; | 830 | return (nd->intent.open.flags & O_EXCL) != 0; |
711 | } | 831 | } |
@@ -772,12 +892,13 @@ struct dentry_operations nfs4_dentry_operations = { | |||
772 | .d_iput = nfs_dentry_iput, | 892 | .d_iput = nfs_dentry_iput, |
773 | }; | 893 | }; |
774 | 894 | ||
895 | /* | ||
896 | * Use intent information to determine whether we need to substitute | ||
897 | * the NFSv4-style stateful OPEN for the LOOKUP call | ||
898 | */ | ||
775 | static int is_atomic_open(struct inode *dir, struct nameidata *nd) | 899 | static int is_atomic_open(struct inode *dir, struct nameidata *nd) |
776 | { | 900 | { |
777 | if (!nd) | 901 | if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0) |
778 | return 0; | ||
779 | /* Check that we are indeed trying to open this file */ | ||
780 | if ((nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_OPEN)) | ||
781 | return 0; | 902 | return 0; |
782 | /* NFS does not (yet) have a stateful open for directories */ | 903 | /* NFS does not (yet) have a stateful open for directories */ |
783 | if (nd->flags & LOOKUP_DIRECTORY) | 904 | if (nd->flags & LOOKUP_DIRECTORY) |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 68df803f27ca..6537f2c4ae44 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -517,7 +517,7 @@ retry: | |||
517 | result = tot_bytes; | 517 | result = tot_bytes; |
518 | 518 | ||
519 | out: | 519 | out: |
520 | nfs_end_data_update_defer(inode); | 520 | nfs_end_data_update(inode); |
521 | nfs_writedata_free(wdata); | 521 | nfs_writedata_free(wdata); |
522 | return result; | 522 | return result; |
523 | 523 | ||
@@ -751,11 +751,6 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, | |||
751 | retval = -EFAULT; | 751 | retval = -EFAULT; |
752 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | 752 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) |
753 | goto out; | 753 | goto out; |
754 | if (file->f_error) { | ||
755 | retval = file->f_error; | ||
756 | file->f_error = 0; | ||
757 | goto out; | ||
758 | } | ||
759 | retval = -EFBIG; | 754 | retval = -EFBIG; |
760 | if (limit != RLIM_INFINITY) { | 755 | if (limit != RLIM_INFINITY) { |
761 | if (pos >= limit) { | 756 | if (pos >= limit) { |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f06eee6dcff5..5621ba9885f4 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | static int nfs_file_open(struct inode *, struct file *); | 38 | static int nfs_file_open(struct inode *, struct file *); |
39 | static int nfs_file_release(struct inode *, struct file *); | 39 | static int nfs_file_release(struct inode *, struct file *); |
40 | static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin); | ||
40 | static int nfs_file_mmap(struct file *, struct vm_area_struct *); | 41 | static int nfs_file_mmap(struct file *, struct vm_area_struct *); |
41 | static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *); | 42 | static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *); |
42 | static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t); | 43 | static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t); |
@@ -48,7 +49,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); | |||
48 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); | 49 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); |
49 | 50 | ||
50 | struct file_operations nfs_file_operations = { | 51 | struct file_operations nfs_file_operations = { |
51 | .llseek = remote_llseek, | 52 | .llseek = nfs_file_llseek, |
52 | .read = do_sync_read, | 53 | .read = do_sync_read, |
53 | .write = do_sync_write, | 54 | .write = do_sync_write, |
54 | .aio_read = nfs_file_read, | 55 | .aio_read = nfs_file_read, |
@@ -70,6 +71,18 @@ struct inode_operations nfs_file_inode_operations = { | |||
70 | .setattr = nfs_setattr, | 71 | .setattr = nfs_setattr, |
71 | }; | 72 | }; |
72 | 73 | ||
74 | #ifdef CONFIG_NFS_V3 | ||
75 | struct inode_operations nfs3_file_inode_operations = { | ||
76 | .permission = nfs_permission, | ||
77 | .getattr = nfs_getattr, | ||
78 | .setattr = nfs_setattr, | ||
79 | .listxattr = nfs3_listxattr, | ||
80 | .getxattr = nfs3_getxattr, | ||
81 | .setxattr = nfs3_setxattr, | ||
82 | .removexattr = nfs3_removexattr, | ||
83 | }; | ||
84 | #endif /* CONFIG_NFS_v3 */ | ||
85 | |||
73 | /* Hack for future NFS swap support */ | 86 | /* Hack for future NFS swap support */ |
74 | #ifndef IS_SWAPFILE | 87 | #ifndef IS_SWAPFILE |
75 | # define IS_SWAPFILE(inode) (0) | 88 | # define IS_SWAPFILE(inode) (0) |
@@ -114,6 +127,61 @@ nfs_file_release(struct inode *inode, struct file *filp) | |||
114 | return NFS_PROTO(inode)->file_release(inode, filp); | 127 | return NFS_PROTO(inode)->file_release(inode, filp); |
115 | } | 128 | } |
116 | 129 | ||
130 | /** | ||
131 | * nfs_revalidate_file - Revalidate the page cache & related metadata | ||
132 | * @inode - pointer to inode struct | ||
133 | * @file - pointer to file | ||
134 | */ | ||
135 | static int nfs_revalidate_file(struct inode *inode, struct file *filp) | ||
136 | { | ||
137 | int retval = 0; | ||
138 | |||
139 | if ((NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode)) | ||
140 | retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | ||
141 | nfs_revalidate_mapping(inode, filp->f_mapping); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | /** | ||
146 | * nfs_revalidate_size - Revalidate the file size | ||
147 | * @inode - pointer to inode struct | ||
148 | * @file - pointer to struct file | ||
149 | * | ||
150 | * Revalidates the file length. This is basically a wrapper around | ||
151 | * nfs_revalidate_inode() that takes into account the fact that we may | ||
152 | * have cached writes (in which case we don't care about the server's | ||
153 | * idea of what the file length is), or O_DIRECT (in which case we | ||
154 | * shouldn't trust the cache). | ||
155 | */ | ||
156 | static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) | ||
157 | { | ||
158 | struct nfs_server *server = NFS_SERVER(inode); | ||
159 | struct nfs_inode *nfsi = NFS_I(inode); | ||
160 | |||
161 | if (server->flags & NFS_MOUNT_NOAC) | ||
162 | goto force_reval; | ||
163 | if (filp->f_flags & O_DIRECT) | ||
164 | goto force_reval; | ||
165 | if (nfsi->npages != 0) | ||
166 | return 0; | ||
167 | if (!(NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) | ||
168 | return 0; | ||
169 | force_reval: | ||
170 | return __nfs_revalidate_inode(server, inode); | ||
171 | } | ||
172 | |||
173 | static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | ||
174 | { | ||
175 | /* origin == SEEK_END => we must revalidate the cached file length */ | ||
176 | if (origin == 2) { | ||
177 | struct inode *inode = filp->f_mapping->host; | ||
178 | int retval = nfs_revalidate_file_size(inode, filp); | ||
179 | if (retval < 0) | ||
180 | return (loff_t)retval; | ||
181 | } | ||
182 | return remote_llseek(filp, offset, origin); | ||
183 | } | ||
184 | |||
117 | /* | 185 | /* |
118 | * Flush all dirty pages, and check for write errors. | 186 | * Flush all dirty pages, and check for write errors. |
119 | * | 187 | * |
@@ -158,7 +226,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos) | |||
158 | dentry->d_parent->d_name.name, dentry->d_name.name, | 226 | dentry->d_parent->d_name.name, dentry->d_name.name, |
159 | (unsigned long) count, (unsigned long) pos); | 227 | (unsigned long) count, (unsigned long) pos); |
160 | 228 | ||
161 | result = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 229 | result = nfs_revalidate_file(inode, iocb->ki_filp); |
162 | if (!result) | 230 | if (!result) |
163 | result = generic_file_aio_read(iocb, buf, count, pos); | 231 | result = generic_file_aio_read(iocb, buf, count, pos); |
164 | return result; | 232 | return result; |
@@ -176,7 +244,7 @@ nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count, | |||
176 | dentry->d_parent->d_name.name, dentry->d_name.name, | 244 | dentry->d_parent->d_name.name, dentry->d_name.name, |
177 | (unsigned long) count, (unsigned long long) *ppos); | 245 | (unsigned long) count, (unsigned long long) *ppos); |
178 | 246 | ||
179 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 247 | res = nfs_revalidate_file(inode, filp); |
180 | if (!res) | 248 | if (!res) |
181 | res = generic_file_sendfile(filp, ppos, count, actor, target); | 249 | res = generic_file_sendfile(filp, ppos, count, actor, target); |
182 | return res; | 250 | return res; |
@@ -192,7 +260,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
192 | dfprintk(VFS, "nfs: mmap(%s/%s)\n", | 260 | dfprintk(VFS, "nfs: mmap(%s/%s)\n", |
193 | dentry->d_parent->d_name.name, dentry->d_name.name); | 261 | dentry->d_parent->d_name.name, dentry->d_name.name); |
194 | 262 | ||
195 | status = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 263 | status = nfs_revalidate_file(inode, file); |
196 | if (!status) | 264 | if (!status) |
197 | status = generic_file_mmap(file, vma); | 265 | status = generic_file_mmap(file, vma); |
198 | return status; | 266 | return status; |
@@ -281,9 +349,15 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t | |||
281 | result = -EBUSY; | 349 | result = -EBUSY; |
282 | if (IS_SWAPFILE(inode)) | 350 | if (IS_SWAPFILE(inode)) |
283 | goto out_swapfile; | 351 | goto out_swapfile; |
284 | result = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 352 | /* |
285 | if (result) | 353 | * O_APPEND implies that we must revalidate the file length. |
286 | goto out; | 354 | */ |
355 | if (iocb->ki_filp->f_flags & O_APPEND) { | ||
356 | result = nfs_revalidate_file_size(inode, iocb->ki_filp); | ||
357 | if (result) | ||
358 | goto out; | ||
359 | } | ||
360 | nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); | ||
287 | 361 | ||
288 | result = count; | 362 | result = count; |
289 | if (!count) | 363 | if (!count) |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 87f4f9aeac86..ffb8df91dc34 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/nfs_fs.h> | 50 | #include <linux/nfs_fs.h> |
51 | 51 | ||
52 | #include <linux/nfs_idmap.h> | 52 | #include <linux/nfs_idmap.h> |
53 | #include "nfs4_fs.h" | ||
53 | 54 | ||
54 | #define IDMAP_HASH_SZ 128 | 55 | #define IDMAP_HASH_SZ 128 |
55 | 56 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f2317f3e29f9..4845911f1c63 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <asm/system.h> | 39 | #include <asm/system.h> |
40 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
41 | 41 | ||
42 | #include "nfs4_fs.h" | ||
42 | #include "delegation.h" | 43 | #include "delegation.h" |
43 | 44 | ||
44 | #define NFSDBG_FACILITY NFSDBG_VFS | 45 | #define NFSDBG_FACILITY NFSDBG_VFS |
@@ -63,6 +64,7 @@ static void nfs_clear_inode(struct inode *); | |||
63 | static void nfs_umount_begin(struct super_block *); | 64 | static void nfs_umount_begin(struct super_block *); |
64 | static int nfs_statfs(struct super_block *, struct kstatfs *); | 65 | static int nfs_statfs(struct super_block *, struct kstatfs *); |
65 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | 66 | static int nfs_show_options(struct seq_file *, struct vfsmount *); |
67 | static void nfs_zap_acl_cache(struct inode *); | ||
66 | 68 | ||
67 | static struct rpc_program nfs_program; | 69 | static struct rpc_program nfs_program; |
68 | 70 | ||
@@ -106,6 +108,21 @@ static struct rpc_program nfs_program = { | |||
106 | .pipe_dir_name = "/nfs", | 108 | .pipe_dir_name = "/nfs", |
107 | }; | 109 | }; |
108 | 110 | ||
111 | #ifdef CONFIG_NFS_V3_ACL | ||
112 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; | ||
113 | static struct rpc_version * nfsacl_version[] = { | ||
114 | [3] = &nfsacl_version3, | ||
115 | }; | ||
116 | |||
117 | struct rpc_program nfsacl_program = { | ||
118 | .name = "nfsacl", | ||
119 | .number = NFS_ACL_PROGRAM, | ||
120 | .nrvers = sizeof(nfsacl_version) / sizeof(nfsacl_version[0]), | ||
121 | .version = nfsacl_version, | ||
122 | .stats = &nfsacl_rpcstat, | ||
123 | }; | ||
124 | #endif /* CONFIG_NFS_V3_ACL */ | ||
125 | |||
109 | static inline unsigned long | 126 | static inline unsigned long |
110 | nfs_fattr_to_ino_t(struct nfs_fattr *fattr) | 127 | nfs_fattr_to_ino_t(struct nfs_fattr *fattr) |
111 | { | 128 | { |
@@ -118,7 +135,7 @@ nfs_write_inode(struct inode *inode, int sync) | |||
118 | int flags = sync ? FLUSH_WAIT : 0; | 135 | int flags = sync ? FLUSH_WAIT : 0; |
119 | int ret; | 136 | int ret; |
120 | 137 | ||
121 | ret = nfs_commit_inode(inode, 0, 0, flags); | 138 | ret = nfs_commit_inode(inode, flags); |
122 | if (ret < 0) | 139 | if (ret < 0) |
123 | return ret; | 140 | return ret; |
124 | return 0; | 141 | return 0; |
@@ -140,10 +157,6 @@ nfs_delete_inode(struct inode * inode) | |||
140 | clear_inode(inode); | 157 | clear_inode(inode); |
141 | } | 158 | } |
142 | 159 | ||
143 | /* | ||
144 | * For the moment, the only task for the NFS clear_inode method is to | ||
145 | * release the mmap credential | ||
146 | */ | ||
147 | static void | 160 | static void |
148 | nfs_clear_inode(struct inode *inode) | 161 | nfs_clear_inode(struct inode *inode) |
149 | { | 162 | { |
@@ -152,6 +165,7 @@ nfs_clear_inode(struct inode *inode) | |||
152 | 165 | ||
153 | nfs_wb_all(inode); | 166 | nfs_wb_all(inode); |
154 | BUG_ON (!list_empty(&nfsi->open_files)); | 167 | BUG_ON (!list_empty(&nfsi->open_files)); |
168 | nfs_zap_acl_cache(inode); | ||
155 | cred = nfsi->cache_access.cred; | 169 | cred = nfsi->cache_access.cred; |
156 | if (cred) | 170 | if (cred) |
157 | put_rpccred(cred); | 171 | put_rpccred(cred); |
@@ -161,11 +175,13 @@ nfs_clear_inode(struct inode *inode) | |||
161 | void | 175 | void |
162 | nfs_umount_begin(struct super_block *sb) | 176 | nfs_umount_begin(struct super_block *sb) |
163 | { | 177 | { |
164 | struct nfs_server *server = NFS_SB(sb); | 178 | struct rpc_clnt *rpc = NFS_SB(sb)->client; |
165 | struct rpc_clnt *rpc; | ||
166 | 179 | ||
167 | /* -EIO all pending I/O */ | 180 | /* -EIO all pending I/O */ |
168 | if ((rpc = server->client) != NULL) | 181 | if (!IS_ERR(rpc)) |
182 | rpc_killall_tasks(rpc); | ||
183 | rpc = NFS_SB(sb)->client_acl; | ||
184 | if (!IS_ERR(rpc)) | ||
169 | rpc_killall_tasks(rpc); | 185 | rpc_killall_tasks(rpc); |
170 | } | 186 | } |
171 | 187 | ||
@@ -366,13 +382,15 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | |||
366 | xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP, | 382 | xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP, |
367 | &server->addr, &timeparms); | 383 | &server->addr, &timeparms); |
368 | if (IS_ERR(xprt)) { | 384 | if (IS_ERR(xprt)) { |
369 | printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); | 385 | dprintk("%s: cannot create RPC transport. Error = %ld\n", |
386 | __FUNCTION__, PTR_ERR(xprt)); | ||
370 | return (struct rpc_clnt *)xprt; | 387 | return (struct rpc_clnt *)xprt; |
371 | } | 388 | } |
372 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, | 389 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, |
373 | server->rpc_ops->version, data->pseudoflavor); | 390 | server->rpc_ops->version, data->pseudoflavor); |
374 | if (IS_ERR(clnt)) { | 391 | if (IS_ERR(clnt)) { |
375 | printk(KERN_WARNING "NFS: cannot create RPC client.\n"); | 392 | dprintk("%s: cannot create RPC client. Error = %ld\n", |
393 | __FUNCTION__, PTR_ERR(xprt)); | ||
376 | goto out_fail; | 394 | goto out_fail; |
377 | } | 395 | } |
378 | 396 | ||
@@ -383,7 +401,6 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | |||
383 | return clnt; | 401 | return clnt; |
384 | 402 | ||
385 | out_fail: | 403 | out_fail: |
386 | xprt_destroy(xprt); | ||
387 | return clnt; | 404 | return clnt; |
388 | } | 405 | } |
389 | 406 | ||
@@ -427,21 +444,16 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) | |||
427 | 444 | ||
428 | /* Check NFS protocol revision and initialize RPC op vector | 445 | /* Check NFS protocol revision and initialize RPC op vector |
429 | * and file handle pool. */ | 446 | * and file handle pool. */ |
430 | if (server->flags & NFS_MOUNT_VER3) { | ||
431 | #ifdef CONFIG_NFS_V3 | 447 | #ifdef CONFIG_NFS_V3 |
448 | if (server->flags & NFS_MOUNT_VER3) { | ||
432 | server->rpc_ops = &nfs_v3_clientops; | 449 | server->rpc_ops = &nfs_v3_clientops; |
433 | server->caps |= NFS_CAP_READDIRPLUS; | 450 | server->caps |= NFS_CAP_READDIRPLUS; |
434 | if (data->version < 4) { | ||
435 | printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n"); | ||
436 | return -EIO; | ||
437 | } | ||
438 | #else | ||
439 | printk(KERN_NOTICE "NFS: NFSv3 not supported.\n"); | ||
440 | return -EIO; | ||
441 | #endif | ||
442 | } else { | 451 | } else { |
443 | server->rpc_ops = &nfs_v2_clientops; | 452 | server->rpc_ops = &nfs_v2_clientops; |
444 | } | 453 | } |
454 | #else | ||
455 | server->rpc_ops = &nfs_v2_clientops; | ||
456 | #endif | ||
445 | 457 | ||
446 | /* Fill in pseudoflavor for mount version < 5 */ | 458 | /* Fill in pseudoflavor for mount version < 5 */ |
447 | if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) | 459 | if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) |
@@ -455,17 +467,34 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) | |||
455 | return PTR_ERR(server->client); | 467 | return PTR_ERR(server->client); |
456 | /* RFC 2623, sec 2.3.2 */ | 468 | /* RFC 2623, sec 2.3.2 */ |
457 | if (authflavor != RPC_AUTH_UNIX) { | 469 | if (authflavor != RPC_AUTH_UNIX) { |
470 | struct rpc_auth *auth; | ||
471 | |||
458 | server->client_sys = rpc_clone_client(server->client); | 472 | server->client_sys = rpc_clone_client(server->client); |
459 | if (IS_ERR(server->client_sys)) | 473 | if (IS_ERR(server->client_sys)) |
460 | return PTR_ERR(server->client_sys); | 474 | return PTR_ERR(server->client_sys); |
461 | if (!rpcauth_create(RPC_AUTH_UNIX, server->client_sys)) | 475 | auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys); |
462 | return -ENOMEM; | 476 | if (IS_ERR(auth)) |
477 | return PTR_ERR(auth); | ||
463 | } else { | 478 | } else { |
464 | atomic_inc(&server->client->cl_count); | 479 | atomic_inc(&server->client->cl_count); |
465 | server->client_sys = server->client; | 480 | server->client_sys = server->client; |
466 | } | 481 | } |
467 | |||
468 | if (server->flags & NFS_MOUNT_VER3) { | 482 | if (server->flags & NFS_MOUNT_VER3) { |
483 | #ifdef CONFIG_NFS_V3_ACL | ||
484 | if (!(server->flags & NFS_MOUNT_NOACL)) { | ||
485 | server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3); | ||
486 | /* No errors! Assume that Sun nfsacls are supported */ | ||
487 | if (!IS_ERR(server->client_acl)) | ||
488 | server->caps |= NFS_CAP_ACLS; | ||
489 | } | ||
490 | #else | ||
491 | server->flags &= ~NFS_MOUNT_NOACL; | ||
492 | #endif /* CONFIG_NFS_V3_ACL */ | ||
493 | /* | ||
494 | * The VFS shouldn't apply the umask to mode bits. We will | ||
495 | * do so ourselves when necessary. | ||
496 | */ | ||
497 | sb->s_flags |= MS_POSIXACL; | ||
469 | if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) | 498 | if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) |
470 | server->namelen = NFS3_MAXNAMLEN; | 499 | server->namelen = NFS3_MAXNAMLEN; |
471 | sb->s_time_gran = 1; | 500 | sb->s_time_gran = 1; |
@@ -549,6 +578,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
549 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 578 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
550 | { NFS_MOUNT_NOAC, ",noac", "" }, | 579 | { NFS_MOUNT_NOAC, ",noac", "" }, |
551 | { NFS_MOUNT_NONLM, ",nolock", ",lock" }, | 580 | { NFS_MOUNT_NONLM, ",nolock", ",lock" }, |
581 | { NFS_MOUNT_NOACL, ",noacl", "" }, | ||
552 | { 0, NULL, NULL } | 582 | { 0, NULL, NULL } |
553 | }; | 583 | }; |
554 | struct proc_nfs_info *nfs_infop; | 584 | struct proc_nfs_info *nfs_infop; |
@@ -590,9 +620,19 @@ nfs_zap_caches(struct inode *inode) | |||
590 | 620 | ||
591 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); | 621 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); |
592 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) | 622 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) |
593 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS; | 623 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
594 | else | 624 | else |
595 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS; | 625 | nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
626 | } | ||
627 | |||
628 | static void nfs_zap_acl_cache(struct inode *inode) | ||
629 | { | ||
630 | void (*clear_acl_cache)(struct inode *); | ||
631 | |||
632 | clear_acl_cache = NFS_PROTO(inode)->clear_acl_cache; | ||
633 | if (clear_acl_cache != NULL) | ||
634 | clear_acl_cache(inode); | ||
635 | NFS_I(inode)->flags &= ~NFS_INO_INVALID_ACL; | ||
596 | } | 636 | } |
597 | 637 | ||
598 | /* | 638 | /* |
@@ -689,7 +729,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
689 | /* Why so? Because we want revalidate for devices/FIFOs, and | 729 | /* Why so? Because we want revalidate for devices/FIFOs, and |
690 | * that's precisely what we have in nfs_file_inode_operations. | 730 | * that's precisely what we have in nfs_file_inode_operations. |
691 | */ | 731 | */ |
692 | inode->i_op = &nfs_file_inode_operations; | 732 | inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops; |
693 | if (S_ISREG(inode->i_mode)) { | 733 | if (S_ISREG(inode->i_mode)) { |
694 | inode->i_fop = &nfs_file_operations; | 734 | inode->i_fop = &nfs_file_operations; |
695 | inode->i_data.a_ops = &nfs_file_aops; | 735 | inode->i_data.a_ops = &nfs_file_aops; |
@@ -792,7 +832,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
792 | } | 832 | } |
793 | } | 833 | } |
794 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) | 834 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) |
795 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS; | 835 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
796 | nfs_end_data_update(inode); | 836 | nfs_end_data_update(inode); |
797 | unlock_kernel(); | 837 | unlock_kernel(); |
798 | return error; | 838 | return error; |
@@ -851,7 +891,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp | |||
851 | ctx->state = NULL; | 891 | ctx->state = NULL; |
852 | ctx->lockowner = current->files; | 892 | ctx->lockowner = current->files; |
853 | ctx->error = 0; | 893 | ctx->error = 0; |
854 | init_waitqueue_head(&ctx->waitq); | 894 | ctx->dir_cookie = 0; |
855 | } | 895 | } |
856 | return ctx; | 896 | return ctx; |
857 | } | 897 | } |
@@ -1015,6 +1055,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
1015 | goto out; | 1055 | goto out; |
1016 | } | 1056 | } |
1017 | flags = nfsi->flags; | 1057 | flags = nfsi->flags; |
1058 | nfsi->flags &= ~NFS_INO_REVAL_PAGECACHE; | ||
1018 | /* | 1059 | /* |
1019 | * We may need to keep the attributes marked as invalid if | 1060 | * We may need to keep the attributes marked as invalid if |
1020 | * we raced with nfs_end_attr_update(). | 1061 | * we raced with nfs_end_attr_update(). |
@@ -1022,21 +1063,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
1022 | if (verifier == nfsi->cache_change_attribute) | 1063 | if (verifier == nfsi->cache_change_attribute) |
1023 | nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); | 1064 | nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); |
1024 | /* Do the page cache invalidation */ | 1065 | /* Do the page cache invalidation */ |
1025 | if (flags & NFS_INO_INVALID_DATA) { | 1066 | nfs_revalidate_mapping(inode, inode->i_mapping); |
1026 | if (S_ISREG(inode->i_mode)) { | 1067 | if (flags & NFS_INO_INVALID_ACL) |
1027 | if (filemap_fdatawrite(inode->i_mapping) == 0) | 1068 | nfs_zap_acl_cache(inode); |
1028 | filemap_fdatawait(inode->i_mapping); | ||
1029 | nfs_wb_all(inode); | ||
1030 | } | ||
1031 | nfsi->flags &= ~NFS_INO_INVALID_DATA; | ||
1032 | invalidate_inode_pages2(inode->i_mapping); | ||
1033 | memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); | ||
1034 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | ||
1035 | inode->i_sb->s_id, | ||
1036 | (long long)NFS_FILEID(inode)); | ||
1037 | /* This ensures we revalidate dentries */ | ||
1038 | nfsi->cache_change_attribute++; | ||
1039 | } | ||
1040 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", | 1069 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", |
1041 | inode->i_sb->s_id, | 1070 | inode->i_sb->s_id, |
1042 | (long long)NFS_FILEID(inode)); | 1071 | (long long)NFS_FILEID(inode)); |
@@ -1074,6 +1103,34 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
1074 | } | 1103 | } |
1075 | 1104 | ||
1076 | /** | 1105 | /** |
1106 | * nfs_revalidate_mapping - Revalidate the pagecache | ||
1107 | * @inode - pointer to host inode | ||
1108 | * @mapping - pointer to mapping | ||
1109 | */ | ||
1110 | void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | ||
1111 | { | ||
1112 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1113 | |||
1114 | if (nfsi->flags & NFS_INO_INVALID_DATA) { | ||
1115 | if (S_ISREG(inode->i_mode)) { | ||
1116 | if (filemap_fdatawrite(mapping) == 0) | ||
1117 | filemap_fdatawait(mapping); | ||
1118 | nfs_wb_all(inode); | ||
1119 | } | ||
1120 | invalidate_inode_pages2(mapping); | ||
1121 | nfsi->flags &= ~NFS_INO_INVALID_DATA; | ||
1122 | if (S_ISDIR(inode->i_mode)) { | ||
1123 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | ||
1124 | /* This ensures we revalidate child dentries */ | ||
1125 | nfsi->cache_change_attribute++; | ||
1126 | } | ||
1127 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | ||
1128 | inode->i_sb->s_id, | ||
1129 | (long long)NFS_FILEID(inode)); | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | /** | ||
1077 | * nfs_begin_data_update | 1134 | * nfs_begin_data_update |
1078 | * @inode - pointer to inode | 1135 | * @inode - pointer to inode |
1079 | * Declare that a set of operations will update file data on the server | 1136 | * Declare that a set of operations will update file data on the server |
@@ -1106,27 +1163,6 @@ void nfs_end_data_update(struct inode *inode) | |||
1106 | } | 1163 | } |
1107 | 1164 | ||
1108 | /** | 1165 | /** |
1109 | * nfs_end_data_update_defer | ||
1110 | * @inode - pointer to inode | ||
1111 | * Declare end of the operations that will update file data | ||
1112 | * This will defer marking the inode as needing revalidation | ||
1113 | * unless there are no other pending updates. | ||
1114 | */ | ||
1115 | void nfs_end_data_update_defer(struct inode *inode) | ||
1116 | { | ||
1117 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1118 | |||
1119 | if (atomic_dec_and_test(&nfsi->data_updates)) { | ||
1120 | /* Mark the attribute cache for revalidation */ | ||
1121 | nfsi->flags |= NFS_INO_INVALID_ATTR; | ||
1122 | /* Directories and symlinks: invalidate page cache too */ | ||
1123 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) | ||
1124 | nfsi->flags |= NFS_INO_INVALID_DATA; | ||
1125 | nfsi->cache_change_attribute ++; | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | /** | ||
1130 | * nfs_refresh_inode - verify consistency of the inode attribute cache | 1166 | * nfs_refresh_inode - verify consistency of the inode attribute cache |
1131 | * @inode - pointer to inode | 1167 | * @inode - pointer to inode |
1132 | * @fattr - updated attributes | 1168 | * @fattr - updated attributes |
@@ -1152,8 +1188,11 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1152 | if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 | 1188 | if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 |
1153 | && nfsi->change_attr == fattr->pre_change_attr) | 1189 | && nfsi->change_attr == fattr->pre_change_attr) |
1154 | nfsi->change_attr = fattr->change_attr; | 1190 | nfsi->change_attr = fattr->change_attr; |
1155 | if (!data_unstable && nfsi->change_attr != fattr->change_attr) | 1191 | if (nfsi->change_attr != fattr->change_attr) { |
1156 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1192 | nfsi->flags |= NFS_INO_INVALID_ATTR; |
1193 | if (!data_unstable) | ||
1194 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; | ||
1195 | } | ||
1157 | } | 1196 | } |
1158 | 1197 | ||
1159 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 1198 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
@@ -1176,18 +1215,22 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1176 | } | 1215 | } |
1177 | 1216 | ||
1178 | /* Verify a few of the more important attributes */ | 1217 | /* Verify a few of the more important attributes */ |
1179 | if (!data_unstable) { | 1218 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { |
1180 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime) | 1219 | nfsi->flags |= NFS_INO_INVALID_ATTR; |
1181 | || cur_size != new_isize) | 1220 | if (!data_unstable) |
1182 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1221 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; |
1183 | } else if (S_ISREG(inode->i_mode) && new_isize > cur_size) | 1222 | } |
1184 | nfsi->flags |= NFS_INO_INVALID_ATTR; | 1223 | if (cur_size != new_isize) { |
1224 | nfsi->flags |= NFS_INO_INVALID_ATTR; | ||
1225 | if (nfsi->npages == 0) | ||
1226 | nfsi->flags |= NFS_INO_REVAL_PAGECACHE; | ||
1227 | } | ||
1185 | 1228 | ||
1186 | /* Have any file permissions changed? */ | 1229 | /* Have any file permissions changed? */ |
1187 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) | 1230 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) |
1188 | || inode->i_uid != fattr->uid | 1231 | || inode->i_uid != fattr->uid |
1189 | || inode->i_gid != fattr->gid) | 1232 | || inode->i_gid != fattr->gid) |
1190 | nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; | 1233 | nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; |
1191 | 1234 | ||
1192 | /* Has the link count changed? */ | 1235 | /* Has the link count changed? */ |
1193 | if (inode->i_nlink != fattr->nlink) | 1236 | if (inode->i_nlink != fattr->nlink) |
@@ -1215,10 +1258,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1215 | static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) | 1258 | static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) |
1216 | { | 1259 | { |
1217 | struct nfs_inode *nfsi = NFS_I(inode); | 1260 | struct nfs_inode *nfsi = NFS_I(inode); |
1218 | __u64 new_size; | 1261 | loff_t cur_isize, new_isize; |
1219 | loff_t new_isize; | ||
1220 | unsigned int invalid = 0; | 1262 | unsigned int invalid = 0; |
1221 | loff_t cur_isize; | ||
1222 | int data_unstable; | 1263 | int data_unstable; |
1223 | 1264 | ||
1224 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", | 1265 | dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", |
@@ -1251,61 +1292,56 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign | |||
1251 | /* Are we racing with known updates of the metadata on the server? */ | 1292 | /* Are we racing with known updates of the metadata on the server? */ |
1252 | data_unstable = ! nfs_verify_change_attribute(inode, verifier); | 1293 | data_unstable = ! nfs_verify_change_attribute(inode, verifier); |
1253 | 1294 | ||
1254 | /* Check if the file size agrees */ | 1295 | /* Check if our cached file size is stale */ |
1255 | new_size = fattr->size; | ||
1256 | new_isize = nfs_size_to_loff_t(fattr->size); | 1296 | new_isize = nfs_size_to_loff_t(fattr->size); |
1257 | cur_isize = i_size_read(inode); | 1297 | cur_isize = i_size_read(inode); |
1258 | if (cur_isize != new_size) { | 1298 | if (new_isize != cur_isize) { |
1259 | #ifdef NFS_DEBUG_VERBOSE | 1299 | /* Do we perhaps have any outstanding writes? */ |
1260 | printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); | 1300 | if (nfsi->npages == 0) { |
1261 | #endif | 1301 | /* No, but did we race with nfs_end_data_update()? */ |
1262 | /* | 1302 | if (verifier == nfsi->cache_change_attribute) { |
1263 | * If we have pending writebacks, things can get | ||
1264 | * messy. | ||
1265 | */ | ||
1266 | if (S_ISREG(inode->i_mode) && data_unstable) { | ||
1267 | if (new_isize > cur_isize) { | ||
1268 | inode->i_size = new_isize; | 1303 | inode->i_size = new_isize; |
1269 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1304 | invalid |= NFS_INO_INVALID_DATA; |
1270 | } | 1305 | } |
1271 | } else { | 1306 | invalid |= NFS_INO_INVALID_ATTR; |
1307 | } else if (new_isize > cur_isize) { | ||
1272 | inode->i_size = new_isize; | 1308 | inode->i_size = new_isize; |
1273 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1309 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; |
1274 | } | 1310 | } |
1311 | dprintk("NFS: isize change on server for file %s/%ld\n", | ||
1312 | inode->i_sb->s_id, inode->i_ino); | ||
1275 | } | 1313 | } |
1276 | 1314 | ||
1277 | /* | 1315 | /* Check if the mtime agrees */ |
1278 | * Note: we don't check inode->i_mtime since pipes etc. | ||
1279 | * can change this value in VFS without requiring a | ||
1280 | * cache revalidation. | ||
1281 | */ | ||
1282 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { | 1316 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { |
1283 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); | 1317 | memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); |
1284 | #ifdef NFS_DEBUG_VERBOSE | 1318 | dprintk("NFS: mtime change on server for file %s/%ld\n", |
1285 | printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); | 1319 | inode->i_sb->s_id, inode->i_ino); |
1286 | #endif | ||
1287 | if (!data_unstable) | 1320 | if (!data_unstable) |
1288 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; | 1321 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; |
1289 | } | 1322 | } |
1290 | 1323 | ||
1291 | if ((fattr->valid & NFS_ATTR_FATTR_V4) | 1324 | if ((fattr->valid & NFS_ATTR_FATTR_V4) |
1292 | && nfsi->change_attr != fattr->change_attr) { | 1325 | && nfsi->change_attr != fattr->change_attr) { |
1293 | #ifdef NFS_DEBUG_VERBOSE | 1326 | dprintk("NFS: change_attr change on server for file %s/%ld\n", |
1294 | printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n", | ||
1295 | inode->i_sb->s_id, inode->i_ino); | 1327 | inode->i_sb->s_id, inode->i_ino); |
1296 | #endif | ||
1297 | nfsi->change_attr = fattr->change_attr; | 1328 | nfsi->change_attr = fattr->change_attr; |
1298 | if (!data_unstable) | 1329 | if (!data_unstable) |
1299 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS; | 1330 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1300 | } | 1331 | } |
1301 | 1332 | ||
1302 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | 1333 | /* If ctime has changed we should definitely clear access+acl caches */ |
1334 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { | ||
1335 | if (!data_unstable) | ||
1336 | invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | ||
1337 | memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); | ||
1338 | } | ||
1303 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); | 1339 | memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); |
1304 | 1340 | ||
1305 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || | 1341 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || |
1306 | inode->i_uid != fattr->uid || | 1342 | inode->i_uid != fattr->uid || |
1307 | inode->i_gid != fattr->gid) | 1343 | inode->i_gid != fattr->gid) |
1308 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS; | 1344 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1309 | 1345 | ||
1310 | inode->i_mode = fattr->mode; | 1346 | inode->i_mode = fattr->mode; |
1311 | inode->i_nlink = fattr->nlink; | 1347 | inode->i_nlink = fattr->nlink; |
@@ -1385,74 +1421,95 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, | |||
1385 | int flags, const char *dev_name, void *raw_data) | 1421 | int flags, const char *dev_name, void *raw_data) |
1386 | { | 1422 | { |
1387 | int error; | 1423 | int error; |
1388 | struct nfs_server *server; | 1424 | struct nfs_server *server = NULL; |
1389 | struct super_block *s; | 1425 | struct super_block *s; |
1390 | struct nfs_fh *root; | 1426 | struct nfs_fh *root; |
1391 | struct nfs_mount_data *data = raw_data; | 1427 | struct nfs_mount_data *data = raw_data; |
1392 | 1428 | ||
1393 | if (!data) { | 1429 | s = ERR_PTR(-EINVAL); |
1394 | printk("nfs_read_super: missing data argument\n"); | 1430 | if (data == NULL) { |
1395 | return ERR_PTR(-EINVAL); | 1431 | dprintk("%s: missing data argument\n", __FUNCTION__); |
1432 | goto out_err; | ||
1433 | } | ||
1434 | if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { | ||
1435 | dprintk("%s: bad mount version\n", __FUNCTION__); | ||
1436 | goto out_err; | ||
1396 | } | 1437 | } |
1438 | switch (data->version) { | ||
1439 | case 1: | ||
1440 | data->namlen = 0; | ||
1441 | case 2: | ||
1442 | data->bsize = 0; | ||
1443 | case 3: | ||
1444 | if (data->flags & NFS_MOUNT_VER3) { | ||
1445 | dprintk("%s: mount structure version %d does not support NFSv3\n", | ||
1446 | __FUNCTION__, | ||
1447 | data->version); | ||
1448 | goto out_err; | ||
1449 | } | ||
1450 | data->root.size = NFS2_FHSIZE; | ||
1451 | memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | ||
1452 | case 4: | ||
1453 | if (data->flags & NFS_MOUNT_SECFLAVOUR) { | ||
1454 | dprintk("%s: mount structure version %d does not support strong security\n", | ||
1455 | __FUNCTION__, | ||
1456 | data->version); | ||
1457 | goto out_err; | ||
1458 | } | ||
1459 | case 5: | ||
1460 | memset(data->context, 0, sizeof(data->context)); | ||
1461 | } | ||
1462 | #ifndef CONFIG_NFS_V3 | ||
1463 | /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ | ||
1464 | s = ERR_PTR(-EPROTONOSUPPORT); | ||
1465 | if (data->flags & NFS_MOUNT_VER3) { | ||
1466 | dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); | ||
1467 | goto out_err; | ||
1468 | } | ||
1469 | #endif /* CONFIG_NFS_V3 */ | ||
1397 | 1470 | ||
1471 | s = ERR_PTR(-ENOMEM); | ||
1398 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); | 1472 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); |
1399 | if (!server) | 1473 | if (!server) |
1400 | return ERR_PTR(-ENOMEM); | 1474 | goto out_err; |
1401 | memset(server, 0, sizeof(struct nfs_server)); | 1475 | memset(server, 0, sizeof(struct nfs_server)); |
1402 | /* Zero out the NFS state stuff */ | 1476 | /* Zero out the NFS state stuff */ |
1403 | init_nfsv4_state(server); | 1477 | init_nfsv4_state(server); |
1404 | 1478 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | |
1405 | if (data->version != NFS_MOUNT_VERSION) { | ||
1406 | printk("nfs warning: mount version %s than kernel\n", | ||
1407 | data->version < NFS_MOUNT_VERSION ? "older" : "newer"); | ||
1408 | if (data->version < 2) | ||
1409 | data->namlen = 0; | ||
1410 | if (data->version < 3) | ||
1411 | data->bsize = 0; | ||
1412 | if (data->version < 4) { | ||
1413 | data->flags &= ~NFS_MOUNT_VER3; | ||
1414 | data->root.size = NFS2_FHSIZE; | ||
1415 | memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | ||
1416 | } | ||
1417 | if (data->version < 5) | ||
1418 | data->flags &= ~NFS_MOUNT_SECFLAVOUR; | ||
1419 | } | ||
1420 | 1479 | ||
1421 | root = &server->fh; | 1480 | root = &server->fh; |
1422 | if (data->flags & NFS_MOUNT_VER3) | 1481 | if (data->flags & NFS_MOUNT_VER3) |
1423 | root->size = data->root.size; | 1482 | root->size = data->root.size; |
1424 | else | 1483 | else |
1425 | root->size = NFS2_FHSIZE; | 1484 | root->size = NFS2_FHSIZE; |
1485 | s = ERR_PTR(-EINVAL); | ||
1426 | if (root->size > sizeof(root->data)) { | 1486 | if (root->size > sizeof(root->data)) { |
1427 | printk("nfs_get_sb: invalid root filehandle\n"); | 1487 | dprintk("%s: invalid root filehandle\n", __FUNCTION__); |
1428 | kfree(server); | 1488 | goto out_err; |
1429 | return ERR_PTR(-EINVAL); | ||
1430 | } | 1489 | } |
1431 | memcpy(root->data, data->root.data, root->size); | 1490 | memcpy(root->data, data->root.data, root->size); |
1432 | 1491 | ||
1433 | /* We now require that the mount process passes the remote address */ | 1492 | /* We now require that the mount process passes the remote address */ |
1434 | memcpy(&server->addr, &data->addr, sizeof(server->addr)); | 1493 | memcpy(&server->addr, &data->addr, sizeof(server->addr)); |
1435 | if (server->addr.sin_addr.s_addr == INADDR_ANY) { | 1494 | if (server->addr.sin_addr.s_addr == INADDR_ANY) { |
1436 | printk("NFS: mount program didn't pass remote address!\n"); | 1495 | dprintk("%s: mount program didn't pass remote address!\n", |
1437 | kfree(server); | 1496 | __FUNCTION__); |
1438 | return ERR_PTR(-EINVAL); | 1497 | goto out_err; |
1439 | } | 1498 | } |
1440 | 1499 | ||
1441 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); | 1500 | /* Fire up rpciod if not yet running */ |
1442 | 1501 | s = ERR_PTR(rpciod_up()); | |
1443 | if (IS_ERR(s) || s->s_root) { | 1502 | if (IS_ERR(s)) { |
1444 | kfree(server); | 1503 | dprintk("%s: couldn't start rpciod! Error = %ld\n", |
1445 | return s; | 1504 | __FUNCTION__, PTR_ERR(s)); |
1505 | goto out_err; | ||
1446 | } | 1506 | } |
1447 | 1507 | ||
1448 | s->s_flags = flags; | 1508 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); |
1509 | if (IS_ERR(s) || s->s_root) | ||
1510 | goto out_rpciod_down; | ||
1449 | 1511 | ||
1450 | /* Fire up rpciod if not yet running */ | 1512 | s->s_flags = flags; |
1451 | if (rpciod_up() != 0) { | ||
1452 | printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); | ||
1453 | kfree(server); | ||
1454 | return ERR_PTR(-EIO); | ||
1455 | } | ||
1456 | 1513 | ||
1457 | error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); | 1514 | error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); |
1458 | if (error) { | 1515 | if (error) { |
@@ -1462,6 +1519,11 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, | |||
1462 | } | 1519 | } |
1463 | s->s_flags |= MS_ACTIVE; | 1520 | s->s_flags |= MS_ACTIVE; |
1464 | return s; | 1521 | return s; |
1522 | out_rpciod_down: | ||
1523 | rpciod_down(); | ||
1524 | out_err: | ||
1525 | kfree(server); | ||
1526 | return s; | ||
1465 | } | 1527 | } |
1466 | 1528 | ||
1467 | static void nfs_kill_super(struct super_block *s) | 1529 | static void nfs_kill_super(struct super_block *s) |
@@ -1470,10 +1532,12 @@ static void nfs_kill_super(struct super_block *s) | |||
1470 | 1532 | ||
1471 | kill_anon_super(s); | 1533 | kill_anon_super(s); |
1472 | 1534 | ||
1473 | if (server->client != NULL && !IS_ERR(server->client)) | 1535 | if (!IS_ERR(server->client)) |
1474 | rpc_shutdown_client(server->client); | 1536 | rpc_shutdown_client(server->client); |
1475 | if (server->client_sys != NULL && !IS_ERR(server->client_sys)) | 1537 | if (!IS_ERR(server->client_sys)) |
1476 | rpc_shutdown_client(server->client_sys); | 1538 | rpc_shutdown_client(server->client_sys); |
1539 | if (!IS_ERR(server->client_acl)) | ||
1540 | rpc_shutdown_client(server->client_acl); | ||
1477 | 1541 | ||
1478 | if (!(server->flags & NFS_MOUNT_NONLM)) | 1542 | if (!(server->flags & NFS_MOUNT_NONLM)) |
1479 | lockd_down(); /* release rpc.lockd */ | 1543 | lockd_down(); /* release rpc.lockd */ |
@@ -1594,15 +1658,19 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1594 | 1658 | ||
1595 | clp = nfs4_get_client(&server->addr.sin_addr); | 1659 | clp = nfs4_get_client(&server->addr.sin_addr); |
1596 | if (!clp) { | 1660 | if (!clp) { |
1597 | printk(KERN_WARNING "NFS: failed to create NFS4 client.\n"); | 1661 | dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); |
1598 | return -EIO; | 1662 | return -EIO; |
1599 | } | 1663 | } |
1600 | 1664 | ||
1601 | /* Now create transport and client */ | 1665 | /* Now create transport and client */ |
1602 | authflavour = RPC_AUTH_UNIX; | 1666 | authflavour = RPC_AUTH_UNIX; |
1603 | if (data->auth_flavourlen != 0) { | 1667 | if (data->auth_flavourlen != 0) { |
1604 | if (data->auth_flavourlen > 1) | 1668 | if (data->auth_flavourlen != 1) { |
1605 | printk(KERN_INFO "NFS: cannot yet deal with multiple auth flavours.\n"); | 1669 | dprintk("%s: Invalid number of RPC auth flavours %d.\n", |
1670 | __FUNCTION__, data->auth_flavourlen); | ||
1671 | err = -EINVAL; | ||
1672 | goto out_fail; | ||
1673 | } | ||
1606 | if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) { | 1674 | if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) { |
1607 | err = -EFAULT; | 1675 | err = -EFAULT; |
1608 | goto out_fail; | 1676 | goto out_fail; |
@@ -1610,21 +1678,22 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1610 | } | 1678 | } |
1611 | 1679 | ||
1612 | down_write(&clp->cl_sem); | 1680 | down_write(&clp->cl_sem); |
1613 | if (clp->cl_rpcclient == NULL) { | 1681 | if (IS_ERR(clp->cl_rpcclient)) { |
1614 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); | 1682 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); |
1615 | if (IS_ERR(xprt)) { | 1683 | if (IS_ERR(xprt)) { |
1616 | up_write(&clp->cl_sem); | 1684 | up_write(&clp->cl_sem); |
1617 | printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); | ||
1618 | err = PTR_ERR(xprt); | 1685 | err = PTR_ERR(xprt); |
1686 | dprintk("%s: cannot create RPC transport. Error = %d\n", | ||
1687 | __FUNCTION__, err); | ||
1619 | goto out_fail; | 1688 | goto out_fail; |
1620 | } | 1689 | } |
1621 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, | 1690 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, |
1622 | server->rpc_ops->version, authflavour); | 1691 | server->rpc_ops->version, authflavour); |
1623 | if (IS_ERR(clnt)) { | 1692 | if (IS_ERR(clnt)) { |
1624 | up_write(&clp->cl_sem); | 1693 | up_write(&clp->cl_sem); |
1625 | printk(KERN_WARNING "NFS: cannot create RPC client.\n"); | ||
1626 | xprt_destroy(xprt); | ||
1627 | err = PTR_ERR(clnt); | 1694 | err = PTR_ERR(clnt); |
1695 | dprintk("%s: cannot create RPC client. Error = %d\n", | ||
1696 | __FUNCTION__, err); | ||
1628 | goto out_fail; | 1697 | goto out_fail; |
1629 | } | 1698 | } |
1630 | clnt->cl_intr = 1; | 1699 | clnt->cl_intr = 1; |
@@ -1656,21 +1725,26 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1656 | clp = NULL; | 1725 | clp = NULL; |
1657 | 1726 | ||
1658 | if (IS_ERR(clnt)) { | 1727 | if (IS_ERR(clnt)) { |
1659 | printk(KERN_WARNING "NFS: cannot create RPC client.\n"); | 1728 | err = PTR_ERR(clnt); |
1660 | return PTR_ERR(clnt); | 1729 | dprintk("%s: cannot create RPC client. Error = %d\n", |
1730 | __FUNCTION__, err); | ||
1731 | return err; | ||
1661 | } | 1732 | } |
1662 | 1733 | ||
1663 | server->client = clnt; | 1734 | server->client = clnt; |
1664 | 1735 | ||
1665 | if (server->nfs4_state->cl_idmap == NULL) { | 1736 | if (server->nfs4_state->cl_idmap == NULL) { |
1666 | printk(KERN_WARNING "NFS: failed to create idmapper.\n"); | 1737 | dprintk("%s: failed to create idmapper.\n", __FUNCTION__); |
1667 | return -ENOMEM; | 1738 | return -ENOMEM; |
1668 | } | 1739 | } |
1669 | 1740 | ||
1670 | if (clnt->cl_auth->au_flavor != authflavour) { | 1741 | if (clnt->cl_auth->au_flavor != authflavour) { |
1671 | if (rpcauth_create(authflavour, clnt) == NULL) { | 1742 | struct rpc_auth *auth; |
1672 | printk(KERN_WARNING "NFS: couldn't create credcache!\n"); | 1743 | |
1673 | return -ENOMEM; | 1744 | auth = rpcauth_create(authflavour, clnt); |
1745 | if (IS_ERR(auth)) { | ||
1746 | dprintk("%s: couldn't create credcache!\n", __FUNCTION__); | ||
1747 | return PTR_ERR(auth); | ||
1674 | } | 1748 | } |
1675 | } | 1749 | } |
1676 | 1750 | ||
@@ -1730,8 +1804,12 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1730 | struct nfs4_mount_data *data = raw_data; | 1804 | struct nfs4_mount_data *data = raw_data; |
1731 | void *p; | 1805 | void *p; |
1732 | 1806 | ||
1733 | if (!data) { | 1807 | if (data == NULL) { |
1734 | printk("nfs_read_super: missing data argument\n"); | 1808 | dprintk("%s: missing data argument\n", __FUNCTION__); |
1809 | return ERR_PTR(-EINVAL); | ||
1810 | } | ||
1811 | if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) { | ||
1812 | dprintk("%s: bad mount version\n", __FUNCTION__); | ||
1735 | return ERR_PTR(-EINVAL); | 1813 | return ERR_PTR(-EINVAL); |
1736 | } | 1814 | } |
1737 | 1815 | ||
@@ -1741,11 +1819,7 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1741 | memset(server, 0, sizeof(struct nfs_server)); | 1819 | memset(server, 0, sizeof(struct nfs_server)); |
1742 | /* Zero out the NFS state stuff */ | 1820 | /* Zero out the NFS state stuff */ |
1743 | init_nfsv4_state(server); | 1821 | init_nfsv4_state(server); |
1744 | 1822 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | |
1745 | if (data->version != NFS4_MOUNT_VERSION) { | ||
1746 | printk("nfs warning: mount version %s than kernel\n", | ||
1747 | data->version < NFS4_MOUNT_VERSION ? "older" : "newer"); | ||
1748 | } | ||
1749 | 1823 | ||
1750 | p = nfs_copy_user_string(NULL, &data->hostname, 256); | 1824 | p = nfs_copy_user_string(NULL, &data->hostname, 256); |
1751 | if (IS_ERR(p)) | 1825 | if (IS_ERR(p)) |
@@ -1773,11 +1847,20 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1773 | } | 1847 | } |
1774 | if (server->addr.sin_family != AF_INET || | 1848 | if (server->addr.sin_family != AF_INET || |
1775 | server->addr.sin_addr.s_addr == INADDR_ANY) { | 1849 | server->addr.sin_addr.s_addr == INADDR_ANY) { |
1776 | printk("NFS: mount program didn't pass remote IP address!\n"); | 1850 | dprintk("%s: mount program didn't pass remote IP address!\n", |
1851 | __FUNCTION__); | ||
1777 | s = ERR_PTR(-EINVAL); | 1852 | s = ERR_PTR(-EINVAL); |
1778 | goto out_free; | 1853 | goto out_free; |
1779 | } | 1854 | } |
1780 | 1855 | ||
1856 | /* Fire up rpciod if not yet running */ | ||
1857 | s = ERR_PTR(rpciod_up()); | ||
1858 | if (IS_ERR(s)) { | ||
1859 | dprintk("%s: couldn't start rpciod! Error = %ld\n", | ||
1860 | __FUNCTION__, PTR_ERR(s)); | ||
1861 | goto out_free; | ||
1862 | } | ||
1863 | |||
1781 | s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); | 1864 | s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); |
1782 | 1865 | ||
1783 | if (IS_ERR(s) || s->s_root) | 1866 | if (IS_ERR(s) || s->s_root) |
@@ -1785,13 +1868,6 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1785 | 1868 | ||
1786 | s->s_flags = flags; | 1869 | s->s_flags = flags; |
1787 | 1870 | ||
1788 | /* Fire up rpciod if not yet running */ | ||
1789 | if (rpciod_up() != 0) { | ||
1790 | printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); | ||
1791 | s = ERR_PTR(-EIO); | ||
1792 | goto out_free; | ||
1793 | } | ||
1794 | |||
1795 | error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); | 1871 | error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); |
1796 | if (error) { | 1872 | if (error) { |
1797 | up_write(&s->s_umount); | 1873 | up_write(&s->s_umount); |
@@ -1875,6 +1951,13 @@ static struct inode *nfs_alloc_inode(struct super_block *sb) | |||
1875 | if (!nfsi) | 1951 | if (!nfsi) |
1876 | return NULL; | 1952 | return NULL; |
1877 | nfsi->flags = 0; | 1953 | nfsi->flags = 0; |
1954 | #ifdef CONFIG_NFS_V3_ACL | ||
1955 | nfsi->acl_access = ERR_PTR(-EAGAIN); | ||
1956 | nfsi->acl_default = ERR_PTR(-EAGAIN); | ||
1957 | #endif | ||
1958 | #ifdef CONFIG_NFS_V4 | ||
1959 | nfsi->nfs4_acl = NULL; | ||
1960 | #endif /* CONFIG_NFS_V4 */ | ||
1878 | return &nfsi->vfs_inode; | 1961 | return &nfsi->vfs_inode; |
1879 | } | 1962 | } |
1880 | 1963 | ||
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 9d3ddad96d9e..0e82617f2de0 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -80,9 +80,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, | |||
80 | clnt = rpc_create_client(xprt, hostname, | 80 | clnt = rpc_create_client(xprt, hostname, |
81 | &mnt_program, version, | 81 | &mnt_program, version, |
82 | RPC_AUTH_UNIX); | 82 | RPC_AUTH_UNIX); |
83 | if (IS_ERR(clnt)) { | 83 | if (!IS_ERR(clnt)) { |
84 | xprt_destroy(xprt); | ||
85 | } else { | ||
86 | clnt->cl_softrtry = 1; | 84 | clnt->cl_softrtry = 1; |
87 | clnt->cl_chatty = 1; | 85 | clnt->cl_chatty = 1; |
88 | clnt->cl_oneshot = 1; | 86 | clnt->cl_oneshot = 1; |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c new file mode 100644 index 000000000000..ee3536fc84a3 --- /dev/null +++ b/fs/nfs/nfs3acl.c | |||
@@ -0,0 +1,403 @@ | |||
1 | #include <linux/fs.h> | ||
2 | #include <linux/nfs.h> | ||
3 | #include <linux/nfs3.h> | ||
4 | #include <linux/nfs_fs.h> | ||
5 | #include <linux/xattr_acl.h> | ||
6 | #include <linux/nfsacl.h> | ||
7 | |||
8 | #define NFSDBG_FACILITY NFSDBG_PROC | ||
9 | |||
10 | ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
11 | { | ||
12 | struct inode *inode = dentry->d_inode; | ||
13 | struct posix_acl *acl; | ||
14 | int pos=0, len=0; | ||
15 | |||
16 | # define output(s) do { \ | ||
17 | if (pos + sizeof(s) <= size) { \ | ||
18 | memcpy(buffer + pos, s, sizeof(s)); \ | ||
19 | pos += sizeof(s); \ | ||
20 | } \ | ||
21 | len += sizeof(s); \ | ||
22 | } while(0) | ||
23 | |||
24 | acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS); | ||
25 | if (IS_ERR(acl)) | ||
26 | return PTR_ERR(acl); | ||
27 | if (acl) { | ||
28 | output("system.posix_acl_access"); | ||
29 | posix_acl_release(acl); | ||
30 | } | ||
31 | |||
32 | if (S_ISDIR(inode->i_mode)) { | ||
33 | acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT); | ||
34 | if (IS_ERR(acl)) | ||
35 | return PTR_ERR(acl); | ||
36 | if (acl) { | ||
37 | output("system.posix_acl_default"); | ||
38 | posix_acl_release(acl); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | # undef output | ||
43 | |||
44 | if (!buffer || len <= size) | ||
45 | return len; | ||
46 | return -ERANGE; | ||
47 | } | ||
48 | |||
49 | ssize_t nfs3_getxattr(struct dentry *dentry, const char *name, | ||
50 | void *buffer, size_t size) | ||
51 | { | ||
52 | struct inode *inode = dentry->d_inode; | ||
53 | struct posix_acl *acl; | ||
54 | int type, error = 0; | ||
55 | |||
56 | if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) | ||
57 | type = ACL_TYPE_ACCESS; | ||
58 | else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) | ||
59 | type = ACL_TYPE_DEFAULT; | ||
60 | else | ||
61 | return -EOPNOTSUPP; | ||
62 | |||
63 | acl = nfs3_proc_getacl(inode, type); | ||
64 | if (IS_ERR(acl)) | ||
65 | return PTR_ERR(acl); | ||
66 | else if (acl) { | ||
67 | if (type == ACL_TYPE_ACCESS && acl->a_count == 0) | ||
68 | error = -ENODATA; | ||
69 | else | ||
70 | error = posix_acl_to_xattr(acl, buffer, size); | ||
71 | posix_acl_release(acl); | ||
72 | } else | ||
73 | error = -ENODATA; | ||
74 | |||
75 | return error; | ||
76 | } | ||
77 | |||
78 | int nfs3_setxattr(struct dentry *dentry, const char *name, | ||
79 | const void *value, size_t size, int flags) | ||
80 | { | ||
81 | struct inode *inode = dentry->d_inode; | ||
82 | struct posix_acl *acl; | ||
83 | int type, error; | ||
84 | |||
85 | if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) | ||
86 | type = ACL_TYPE_ACCESS; | ||
87 | else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) | ||
88 | type = ACL_TYPE_DEFAULT; | ||
89 | else | ||
90 | return -EOPNOTSUPP; | ||
91 | |||
92 | acl = posix_acl_from_xattr(value, size); | ||
93 | if (IS_ERR(acl)) | ||
94 | return PTR_ERR(acl); | ||
95 | error = nfs3_proc_setacl(inode, type, acl); | ||
96 | posix_acl_release(acl); | ||
97 | |||
98 | return error; | ||
99 | } | ||
100 | |||
101 | int nfs3_removexattr(struct dentry *dentry, const char *name) | ||
102 | { | ||
103 | struct inode *inode = dentry->d_inode; | ||
104 | int type; | ||
105 | |||
106 | if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) | ||
107 | type = ACL_TYPE_ACCESS; | ||
108 | else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) | ||
109 | type = ACL_TYPE_DEFAULT; | ||
110 | else | ||
111 | return -EOPNOTSUPP; | ||
112 | |||
113 | return nfs3_proc_setacl(inode, type, NULL); | ||
114 | } | ||
115 | |||
116 | static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi) | ||
117 | { | ||
118 | if (!IS_ERR(nfsi->acl_access)) { | ||
119 | posix_acl_release(nfsi->acl_access); | ||
120 | nfsi->acl_access = ERR_PTR(-EAGAIN); | ||
121 | } | ||
122 | if (!IS_ERR(nfsi->acl_default)) { | ||
123 | posix_acl_release(nfsi->acl_default); | ||
124 | nfsi->acl_default = ERR_PTR(-EAGAIN); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | void nfs3_forget_cached_acls(struct inode *inode) | ||
129 | { | ||
130 | dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id, | ||
131 | inode->i_ino); | ||
132 | spin_lock(&inode->i_lock); | ||
133 | __nfs3_forget_cached_acls(NFS_I(inode)); | ||
134 | spin_unlock(&inode->i_lock); | ||
135 | } | ||
136 | |||
137 | static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) | ||
138 | { | ||
139 | struct nfs_inode *nfsi = NFS_I(inode); | ||
140 | struct posix_acl *acl = ERR_PTR(-EINVAL); | ||
141 | |||
142 | spin_lock(&inode->i_lock); | ||
143 | switch(type) { | ||
144 | case ACL_TYPE_ACCESS: | ||
145 | acl = nfsi->acl_access; | ||
146 | break; | ||
147 | |||
148 | case ACL_TYPE_DEFAULT: | ||
149 | acl = nfsi->acl_default; | ||
150 | break; | ||
151 | |||
152 | default: | ||
153 | goto out; | ||
154 | } | ||
155 | if (IS_ERR(acl)) | ||
156 | acl = ERR_PTR(-EAGAIN); | ||
157 | else | ||
158 | acl = posix_acl_dup(acl); | ||
159 | out: | ||
160 | spin_unlock(&inode->i_lock); | ||
161 | dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id, | ||
162 | inode->i_ino, type, acl); | ||
163 | return acl; | ||
164 | } | ||
165 | |||
166 | static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, | ||
167 | struct posix_acl *dfacl) | ||
168 | { | ||
169 | struct nfs_inode *nfsi = NFS_I(inode); | ||
170 | |||
171 | dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id, | ||
172 | inode->i_ino, acl, dfacl); | ||
173 | spin_lock(&inode->i_lock); | ||
174 | __nfs3_forget_cached_acls(NFS_I(inode)); | ||
175 | nfsi->acl_access = posix_acl_dup(acl); | ||
176 | nfsi->acl_default = posix_acl_dup(dfacl); | ||
177 | spin_unlock(&inode->i_lock); | ||
178 | } | ||
179 | |||
180 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | ||
181 | { | ||
182 | struct nfs_server *server = NFS_SERVER(inode); | ||
183 | struct nfs_fattr fattr; | ||
184 | struct page *pages[NFSACL_MAXPAGES] = { }; | ||
185 | struct nfs3_getaclargs args = { | ||
186 | .fh = NFS_FH(inode), | ||
187 | /* The xdr layer may allocate pages here. */ | ||
188 | .pages = pages, | ||
189 | }; | ||
190 | struct nfs3_getaclres res = { | ||
191 | .fattr = &fattr, | ||
192 | }; | ||
193 | struct posix_acl *acl; | ||
194 | int status, count; | ||
195 | |||
196 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) | ||
197 | return ERR_PTR(-EOPNOTSUPP); | ||
198 | |||
199 | status = nfs_revalidate_inode(server, inode); | ||
200 | if (status < 0) | ||
201 | return ERR_PTR(status); | ||
202 | acl = nfs3_get_cached_acl(inode, type); | ||
203 | if (acl != ERR_PTR(-EAGAIN)) | ||
204 | return acl; | ||
205 | acl = NULL; | ||
206 | |||
207 | /* | ||
208 | * Only get the access acl when explicitly requested: We don't | ||
209 | * need it for access decisions, and only some applications use | ||
210 | * it. Applications which request the access acl first are not | ||
211 | * penalized from this optimization. | ||
212 | */ | ||
213 | if (type == ACL_TYPE_ACCESS) | ||
214 | args.mask |= NFS_ACLCNT|NFS_ACL; | ||
215 | if (S_ISDIR(inode->i_mode)) | ||
216 | args.mask |= NFS_DFACLCNT|NFS_DFACL; | ||
217 | if (args.mask == 0) | ||
218 | return NULL; | ||
219 | |||
220 | dprintk("NFS call getacl\n"); | ||
221 | status = rpc_call(server->client_acl, ACLPROC3_GETACL, | ||
222 | &args, &res, 0); | ||
223 | dprintk("NFS reply getacl: %d\n", status); | ||
224 | |||
225 | /* pages may have been allocated at the xdr layer. */ | ||
226 | for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) | ||
227 | __free_page(args.pages[count]); | ||
228 | |||
229 | switch (status) { | ||
230 | case 0: | ||
231 | status = nfs_refresh_inode(inode, &fattr); | ||
232 | break; | ||
233 | case -EPFNOSUPPORT: | ||
234 | case -EPROTONOSUPPORT: | ||
235 | dprintk("NFS_V3_ACL extension not supported; disabling\n"); | ||
236 | server->caps &= ~NFS_CAP_ACLS; | ||
237 | case -ENOTSUPP: | ||
238 | status = -EOPNOTSUPP; | ||
239 | default: | ||
240 | goto getout; | ||
241 | } | ||
242 | if ((args.mask & res.mask) != args.mask) { | ||
243 | status = -EIO; | ||
244 | goto getout; | ||
245 | } | ||
246 | |||
247 | if (res.acl_access != NULL) { | ||
248 | if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) { | ||
249 | posix_acl_release(res.acl_access); | ||
250 | res.acl_access = NULL; | ||
251 | } | ||
252 | } | ||
253 | nfs3_cache_acls(inode, res.acl_access, res.acl_default); | ||
254 | |||
255 | switch(type) { | ||
256 | case ACL_TYPE_ACCESS: | ||
257 | acl = res.acl_access; | ||
258 | res.acl_access = NULL; | ||
259 | break; | ||
260 | |||
261 | case ACL_TYPE_DEFAULT: | ||
262 | acl = res.acl_default; | ||
263 | res.acl_default = NULL; | ||
264 | } | ||
265 | |||
266 | getout: | ||
267 | posix_acl_release(res.acl_access); | ||
268 | posix_acl_release(res.acl_default); | ||
269 | |||
270 | if (status != 0) { | ||
271 | posix_acl_release(acl); | ||
272 | acl = ERR_PTR(status); | ||
273 | } | ||
274 | return acl; | ||
275 | } | ||
276 | |||
277 | static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | ||
278 | struct posix_acl *dfacl) | ||
279 | { | ||
280 | struct nfs_server *server = NFS_SERVER(inode); | ||
281 | struct nfs_fattr fattr; | ||
282 | struct page *pages[NFSACL_MAXPAGES] = { }; | ||
283 | struct nfs3_setaclargs args = { | ||
284 | .inode = inode, | ||
285 | .mask = NFS_ACL, | ||
286 | .acl_access = acl, | ||
287 | .pages = pages, | ||
288 | }; | ||
289 | int status, count; | ||
290 | |||
291 | status = -EOPNOTSUPP; | ||
292 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) | ||
293 | goto out; | ||
294 | |||
295 | /* We are doing this here, because XDR marshalling can only | ||
296 | return -ENOMEM. */ | ||
297 | status = -ENOSPC; | ||
298 | if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) | ||
299 | goto out; | ||
300 | if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES) | ||
301 | goto out; | ||
302 | if (S_ISDIR(inode->i_mode)) { | ||
303 | args.mask |= NFS_DFACL; | ||
304 | args.acl_default = dfacl; | ||
305 | } | ||
306 | |||
307 | dprintk("NFS call setacl\n"); | ||
308 | nfs_begin_data_update(inode); | ||
309 | status = rpc_call(server->client_acl, ACLPROC3_SETACL, | ||
310 | &args, &fattr, 0); | ||
311 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS; | ||
312 | nfs_end_data_update(inode); | ||
313 | dprintk("NFS reply setacl: %d\n", status); | ||
314 | |||
315 | /* pages may have been allocated at the xdr layer. */ | ||
316 | for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) | ||
317 | __free_page(args.pages[count]); | ||
318 | |||
319 | switch (status) { | ||
320 | case 0: | ||
321 | status = nfs_refresh_inode(inode, &fattr); | ||
322 | break; | ||
323 | case -EPFNOSUPPORT: | ||
324 | case -EPROTONOSUPPORT: | ||
325 | dprintk("NFS_V3_ACL SETACL RPC not supported" | ||
326 | "(will not retry)\n"); | ||
327 | server->caps &= ~NFS_CAP_ACLS; | ||
328 | case -ENOTSUPP: | ||
329 | status = -EOPNOTSUPP; | ||
330 | } | ||
331 | out: | ||
332 | return status; | ||
333 | } | ||
334 | |||
335 | int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl) | ||
336 | { | ||
337 | struct posix_acl *alloc = NULL, *dfacl = NULL; | ||
338 | int status; | ||
339 | |||
340 | if (S_ISDIR(inode->i_mode)) { | ||
341 | switch(type) { | ||
342 | case ACL_TYPE_ACCESS: | ||
343 | alloc = dfacl = nfs3_proc_getacl(inode, | ||
344 | ACL_TYPE_DEFAULT); | ||
345 | if (IS_ERR(alloc)) | ||
346 | goto fail; | ||
347 | break; | ||
348 | |||
349 | case ACL_TYPE_DEFAULT: | ||
350 | dfacl = acl; | ||
351 | alloc = acl = nfs3_proc_getacl(inode, | ||
352 | ACL_TYPE_ACCESS); | ||
353 | if (IS_ERR(alloc)) | ||
354 | goto fail; | ||
355 | break; | ||
356 | |||
357 | default: | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | } else if (type != ACL_TYPE_ACCESS) | ||
361 | return -EINVAL; | ||
362 | |||
363 | if (acl == NULL) { | ||
364 | alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||
365 | if (IS_ERR(alloc)) | ||
366 | goto fail; | ||
367 | } | ||
368 | status = nfs3_proc_setacls(inode, acl, dfacl); | ||
369 | posix_acl_release(alloc); | ||
370 | return status; | ||
371 | |||
372 | fail: | ||
373 | return PTR_ERR(alloc); | ||
374 | } | ||
375 | |||
376 | int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, | ||
377 | mode_t mode) | ||
378 | { | ||
379 | struct posix_acl *dfacl, *acl; | ||
380 | int error = 0; | ||
381 | |||
382 | dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT); | ||
383 | if (IS_ERR(dfacl)) { | ||
384 | error = PTR_ERR(dfacl); | ||
385 | return (error == -EOPNOTSUPP) ? 0 : error; | ||
386 | } | ||
387 | if (!dfacl) | ||
388 | return 0; | ||
389 | acl = posix_acl_clone(dfacl, GFP_KERNEL); | ||
390 | error = -ENOMEM; | ||
391 | if (!acl) | ||
392 | goto out_release_dfacl; | ||
393 | error = posix_acl_create_masq(acl, &mode); | ||
394 | if (error < 0) | ||
395 | goto out_release_acl; | ||
396 | error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ? | ||
397 | dfacl : NULL); | ||
398 | out_release_acl: | ||
399 | posix_acl_release(acl); | ||
400 | out_release_dfacl: | ||
401 | posix_acl_release(dfacl); | ||
402 | return error; | ||
403 | } | ||
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 3878494dfc2c..7851569b31c6 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/nfs_page.h> | 17 | #include <linux/nfs_page.h> |
18 | #include <linux/lockd/bind.h> | 18 | #include <linux/lockd/bind.h> |
19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
20 | #include <linux/nfs_mount.h> | ||
20 | 21 | ||
21 | #define NFSDBG_FACILITY NFSDBG_PROC | 22 | #define NFSDBG_FACILITY NFSDBG_PROC |
22 | 23 | ||
@@ -45,7 +46,7 @@ static inline int | |||
45 | nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) | 46 | nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) |
46 | { | 47 | { |
47 | struct rpc_message msg = { | 48 | struct rpc_message msg = { |
48 | .rpc_proc = &nfs3_procedures[proc], | 49 | .rpc_proc = &clnt->cl_procinfo[proc], |
49 | .rpc_argp = argp, | 50 | .rpc_argp = argp, |
50 | .rpc_resp = resp, | 51 | .rpc_resp = resp, |
51 | }; | 52 | }; |
@@ -313,7 +314,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
313 | .fh = &fhandle, | 314 | .fh = &fhandle, |
314 | .fattr = &fattr | 315 | .fattr = &fattr |
315 | }; | 316 | }; |
316 | int status; | 317 | mode_t mode = sattr->ia_mode; |
318 | int status; | ||
317 | 319 | ||
318 | dprintk("NFS call create %s\n", dentry->d_name.name); | 320 | dprintk("NFS call create %s\n", dentry->d_name.name); |
319 | arg.createmode = NFS3_CREATE_UNCHECKED; | 321 | arg.createmode = NFS3_CREATE_UNCHECKED; |
@@ -323,6 +325,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
323 | arg.verifier[1] = current->pid; | 325 | arg.verifier[1] = current->pid; |
324 | } | 326 | } |
325 | 327 | ||
328 | sattr->ia_mode &= ~current->fs->umask; | ||
329 | |||
326 | again: | 330 | again: |
327 | dir_attr.valid = 0; | 331 | dir_attr.valid = 0; |
328 | fattr.valid = 0; | 332 | fattr.valid = 0; |
@@ -369,6 +373,9 @@ again: | |||
369 | nfs_refresh_inode(dentry->d_inode, &fattr); | 373 | nfs_refresh_inode(dentry->d_inode, &fattr); |
370 | dprintk("NFS reply setattr (post-create): %d\n", status); | 374 | dprintk("NFS reply setattr (post-create): %d\n", status); |
371 | } | 375 | } |
376 | if (status != 0) | ||
377 | goto out; | ||
378 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | ||
372 | out: | 379 | out: |
373 | dprintk("NFS reply create: %d\n", status); | 380 | dprintk("NFS reply create: %d\n", status); |
374 | return status; | 381 | return status; |
@@ -538,15 +545,24 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | |||
538 | .fh = &fhandle, | 545 | .fh = &fhandle, |
539 | .fattr = &fattr | 546 | .fattr = &fattr |
540 | }; | 547 | }; |
541 | int status; | 548 | int mode = sattr->ia_mode; |
549 | int status; | ||
542 | 550 | ||
543 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); | 551 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); |
544 | dir_attr.valid = 0; | 552 | dir_attr.valid = 0; |
545 | fattr.valid = 0; | 553 | fattr.valid = 0; |
554 | |||
555 | sattr->ia_mode &= ~current->fs->umask; | ||
556 | |||
546 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); | 557 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); |
547 | nfs_refresh_inode(dir, &dir_attr); | 558 | nfs_refresh_inode(dir, &dir_attr); |
548 | if (status == 0) | 559 | if (status != 0) |
549 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 560 | goto out; |
561 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
562 | if (status != 0) | ||
563 | goto out; | ||
564 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | ||
565 | out: | ||
550 | dprintk("NFS reply mkdir: %d\n", status); | 566 | dprintk("NFS reply mkdir: %d\n", status); |
551 | return status; | 567 | return status; |
552 | } | 568 | } |
@@ -641,6 +657,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
641 | .fh = &fh, | 657 | .fh = &fh, |
642 | .fattr = &fattr | 658 | .fattr = &fattr |
643 | }; | 659 | }; |
660 | mode_t mode = sattr->ia_mode; | ||
644 | int status; | 661 | int status; |
645 | 662 | ||
646 | switch (sattr->ia_mode & S_IFMT) { | 663 | switch (sattr->ia_mode & S_IFMT) { |
@@ -653,12 +670,20 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
653 | 670 | ||
654 | dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, | 671 | dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, |
655 | MAJOR(rdev), MINOR(rdev)); | 672 | MAJOR(rdev), MINOR(rdev)); |
673 | |||
674 | sattr->ia_mode &= ~current->fs->umask; | ||
675 | |||
656 | dir_attr.valid = 0; | 676 | dir_attr.valid = 0; |
657 | fattr.valid = 0; | 677 | fattr.valid = 0; |
658 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); | 678 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); |
659 | nfs_refresh_inode(dir, &dir_attr); | 679 | nfs_refresh_inode(dir, &dir_attr); |
660 | if (status == 0) | 680 | if (status != 0) |
661 | status = nfs_instantiate(dentry, &fh, &fattr); | 681 | goto out; |
682 | status = nfs_instantiate(dentry, &fh, &fattr); | ||
683 | if (status != 0) | ||
684 | goto out; | ||
685 | status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); | ||
686 | out: | ||
662 | dprintk("NFS reply mknod: %d\n", status); | 687 | dprintk("NFS reply mknod: %d\n", status); |
663 | return status; | 688 | return status; |
664 | } | 689 | } |
@@ -825,7 +850,8 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
825 | struct nfs_rpc_ops nfs_v3_clientops = { | 850 | struct nfs_rpc_ops nfs_v3_clientops = { |
826 | .version = 3, /* protocol version */ | 851 | .version = 3, /* protocol version */ |
827 | .dentry_ops = &nfs_dentry_operations, | 852 | .dentry_ops = &nfs_dentry_operations, |
828 | .dir_inode_ops = &nfs_dir_inode_operations, | 853 | .dir_inode_ops = &nfs3_dir_inode_operations, |
854 | .file_inode_ops = &nfs3_file_inode_operations, | ||
829 | .getroot = nfs3_proc_get_root, | 855 | .getroot = nfs3_proc_get_root, |
830 | .getattr = nfs3_proc_getattr, | 856 | .getattr = nfs3_proc_getattr, |
831 | .setattr = nfs3_proc_setattr, | 857 | .setattr = nfs3_proc_setattr, |
@@ -856,4 +882,5 @@ struct nfs_rpc_ops nfs_v3_clientops = { | |||
856 | .file_open = nfs_open, | 882 | .file_open = nfs_open, |
857 | .file_release = nfs_release, | 883 | .file_release = nfs_release, |
858 | .lock = nfs3_proc_lock, | 884 | .lock = nfs3_proc_lock, |
885 | .clear_acl_cache = nfs3_forget_cached_acls, | ||
859 | }; | 886 | }; |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index a3593d47e5ab..db4a904810a4 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/nfs.h> | 21 | #include <linux/nfs.h> |
22 | #include <linux/nfs3.h> | 22 | #include <linux/nfs3.h> |
23 | #include <linux/nfs_fs.h> | 23 | #include <linux/nfs_fs.h> |
24 | #include <linux/nfsacl.h> | ||
24 | 25 | ||
25 | #define NFSDBG_FACILITY NFSDBG_XDR | 26 | #define NFSDBG_FACILITY NFSDBG_XDR |
26 | 27 | ||
@@ -79,6 +80,11 @@ extern int nfs_stat_to_errno(int); | |||
79 | #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) | 80 | #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) |
80 | #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) | 81 | #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) |
81 | 82 | ||
83 | #define ACL3_getaclargs_sz (NFS3_fh_sz+1) | ||
84 | #define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3)) | ||
85 | #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3)) | ||
86 | #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) | ||
87 | |||
82 | /* | 88 | /* |
83 | * Map file type to S_IFMT bits | 89 | * Map file type to S_IFMT bits |
84 | */ | 90 | */ |
@@ -627,6 +633,74 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) | |||
627 | return 0; | 633 | return 0; |
628 | } | 634 | } |
629 | 635 | ||
636 | #ifdef CONFIG_NFS_V3_ACL | ||
637 | /* | ||
638 | * Encode GETACL arguments | ||
639 | */ | ||
640 | static int | ||
641 | nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p, | ||
642 | struct nfs3_getaclargs *args) | ||
643 | { | ||
644 | struct rpc_auth *auth = req->rq_task->tk_auth; | ||
645 | unsigned int replen; | ||
646 | |||
647 | p = xdr_encode_fhandle(p, args->fh); | ||
648 | *p++ = htonl(args->mask); | ||
649 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | ||
650 | |||
651 | if (args->mask & (NFS_ACL | NFS_DFACL)) { | ||
652 | /* Inline the page array */ | ||
653 | replen = (RPC_REPHDRSIZE + auth->au_rslack + | ||
654 | ACL3_getaclres_sz) << 2; | ||
655 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, | ||
656 | NFSACL_MAXPAGES << PAGE_SHIFT); | ||
657 | } | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * Encode SETACL arguments | ||
663 | */ | ||
664 | static int | ||
665 | nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p, | ||
666 | struct nfs3_setaclargs *args) | ||
667 | { | ||
668 | struct xdr_buf *buf = &req->rq_snd_buf; | ||
669 | unsigned int base, len_in_head, len = nfsacl_size( | ||
670 | (args->mask & NFS_ACL) ? args->acl_access : NULL, | ||
671 | (args->mask & NFS_DFACL) ? args->acl_default : NULL); | ||
672 | int count, err; | ||
673 | |||
674 | p = xdr_encode_fhandle(p, NFS_FH(args->inode)); | ||
675 | *p++ = htonl(args->mask); | ||
676 | base = (char *)p - (char *)buf->head->iov_base; | ||
677 | /* put as much of the acls into head as possible. */ | ||
678 | len_in_head = min_t(unsigned int, buf->head->iov_len - base, len); | ||
679 | len -= len_in_head; | ||
680 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2)); | ||
681 | |||
682 | for (count = 0; (count << PAGE_SHIFT) < len; count++) { | ||
683 | args->pages[count] = alloc_page(GFP_KERNEL); | ||
684 | if (!args->pages[count]) { | ||
685 | while (count) | ||
686 | __free_page(args->pages[--count]); | ||
687 | return -ENOMEM; | ||
688 | } | ||
689 | } | ||
690 | xdr_encode_pages(buf, args->pages, 0, len); | ||
691 | |||
692 | err = nfsacl_encode(buf, base, args->inode, | ||
693 | (args->mask & NFS_ACL) ? | ||
694 | args->acl_access : NULL, 1, 0); | ||
695 | if (err > 0) | ||
696 | err = nfsacl_encode(buf, base + err, args->inode, | ||
697 | (args->mask & NFS_DFACL) ? | ||
698 | args->acl_default : NULL, 1, | ||
699 | NFS_ACL_DEFAULT); | ||
700 | return (err > 0) ? 0 : err; | ||
701 | } | ||
702 | #endif /* CONFIG_NFS_V3_ACL */ | ||
703 | |||
630 | /* | 704 | /* |
631 | * NFS XDR decode functions | 705 | * NFS XDR decode functions |
632 | */ | 706 | */ |
@@ -978,6 +1052,54 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) | |||
978 | return 0; | 1052 | return 0; |
979 | } | 1053 | } |
980 | 1054 | ||
1055 | #ifdef CONFIG_NFS_V3_ACL | ||
1056 | /* | ||
1057 | * Decode GETACL reply | ||
1058 | */ | ||
1059 | static int | ||
1060 | nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p, | ||
1061 | struct nfs3_getaclres *res) | ||
1062 | { | ||
1063 | struct xdr_buf *buf = &req->rq_rcv_buf; | ||
1064 | int status = ntohl(*p++); | ||
1065 | struct posix_acl **acl; | ||
1066 | unsigned int *aclcnt; | ||
1067 | int err, base; | ||
1068 | |||
1069 | if (status != 0) | ||
1070 | return -nfs_stat_to_errno(status); | ||
1071 | p = xdr_decode_post_op_attr(p, res->fattr); | ||
1072 | res->mask = ntohl(*p++); | ||
1073 | if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | ||
1074 | return -EINVAL; | ||
1075 | base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base; | ||
1076 | |||
1077 | acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL; | ||
1078 | aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL; | ||
1079 | err = nfsacl_decode(buf, base, aclcnt, acl); | ||
1080 | |||
1081 | acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL; | ||
1082 | aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL; | ||
1083 | if (err > 0) | ||
1084 | err = nfsacl_decode(buf, base + err, aclcnt, acl); | ||
1085 | return (err > 0) ? 0 : err; | ||
1086 | } | ||
1087 | |||
1088 | /* | ||
1089 | * Decode setacl reply. | ||
1090 | */ | ||
1091 | static int | ||
1092 | nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) | ||
1093 | { | ||
1094 | int status = ntohl(*p++); | ||
1095 | |||
1096 | if (status) | ||
1097 | return -nfs_stat_to_errno(status); | ||
1098 | xdr_decode_post_op_attr(p, fattr); | ||
1099 | return 0; | ||
1100 | } | ||
1101 | #endif /* CONFIG_NFS_V3_ACL */ | ||
1102 | |||
981 | #ifndef MAX | 1103 | #ifndef MAX |
982 | # define MAX(a, b) (((a) > (b))? (a) : (b)) | 1104 | # define MAX(a, b) (((a) > (b))? (a) : (b)) |
983 | #endif | 1105 | #endif |
@@ -1021,3 +1143,28 @@ struct rpc_version nfs_version3 = { | |||
1021 | .procs = nfs3_procedures | 1143 | .procs = nfs3_procedures |
1022 | }; | 1144 | }; |
1023 | 1145 | ||
1146 | #ifdef CONFIG_NFS_V3_ACL | ||
1147 | static struct rpc_procinfo nfs3_acl_procedures[] = { | ||
1148 | [ACLPROC3_GETACL] = { | ||
1149 | .p_proc = ACLPROC3_GETACL, | ||
1150 | .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs, | ||
1151 | .p_decode = (kxdrproc_t) nfs3_xdr_getaclres, | ||
1152 | .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2, | ||
1153 | .p_timer = 1, | ||
1154 | }, | ||
1155 | [ACLPROC3_SETACL] = { | ||
1156 | .p_proc = ACLPROC3_SETACL, | ||
1157 | .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs, | ||
1158 | .p_decode = (kxdrproc_t) nfs3_xdr_setaclres, | ||
1159 | .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2, | ||
1160 | .p_timer = 0, | ||
1161 | }, | ||
1162 | }; | ||
1163 | |||
1164 | struct rpc_version nfsacl_version3 = { | ||
1165 | .number = 3, | ||
1166 | .nrprocs = sizeof(nfs3_acl_procedures)/ | ||
1167 | sizeof(nfs3_acl_procedures[0]), | ||
1168 | .procs = nfs3_acl_procedures, | ||
1169 | }; | ||
1170 | #endif /* CONFIG_NFS_V3_ACL */ | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h new file mode 100644 index 000000000000..ec1a22d7b876 --- /dev/null +++ b/fs/nfs/nfs4_fs.h | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * linux/fs/nfs/nfs4_fs.h | ||
3 | * | ||
4 | * Copyright (C) 2005 Trond Myklebust | ||
5 | * | ||
6 | * NFSv4-specific filesystem definitions and declarations | ||
7 | */ | ||
8 | |||
9 | #ifndef __LINUX_FS_NFS_NFS4_FS_H | ||
10 | #define __LINUX_FS_NFS_NFS4_FS_H | ||
11 | |||
12 | #ifdef CONFIG_NFS_V4 | ||
13 | |||
14 | struct idmap; | ||
15 | |||
16 | /* | ||
17 | * In a seqid-mutating op, this macro controls which error return | ||
18 | * values trigger incrementation of the seqid. | ||
19 | * | ||
20 | * from rfc 3010: | ||
21 | * The client MUST monotonically increment the sequence number for the | ||
22 | * CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE | ||
23 | * operations. This is true even in the event that the previous | ||
24 | * operation that used the sequence number received an error. The only | ||
25 | * exception to this rule is if the previous operation received one of | ||
26 | * the following errors: NFSERR_STALE_CLIENTID, NFSERR_STALE_STATEID, | ||
27 | * NFSERR_BAD_STATEID, NFSERR_BAD_SEQID, NFSERR_BADXDR, | ||
28 | * NFSERR_RESOURCE, NFSERR_NOFILEHANDLE. | ||
29 | * | ||
30 | */ | ||
31 | #define seqid_mutating_err(err) \ | ||
32 | (((err) != NFSERR_STALE_CLIENTID) && \ | ||
33 | ((err) != NFSERR_STALE_STATEID) && \ | ||
34 | ((err) != NFSERR_BAD_STATEID) && \ | ||
35 | ((err) != NFSERR_BAD_SEQID) && \ | ||
36 | ((err) != NFSERR_BAD_XDR) && \ | ||
37 | ((err) != NFSERR_RESOURCE) && \ | ||
38 | ((err) != NFSERR_NOFILEHANDLE)) | ||
39 | |||
40 | enum nfs4_client_state { | ||
41 | NFS4CLNT_OK = 0, | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * The nfs4_client identifies our client state to the server. | ||
46 | */ | ||
47 | struct nfs4_client { | ||
48 | struct list_head cl_servers; /* Global list of servers */ | ||
49 | struct in_addr cl_addr; /* Server identifier */ | ||
50 | u64 cl_clientid; /* constant */ | ||
51 | nfs4_verifier cl_confirm; | ||
52 | unsigned long cl_state; | ||
53 | |||
54 | u32 cl_lockowner_id; | ||
55 | |||
56 | /* | ||
57 | * The following rwsem ensures exclusive access to the server | ||
58 | * while we recover the state following a lease expiration. | ||
59 | */ | ||
60 | struct rw_semaphore cl_sem; | ||
61 | |||
62 | struct list_head cl_delegations; | ||
63 | struct list_head cl_state_owners; | ||
64 | struct list_head cl_unused; | ||
65 | int cl_nunused; | ||
66 | spinlock_t cl_lock; | ||
67 | atomic_t cl_count; | ||
68 | |||
69 | struct rpc_clnt * cl_rpcclient; | ||
70 | struct rpc_cred * cl_cred; | ||
71 | |||
72 | struct list_head cl_superblocks; /* List of nfs_server structs */ | ||
73 | |||
74 | unsigned long cl_lease_time; | ||
75 | unsigned long cl_last_renewal; | ||
76 | struct work_struct cl_renewd; | ||
77 | struct work_struct cl_recoverd; | ||
78 | |||
79 | wait_queue_head_t cl_waitq; | ||
80 | struct rpc_wait_queue cl_rpcwaitq; | ||
81 | |||
82 | /* used for the setclientid verifier */ | ||
83 | struct timespec cl_boot_time; | ||
84 | |||
85 | /* idmapper */ | ||
86 | struct idmap * cl_idmap; | ||
87 | |||
88 | /* Our own IP address, as a null-terminated string. | ||
89 | * This is used to generate the clientid, and the callback address. | ||
90 | */ | ||
91 | char cl_ipaddr[16]; | ||
92 | unsigned char cl_id_uniquifier; | ||
93 | }; | ||
94 | |||
95 | /* | ||
96 | * NFS4 state_owners and lock_owners are simply labels for ordered | ||
97 | * sequences of RPC calls. Their sole purpose is to provide once-only | ||
98 | * semantics by allowing the server to identify replayed requests. | ||
99 | * | ||
100 | * The ->so_sema is held during all state_owner seqid-mutating operations: | ||
101 | * OPEN, OPEN_DOWNGRADE, and CLOSE. Its purpose is to properly serialize | ||
102 | * so_seqid. | ||
103 | */ | ||
104 | struct nfs4_state_owner { | ||
105 | struct list_head so_list; /* per-clientid list of state_owners */ | ||
106 | struct nfs4_client *so_client; | ||
107 | u32 so_id; /* 32-bit identifier, unique */ | ||
108 | struct semaphore so_sema; | ||
109 | u32 so_seqid; /* protected by so_sema */ | ||
110 | atomic_t so_count; | ||
111 | |||
112 | struct rpc_cred *so_cred; /* Associated cred */ | ||
113 | struct list_head so_states; | ||
114 | struct list_head so_delegations; | ||
115 | }; | ||
116 | |||
117 | /* | ||
118 | * struct nfs4_state maintains the client-side state for a given | ||
119 | * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). | ||
120 | * | ||
121 | * OPEN: | ||
122 | * In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server, | ||
123 | * we need to know how many files are open for reading or writing on a | ||
124 | * given inode. This information too is stored here. | ||
125 | * | ||
126 | * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) | ||
127 | */ | ||
128 | |||
129 | struct nfs4_lock_state { | ||
130 | struct list_head ls_locks; /* Other lock stateids */ | ||
131 | struct nfs4_state * ls_state; /* Pointer to open state */ | ||
132 | fl_owner_t ls_owner; /* POSIX lock owner */ | ||
133 | #define NFS_LOCK_INITIALIZED 1 | ||
134 | int ls_flags; | ||
135 | u32 ls_seqid; | ||
136 | u32 ls_id; | ||
137 | nfs4_stateid ls_stateid; | ||
138 | atomic_t ls_count; | ||
139 | }; | ||
140 | |||
141 | /* bits for nfs4_state->flags */ | ||
142 | enum { | ||
143 | LK_STATE_IN_USE, | ||
144 | NFS_DELEGATED_STATE, | ||
145 | }; | ||
146 | |||
147 | struct nfs4_state { | ||
148 | struct list_head open_states; /* List of states for the same state_owner */ | ||
149 | struct list_head inode_states; /* List of states for the same inode */ | ||
150 | struct list_head lock_states; /* List of subservient lock stateids */ | ||
151 | |||
152 | struct nfs4_state_owner *owner; /* Pointer to the open owner */ | ||
153 | struct inode *inode; /* Pointer to the inode */ | ||
154 | |||
155 | unsigned long flags; /* Do we hold any locks? */ | ||
156 | struct semaphore lock_sema; /* Serializes file locking operations */ | ||
157 | spinlock_t state_lock; /* Protects the lock_states list */ | ||
158 | |||
159 | nfs4_stateid stateid; | ||
160 | |||
161 | unsigned int nreaders; | ||
162 | unsigned int nwriters; | ||
163 | int state; /* State on the server (R,W, or RW) */ | ||
164 | atomic_t count; | ||
165 | }; | ||
166 | |||
167 | |||
168 | struct nfs4_exception { | ||
169 | long timeout; | ||
170 | int retry; | ||
171 | }; | ||
172 | |||
173 | struct nfs4_state_recovery_ops { | ||
174 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); | ||
175 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | ||
176 | }; | ||
177 | |||
178 | extern struct dentry_operations nfs4_dentry_operations; | ||
179 | extern struct inode_operations nfs4_dir_inode_operations; | ||
180 | |||
181 | /* inode.c */ | ||
182 | extern ssize_t nfs4_getxattr(struct dentry *, const char *, void *, size_t); | ||
183 | extern int nfs4_setxattr(struct dentry *, const char *, const void *, size_t, int); | ||
184 | extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | ||
185 | |||
186 | |||
187 | /* nfs4proc.c */ | ||
188 | extern int nfs4_map_errors(int err); | ||
189 | extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short); | ||
190 | extern int nfs4_proc_setclientid_confirm(struct nfs4_client *); | ||
191 | extern int nfs4_proc_async_renew(struct nfs4_client *); | ||
192 | extern int nfs4_proc_renew(struct nfs4_client *); | ||
193 | extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state, mode_t mode); | ||
194 | extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | ||
195 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int); | ||
196 | |||
197 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | ||
198 | extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops; | ||
199 | |||
200 | extern const u32 nfs4_fattr_bitmap[2]; | ||
201 | extern const u32 nfs4_statfs_bitmap[2]; | ||
202 | extern const u32 nfs4_pathconf_bitmap[2]; | ||
203 | extern const u32 nfs4_fsinfo_bitmap[2]; | ||
204 | |||
205 | /* nfs4renewd.c */ | ||
206 | extern void nfs4_schedule_state_renewal(struct nfs4_client *); | ||
207 | extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); | ||
208 | extern void nfs4_kill_renewd(struct nfs4_client *); | ||
209 | extern void nfs4_renew_state(void *); | ||
210 | |||
211 | /* nfs4state.c */ | ||
212 | extern void init_nfsv4_state(struct nfs_server *); | ||
213 | extern void destroy_nfsv4_state(struct nfs_server *); | ||
214 | extern struct nfs4_client *nfs4_get_client(struct in_addr *); | ||
215 | extern void nfs4_put_client(struct nfs4_client *clp); | ||
216 | extern int nfs4_init_client(struct nfs4_client *clp); | ||
217 | extern struct nfs4_client *nfs4_find_client(struct in_addr *); | ||
218 | extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); | ||
219 | |||
220 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | ||
221 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | ||
222 | extern void nfs4_drop_state_owner(struct nfs4_state_owner *); | ||
223 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); | ||
224 | extern void nfs4_put_open_state(struct nfs4_state *); | ||
225 | extern void nfs4_close_state(struct nfs4_state *, mode_t); | ||
226 | extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); | ||
227 | extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp); | ||
228 | extern void nfs4_schedule_state_recovery(struct nfs4_client *); | ||
229 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | ||
230 | extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls); | ||
231 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | ||
232 | |||
233 | extern const nfs4_stateid zero_stateid; | ||
234 | |||
235 | /* nfs4xdr.c */ | ||
236 | extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus); | ||
237 | extern struct rpc_procinfo nfs4_procedures[]; | ||
238 | |||
239 | struct nfs4_mount_data; | ||
240 | |||
241 | /* callback_xdr.c */ | ||
242 | extern struct svc_version nfs4_callback_version1; | ||
243 | |||
244 | #else | ||
245 | |||
246 | #define init_nfsv4_state(server) do { } while (0) | ||
247 | #define destroy_nfsv4_state(server) do { } while (0) | ||
248 | #define nfs4_put_state_owner(inode, owner) do { } while (0) | ||
249 | #define nfs4_put_open_state(state) do { } while (0) | ||
250 | #define nfs4_close_state(a, b) do { } while (0) | ||
251 | |||
252 | #endif /* CONFIG_NFS_V4 */ | ||
253 | #endif /* __LINUX_FS_NFS_NFS4_FS.H */ | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1d5cb3e80c3e..1b76f80aedb9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
50 | 50 | ||
51 | #include "nfs4_fs.h" | ||
51 | #include "delegation.h" | 52 | #include "delegation.h" |
52 | 53 | ||
53 | #define NFSDBG_FACILITY NFSDBG_PROC | 54 | #define NFSDBG_FACILITY NFSDBG_PROC |
@@ -62,8 +63,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
62 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 63 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
63 | extern struct rpc_procinfo nfs4_procedures[]; | 64 | extern struct rpc_procinfo nfs4_procedures[]; |
64 | 65 | ||
65 | extern nfs4_stateid zero_stateid; | ||
66 | |||
67 | /* Prevent leaks of NFSv4 errors into userland */ | 66 | /* Prevent leaks of NFSv4 errors into userland */ |
68 | int nfs4_map_errors(int err) | 67 | int nfs4_map_errors(int err) |
69 | { | 68 | { |
@@ -104,7 +103,7 @@ const u32 nfs4_statfs_bitmap[2] = { | |||
104 | | FATTR4_WORD1_SPACE_TOTAL | 103 | | FATTR4_WORD1_SPACE_TOTAL |
105 | }; | 104 | }; |
106 | 105 | ||
107 | u32 nfs4_pathconf_bitmap[2] = { | 106 | const u32 nfs4_pathconf_bitmap[2] = { |
108 | FATTR4_WORD0_MAXLINK | 107 | FATTR4_WORD0_MAXLINK |
109 | | FATTR4_WORD0_MAXNAME, | 108 | | FATTR4_WORD0_MAXNAME, |
110 | 0 | 109 | 0 |
@@ -124,7 +123,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, | |||
124 | 123 | ||
125 | BUG_ON(readdir->count < 80); | 124 | BUG_ON(readdir->count < 80); |
126 | if (cookie > 2) { | 125 | if (cookie > 2) { |
127 | readdir->cookie = (cookie > 2) ? cookie : 0; | 126 | readdir->cookie = cookie; |
128 | memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); | 127 | memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); |
129 | return; | 128 | return; |
130 | } | 129 | } |
@@ -270,14 +269,9 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
270 | int err; | 269 | int err; |
271 | do { | 270 | do { |
272 | err = _nfs4_open_reclaim(sp, state); | 271 | err = _nfs4_open_reclaim(sp, state); |
273 | switch (err) { | 272 | if (err != -NFS4ERR_DELAY) |
274 | case 0: | 273 | break; |
275 | case -NFS4ERR_STALE_CLIENTID: | 274 | nfs4_handle_exception(server, err, &exception); |
276 | case -NFS4ERR_STALE_STATEID: | ||
277 | case -NFS4ERR_EXPIRED: | ||
278 | return err; | ||
279 | } | ||
280 | err = nfs4_handle_exception(server, err, &exception); | ||
281 | } while (exception.retry); | 275 | } while (exception.retry); |
282 | return err; | 276 | return err; |
283 | } | 277 | } |
@@ -509,6 +503,20 @@ out_stale: | |||
509 | goto out_nodeleg; | 503 | goto out_nodeleg; |
510 | } | 504 | } |
511 | 505 | ||
506 | static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | ||
507 | { | ||
508 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | ||
509 | struct nfs4_exception exception = { }; | ||
510 | int err; | ||
511 | |||
512 | do { | ||
513 | err = _nfs4_open_expired(sp, state, dentry); | ||
514 | if (err == -NFS4ERR_DELAY) | ||
515 | nfs4_handle_exception(server, err, &exception); | ||
516 | } while (exception.retry); | ||
517 | return err; | ||
518 | } | ||
519 | |||
512 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) | 520 | static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) |
513 | { | 521 | { |
514 | struct nfs_inode *nfsi = NFS_I(state->inode); | 522 | struct nfs_inode *nfsi = NFS_I(state->inode); |
@@ -521,7 +529,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
521 | continue; | 529 | continue; |
522 | get_nfs_open_context(ctx); | 530 | get_nfs_open_context(ctx); |
523 | spin_unlock(&state->inode->i_lock); | 531 | spin_unlock(&state->inode->i_lock); |
524 | status = _nfs4_open_expired(sp, state, ctx->dentry); | 532 | status = nfs4_do_open_expired(sp, state, ctx->dentry); |
525 | put_nfs_open_context(ctx); | 533 | put_nfs_open_context(ctx); |
526 | return status; | 534 | return status; |
527 | } | 535 | } |
@@ -748,11 +756,10 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
748 | 756 | ||
749 | fattr->valid = 0; | 757 | fattr->valid = 0; |
750 | 758 | ||
751 | if (state != NULL) | 759 | if (state != NULL) { |
752 | msg.rpc_cred = state->owner->so_cred; | 760 | msg.rpc_cred = state->owner->so_cred; |
753 | if (sattr->ia_valid & ATTR_SIZE) | 761 | nfs4_copy_stateid(&arg.stateid, state, current->files); |
754 | nfs4_copy_stateid(&arg.stateid, state, NULL); | 762 | } else |
755 | else | ||
756 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 763 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
757 | 764 | ||
758 | return rpc_call_sync(server->client, &msg, 0); | 765 | return rpc_call_sync(server->client, &msg, 0); |
@@ -1116,47 +1123,31 @@ static int | |||
1116 | nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | 1123 | nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, |
1117 | struct iattr *sattr) | 1124 | struct iattr *sattr) |
1118 | { | 1125 | { |
1119 | struct inode * inode = dentry->d_inode; | 1126 | struct rpc_cred *cred; |
1120 | int size_change = sattr->ia_valid & ATTR_SIZE; | 1127 | struct inode *inode = dentry->d_inode; |
1121 | struct nfs4_state *state = NULL; | 1128 | struct nfs4_state *state; |
1122 | int need_iput = 0; | ||
1123 | int status; | 1129 | int status; |
1124 | 1130 | ||
1125 | fattr->valid = 0; | 1131 | fattr->valid = 0; |
1126 | 1132 | ||
1127 | if (size_change) { | 1133 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); |
1128 | struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); | 1134 | if (IS_ERR(cred)) |
1129 | if (IS_ERR(cred)) | 1135 | return PTR_ERR(cred); |
1130 | return PTR_ERR(cred); | 1136 | /* Search for an existing WRITE delegation first */ |
1137 | state = nfs4_open_delegated(inode, FMODE_WRITE, cred); | ||
1138 | if (!IS_ERR(state)) { | ||
1139 | /* NB: nfs4_open_delegated() bumps the inode->i_count */ | ||
1140 | iput(inode); | ||
1141 | } else { | ||
1142 | /* Search for an existing open(O_WRITE) stateid */ | ||
1131 | state = nfs4_find_state(inode, cred, FMODE_WRITE); | 1143 | state = nfs4_find_state(inode, cred, FMODE_WRITE); |
1132 | if (state == NULL) { | ||
1133 | state = nfs4_open_delegated(dentry->d_inode, | ||
1134 | FMODE_WRITE, cred); | ||
1135 | if (IS_ERR(state)) | ||
1136 | state = nfs4_do_open(dentry->d_parent->d_inode, | ||
1137 | dentry, FMODE_WRITE, | ||
1138 | NULL, cred); | ||
1139 | need_iput = 1; | ||
1140 | } | ||
1141 | put_rpccred(cred); | ||
1142 | if (IS_ERR(state)) | ||
1143 | return PTR_ERR(state); | ||
1144 | |||
1145 | if (state->inode != inode) { | ||
1146 | printk(KERN_WARNING "nfs: raced in setattr (%p != %p), returning -EIO\n", inode, state->inode); | ||
1147 | status = -EIO; | ||
1148 | goto out; | ||
1149 | } | ||
1150 | } | 1144 | } |
1145 | |||
1151 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, | 1146 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, |
1152 | NFS_FH(inode), sattr, state); | 1147 | NFS_FH(inode), sattr, state); |
1153 | out: | 1148 | if (state != NULL) |
1154 | if (state) { | ||
1155 | inode = state->inode; | ||
1156 | nfs4_close_state(state, FMODE_WRITE); | 1149 | nfs4_close_state(state, FMODE_WRITE); |
1157 | if (need_iput) | 1150 | put_rpccred(cred); |
1158 | iput(inode); | ||
1159 | } | ||
1160 | return status; | 1151 | return status; |
1161 | } | 1152 | } |
1162 | 1153 | ||
@@ -1731,6 +1722,10 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
1731 | }; | 1722 | }; |
1732 | int status; | 1723 | int status; |
1733 | 1724 | ||
1725 | dprintk("%s: dentry = %s/%s, cookie = %Lu\n", __FUNCTION__, | ||
1726 | dentry->d_parent->d_name.name, | ||
1727 | dentry->d_name.name, | ||
1728 | (unsigned long long)cookie); | ||
1734 | lock_kernel(); | 1729 | lock_kernel(); |
1735 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 1730 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
1736 | res.pgbase = args.pgbase; | 1731 | res.pgbase = args.pgbase; |
@@ -1738,6 +1733,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
1738 | if (status == 0) | 1733 | if (status == 0) |
1739 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 1734 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
1740 | unlock_kernel(); | 1735 | unlock_kernel(); |
1736 | dprintk("%s: returns %d\n", __FUNCTION__, status); | ||
1741 | return status; | 1737 | return status; |
1742 | } | 1738 | } |
1743 | 1739 | ||
@@ -2163,6 +2159,193 @@ nfs4_proc_file_release(struct inode *inode, struct file *filp) | |||
2163 | return 0; | 2159 | return 0; |
2164 | } | 2160 | } |
2165 | 2161 | ||
2162 | static inline int nfs4_server_supports_acls(struct nfs_server *server) | ||
2163 | { | ||
2164 | return (server->caps & NFS_CAP_ACLS) | ||
2165 | && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL) | ||
2166 | && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL); | ||
2167 | } | ||
2168 | |||
2169 | /* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that | ||
2170 | * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on | ||
2171 | * the stack. | ||
2172 | */ | ||
2173 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) | ||
2174 | |||
2175 | static void buf_to_pages(const void *buf, size_t buflen, | ||
2176 | struct page **pages, unsigned int *pgbase) | ||
2177 | { | ||
2178 | const void *p = buf; | ||
2179 | |||
2180 | *pgbase = offset_in_page(buf); | ||
2181 | p -= *pgbase; | ||
2182 | while (p < buf + buflen) { | ||
2183 | *(pages++) = virt_to_page(p); | ||
2184 | p += PAGE_CACHE_SIZE; | ||
2185 | } | ||
2186 | } | ||
2187 | |||
2188 | struct nfs4_cached_acl { | ||
2189 | int cached; | ||
2190 | size_t len; | ||
2191 | char data[0]; | ||
2192 | }; | ||
2193 | |||
2194 | static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl) | ||
2195 | { | ||
2196 | struct nfs_inode *nfsi = NFS_I(inode); | ||
2197 | |||
2198 | spin_lock(&inode->i_lock); | ||
2199 | kfree(nfsi->nfs4_acl); | ||
2200 | nfsi->nfs4_acl = acl; | ||
2201 | spin_unlock(&inode->i_lock); | ||
2202 | } | ||
2203 | |||
2204 | static void nfs4_zap_acl_attr(struct inode *inode) | ||
2205 | { | ||
2206 | nfs4_set_cached_acl(inode, NULL); | ||
2207 | } | ||
2208 | |||
2209 | static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen) | ||
2210 | { | ||
2211 | struct nfs_inode *nfsi = NFS_I(inode); | ||
2212 | struct nfs4_cached_acl *acl; | ||
2213 | int ret = -ENOENT; | ||
2214 | |||
2215 | spin_lock(&inode->i_lock); | ||
2216 | acl = nfsi->nfs4_acl; | ||
2217 | if (acl == NULL) | ||
2218 | goto out; | ||
2219 | if (buf == NULL) /* user is just asking for length */ | ||
2220 | goto out_len; | ||
2221 | if (acl->cached == 0) | ||
2222 | goto out; | ||
2223 | ret = -ERANGE; /* see getxattr(2) man page */ | ||
2224 | if (acl->len > buflen) | ||
2225 | goto out; | ||
2226 | memcpy(buf, acl->data, acl->len); | ||
2227 | out_len: | ||
2228 | ret = acl->len; | ||
2229 | out: | ||
2230 | spin_unlock(&inode->i_lock); | ||
2231 | return ret; | ||
2232 | } | ||
2233 | |||
2234 | static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len) | ||
2235 | { | ||
2236 | struct nfs4_cached_acl *acl; | ||
2237 | |||
2238 | if (buf && acl_len <= PAGE_SIZE) { | ||
2239 | acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); | ||
2240 | if (acl == NULL) | ||
2241 | goto out; | ||
2242 | acl->cached = 1; | ||
2243 | memcpy(acl->data, buf, acl_len); | ||
2244 | } else { | ||
2245 | acl = kmalloc(sizeof(*acl), GFP_KERNEL); | ||
2246 | if (acl == NULL) | ||
2247 | goto out; | ||
2248 | acl->cached = 0; | ||
2249 | } | ||
2250 | acl->len = acl_len; | ||
2251 | out: | ||
2252 | nfs4_set_cached_acl(inode, acl); | ||
2253 | } | ||
2254 | |||
2255 | static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | ||
2256 | { | ||
2257 | struct page *pages[NFS4ACL_MAXPAGES]; | ||
2258 | struct nfs_getaclargs args = { | ||
2259 | .fh = NFS_FH(inode), | ||
2260 | .acl_pages = pages, | ||
2261 | .acl_len = buflen, | ||
2262 | }; | ||
2263 | size_t resp_len = buflen; | ||
2264 | void *resp_buf; | ||
2265 | struct rpc_message msg = { | ||
2266 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | ||
2267 | .rpc_argp = &args, | ||
2268 | .rpc_resp = &resp_len, | ||
2269 | }; | ||
2270 | struct page *localpage = NULL; | ||
2271 | int ret; | ||
2272 | |||
2273 | if (buflen < PAGE_SIZE) { | ||
2274 | /* As long as we're doing a round trip to the server anyway, | ||
2275 | * let's be prepared for a page of acl data. */ | ||
2276 | localpage = alloc_page(GFP_KERNEL); | ||
2277 | resp_buf = page_address(localpage); | ||
2278 | if (localpage == NULL) | ||
2279 | return -ENOMEM; | ||
2280 | args.acl_pages[0] = localpage; | ||
2281 | args.acl_pgbase = 0; | ||
2282 | args.acl_len = PAGE_SIZE; | ||
2283 | } else { | ||
2284 | resp_buf = buf; | ||
2285 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | ||
2286 | } | ||
2287 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | ||
2288 | if (ret) | ||
2289 | goto out_free; | ||
2290 | if (resp_len > args.acl_len) | ||
2291 | nfs4_write_cached_acl(inode, NULL, resp_len); | ||
2292 | else | ||
2293 | nfs4_write_cached_acl(inode, resp_buf, resp_len); | ||
2294 | if (buf) { | ||
2295 | ret = -ERANGE; | ||
2296 | if (resp_len > buflen) | ||
2297 | goto out_free; | ||
2298 | if (localpage) | ||
2299 | memcpy(buf, resp_buf, resp_len); | ||
2300 | } | ||
2301 | ret = resp_len; | ||
2302 | out_free: | ||
2303 | if (localpage) | ||
2304 | __free_page(localpage); | ||
2305 | return ret; | ||
2306 | } | ||
2307 | |||
2308 | static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | ||
2309 | { | ||
2310 | struct nfs_server *server = NFS_SERVER(inode); | ||
2311 | int ret; | ||
2312 | |||
2313 | if (!nfs4_server_supports_acls(server)) | ||
2314 | return -EOPNOTSUPP; | ||
2315 | ret = nfs_revalidate_inode(server, inode); | ||
2316 | if (ret < 0) | ||
2317 | return ret; | ||
2318 | ret = nfs4_read_cached_acl(inode, buf, buflen); | ||
2319 | if (ret != -ENOENT) | ||
2320 | return ret; | ||
2321 | return nfs4_get_acl_uncached(inode, buf, buflen); | ||
2322 | } | ||
2323 | |||
2324 | static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) | ||
2325 | { | ||
2326 | struct nfs_server *server = NFS_SERVER(inode); | ||
2327 | struct page *pages[NFS4ACL_MAXPAGES]; | ||
2328 | struct nfs_setaclargs arg = { | ||
2329 | .fh = NFS_FH(inode), | ||
2330 | .acl_pages = pages, | ||
2331 | .acl_len = buflen, | ||
2332 | }; | ||
2333 | struct rpc_message msg = { | ||
2334 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], | ||
2335 | .rpc_argp = &arg, | ||
2336 | .rpc_resp = NULL, | ||
2337 | }; | ||
2338 | int ret; | ||
2339 | |||
2340 | if (!nfs4_server_supports_acls(server)) | ||
2341 | return -EOPNOTSUPP; | ||
2342 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | ||
2343 | ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); | ||
2344 | if (ret == 0) | ||
2345 | nfs4_write_cached_acl(inode, buf, buflen); | ||
2346 | return ret; | ||
2347 | } | ||
2348 | |||
2166 | static int | 2349 | static int |
2167 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) | 2350 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) |
2168 | { | 2351 | { |
@@ -2448,14 +2631,11 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2448 | down_read(&clp->cl_sem); | 2631 | down_read(&clp->cl_sem); |
2449 | nlo.clientid = clp->cl_clientid; | 2632 | nlo.clientid = clp->cl_clientid; |
2450 | down(&state->lock_sema); | 2633 | down(&state->lock_sema); |
2451 | lsp = nfs4_find_lock_state(state, request->fl_owner); | 2634 | status = nfs4_set_lock_state(state, request); |
2452 | if (lsp) | 2635 | if (status != 0) |
2453 | nlo.id = lsp->ls_id; | 2636 | goto out; |
2454 | else { | 2637 | lsp = request->fl_u.nfs4_fl.owner; |
2455 | spin_lock(&clp->cl_lock); | 2638 | nlo.id = lsp->ls_id; |
2456 | nlo.id = nfs4_alloc_lockowner_id(clp); | ||
2457 | spin_unlock(&clp->cl_lock); | ||
2458 | } | ||
2459 | arg.u.lockt = &nlo; | 2639 | arg.u.lockt = &nlo; |
2460 | status = rpc_call_sync(server->client, &msg, 0); | 2640 | status = rpc_call_sync(server->client, &msg, 0); |
2461 | if (!status) { | 2641 | if (!status) { |
@@ -2476,8 +2656,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2476 | request->fl_pid = 0; | 2656 | request->fl_pid = 0; |
2477 | status = 0; | 2657 | status = 0; |
2478 | } | 2658 | } |
2479 | if (lsp) | 2659 | out: |
2480 | nfs4_put_lock_state(lsp); | ||
2481 | up(&state->lock_sema); | 2660 | up(&state->lock_sema); |
2482 | up_read(&clp->cl_sem); | 2661 | up_read(&clp->cl_sem); |
2483 | return status; | 2662 | return status; |
@@ -2537,28 +2716,26 @@ static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock | |||
2537 | }; | 2716 | }; |
2538 | struct nfs4_lock_state *lsp; | 2717 | struct nfs4_lock_state *lsp; |
2539 | struct nfs_locku_opargs luargs; | 2718 | struct nfs_locku_opargs luargs; |
2540 | int status = 0; | 2719 | int status; |
2541 | 2720 | ||
2542 | down_read(&clp->cl_sem); | 2721 | down_read(&clp->cl_sem); |
2543 | down(&state->lock_sema); | 2722 | down(&state->lock_sema); |
2544 | lsp = nfs4_find_lock_state(state, request->fl_owner); | 2723 | status = nfs4_set_lock_state(state, request); |
2545 | if (!lsp) | 2724 | if (status != 0) |
2546 | goto out; | 2725 | goto out; |
2726 | lsp = request->fl_u.nfs4_fl.owner; | ||
2547 | /* We might have lost the locks! */ | 2727 | /* We might have lost the locks! */ |
2548 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) { | 2728 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) |
2549 | luargs.seqid = lsp->ls_seqid; | 2729 | goto out; |
2550 | memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); | 2730 | luargs.seqid = lsp->ls_seqid; |
2551 | arg.u.locku = &luargs; | 2731 | memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid)); |
2552 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 2732 | arg.u.locku = &luargs; |
2553 | nfs4_increment_lock_seqid(status, lsp); | 2733 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
2554 | } | 2734 | nfs4_increment_lock_seqid(status, lsp); |
2555 | 2735 | ||
2556 | if (status == 0) { | 2736 | if (status == 0) |
2557 | memcpy(&lsp->ls_stateid, &res.u.stateid, | 2737 | memcpy(&lsp->ls_stateid, &res.u.stateid, |
2558 | sizeof(lsp->ls_stateid)); | 2738 | sizeof(lsp->ls_stateid)); |
2559 | nfs4_notify_unlck(state, request, lsp); | ||
2560 | } | ||
2561 | nfs4_put_lock_state(lsp); | ||
2562 | out: | 2739 | out: |
2563 | up(&state->lock_sema); | 2740 | up(&state->lock_sema); |
2564 | if (status == 0) | 2741 | if (status == 0) |
@@ -2584,7 +2761,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2584 | { | 2761 | { |
2585 | struct inode *inode = state->inode; | 2762 | struct inode *inode = state->inode; |
2586 | struct nfs_server *server = NFS_SERVER(inode); | 2763 | struct nfs_server *server = NFS_SERVER(inode); |
2587 | struct nfs4_lock_state *lsp; | 2764 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; |
2588 | struct nfs_lockargs arg = { | 2765 | struct nfs_lockargs arg = { |
2589 | .fh = NFS_FH(inode), | 2766 | .fh = NFS_FH(inode), |
2590 | .type = nfs4_lck_type(cmd, request), | 2767 | .type = nfs4_lck_type(cmd, request), |
@@ -2606,9 +2783,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2606 | }; | 2783 | }; |
2607 | int status; | 2784 | int status; |
2608 | 2785 | ||
2609 | lsp = nfs4_get_lock_state(state, request->fl_owner); | ||
2610 | if (lsp == NULL) | ||
2611 | return -ENOMEM; | ||
2612 | if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { | 2786 | if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) { |
2613 | struct nfs4_state_owner *owner = state->owner; | 2787 | struct nfs4_state_owner *owner = state->owner; |
2614 | struct nfs_open_to_lock otl = { | 2788 | struct nfs_open_to_lock otl = { |
@@ -2630,38 +2804,57 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
2630 | * seqid mutating errors */ | 2804 | * seqid mutating errors */ |
2631 | nfs4_increment_seqid(status, owner); | 2805 | nfs4_increment_seqid(status, owner); |
2632 | up(&owner->so_sema); | 2806 | up(&owner->so_sema); |
2807 | if (status == 0) { | ||
2808 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | ||
2809 | lsp->ls_seqid++; | ||
2810 | } | ||
2633 | } else { | 2811 | } else { |
2634 | struct nfs_exist_lock el = { | 2812 | struct nfs_exist_lock el = { |
2635 | .seqid = lsp->ls_seqid, | 2813 | .seqid = lsp->ls_seqid, |
2636 | }; | 2814 | }; |
2637 | memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); | 2815 | memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid)); |
2638 | largs.u.exist_lock = ⪙ | 2816 | largs.u.exist_lock = ⪙ |
2639 | largs.new_lock_owner = 0; | ||
2640 | arg.u.lock = &largs; | 2817 | arg.u.lock = &largs; |
2641 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 2818 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
2819 | /* increment seqid on success, and * seqid mutating errors*/ | ||
2820 | nfs4_increment_lock_seqid(status, lsp); | ||
2642 | } | 2821 | } |
2643 | /* increment seqid on success, and * seqid mutating errors*/ | ||
2644 | nfs4_increment_lock_seqid(status, lsp); | ||
2645 | /* save the returned stateid. */ | 2822 | /* save the returned stateid. */ |
2646 | if (status == 0) { | 2823 | if (status == 0) |
2647 | memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); | 2824 | memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid)); |
2648 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 2825 | else if (status == -NFS4ERR_DENIED) |
2649 | if (!reclaim) | ||
2650 | nfs4_notify_setlk(state, request, lsp); | ||
2651 | } else if (status == -NFS4ERR_DENIED) | ||
2652 | status = -EAGAIN; | 2826 | status = -EAGAIN; |
2653 | nfs4_put_lock_state(lsp); | ||
2654 | return status; | 2827 | return status; |
2655 | } | 2828 | } |
2656 | 2829 | ||
2657 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) | 2830 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) |
2658 | { | 2831 | { |
2659 | return _nfs4_do_setlk(state, F_SETLK, request, 1); | 2832 | struct nfs_server *server = NFS_SERVER(state->inode); |
2833 | struct nfs4_exception exception = { }; | ||
2834 | int err; | ||
2835 | |||
2836 | do { | ||
2837 | err = _nfs4_do_setlk(state, F_SETLK, request, 1); | ||
2838 | if (err != -NFS4ERR_DELAY) | ||
2839 | break; | ||
2840 | nfs4_handle_exception(server, err, &exception); | ||
2841 | } while (exception.retry); | ||
2842 | return err; | ||
2660 | } | 2843 | } |
2661 | 2844 | ||
2662 | static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) | 2845 | static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) |
2663 | { | 2846 | { |
2664 | return _nfs4_do_setlk(state, F_SETLK, request, 0); | 2847 | struct nfs_server *server = NFS_SERVER(state->inode); |
2848 | struct nfs4_exception exception = { }; | ||
2849 | int err; | ||
2850 | |||
2851 | do { | ||
2852 | err = _nfs4_do_setlk(state, F_SETLK, request, 0); | ||
2853 | if (err != -NFS4ERR_DELAY) | ||
2854 | break; | ||
2855 | nfs4_handle_exception(server, err, &exception); | ||
2856 | } while (exception.retry); | ||
2857 | return err; | ||
2665 | } | 2858 | } |
2666 | 2859 | ||
2667 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 2860 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
@@ -2671,7 +2864,9 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2671 | 2864 | ||
2672 | down_read(&clp->cl_sem); | 2865 | down_read(&clp->cl_sem); |
2673 | down(&state->lock_sema); | 2866 | down(&state->lock_sema); |
2674 | status = _nfs4_do_setlk(state, cmd, request, 0); | 2867 | status = nfs4_set_lock_state(state, request); |
2868 | if (status == 0) | ||
2869 | status = _nfs4_do_setlk(state, cmd, request, 0); | ||
2675 | up(&state->lock_sema); | 2870 | up(&state->lock_sema); |
2676 | if (status == 0) { | 2871 | if (status == 0) { |
2677 | /* Note: we always want to sleep here! */ | 2872 | /* Note: we always want to sleep here! */ |
@@ -2729,10 +2924,53 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) | |||
2729 | if (signalled()) | 2924 | if (signalled()) |
2730 | break; | 2925 | break; |
2731 | } while(status < 0); | 2926 | } while(status < 0); |
2732 | |||
2733 | return status; | 2927 | return status; |
2734 | } | 2928 | } |
2735 | 2929 | ||
2930 | |||
2931 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" | ||
2932 | |||
2933 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | ||
2934 | size_t buflen, int flags) | ||
2935 | { | ||
2936 | struct inode *inode = dentry->d_inode; | ||
2937 | |||
2938 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | ||
2939 | return -EOPNOTSUPP; | ||
2940 | |||
2941 | if (!S_ISREG(inode->i_mode) && | ||
2942 | (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) | ||
2943 | return -EPERM; | ||
2944 | |||
2945 | return nfs4_proc_set_acl(inode, buf, buflen); | ||
2946 | } | ||
2947 | |||
2948 | /* The getxattr man page suggests returning -ENODATA for unknown attributes, | ||
2949 | * and that's what we'll do for e.g. user attributes that haven't been set. | ||
2950 | * But we'll follow ext2/ext3's lead by returning -EOPNOTSUPP for unsupported | ||
2951 | * attributes in kernel-managed attribute namespaces. */ | ||
2952 | ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf, | ||
2953 | size_t buflen) | ||
2954 | { | ||
2955 | struct inode *inode = dentry->d_inode; | ||
2956 | |||
2957 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | ||
2958 | return -EOPNOTSUPP; | ||
2959 | |||
2960 | return nfs4_proc_get_acl(inode, buf, buflen); | ||
2961 | } | ||
2962 | |||
2963 | ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | ||
2964 | { | ||
2965 | size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1; | ||
2966 | |||
2967 | if (buf && buflen < len) | ||
2968 | return -ERANGE; | ||
2969 | if (buf) | ||
2970 | memcpy(buf, XATTR_NAME_NFSV4_ACL, len); | ||
2971 | return len; | ||
2972 | } | ||
2973 | |||
2736 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 2974 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { |
2737 | .recover_open = nfs4_open_reclaim, | 2975 | .recover_open = nfs4_open_reclaim, |
2738 | .recover_lock = nfs4_lock_reclaim, | 2976 | .recover_lock = nfs4_lock_reclaim, |
@@ -2743,10 +2981,20 @@ struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = { | |||
2743 | .recover_lock = nfs4_lock_expired, | 2981 | .recover_lock = nfs4_lock_expired, |
2744 | }; | 2982 | }; |
2745 | 2983 | ||
2984 | static struct inode_operations nfs4_file_inode_operations = { | ||
2985 | .permission = nfs_permission, | ||
2986 | .getattr = nfs_getattr, | ||
2987 | .setattr = nfs_setattr, | ||
2988 | .getxattr = nfs4_getxattr, | ||
2989 | .setxattr = nfs4_setxattr, | ||
2990 | .listxattr = nfs4_listxattr, | ||
2991 | }; | ||
2992 | |||
2746 | struct nfs_rpc_ops nfs_v4_clientops = { | 2993 | struct nfs_rpc_ops nfs_v4_clientops = { |
2747 | .version = 4, /* protocol version */ | 2994 | .version = 4, /* protocol version */ |
2748 | .dentry_ops = &nfs4_dentry_operations, | 2995 | .dentry_ops = &nfs4_dentry_operations, |
2749 | .dir_inode_ops = &nfs4_dir_inode_operations, | 2996 | .dir_inode_ops = &nfs4_dir_inode_operations, |
2997 | .file_inode_ops = &nfs4_file_inode_operations, | ||
2750 | .getroot = nfs4_proc_get_root, | 2998 | .getroot = nfs4_proc_get_root, |
2751 | .getattr = nfs4_proc_getattr, | 2999 | .getattr = nfs4_proc_getattr, |
2752 | .setattr = nfs4_proc_setattr, | 3000 | .setattr = nfs4_proc_setattr, |
@@ -2777,6 +3025,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
2777 | .file_open = nfs4_proc_file_open, | 3025 | .file_open = nfs4_proc_file_open, |
2778 | .file_release = nfs4_proc_file_release, | 3026 | .file_release = nfs4_proc_file_release, |
2779 | .lock = nfs4_proc_lock, | 3027 | .lock = nfs4_proc_lock, |
3028 | .clear_acl_cache = nfs4_zap_acl_attr, | ||
2780 | }; | 3029 | }; |
2781 | 3030 | ||
2782 | /* | 3031 | /* |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 667e06f1c647..a3001628ad32 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/nfs.h> | 53 | #include <linux/nfs.h> |
54 | #include <linux/nfs4.h> | 54 | #include <linux/nfs4.h> |
55 | #include <linux/nfs_fs.h> | 55 | #include <linux/nfs_fs.h> |
56 | #include "nfs4_fs.h" | ||
56 | 57 | ||
57 | #define NFSDBG_FACILITY NFSDBG_PROC | 58 | #define NFSDBG_FACILITY NFSDBG_PROC |
58 | 59 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 231cebce3c87..afe587d82f1e 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -46,24 +46,18 @@ | |||
46 | #include <linux/workqueue.h> | 46 | #include <linux/workqueue.h> |
47 | #include <linux/bitops.h> | 47 | #include <linux/bitops.h> |
48 | 48 | ||
49 | #include "nfs4_fs.h" | ||
49 | #include "callback.h" | 50 | #include "callback.h" |
50 | #include "delegation.h" | 51 | #include "delegation.h" |
51 | 52 | ||
52 | #define OPENOWNER_POOL_SIZE 8 | 53 | #define OPENOWNER_POOL_SIZE 8 |
53 | 54 | ||
54 | static DEFINE_SPINLOCK(state_spinlock); | 55 | const nfs4_stateid zero_stateid; |
55 | |||
56 | nfs4_stateid zero_stateid; | ||
57 | |||
58 | #if 0 | ||
59 | nfs4_stateid one_stateid = | ||
60 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
61 | #endif | ||
62 | 56 | ||
57 | static DEFINE_SPINLOCK(state_spinlock); | ||
63 | static LIST_HEAD(nfs4_clientid_list); | 58 | static LIST_HEAD(nfs4_clientid_list); |
64 | 59 | ||
65 | static void nfs4_recover_state(void *); | 60 | static void nfs4_recover_state(void *); |
66 | extern void nfs4_renew_state(void *); | ||
67 | 61 | ||
68 | void | 62 | void |
69 | init_nfsv4_state(struct nfs_server *server) | 63 | init_nfsv4_state(struct nfs_server *server) |
@@ -116,6 +110,7 @@ nfs4_alloc_client(struct in_addr *addr) | |||
116 | INIT_LIST_HEAD(&clp->cl_superblocks); | 110 | INIT_LIST_HEAD(&clp->cl_superblocks); |
117 | init_waitqueue_head(&clp->cl_waitq); | 111 | init_waitqueue_head(&clp->cl_waitq); |
118 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); | 112 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); |
113 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | ||
119 | clp->cl_boot_time = CURRENT_TIME; | 114 | clp->cl_boot_time = CURRENT_TIME; |
120 | clp->cl_state = 1 << NFS4CLNT_OK; | 115 | clp->cl_state = 1 << NFS4CLNT_OK; |
121 | return clp; | 116 | return clp; |
@@ -137,7 +132,7 @@ nfs4_free_client(struct nfs4_client *clp) | |||
137 | if (clp->cl_cred) | 132 | if (clp->cl_cred) |
138 | put_rpccred(clp->cl_cred); | 133 | put_rpccred(clp->cl_cred); |
139 | nfs_idmap_delete(clp); | 134 | nfs_idmap_delete(clp); |
140 | if (clp->cl_rpcclient) | 135 | if (!IS_ERR(clp->cl_rpcclient)) |
141 | rpc_shutdown_client(clp->cl_rpcclient); | 136 | rpc_shutdown_client(clp->cl_rpcclient); |
142 | kfree(clp); | 137 | kfree(clp); |
143 | nfs_callback_down(); | 138 | nfs_callback_down(); |
@@ -365,7 +360,7 @@ nfs4_alloc_open_state(void) | |||
365 | atomic_set(&state->count, 1); | 360 | atomic_set(&state->count, 1); |
366 | INIT_LIST_HEAD(&state->lock_states); | 361 | INIT_LIST_HEAD(&state->lock_states); |
367 | init_MUTEX(&state->lock_sema); | 362 | init_MUTEX(&state->lock_sema); |
368 | rwlock_init(&state->state_lock); | 363 | spin_lock_init(&state->state_lock); |
369 | return state; | 364 | return state; |
370 | } | 365 | } |
371 | 366 | ||
@@ -547,16 +542,6 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | |||
547 | return NULL; | 542 | return NULL; |
548 | } | 543 | } |
549 | 544 | ||
550 | struct nfs4_lock_state * | ||
551 | nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | ||
552 | { | ||
553 | struct nfs4_lock_state *lsp; | ||
554 | read_lock(&state->state_lock); | ||
555 | lsp = __nfs4_find_lock_state(state, fl_owner); | ||
556 | read_unlock(&state->state_lock); | ||
557 | return lsp; | ||
558 | } | ||
559 | |||
560 | /* | 545 | /* |
561 | * Return a compatible lock_state. If no initialized lock_state structure | 546 | * Return a compatible lock_state. If no initialized lock_state structure |
562 | * exists, return an uninitialized one. | 547 | * exists, return an uninitialized one. |
@@ -573,14 +558,13 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
573 | return NULL; | 558 | return NULL; |
574 | lsp->ls_flags = 0; | 559 | lsp->ls_flags = 0; |
575 | lsp->ls_seqid = 0; /* arbitrary */ | 560 | lsp->ls_seqid = 0; /* arbitrary */ |
576 | lsp->ls_id = -1; | ||
577 | memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data)); | 561 | memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data)); |
578 | atomic_set(&lsp->ls_count, 1); | 562 | atomic_set(&lsp->ls_count, 1); |
579 | lsp->ls_owner = fl_owner; | 563 | lsp->ls_owner = fl_owner; |
580 | INIT_LIST_HEAD(&lsp->ls_locks); | ||
581 | spin_lock(&clp->cl_lock); | 564 | spin_lock(&clp->cl_lock); |
582 | lsp->ls_id = nfs4_alloc_lockowner_id(clp); | 565 | lsp->ls_id = nfs4_alloc_lockowner_id(clp); |
583 | spin_unlock(&clp->cl_lock); | 566 | spin_unlock(&clp->cl_lock); |
567 | INIT_LIST_HEAD(&lsp->ls_locks); | ||
584 | return lsp; | 568 | return lsp; |
585 | } | 569 | } |
586 | 570 | ||
@@ -590,121 +574,112 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
590 | * | 574 | * |
591 | * The caller must be holding state->lock_sema and clp->cl_sem | 575 | * The caller must be holding state->lock_sema and clp->cl_sem |
592 | */ | 576 | */ |
593 | struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) | 577 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) |
594 | { | 578 | { |
595 | struct nfs4_lock_state * lsp; | 579 | struct nfs4_lock_state *lsp, *new = NULL; |
596 | 580 | ||
597 | lsp = nfs4_find_lock_state(state, owner); | 581 | for(;;) { |
598 | if (lsp == NULL) | 582 | spin_lock(&state->state_lock); |
599 | lsp = nfs4_alloc_lock_state(state, owner); | 583 | lsp = __nfs4_find_lock_state(state, owner); |
584 | if (lsp != NULL) | ||
585 | break; | ||
586 | if (new != NULL) { | ||
587 | new->ls_state = state; | ||
588 | list_add(&new->ls_locks, &state->lock_states); | ||
589 | set_bit(LK_STATE_IN_USE, &state->flags); | ||
590 | lsp = new; | ||
591 | new = NULL; | ||
592 | break; | ||
593 | } | ||
594 | spin_unlock(&state->state_lock); | ||
595 | new = nfs4_alloc_lock_state(state, owner); | ||
596 | if (new == NULL) | ||
597 | return NULL; | ||
598 | } | ||
599 | spin_unlock(&state->state_lock); | ||
600 | kfree(new); | ||
600 | return lsp; | 601 | return lsp; |
601 | } | 602 | } |
602 | 603 | ||
603 | /* | 604 | /* |
604 | * Byte-range lock aware utility to initialize the stateid of read/write | 605 | * Release reference to lock_state, and free it if we see that |
605 | * requests. | 606 | * it is no longer in use |
606 | */ | 607 | */ |
607 | void | 608 | static void nfs4_put_lock_state(struct nfs4_lock_state *lsp) |
608 | nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) | ||
609 | { | 609 | { |
610 | if (test_bit(LK_STATE_IN_USE, &state->flags)) { | 610 | struct nfs4_state *state; |
611 | struct nfs4_lock_state *lsp; | ||
612 | 611 | ||
613 | lsp = nfs4_find_lock_state(state, fl_owner); | 612 | if (lsp == NULL) |
614 | if (lsp) { | 613 | return; |
615 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); | 614 | state = lsp->ls_state; |
616 | nfs4_put_lock_state(lsp); | 615 | if (!atomic_dec_and_lock(&lsp->ls_count, &state->state_lock)) |
617 | return; | 616 | return; |
618 | } | 617 | list_del(&lsp->ls_locks); |
619 | } | 618 | if (list_empty(&state->lock_states)) |
620 | memcpy(dst, &state->stateid, sizeof(*dst)); | 619 | clear_bit(LK_STATE_IN_USE, &state->flags); |
620 | spin_unlock(&state->state_lock); | ||
621 | kfree(lsp); | ||
621 | } | 622 | } |
622 | 623 | ||
623 | /* | 624 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) |
624 | * Called with state->lock_sema and clp->cl_sem held. | ||
625 | */ | ||
626 | void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp) | ||
627 | { | 625 | { |
628 | if (status == NFS_OK || seqid_mutating_err(-status)) | 626 | struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner; |
629 | lsp->ls_seqid++; | ||
630 | } | ||
631 | 627 | ||
632 | /* | 628 | dst->fl_u.nfs4_fl.owner = lsp; |
633 | * Check to see if the request lock (type FL_UNLK) effects the fl lock. | 629 | atomic_inc(&lsp->ls_count); |
634 | * | 630 | } |
635 | * fl and request must have the same posix owner | ||
636 | * | ||
637 | * return: | ||
638 | * 0 -> fl not effected by request | ||
639 | * 1 -> fl consumed by request | ||
640 | */ | ||
641 | 631 | ||
642 | static int | 632 | static void nfs4_fl_release_lock(struct file_lock *fl) |
643 | nfs4_check_unlock(struct file_lock *fl, struct file_lock *request) | ||
644 | { | 633 | { |
645 | if (fl->fl_start >= request->fl_start && fl->fl_end <= request->fl_end) | 634 | nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner); |
646 | return 1; | ||
647 | return 0; | ||
648 | } | 635 | } |
649 | 636 | ||
650 | /* | 637 | static struct file_lock_operations nfs4_fl_lock_ops = { |
651 | * Post an initialized lock_state on the state->lock_states list. | 638 | .fl_copy_lock = nfs4_fl_copy_lock, |
652 | */ | 639 | .fl_release_private = nfs4_fl_release_lock, |
653 | void nfs4_notify_setlk(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp) | 640 | }; |
641 | |||
642 | int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | ||
654 | { | 643 | { |
655 | if (!list_empty(&lsp->ls_locks)) | 644 | struct nfs4_lock_state *lsp; |
656 | return; | 645 | |
657 | atomic_inc(&lsp->ls_count); | 646 | if (fl->fl_ops != NULL) |
658 | write_lock(&state->state_lock); | 647 | return 0; |
659 | list_add(&lsp->ls_locks, &state->lock_states); | 648 | lsp = nfs4_get_lock_state(state, fl->fl_owner); |
660 | set_bit(LK_STATE_IN_USE, &state->flags); | 649 | if (lsp == NULL) |
661 | write_unlock(&state->state_lock); | 650 | return -ENOMEM; |
651 | fl->fl_u.nfs4_fl.owner = lsp; | ||
652 | fl->fl_ops = &nfs4_fl_lock_ops; | ||
653 | return 0; | ||
662 | } | 654 | } |
663 | 655 | ||
664 | /* | 656 | /* |
665 | * to decide to 'reap' lock state: | 657 | * Byte-range lock aware utility to initialize the stateid of read/write |
666 | * 1) search i_flock for file_locks with fl.lock_state = to ls. | 658 | * requests. |
667 | * 2) determine if unlock will consume found lock. | ||
668 | * if so, reap | ||
669 | * | ||
670 | * else, don't reap. | ||
671 | * | ||
672 | */ | 659 | */ |
673 | void | 660 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) |
674 | nfs4_notify_unlck(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp) | ||
675 | { | 661 | { |
676 | struct inode *inode = state->inode; | 662 | struct nfs4_lock_state *lsp; |
677 | struct file_lock *fl; | ||
678 | 663 | ||
679 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 664 | memcpy(dst, &state->stateid, sizeof(*dst)); |
680 | if (!(fl->fl_flags & FL_POSIX)) | 665 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) |
681 | continue; | 666 | return; |
682 | if (fl->fl_owner != lsp->ls_owner) | ||
683 | continue; | ||
684 | /* Exit if we find at least one lock which is not consumed */ | ||
685 | if (nfs4_check_unlock(fl,request) == 0) | ||
686 | return; | ||
687 | } | ||
688 | 667 | ||
689 | write_lock(&state->state_lock); | 668 | spin_lock(&state->state_lock); |
690 | list_del_init(&lsp->ls_locks); | 669 | lsp = __nfs4_find_lock_state(state, fl_owner); |
691 | if (list_empty(&state->lock_states)) | 670 | if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) |
692 | clear_bit(LK_STATE_IN_USE, &state->flags); | 671 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); |
693 | write_unlock(&state->state_lock); | 672 | spin_unlock(&state->state_lock); |
694 | nfs4_put_lock_state(lsp); | 673 | nfs4_put_lock_state(lsp); |
695 | } | 674 | } |
696 | 675 | ||
697 | /* | 676 | /* |
698 | * Release reference to lock_state, and free it if we see that | 677 | * Called with state->lock_sema and clp->cl_sem held. |
699 | * it is no longer in use | 678 | */ |
700 | */ | 679 | void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp) |
701 | void | ||
702 | nfs4_put_lock_state(struct nfs4_lock_state *lsp) | ||
703 | { | 680 | { |
704 | if (!atomic_dec_and_test(&lsp->ls_count)) | 681 | if (status == NFS_OK || seqid_mutating_err(-status)) |
705 | return; | 682 | lsp->ls_seqid++; |
706 | BUG_ON (!list_empty(&lsp->ls_locks)); | ||
707 | kfree(lsp); | ||
708 | } | 683 | } |
709 | 684 | ||
710 | /* | 685 | /* |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5f4de05763c9..6c564ef9489e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/nfs4.h> | 51 | #include <linux/nfs4.h> |
52 | #include <linux/nfs_fs.h> | 52 | #include <linux/nfs_fs.h> |
53 | #include <linux/nfs_idmap.h> | 53 | #include <linux/nfs_idmap.h> |
54 | #include "nfs4_fs.h" | ||
54 | 55 | ||
55 | #define NFSDBG_FACILITY NFSDBG_XDR | 56 | #define NFSDBG_FACILITY NFSDBG_XDR |
56 | 57 | ||
@@ -82,12 +83,16 @@ static int nfs_stat_to_errno(int); | |||
82 | #define encode_getfh_maxsz (op_encode_hdr_maxsz) | 83 | #define encode_getfh_maxsz (op_encode_hdr_maxsz) |
83 | #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ | 84 | #define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ |
84 | ((3+NFS4_FHSIZE) >> 2)) | 85 | ((3+NFS4_FHSIZE) >> 2)) |
85 | #define encode_getattr_maxsz (op_encode_hdr_maxsz + 3) | 86 | #define nfs4_fattr_bitmap_maxsz 3 |
87 | #define encode_getattr_maxsz (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) | ||
86 | #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) | 88 | #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) |
87 | #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) | 89 | #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) |
88 | #define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz) | 90 | /* This is based on getfattr, which uses the most attributes: */ |
89 | #define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \ | 91 | #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \ |
90 | nfs4_fattr_bitmap_maxsz) | 92 | 3 + 3 + 3 + 2 * nfs4_name_maxsz)) |
93 | #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ | ||
94 | nfs4_fattr_value_maxsz) | ||
95 | #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) | ||
91 | #define encode_savefh_maxsz (op_encode_hdr_maxsz) | 96 | #define encode_savefh_maxsz (op_encode_hdr_maxsz) |
92 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) | 97 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) |
93 | #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) | 98 | #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) |
@@ -122,11 +127,11 @@ static int nfs_stat_to_errno(int); | |||
122 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ | 127 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ |
123 | 1 + nfs4_name_maxsz + \ | 128 | 1 + nfs4_name_maxsz + \ |
124 | nfs4_path_maxsz + \ | 129 | nfs4_path_maxsz + \ |
125 | nfs4_fattr_bitmap_maxsz) | 130 | nfs4_fattr_maxsz) |
126 | #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) | 131 | #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) |
127 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ | 132 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ |
128 | 2 + nfs4_name_maxsz + \ | 133 | 2 + nfs4_name_maxsz + \ |
129 | nfs4_fattr_bitmap_maxsz) | 134 | nfs4_fattr_maxsz) |
130 | #define decode_create_maxsz (op_decode_hdr_maxsz + 8) | 135 | #define decode_create_maxsz (op_decode_hdr_maxsz + 8) |
131 | #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) | 136 | #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) |
132 | #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) | 137 | #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) |
@@ -205,7 +210,7 @@ static int nfs_stat_to_errno(int); | |||
205 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ | 210 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ |
206 | encode_putfh_maxsz + \ | 211 | encode_putfh_maxsz + \ |
207 | op_encode_hdr_maxsz + 4 + \ | 212 | op_encode_hdr_maxsz + 4 + \ |
208 | nfs4_fattr_bitmap_maxsz + \ | 213 | nfs4_fattr_maxsz + \ |
209 | encode_getattr_maxsz) | 214 | encode_getattr_maxsz) |
210 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ | 215 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ |
211 | decode_putfh_maxsz + \ | 216 | decode_putfh_maxsz + \ |
@@ -360,6 +365,20 @@ static int nfs_stat_to_errno(int); | |||
360 | encode_delegreturn_maxsz) | 365 | encode_delegreturn_maxsz) |
361 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ | 366 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ |
362 | decode_delegreturn_maxsz) | 367 | decode_delegreturn_maxsz) |
368 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ | ||
369 | encode_putfh_maxsz + \ | ||
370 | encode_getattr_maxsz) | ||
371 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ | ||
372 | decode_putfh_maxsz + \ | ||
373 | op_decode_hdr_maxsz + \ | ||
374 | nfs4_fattr_bitmap_maxsz + 1) | ||
375 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ | ||
376 | encode_putfh_maxsz + \ | ||
377 | op_encode_hdr_maxsz + 4 + \ | ||
378 | nfs4_fattr_bitmap_maxsz + 1) | ||
379 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ | ||
380 | decode_putfh_maxsz + \ | ||
381 | op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) | ||
363 | 382 | ||
364 | static struct { | 383 | static struct { |
365 | unsigned int mode; | 384 | unsigned int mode; |
@@ -459,7 +478,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
459 | * In the worst-case, this would be | 478 | * In the worst-case, this would be |
460 | * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) | 479 | * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) |
461 | * = 36 bytes, plus any contribution from variable-length fields | 480 | * = 36 bytes, plus any contribution from variable-length fields |
462 | * such as owner/group/acl's. | 481 | * such as owner/group. |
463 | */ | 482 | */ |
464 | len = 16; | 483 | len = 16; |
465 | 484 | ||
@@ -660,8 +679,6 @@ static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1 | |||
660 | 679 | ||
661 | static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) | 680 | static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) |
662 | { | 681 | { |
663 | extern u32 nfs4_fattr_bitmap[]; | ||
664 | |||
665 | return encode_getattr_two(xdr, | 682 | return encode_getattr_two(xdr, |
666 | bitmask[0] & nfs4_fattr_bitmap[0], | 683 | bitmask[0] & nfs4_fattr_bitmap[0], |
667 | bitmask[1] & nfs4_fattr_bitmap[1]); | 684 | bitmask[1] & nfs4_fattr_bitmap[1]); |
@@ -669,8 +686,6 @@ static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask) | |||
669 | 686 | ||
670 | static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) | 687 | static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask) |
671 | { | 688 | { |
672 | extern u32 nfs4_fsinfo_bitmap[]; | ||
673 | |||
674 | return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], | 689 | return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0], |
675 | bitmask[1] & nfs4_fsinfo_bitmap[1]); | 690 | bitmask[1] & nfs4_fsinfo_bitmap[1]); |
676 | } | 691 | } |
@@ -969,7 +984,6 @@ static int encode_putrootfh(struct xdr_stream *xdr) | |||
969 | 984 | ||
970 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 985 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) |
971 | { | 986 | { |
972 | extern nfs4_stateid zero_stateid; | ||
973 | nfs4_stateid stateid; | 987 | nfs4_stateid stateid; |
974 | uint32_t *p; | 988 | uint32_t *p; |
975 | 989 | ||
@@ -1000,6 +1014,10 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) | |||
1000 | static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) | 1014 | static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) |
1001 | { | 1015 | { |
1002 | struct rpc_auth *auth = req->rq_task->tk_auth; | 1016 | struct rpc_auth *auth = req->rq_task->tk_auth; |
1017 | uint32_t attrs[2] = { | ||
1018 | FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, | ||
1019 | FATTR4_WORD1_MOUNTED_ON_FILEID, | ||
1020 | }; | ||
1003 | int replen; | 1021 | int replen; |
1004 | uint32_t *p; | 1022 | uint32_t *p; |
1005 | 1023 | ||
@@ -1010,13 +1028,20 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1010 | WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ | 1028 | WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ |
1011 | WRITE32(readdir->count); | 1029 | WRITE32(readdir->count); |
1012 | WRITE32(2); | 1030 | WRITE32(2); |
1013 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) { | 1031 | /* Switch to mounted_on_fileid if the server supports it */ |
1014 | WRITE32(0); | 1032 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) |
1015 | WRITE32(FATTR4_WORD1_MOUNTED_ON_FILEID); | 1033 | attrs[0] &= ~FATTR4_WORD0_FILEID; |
1016 | } else { | 1034 | else |
1017 | WRITE32(FATTR4_WORD0_FILEID); | 1035 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; |
1018 | WRITE32(0); | 1036 | WRITE32(attrs[0] & readdir->bitmask[0]); |
1019 | } | 1037 | WRITE32(attrs[1] & readdir->bitmask[1]); |
1038 | dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n", | ||
1039 | __FUNCTION__, | ||
1040 | (unsigned long long)readdir->cookie, | ||
1041 | ((u32 *)readdir->verifier.data)[0], | ||
1042 | ((u32 *)readdir->verifier.data)[1], | ||
1043 | attrs[0] & readdir->bitmask[0], | ||
1044 | attrs[1] & readdir->bitmask[1]); | ||
1020 | 1045 | ||
1021 | /* set up reply kvec | 1046 | /* set up reply kvec |
1022 | * toplevel_status + taglen + rescount + OP_PUTFH + status | 1047 | * toplevel_status + taglen + rescount + OP_PUTFH + status |
@@ -1025,6 +1050,9 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1025 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; | 1050 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2; |
1026 | xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, | 1051 | xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages, |
1027 | readdir->pgbase, readdir->count); | 1052 | readdir->pgbase, readdir->count); |
1053 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", | ||
1054 | __FUNCTION__, replen, readdir->pages, | ||
1055 | readdir->pgbase, readdir->count); | ||
1028 | 1056 | ||
1029 | return 0; | 1057 | return 0; |
1030 | } | 1058 | } |
@@ -1089,6 +1117,25 @@ static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client | |||
1089 | } | 1117 | } |
1090 | 1118 | ||
1091 | static int | 1119 | static int |
1120 | encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg) | ||
1121 | { | ||
1122 | uint32_t *p; | ||
1123 | |||
1124 | RESERVE_SPACE(4+sizeof(zero_stateid.data)); | ||
1125 | WRITE32(OP_SETATTR); | ||
1126 | WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data)); | ||
1127 | RESERVE_SPACE(2*4); | ||
1128 | WRITE32(1); | ||
1129 | WRITE32(FATTR4_WORD0_ACL); | ||
1130 | if (arg->acl_len % 4) | ||
1131 | return -EINVAL; | ||
1132 | RESERVE_SPACE(4); | ||
1133 | WRITE32(arg->acl_len); | ||
1134 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | ||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | static int | ||
1092 | encode_savefh(struct xdr_stream *xdr) | 1139 | encode_savefh(struct xdr_stream *xdr) |
1093 | { | 1140 | { |
1094 | uint32_t *p; | 1141 | uint32_t *p; |
@@ -1632,6 +1679,34 @@ out: | |||
1632 | } | 1679 | } |
1633 | 1680 | ||
1634 | /* | 1681 | /* |
1682 | * Encode a GETACL request | ||
1683 | */ | ||
1684 | static int | ||
1685 | nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p, | ||
1686 | struct nfs_getaclargs *args) | ||
1687 | { | ||
1688 | struct xdr_stream xdr; | ||
1689 | struct rpc_auth *auth = req->rq_task->tk_auth; | ||
1690 | struct compound_hdr hdr = { | ||
1691 | .nops = 2, | ||
1692 | }; | ||
1693 | int replen, status; | ||
1694 | |||
1695 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
1696 | encode_compound_hdr(&xdr, &hdr); | ||
1697 | status = encode_putfh(&xdr, args->fh); | ||
1698 | if (status) | ||
1699 | goto out; | ||
1700 | status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0); | ||
1701 | /* set up reply buffer: */ | ||
1702 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; | ||
1703 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1704 | args->acl_pages, args->acl_pgbase, args->acl_len); | ||
1705 | out: | ||
1706 | return status; | ||
1707 | } | ||
1708 | |||
1709 | /* | ||
1635 | * Encode a WRITE request | 1710 | * Encode a WRITE request |
1636 | */ | 1711 | */ |
1637 | static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) | 1712 | static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args) |
@@ -1697,7 +1772,6 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs | |||
1697 | */ | 1772 | */ |
1698 | static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args) | 1773 | static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args) |
1699 | { | 1774 | { |
1700 | extern u32 nfs4_pathconf_bitmap[2]; | ||
1701 | struct xdr_stream xdr; | 1775 | struct xdr_stream xdr; |
1702 | struct compound_hdr hdr = { | 1776 | struct compound_hdr hdr = { |
1703 | .nops = 2, | 1777 | .nops = 2, |
@@ -1718,7 +1792,6 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct | |||
1718 | */ | 1792 | */ |
1719 | static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args) | 1793 | static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args) |
1720 | { | 1794 | { |
1721 | extern u32 nfs4_statfs_bitmap[]; | ||
1722 | struct xdr_stream xdr; | 1795 | struct xdr_stream xdr; |
1723 | struct compound_hdr hdr = { | 1796 | struct compound_hdr hdr = { |
1724 | .nops = 2, | 1797 | .nops = 2, |
@@ -3003,6 +3076,11 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3003 | return status; | 3076 | return status; |
3004 | READ_BUF(8); | 3077 | READ_BUF(8); |
3005 | COPYMEM(readdir->verifier.data, 8); | 3078 | COPYMEM(readdir->verifier.data, 8); |
3079 | dprintk("%s: verifier = 0x%x%x\n", | ||
3080 | __FUNCTION__, | ||
3081 | ((u32 *)readdir->verifier.data)[0], | ||
3082 | ((u32 *)readdir->verifier.data)[1]); | ||
3083 | |||
3006 | 3084 | ||
3007 | hdrlen = (char *) p - (char *) iov->iov_base; | 3085 | hdrlen = (char *) p - (char *) iov->iov_base; |
3008 | recvd = rcvbuf->len - hdrlen; | 3086 | recvd = rcvbuf->len - hdrlen; |
@@ -3017,12 +3095,14 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3017 | for (nr = 0; *p++; nr++) { | 3095 | for (nr = 0; *p++; nr++) { |
3018 | if (p + 3 > end) | 3096 | if (p + 3 > end) |
3019 | goto short_pkt; | 3097 | goto short_pkt; |
3098 | dprintk("cookie = %Lu, ", *((unsigned long long *)p)); | ||
3020 | p += 2; /* cookie */ | 3099 | p += 2; /* cookie */ |
3021 | len = ntohl(*p++); /* filename length */ | 3100 | len = ntohl(*p++); /* filename length */ |
3022 | if (len > NFS4_MAXNAMLEN) { | 3101 | if (len > NFS4_MAXNAMLEN) { |
3023 | printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); | 3102 | printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); |
3024 | goto err_unmap; | 3103 | goto err_unmap; |
3025 | } | 3104 | } |
3105 | dprintk("filename = %*s\n", len, (char *)p); | ||
3026 | p += XDR_QUADLEN(len); | 3106 | p += XDR_QUADLEN(len); |
3027 | if (p + 1 > end) | 3107 | if (p + 1 > end) |
3028 | goto short_pkt; | 3108 | goto short_pkt; |
@@ -3042,6 +3122,7 @@ out: | |||
3042 | kunmap_atomic(kaddr, KM_USER0); | 3122 | kunmap_atomic(kaddr, KM_USER0); |
3043 | return 0; | 3123 | return 0; |
3044 | short_pkt: | 3124 | short_pkt: |
3125 | dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); | ||
3045 | entry[0] = entry[1] = 0; | 3126 | entry[0] = entry[1] = 0; |
3046 | /* truncate listing ? */ | 3127 | /* truncate listing ? */ |
3047 | if (!nr) { | 3128 | if (!nr) { |
@@ -3127,6 +3208,47 @@ static int decode_renew(struct xdr_stream *xdr) | |||
3127 | return decode_op_hdr(xdr, OP_RENEW); | 3208 | return decode_op_hdr(xdr, OP_RENEW); |
3128 | } | 3209 | } |
3129 | 3210 | ||
3211 | static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | ||
3212 | size_t *acl_len) | ||
3213 | { | ||
3214 | uint32_t *savep; | ||
3215 | uint32_t attrlen, | ||
3216 | bitmap[2] = {0}; | ||
3217 | struct kvec *iov = req->rq_rcv_buf.head; | ||
3218 | int status; | ||
3219 | |||
3220 | *acl_len = 0; | ||
3221 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | ||
3222 | goto out; | ||
3223 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | ||
3224 | goto out; | ||
3225 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) | ||
3226 | goto out; | ||
3227 | |||
3228 | if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) | ||
3229 | return -EIO; | ||
3230 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { | ||
3231 | int hdrlen, recvd; | ||
3232 | |||
3233 | /* We ignore &savep and don't do consistency checks on | ||
3234 | * the attr length. Let userspace figure it out.... */ | ||
3235 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; | ||
3236 | recvd = req->rq_rcv_buf.len - hdrlen; | ||
3237 | if (attrlen > recvd) { | ||
3238 | printk(KERN_WARNING "NFS: server cheating in getattr" | ||
3239 | " acl reply: attrlen %u > recvd %u\n", | ||
3240 | attrlen, recvd); | ||
3241 | return -EINVAL; | ||
3242 | } | ||
3243 | if (attrlen <= *acl_len) | ||
3244 | xdr_read_pages(xdr, attrlen); | ||
3245 | *acl_len = attrlen; | ||
3246 | } | ||
3247 | |||
3248 | out: | ||
3249 | return status; | ||
3250 | } | ||
3251 | |||
3130 | static int | 3252 | static int |
3131 | decode_savefh(struct xdr_stream *xdr) | 3253 | decode_savefh(struct xdr_stream *xdr) |
3132 | { | 3254 | { |
@@ -3418,6 +3540,71 @@ out: | |||
3418 | 3540 | ||
3419 | } | 3541 | } |
3420 | 3542 | ||
3543 | /* | ||
3544 | * Encode an SETACL request | ||
3545 | */ | ||
3546 | static int | ||
3547 | nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args) | ||
3548 | { | ||
3549 | struct xdr_stream xdr; | ||
3550 | struct compound_hdr hdr = { | ||
3551 | .nops = 2, | ||
3552 | }; | ||
3553 | int status; | ||
3554 | |||
3555 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
3556 | encode_compound_hdr(&xdr, &hdr); | ||
3557 | status = encode_putfh(&xdr, args->fh); | ||
3558 | if (status) | ||
3559 | goto out; | ||
3560 | status = encode_setacl(&xdr, args); | ||
3561 | out: | ||
3562 | return status; | ||
3563 | } | ||
3564 | /* | ||
3565 | * Decode SETACL response | ||
3566 | */ | ||
3567 | static int | ||
3568 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res) | ||
3569 | { | ||
3570 | struct xdr_stream xdr; | ||
3571 | struct compound_hdr hdr; | ||
3572 | int status; | ||
3573 | |||
3574 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
3575 | status = decode_compound_hdr(&xdr, &hdr); | ||
3576 | if (status) | ||
3577 | goto out; | ||
3578 | status = decode_putfh(&xdr); | ||
3579 | if (status) | ||
3580 | goto out; | ||
3581 | status = decode_setattr(&xdr, res); | ||
3582 | out: | ||
3583 | return status; | ||
3584 | } | ||
3585 | |||
3586 | /* | ||
3587 | * Decode GETACL response | ||
3588 | */ | ||
3589 | static int | ||
3590 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len) | ||
3591 | { | ||
3592 | struct xdr_stream xdr; | ||
3593 | struct compound_hdr hdr; | ||
3594 | int status; | ||
3595 | |||
3596 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
3597 | status = decode_compound_hdr(&xdr, &hdr); | ||
3598 | if (status) | ||
3599 | goto out; | ||
3600 | status = decode_putfh(&xdr); | ||
3601 | if (status) | ||
3602 | goto out; | ||
3603 | status = decode_getacl(&xdr, rqstp, acl_len); | ||
3604 | |||
3605 | out: | ||
3606 | return status; | ||
3607 | } | ||
3421 | 3608 | ||
3422 | /* | 3609 | /* |
3423 | * Decode CLOSE response | 3610 | * Decode CLOSE response |
@@ -3895,6 +4082,12 @@ uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) | |||
3895 | } | 4082 | } |
3896 | len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ | 4083 | len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ |
3897 | if (len > 0) { | 4084 | if (len > 0) { |
4085 | if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) { | ||
4086 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; | ||
4087 | /* Ignore the return value of rdattr_error for now */ | ||
4088 | p++; | ||
4089 | len--; | ||
4090 | } | ||
3898 | if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) | 4091 | if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) |
3899 | xdr_decode_hyper(p, &entry->ino); | 4092 | xdr_decode_hyper(p, &entry->ino); |
3900 | else if (bitmap[0] == FATTR4_WORD0_FILEID) | 4093 | else if (bitmap[0] == FATTR4_WORD0_FILEID) |
@@ -3934,6 +4127,8 @@ static struct { | |||
3934 | { NFS4ERR_DQUOT, EDQUOT }, | 4127 | { NFS4ERR_DQUOT, EDQUOT }, |
3935 | { NFS4ERR_STALE, ESTALE }, | 4128 | { NFS4ERR_STALE, ESTALE }, |
3936 | { NFS4ERR_BADHANDLE, EBADHANDLE }, | 4129 | { NFS4ERR_BADHANDLE, EBADHANDLE }, |
4130 | { NFS4ERR_BADOWNER, EINVAL }, | ||
4131 | { NFS4ERR_BADNAME, EINVAL }, | ||
3937 | { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, | 4132 | { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, |
3938 | { NFS4ERR_NOTSUPP, ENOTSUPP }, | 4133 | { NFS4ERR_NOTSUPP, ENOTSUPP }, |
3939 | { NFS4ERR_TOOSMALL, ETOOSMALL }, | 4134 | { NFS4ERR_TOOSMALL, ETOOSMALL }, |
@@ -4019,6 +4214,8 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
4019 | PROC(READDIR, enc_readdir, dec_readdir), | 4214 | PROC(READDIR, enc_readdir, dec_readdir), |
4020 | PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), | 4215 | PROC(SERVER_CAPS, enc_server_caps, dec_server_caps), |
4021 | PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), | 4216 | PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn), |
4217 | PROC(GETACL, enc_getacl, dec_getacl), | ||
4218 | PROC(SETACL, enc_setacl, dec_setacl), | ||
4022 | }; | 4219 | }; |
4023 | 4220 | ||
4024 | struct rpc_version nfs_version4 = { | 4221 | struct rpc_version nfs_version4 = { |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index fd5bc596fe8a..1b272a135a31 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -124,6 +124,7 @@ enum { | |||
124 | Opt_soft, Opt_hard, Opt_intr, | 124 | Opt_soft, Opt_hard, Opt_intr, |
125 | Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, | 125 | Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, |
126 | Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, | 126 | Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, |
127 | Opt_acl, Opt_noacl, | ||
127 | /* Error token */ | 128 | /* Error token */ |
128 | Opt_err | 129 | Opt_err |
129 | }; | 130 | }; |
@@ -158,6 +159,8 @@ static match_table_t __initdata tokens = { | |||
158 | {Opt_udp, "udp"}, | 159 | {Opt_udp, "udp"}, |
159 | {Opt_tcp, "proto=tcp"}, | 160 | {Opt_tcp, "proto=tcp"}, |
160 | {Opt_tcp, "tcp"}, | 161 | {Opt_tcp, "tcp"}, |
162 | {Opt_acl, "acl"}, | ||
163 | {Opt_noacl, "noacl"}, | ||
161 | {Opt_err, NULL} | 164 | {Opt_err, NULL} |
162 | 165 | ||
163 | }; | 166 | }; |
@@ -266,6 +269,12 @@ static int __init root_nfs_parse(char *name, char *buf) | |||
266 | case Opt_tcp: | 269 | case Opt_tcp: |
267 | nfs_data.flags |= NFS_MOUNT_TCP; | 270 | nfs_data.flags |= NFS_MOUNT_TCP; |
268 | break; | 271 | break; |
272 | case Opt_acl: | ||
273 | nfs_data.flags &= ~NFS_MOUNT_NOACL; | ||
274 | break; | ||
275 | case Opt_noacl: | ||
276 | nfs_data.flags |= NFS_MOUNT_NOACL; | ||
277 | break; | ||
269 | default : | 278 | default : |
270 | return 0; | 279 | return 0; |
271 | } | 280 | } |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 4f1ba723848d..d53857b148e2 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -107,11 +107,38 @@ void nfs_unlock_request(struct nfs_page *req) | |||
107 | smp_mb__before_clear_bit(); | 107 | smp_mb__before_clear_bit(); |
108 | clear_bit(PG_BUSY, &req->wb_flags); | 108 | clear_bit(PG_BUSY, &req->wb_flags); |
109 | smp_mb__after_clear_bit(); | 109 | smp_mb__after_clear_bit(); |
110 | wake_up_all(&req->wb_context->waitq); | 110 | wake_up_bit(&req->wb_flags, PG_BUSY); |
111 | nfs_release_request(req); | 111 | nfs_release_request(req); |
112 | } | 112 | } |
113 | 113 | ||
114 | /** | 114 | /** |
115 | * nfs_set_page_writeback_locked - Lock a request for writeback | ||
116 | * @req: | ||
117 | */ | ||
118 | int nfs_set_page_writeback_locked(struct nfs_page *req) | ||
119 | { | ||
120 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | ||
121 | |||
122 | if (!nfs_lock_request(req)) | ||
123 | return 0; | ||
124 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | ||
125 | return 1; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * nfs_clear_page_writeback - Unlock request and wake up sleepers | ||
130 | */ | ||
131 | void nfs_clear_page_writeback(struct nfs_page *req) | ||
132 | { | ||
133 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | ||
134 | |||
135 | spin_lock(&nfsi->req_lock); | ||
136 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | ||
137 | spin_unlock(&nfsi->req_lock); | ||
138 | nfs_unlock_request(req); | ||
139 | } | ||
140 | |||
141 | /** | ||
115 | * nfs_clear_request - Free up all resources allocated to the request | 142 | * nfs_clear_request - Free up all resources allocated to the request |
116 | * @req: | 143 | * @req: |
117 | * | 144 | * |
@@ -150,34 +177,15 @@ nfs_release_request(struct nfs_page *req) | |||
150 | nfs_page_free(req); | 177 | nfs_page_free(req); |
151 | } | 178 | } |
152 | 179 | ||
153 | /** | 180 | static int nfs_wait_bit_interruptible(void *word) |
154 | * nfs_list_add_request - Insert a request into a sorted list | ||
155 | * @req: request | ||
156 | * @head: head of list into which to insert the request. | ||
157 | * | ||
158 | * Note that the wb_list is sorted by page index in order to facilitate | ||
159 | * coalescing of requests. | ||
160 | * We use an insertion sort that is optimized for the case of appended | ||
161 | * writes. | ||
162 | */ | ||
163 | void | ||
164 | nfs_list_add_request(struct nfs_page *req, struct list_head *head) | ||
165 | { | 181 | { |
166 | struct list_head *pos; | 182 | int ret = 0; |
167 | 183 | ||
168 | #ifdef NFS_PARANOIA | 184 | if (signal_pending(current)) |
169 | if (!list_empty(&req->wb_list)) { | 185 | ret = -ERESTARTSYS; |
170 | printk(KERN_ERR "NFS: Add to list failed!\n"); | 186 | else |
171 | BUG(); | 187 | schedule(); |
172 | } | 188 | return ret; |
173 | #endif | ||
174 | list_for_each_prev(pos, head) { | ||
175 | struct nfs_page *p = nfs_list_entry(pos); | ||
176 | if (p->wb_index < req->wb_index) | ||
177 | break; | ||
178 | } | ||
179 | list_add(&req->wb_list, pos); | ||
180 | req->wb_list_head = head; | ||
181 | } | 189 | } |
182 | 190 | ||
183 | /** | 191 | /** |
@@ -190,12 +198,22 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head) | |||
190 | int | 198 | int |
191 | nfs_wait_on_request(struct nfs_page *req) | 199 | nfs_wait_on_request(struct nfs_page *req) |
192 | { | 200 | { |
193 | struct inode *inode = req->wb_context->dentry->d_inode; | 201 | struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->dentry->d_inode); |
194 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | 202 | sigset_t oldmask; |
195 | 203 | int ret = 0; | |
196 | if (!NFS_WBACK_BUSY(req)) | 204 | |
197 | return 0; | 205 | if (!test_bit(PG_BUSY, &req->wb_flags)) |
198 | return nfs_wait_event(clnt, req->wb_context->waitq, !NFS_WBACK_BUSY(req)); | 206 | goto out; |
207 | /* | ||
208 | * Note: the call to rpc_clnt_sigmask() suffices to ensure that we | ||
209 | * are not interrupted if intr flag is not set | ||
210 | */ | ||
211 | rpc_clnt_sigmask(clnt, &oldmask); | ||
212 | ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY, | ||
213 | nfs_wait_bit_interruptible, TASK_INTERRUPTIBLE); | ||
214 | rpc_clnt_sigunmask(clnt, &oldmask); | ||
215 | out: | ||
216 | return ret; | ||
199 | } | 217 | } |
200 | 218 | ||
201 | /** | 219 | /** |
@@ -243,6 +261,62 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst, | |||
243 | return npages; | 261 | return npages; |
244 | } | 262 | } |
245 | 263 | ||
264 | #define NFS_SCAN_MAXENTRIES 16 | ||
265 | /** | ||
266 | * nfs_scan_lock_dirty - Scan the radix tree for dirty requests | ||
267 | * @nfsi: NFS inode | ||
268 | * @dst: Destination list | ||
269 | * @idx_start: lower bound of page->index to scan | ||
270 | * @npages: idx_start + npages sets the upper bound to scan. | ||
271 | * | ||
272 | * Moves elements from one of the inode request lists. | ||
273 | * If the number of requests is set to 0, the entire address_space | ||
274 | * starting at index idx_start, is scanned. | ||
275 | * The requests are *not* checked to ensure that they form a contiguous set. | ||
276 | * You must be holding the inode's req_lock when calling this function | ||
277 | */ | ||
278 | int | ||
279 | nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, | ||
280 | unsigned long idx_start, unsigned int npages) | ||
281 | { | ||
282 | struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; | ||
283 | struct nfs_page *req; | ||
284 | unsigned long idx_end; | ||
285 | int found, i; | ||
286 | int res; | ||
287 | |||
288 | res = 0; | ||
289 | if (npages == 0) | ||
290 | idx_end = ~0; | ||
291 | else | ||
292 | idx_end = idx_start + npages - 1; | ||
293 | |||
294 | for (;;) { | ||
295 | found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, | ||
296 | (void **)&pgvec[0], idx_start, NFS_SCAN_MAXENTRIES, | ||
297 | NFS_PAGE_TAG_DIRTY); | ||
298 | if (found <= 0) | ||
299 | break; | ||
300 | for (i = 0; i < found; i++) { | ||
301 | req = pgvec[i]; | ||
302 | if (req->wb_index > idx_end) | ||
303 | goto out; | ||
304 | |||
305 | idx_start = req->wb_index + 1; | ||
306 | |||
307 | if (nfs_set_page_writeback_locked(req)) { | ||
308 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | ||
309 | req->wb_index, NFS_PAGE_TAG_DIRTY); | ||
310 | nfs_list_remove_request(req); | ||
311 | nfs_list_add_request(req, dst); | ||
312 | res++; | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | out: | ||
317 | return res; | ||
318 | } | ||
319 | |||
246 | /** | 320 | /** |
247 | * nfs_scan_list - Scan a list for matching requests | 321 | * nfs_scan_list - Scan a list for matching requests |
248 | * @head: One of the NFS inode request lists | 322 | * @head: One of the NFS inode request lists |
@@ -280,7 +354,7 @@ nfs_scan_list(struct list_head *head, struct list_head *dst, | |||
280 | if (req->wb_index > idx_end) | 354 | if (req->wb_index > idx_end) |
281 | break; | 355 | break; |
282 | 356 | ||
283 | if (!nfs_lock_request(req)) | 357 | if (!nfs_set_page_writeback_locked(req)) |
284 | continue; | 358 | continue; |
285 | nfs_list_remove_request(req); | 359 | nfs_list_remove_request(req); |
286 | nfs_list_add_request(req, dst); | 360 | nfs_list_add_request(req, dst); |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index d31b4d6e5a5e..cedf636bcf3c 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -622,6 +622,7 @@ struct nfs_rpc_ops nfs_v2_clientops = { | |||
622 | .version = 2, /* protocol version */ | 622 | .version = 2, /* protocol version */ |
623 | .dentry_ops = &nfs_dentry_operations, | 623 | .dentry_ops = &nfs_dentry_operations, |
624 | .dir_inode_ops = &nfs_dir_inode_operations, | 624 | .dir_inode_ops = &nfs_dir_inode_operations, |
625 | .file_inode_ops = &nfs_file_inode_operations, | ||
625 | .getroot = nfs_proc_get_root, | 626 | .getroot = nfs_proc_get_root, |
626 | .getattr = nfs_proc_getattr, | 627 | .getattr = nfs_proc_getattr, |
627 | .setattr = nfs_proc_setattr, | 628 | .setattr = nfs_proc_setattr, |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index a0042fb58634..6f866b8aa2d5 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -173,7 +173,6 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
173 | if (len < PAGE_CACHE_SIZE) | 173 | if (len < PAGE_CACHE_SIZE) |
174 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 174 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
175 | 175 | ||
176 | nfs_lock_request(new); | ||
177 | nfs_list_add_request(new, &one_request); | 176 | nfs_list_add_request(new, &one_request); |
178 | nfs_pagein_one(&one_request, inode); | 177 | nfs_pagein_one(&one_request, inode); |
179 | return 0; | 178 | return 0; |
@@ -185,7 +184,6 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
185 | 184 | ||
186 | nfs_clear_request(req); | 185 | nfs_clear_request(req); |
187 | nfs_release_request(req); | 186 | nfs_release_request(req); |
188 | nfs_unlock_request(req); | ||
189 | 187 | ||
190 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", | 188 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", |
191 | req->wb_context->dentry->d_inode->i_sb->s_id, | 189 | req->wb_context->dentry->d_inode->i_sb->s_id, |
@@ -553,7 +551,6 @@ readpage_async_filler(void *data, struct page *page) | |||
553 | } | 551 | } |
554 | if (len < PAGE_CACHE_SIZE) | 552 | if (len < PAGE_CACHE_SIZE) |
555 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 553 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
556 | nfs_lock_request(new); | ||
557 | nfs_list_add_request(new, desc->head); | 554 | nfs_list_add_request(new, desc->head); |
558 | return 0; | 555 | return 0; |
559 | } | 556 | } |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 6f7a4af3bc46..5130eda231d7 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -220,7 +220,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
220 | ClearPageError(page); | 220 | ClearPageError(page); |
221 | 221 | ||
222 | io_error: | 222 | io_error: |
223 | nfs_end_data_update_defer(inode); | 223 | nfs_end_data_update(inode); |
224 | nfs_writedata_free(wdata); | 224 | nfs_writedata_free(wdata); |
225 | return written ? written : result; | 225 | return written ? written : result; |
226 | } | 226 | } |
@@ -352,7 +352,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
352 | if (err < 0) | 352 | if (err < 0) |
353 | goto out; | 353 | goto out; |
354 | } | 354 | } |
355 | err = nfs_commit_inode(inode, 0, 0, wb_priority(wbc)); | 355 | err = nfs_commit_inode(inode, wb_priority(wbc)); |
356 | if (err > 0) { | 356 | if (err > 0) { |
357 | wbc->nr_to_write -= err; | 357 | wbc->nr_to_write -= err; |
358 | err = 0; | 358 | err = 0; |
@@ -401,7 +401,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
401 | nfsi->npages--; | 401 | nfsi->npages--; |
402 | if (!nfsi->npages) { | 402 | if (!nfsi->npages) { |
403 | spin_unlock(&nfsi->req_lock); | 403 | spin_unlock(&nfsi->req_lock); |
404 | nfs_end_data_update_defer(inode); | 404 | nfs_end_data_update(inode); |
405 | iput(inode); | 405 | iput(inode); |
406 | } else | 406 | } else |
407 | spin_unlock(&nfsi->req_lock); | 407 | spin_unlock(&nfsi->req_lock); |
@@ -446,6 +446,8 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
446 | struct nfs_inode *nfsi = NFS_I(inode); | 446 | struct nfs_inode *nfsi = NFS_I(inode); |
447 | 447 | ||
448 | spin_lock(&nfsi->req_lock); | 448 | spin_lock(&nfsi->req_lock); |
449 | radix_tree_tag_set(&nfsi->nfs_page_tree, | ||
450 | req->wb_index, NFS_PAGE_TAG_DIRTY); | ||
449 | nfs_list_add_request(req, &nfsi->dirty); | 451 | nfs_list_add_request(req, &nfsi->dirty); |
450 | nfsi->ndirty++; | 452 | nfsi->ndirty++; |
451 | spin_unlock(&nfsi->req_lock); | 453 | spin_unlock(&nfsi->req_lock); |
@@ -503,13 +505,12 @@ nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int | |||
503 | 505 | ||
504 | spin_lock(&nfsi->req_lock); | 506 | spin_lock(&nfsi->req_lock); |
505 | next = idx_start; | 507 | next = idx_start; |
506 | while (radix_tree_gang_lookup(&nfsi->nfs_page_tree, (void **)&req, next, 1)) { | 508 | while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { |
507 | if (req->wb_index > idx_end) | 509 | if (req->wb_index > idx_end) |
508 | break; | 510 | break; |
509 | 511 | ||
510 | next = req->wb_index + 1; | 512 | next = req->wb_index + 1; |
511 | if (!NFS_WBACK_BUSY(req)) | 513 | BUG_ON(!NFS_WBACK_BUSY(req)); |
512 | continue; | ||
513 | 514 | ||
514 | atomic_inc(&req->wb_count); | 515 | atomic_inc(&req->wb_count); |
515 | spin_unlock(&nfsi->req_lock); | 516 | spin_unlock(&nfsi->req_lock); |
@@ -538,12 +539,15 @@ static int | |||
538 | nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | 539 | nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) |
539 | { | 540 | { |
540 | struct nfs_inode *nfsi = NFS_I(inode); | 541 | struct nfs_inode *nfsi = NFS_I(inode); |
541 | int res; | 542 | int res = 0; |
542 | res = nfs_scan_list(&nfsi->dirty, dst, idx_start, npages); | 543 | |
543 | nfsi->ndirty -= res; | 544 | if (nfsi->ndirty != 0) { |
544 | sub_page_state(nr_dirty,res); | 545 | res = nfs_scan_lock_dirty(nfsi, dst, idx_start, npages); |
545 | if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) | 546 | nfsi->ndirty -= res; |
546 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); | 547 | sub_page_state(nr_dirty,res); |
548 | if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) | ||
549 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); | ||
550 | } | ||
547 | return res; | 551 | return res; |
548 | } | 552 | } |
549 | 553 | ||
@@ -562,11 +566,14 @@ static int | |||
562 | nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | 566 | nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) |
563 | { | 567 | { |
564 | struct nfs_inode *nfsi = NFS_I(inode); | 568 | struct nfs_inode *nfsi = NFS_I(inode); |
565 | int res; | 569 | int res = 0; |
566 | res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); | 570 | |
567 | nfsi->ncommit -= res; | 571 | if (nfsi->ncommit != 0) { |
568 | if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) | 572 | res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); |
569 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); | 573 | nfsi->ncommit -= res; |
574 | if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) | ||
575 | printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); | ||
576 | } | ||
570 | return res; | 577 | return res; |
571 | } | 578 | } |
572 | #endif | 579 | #endif |
@@ -750,7 +757,7 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
750 | * is entirely in cache, it may be more efficient to avoid | 757 | * is entirely in cache, it may be more efficient to avoid |
751 | * fragmenting write requests. | 758 | * fragmenting write requests. |
752 | */ | 759 | */ |
753 | if (PageUptodate(page) && inode->i_flock == NULL) { | 760 | if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { |
754 | loff_t end_offs = i_size_read(inode) - 1; | 761 | loff_t end_offs = i_size_read(inode) - 1; |
755 | unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT; | 762 | unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT; |
756 | 763 | ||
@@ -821,7 +828,7 @@ out: | |||
821 | #else | 828 | #else |
822 | nfs_inode_remove_request(req); | 829 | nfs_inode_remove_request(req); |
823 | #endif | 830 | #endif |
824 | nfs_unlock_request(req); | 831 | nfs_clear_page_writeback(req); |
825 | } | 832 | } |
826 | 833 | ||
827 | static inline int flush_task_priority(int how) | 834 | static inline int flush_task_priority(int how) |
@@ -952,7 +959,7 @@ out_bad: | |||
952 | nfs_writedata_free(data); | 959 | nfs_writedata_free(data); |
953 | } | 960 | } |
954 | nfs_mark_request_dirty(req); | 961 | nfs_mark_request_dirty(req); |
955 | nfs_unlock_request(req); | 962 | nfs_clear_page_writeback(req); |
956 | return -ENOMEM; | 963 | return -ENOMEM; |
957 | } | 964 | } |
958 | 965 | ||
@@ -1002,7 +1009,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | |||
1002 | struct nfs_page *req = nfs_list_entry(head->next); | 1009 | struct nfs_page *req = nfs_list_entry(head->next); |
1003 | nfs_list_remove_request(req); | 1010 | nfs_list_remove_request(req); |
1004 | nfs_mark_request_dirty(req); | 1011 | nfs_mark_request_dirty(req); |
1005 | nfs_unlock_request(req); | 1012 | nfs_clear_page_writeback(req); |
1006 | } | 1013 | } |
1007 | return -ENOMEM; | 1014 | return -ENOMEM; |
1008 | } | 1015 | } |
@@ -1029,7 +1036,7 @@ nfs_flush_list(struct list_head *head, int wpages, int how) | |||
1029 | req = nfs_list_entry(head->next); | 1036 | req = nfs_list_entry(head->next); |
1030 | nfs_list_remove_request(req); | 1037 | nfs_list_remove_request(req); |
1031 | nfs_mark_request_dirty(req); | 1038 | nfs_mark_request_dirty(req); |
1032 | nfs_unlock_request(req); | 1039 | nfs_clear_page_writeback(req); |
1033 | } | 1040 | } |
1034 | return error; | 1041 | return error; |
1035 | } | 1042 | } |
@@ -1121,7 +1128,7 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1121 | nfs_inode_remove_request(req); | 1128 | nfs_inode_remove_request(req); |
1122 | #endif | 1129 | #endif |
1123 | next: | 1130 | next: |
1124 | nfs_unlock_request(req); | 1131 | nfs_clear_page_writeback(req); |
1125 | } | 1132 | } |
1126 | } | 1133 | } |
1127 | 1134 | ||
@@ -1210,36 +1217,24 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1210 | struct nfs_write_data *data, int how) | 1217 | struct nfs_write_data *data, int how) |
1211 | { | 1218 | { |
1212 | struct rpc_task *task = &data->task; | 1219 | struct rpc_task *task = &data->task; |
1213 | struct nfs_page *first, *last; | 1220 | struct nfs_page *first; |
1214 | struct inode *inode; | 1221 | struct inode *inode; |
1215 | loff_t start, end, len; | ||
1216 | 1222 | ||
1217 | /* Set up the RPC argument and reply structs | 1223 | /* Set up the RPC argument and reply structs |
1218 | * NB: take care not to mess about with data->commit et al. */ | 1224 | * NB: take care not to mess about with data->commit et al. */ |
1219 | 1225 | ||
1220 | list_splice_init(head, &data->pages); | 1226 | list_splice_init(head, &data->pages); |
1221 | first = nfs_list_entry(data->pages.next); | 1227 | first = nfs_list_entry(data->pages.next); |
1222 | last = nfs_list_entry(data->pages.prev); | ||
1223 | inode = first->wb_context->dentry->d_inode; | 1228 | inode = first->wb_context->dentry->d_inode; |
1224 | 1229 | ||
1225 | /* | ||
1226 | * Determine the offset range of requests in the COMMIT call. | ||
1227 | * We rely on the fact that data->pages is an ordered list... | ||
1228 | */ | ||
1229 | start = req_offset(first); | ||
1230 | end = req_offset(last) + last->wb_bytes; | ||
1231 | len = end - start; | ||
1232 | /* If 'len' is not a 32-bit quantity, pass '0' in the COMMIT call */ | ||
1233 | if (end >= i_size_read(inode) || len < 0 || len > (~((u32)0) >> 1)) | ||
1234 | len = 0; | ||
1235 | |||
1236 | data->inode = inode; | 1230 | data->inode = inode; |
1237 | data->cred = first->wb_context->cred; | 1231 | data->cred = first->wb_context->cred; |
1238 | 1232 | ||
1239 | data->args.fh = NFS_FH(data->inode); | 1233 | data->args.fh = NFS_FH(data->inode); |
1240 | data->args.offset = start; | 1234 | /* Note: we always request a commit of the entire inode */ |
1241 | data->args.count = len; | 1235 | data->args.offset = 0; |
1242 | data->res.count = len; | 1236 | data->args.count = 0; |
1237 | data->res.count = 0; | ||
1243 | data->res.fattr = &data->fattr; | 1238 | data->res.fattr = &data->fattr; |
1244 | data->res.verf = &data->verf; | 1239 | data->res.verf = &data->verf; |
1245 | 1240 | ||
@@ -1278,7 +1273,7 @@ nfs_commit_list(struct list_head *head, int how) | |||
1278 | req = nfs_list_entry(head->next); | 1273 | req = nfs_list_entry(head->next); |
1279 | nfs_list_remove_request(req); | 1274 | nfs_list_remove_request(req); |
1280 | nfs_mark_request_commit(req); | 1275 | nfs_mark_request_commit(req); |
1281 | nfs_unlock_request(req); | 1276 | nfs_clear_page_writeback(req); |
1282 | } | 1277 | } |
1283 | return -ENOMEM; | 1278 | return -ENOMEM; |
1284 | } | 1279 | } |
@@ -1324,7 +1319,7 @@ nfs_commit_done(struct rpc_task *task) | |||
1324 | dprintk(" mismatch\n"); | 1319 | dprintk(" mismatch\n"); |
1325 | nfs_mark_request_dirty(req); | 1320 | nfs_mark_request_dirty(req); |
1326 | next: | 1321 | next: |
1327 | nfs_unlock_request(req); | 1322 | nfs_clear_page_writeback(req); |
1328 | res++; | 1323 | res++; |
1329 | } | 1324 | } |
1330 | sub_page_state(nr_unstable,res); | 1325 | sub_page_state(nr_unstable,res); |
@@ -1342,16 +1337,23 @@ static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | |||
1342 | spin_lock(&nfsi->req_lock); | 1337 | spin_lock(&nfsi->req_lock); |
1343 | res = nfs_scan_dirty(inode, &head, idx_start, npages); | 1338 | res = nfs_scan_dirty(inode, &head, idx_start, npages); |
1344 | spin_unlock(&nfsi->req_lock); | 1339 | spin_unlock(&nfsi->req_lock); |
1345 | if (res) | 1340 | if (res) { |
1346 | error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how); | 1341 | struct nfs_server *server = NFS_SERVER(inode); |
1342 | |||
1343 | /* For single writes, FLUSH_STABLE is more efficient */ | ||
1344 | if (res == nfsi->npages && nfsi->npages <= server->wpages) { | ||
1345 | if (res > 1 || nfs_list_entry(head.next)->wb_bytes <= server->wsize) | ||
1346 | how |= FLUSH_STABLE; | ||
1347 | } | ||
1348 | error = nfs_flush_list(&head, server->wpages, how); | ||
1349 | } | ||
1347 | if (error < 0) | 1350 | if (error < 0) |
1348 | return error; | 1351 | return error; |
1349 | return res; | 1352 | return res; |
1350 | } | 1353 | } |
1351 | 1354 | ||
1352 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1355 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1353 | int nfs_commit_inode(struct inode *inode, unsigned long idx_start, | 1356 | int nfs_commit_inode(struct inode *inode, int how) |
1354 | unsigned int npages, int how) | ||
1355 | { | 1357 | { |
1356 | struct nfs_inode *nfsi = NFS_I(inode); | 1358 | struct nfs_inode *nfsi = NFS_I(inode); |
1357 | LIST_HEAD(head); | 1359 | LIST_HEAD(head); |
@@ -1359,15 +1361,13 @@ int nfs_commit_inode(struct inode *inode, unsigned long idx_start, | |||
1359 | error = 0; | 1361 | error = 0; |
1360 | 1362 | ||
1361 | spin_lock(&nfsi->req_lock); | 1363 | spin_lock(&nfsi->req_lock); |
1362 | res = nfs_scan_commit(inode, &head, idx_start, npages); | 1364 | res = nfs_scan_commit(inode, &head, 0, 0); |
1365 | spin_unlock(&nfsi->req_lock); | ||
1363 | if (res) { | 1366 | if (res) { |
1364 | res += nfs_scan_commit(inode, &head, 0, 0); | ||
1365 | spin_unlock(&nfsi->req_lock); | ||
1366 | error = nfs_commit_list(&head, how); | 1367 | error = nfs_commit_list(&head, how); |
1367 | } else | 1368 | if (error < 0) |
1368 | spin_unlock(&nfsi->req_lock); | 1369 | return error; |
1369 | if (error < 0) | 1370 | } |
1370 | return error; | ||
1371 | return res; | 1371 | return res; |
1372 | } | 1372 | } |
1373 | #endif | 1373 | #endif |
@@ -1389,7 +1389,7 @@ int nfs_sync_inode(struct inode *inode, unsigned long idx_start, | |||
1389 | error = nfs_flush_inode(inode, idx_start, npages, how); | 1389 | error = nfs_flush_inode(inode, idx_start, npages, how); |
1390 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1390 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1391 | if (error == 0) | 1391 | if (error == 0) |
1392 | error = nfs_commit_inode(inode, idx_start, npages, how); | 1392 | error = nfs_commit_inode(inode, how); |
1393 | #endif | 1393 | #endif |
1394 | } while (error > 0); | 1394 | } while (error > 0); |
1395 | return error; | 1395 | return error; |
diff --git a/fs/nfs_common/Makefile b/fs/nfs_common/Makefile new file mode 100644 index 000000000000..f689ed82af3a --- /dev/null +++ b/fs/nfs_common/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for Linux filesystem routines that are shared by client and server. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o | ||
6 | |||
7 | nfs_acl-objs := nfsacl.o | ||
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c new file mode 100644 index 000000000000..18c58c32e326 --- /dev/null +++ b/fs/nfs_common/nfsacl.c | |||
@@ -0,0 +1,257 @@ | |||
1 | /* | ||
2 | * fs/nfs_common/nfsacl.c | ||
3 | * | ||
4 | * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * The Solaris nfsacl protocol represents some ACLs slightly differently | ||
9 | * than POSIX 1003.1e draft 17 does (and we do): | ||
10 | * | ||
11 | * - Minimal ACLs always have an ACL_MASK entry, so they have | ||
12 | * four instead of three entries. | ||
13 | * - The ACL_MASK entry in such minimal ACLs always has the same | ||
14 | * permissions as the ACL_GROUP_OBJ entry. (In extended ACLs | ||
15 | * the ACL_MASK and ACL_GROUP_OBJ entries may differ.) | ||
16 | * - The identifier fields of the ACL_USER_OBJ and ACL_GROUP_OBJ | ||
17 | * entries contain the identifiers of the owner and owning group. | ||
18 | * (In POSIX ACLs we always set them to ACL_UNDEFINED_ID). | ||
19 | * - ACL entries in the kernel are kept sorted in ascending order | ||
20 | * of (e_tag, e_id). Solaris ACLs are unsorted. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include <linux/sunrpc/xdr.h> | ||
26 | #include <linux/nfsacl.h> | ||
27 | #include <linux/nfs3.h> | ||
28 | #include <linux/sort.h> | ||
29 | |||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | EXPORT_SYMBOL(nfsacl_encode); | ||
33 | EXPORT_SYMBOL(nfsacl_decode); | ||
34 | |||
35 | struct nfsacl_encode_desc { | ||
36 | struct xdr_array2_desc desc; | ||
37 | unsigned int count; | ||
38 | struct posix_acl *acl; | ||
39 | int typeflag; | ||
40 | uid_t uid; | ||
41 | gid_t gid; | ||
42 | }; | ||
43 | |||
44 | static int | ||
45 | xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) | ||
46 | { | ||
47 | struct nfsacl_encode_desc *nfsacl_desc = | ||
48 | (struct nfsacl_encode_desc *) desc; | ||
49 | u32 *p = (u32 *) elem; | ||
50 | |||
51 | if (nfsacl_desc->count < nfsacl_desc->acl->a_count) { | ||
52 | struct posix_acl_entry *entry = | ||
53 | &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; | ||
54 | |||
55 | *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag); | ||
56 | switch(entry->e_tag) { | ||
57 | case ACL_USER_OBJ: | ||
58 | *p++ = htonl(nfsacl_desc->uid); | ||
59 | break; | ||
60 | case ACL_GROUP_OBJ: | ||
61 | *p++ = htonl(nfsacl_desc->gid); | ||
62 | break; | ||
63 | case ACL_USER: | ||
64 | case ACL_GROUP: | ||
65 | *p++ = htonl(entry->e_id); | ||
66 | break; | ||
67 | default: /* Solaris depends on that! */ | ||
68 | *p++ = 0; | ||
69 | break; | ||
70 | } | ||
71 | *p++ = htonl(entry->e_perm & S_IRWXO); | ||
72 | } else { | ||
73 | const struct posix_acl_entry *pa, *pe; | ||
74 | int group_obj_perm = ACL_READ|ACL_WRITE|ACL_EXECUTE; | ||
75 | |||
76 | FOREACH_ACL_ENTRY(pa, nfsacl_desc->acl, pe) { | ||
77 | if (pa->e_tag == ACL_GROUP_OBJ) { | ||
78 | group_obj_perm = pa->e_perm & S_IRWXO; | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | /* fake up ACL_MASK entry */ | ||
83 | *p++ = htonl(ACL_MASK | nfsacl_desc->typeflag); | ||
84 | *p++ = htonl(0); | ||
85 | *p++ = htonl(group_obj_perm); | ||
86 | } | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | unsigned int | ||
92 | nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, | ||
93 | struct posix_acl *acl, int encode_entries, int typeflag) | ||
94 | { | ||
95 | int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0; | ||
96 | struct nfsacl_encode_desc nfsacl_desc = { | ||
97 | .desc = { | ||
98 | .elem_size = 12, | ||
99 | .array_len = encode_entries ? entries : 0, | ||
100 | .xcode = xdr_nfsace_encode, | ||
101 | }, | ||
102 | .acl = acl, | ||
103 | .typeflag = typeflag, | ||
104 | .uid = inode->i_uid, | ||
105 | .gid = inode->i_gid, | ||
106 | }; | ||
107 | int err; | ||
108 | |||
109 | if (entries > NFS_ACL_MAX_ENTRIES || | ||
110 | xdr_encode_word(buf, base, entries)) | ||
111 | return -EINVAL; | ||
112 | err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); | ||
113 | if (!err) | ||
114 | err = 8 + nfsacl_desc.desc.elem_size * | ||
115 | nfsacl_desc.desc.array_len; | ||
116 | return err; | ||
117 | } | ||
118 | |||
119 | struct nfsacl_decode_desc { | ||
120 | struct xdr_array2_desc desc; | ||
121 | unsigned int count; | ||
122 | struct posix_acl *acl; | ||
123 | }; | ||
124 | |||
125 | static int | ||
126 | xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem) | ||
127 | { | ||
128 | struct nfsacl_decode_desc *nfsacl_desc = | ||
129 | (struct nfsacl_decode_desc *) desc; | ||
130 | u32 *p = (u32 *) elem; | ||
131 | struct posix_acl_entry *entry; | ||
132 | |||
133 | if (!nfsacl_desc->acl) { | ||
134 | if (desc->array_len > NFS_ACL_MAX_ENTRIES) | ||
135 | return -EINVAL; | ||
136 | nfsacl_desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL); | ||
137 | if (!nfsacl_desc->acl) | ||
138 | return -ENOMEM; | ||
139 | nfsacl_desc->count = 0; | ||
140 | } | ||
141 | |||
142 | entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; | ||
143 | entry->e_tag = ntohl(*p++) & ~NFS_ACL_DEFAULT; | ||
144 | entry->e_id = ntohl(*p++); | ||
145 | entry->e_perm = ntohl(*p++); | ||
146 | |||
147 | switch(entry->e_tag) { | ||
148 | case ACL_USER_OBJ: | ||
149 | case ACL_USER: | ||
150 | case ACL_GROUP_OBJ: | ||
151 | case ACL_GROUP: | ||
152 | case ACL_OTHER: | ||
153 | if (entry->e_perm & ~S_IRWXO) | ||
154 | return -EINVAL; | ||
155 | break; | ||
156 | case ACL_MASK: | ||
157 | /* Solaris sometimes sets additonal bits in the mask */ | ||
158 | entry->e_perm &= S_IRWXO; | ||
159 | break; | ||
160 | default: | ||
161 | return -EINVAL; | ||
162 | } | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int | ||
168 | cmp_acl_entry(const void *x, const void *y) | ||
169 | { | ||
170 | const struct posix_acl_entry *a = x, *b = y; | ||
171 | |||
172 | if (a->e_tag != b->e_tag) | ||
173 | return a->e_tag - b->e_tag; | ||
174 | else if (a->e_id > b->e_id) | ||
175 | return 1; | ||
176 | else if (a->e_id < b->e_id) | ||
177 | return -1; | ||
178 | else | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL. | ||
184 | */ | ||
185 | static int | ||
186 | posix_acl_from_nfsacl(struct posix_acl *acl) | ||
187 | { | ||
188 | struct posix_acl_entry *pa, *pe, | ||
189 | *group_obj = NULL, *mask = NULL; | ||
190 | |||
191 | if (!acl) | ||
192 | return 0; | ||
193 | |||
194 | sort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry), | ||
195 | cmp_acl_entry, NULL); | ||
196 | |||
197 | /* Clear undefined identifier fields and find the ACL_GROUP_OBJ | ||
198 | and ACL_MASK entries. */ | ||
199 | FOREACH_ACL_ENTRY(pa, acl, pe) { | ||
200 | switch(pa->e_tag) { | ||
201 | case ACL_USER_OBJ: | ||
202 | pa->e_id = ACL_UNDEFINED_ID; | ||
203 | break; | ||
204 | case ACL_GROUP_OBJ: | ||
205 | pa->e_id = ACL_UNDEFINED_ID; | ||
206 | group_obj = pa; | ||
207 | break; | ||
208 | case ACL_MASK: | ||
209 | mask = pa; | ||
210 | /* fall through */ | ||
211 | case ACL_OTHER: | ||
212 | pa->e_id = ACL_UNDEFINED_ID; | ||
213 | break; | ||
214 | } | ||
215 | } | ||
216 | if (acl->a_count == 4 && group_obj && mask && | ||
217 | mask->e_perm == group_obj->e_perm) { | ||
218 | /* remove bogus ACL_MASK entry */ | ||
219 | memmove(mask, mask+1, (3 - (mask - acl->a_entries)) * | ||
220 | sizeof(struct posix_acl_entry)); | ||
221 | acl->a_count = 3; | ||
222 | } | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | unsigned int | ||
227 | nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, | ||
228 | struct posix_acl **pacl) | ||
229 | { | ||
230 | struct nfsacl_decode_desc nfsacl_desc = { | ||
231 | .desc = { | ||
232 | .elem_size = 12, | ||
233 | .xcode = pacl ? xdr_nfsace_decode : NULL, | ||
234 | }, | ||
235 | }; | ||
236 | u32 entries; | ||
237 | int err; | ||
238 | |||
239 | if (xdr_decode_word(buf, base, &entries) || | ||
240 | entries > NFS_ACL_MAX_ENTRIES) | ||
241 | return -EINVAL; | ||
242 | err = xdr_decode_array2(buf, base + 4, &nfsacl_desc.desc); | ||
243 | if (err) | ||
244 | return err; | ||
245 | if (pacl) { | ||
246 | if (entries != nfsacl_desc.desc.array_len || | ||
247 | posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) { | ||
248 | posix_acl_release(nfsacl_desc.acl); | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | *pacl = nfsacl_desc.acl; | ||
252 | } | ||
253 | if (aclcnt) | ||
254 | *aclcnt = entries; | ||
255 | return 8 + nfsacl_desc.desc.elem_size * | ||
256 | nfsacl_desc.desc.array_len; | ||
257 | } | ||
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index b8680a247f8b..ce341dc76d5e 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile | |||
@@ -6,7 +6,9 @@ obj-$(CONFIG_NFSD) += nfsd.o | |||
6 | 6 | ||
7 | nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ | 7 | nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ |
8 | export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o | 8 | export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o |
9 | nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o | ||
9 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o | 10 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o |
11 | nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o | ||
10 | nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ | 12 | nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ |
11 | nfs4acl.o nfs4callback.o | 13 | nfs4acl.o nfs4callback.o nfs4recover.o |
12 | nfsd-objs := $(nfsd-y) | 14 | nfsd-objs := $(nfsd-y) |
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c new file mode 100644 index 000000000000..7cbf0682b2f0 --- /dev/null +++ b/fs/nfsd/nfs2acl.c | |||
@@ -0,0 +1,336 @@ | |||
1 | /* | ||
2 | * linux/fs/nfsd/nfsacl.c | ||
3 | * | ||
4 | * Process version 2 NFSACL requests. | ||
5 | * | ||
6 | * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> | ||
7 | */ | ||
8 | |||
9 | #include <linux/sunrpc/svc.h> | ||
10 | #include <linux/nfs.h> | ||
11 | #include <linux/nfsd/nfsd.h> | ||
12 | #include <linux/nfsd/cache.h> | ||
13 | #include <linux/nfsd/xdr.h> | ||
14 | #include <linux/nfsd/xdr3.h> | ||
15 | #include <linux/posix_acl.h> | ||
16 | #include <linux/nfsacl.h> | ||
17 | |||
18 | #define NFSDDBG_FACILITY NFSDDBG_PROC | ||
19 | #define RETURN_STATUS(st) { resp->status = (st); return (st); } | ||
20 | |||
21 | /* | ||
22 | * NULL call. | ||
23 | */ | ||
24 | static int | ||
25 | nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) | ||
26 | { | ||
27 | return nfs_ok; | ||
28 | } | ||
29 | |||
30 | /* | ||
31 | * Get the Access and/or Default ACL of a file. | ||
32 | */ | ||
33 | static int nfsacld_proc_getacl(struct svc_rqst * rqstp, | ||
34 | struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) | ||
35 | { | ||
36 | svc_fh *fh; | ||
37 | struct posix_acl *acl; | ||
38 | int nfserr = 0; | ||
39 | |||
40 | dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); | ||
41 | |||
42 | fh = fh_copy(&resp->fh, &argp->fh); | ||
43 | if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) | ||
44 | RETURN_STATUS(nfserr_inval); | ||
45 | |||
46 | if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | ||
47 | RETURN_STATUS(nfserr_inval); | ||
48 | resp->mask = argp->mask; | ||
49 | |||
50 | if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { | ||
51 | acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); | ||
52 | if (IS_ERR(acl)) { | ||
53 | int err = PTR_ERR(acl); | ||
54 | |||
55 | if (err == -ENODATA || err == -EOPNOTSUPP) | ||
56 | acl = NULL; | ||
57 | else { | ||
58 | nfserr = nfserrno(err); | ||
59 | goto fail; | ||
60 | } | ||
61 | } | ||
62 | if (acl == NULL) { | ||
63 | /* Solaris returns the inode's minimum ACL. */ | ||
64 | |||
65 | struct inode *inode = fh->fh_dentry->d_inode; | ||
66 | acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||
67 | } | ||
68 | resp->acl_access = acl; | ||
69 | } | ||
70 | if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { | ||
71 | /* Check how Solaris handles requests for the Default ACL | ||
72 | of a non-directory! */ | ||
73 | |||
74 | acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); | ||
75 | if (IS_ERR(acl)) { | ||
76 | int err = PTR_ERR(acl); | ||
77 | |||
78 | if (err == -ENODATA || err == -EOPNOTSUPP) | ||
79 | acl = NULL; | ||
80 | else { | ||
81 | nfserr = nfserrno(err); | ||
82 | goto fail; | ||
83 | } | ||
84 | } | ||
85 | resp->acl_default = acl; | ||
86 | } | ||
87 | |||
88 | /* resp->acl_{access,default} are released in nfssvc_release_getacl. */ | ||
89 | RETURN_STATUS(0); | ||
90 | |||
91 | fail: | ||
92 | posix_acl_release(resp->acl_access); | ||
93 | posix_acl_release(resp->acl_default); | ||
94 | RETURN_STATUS(nfserr); | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * Set the Access and/or Default ACL of a file. | ||
99 | */ | ||
100 | static int nfsacld_proc_setacl(struct svc_rqst * rqstp, | ||
101 | struct nfsd3_setaclargs *argp, | ||
102 | struct nfsd_attrstat *resp) | ||
103 | { | ||
104 | svc_fh *fh; | ||
105 | int nfserr = 0; | ||
106 | |||
107 | dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); | ||
108 | |||
109 | fh = fh_copy(&resp->fh, &argp->fh); | ||
110 | nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); | ||
111 | |||
112 | if (!nfserr) { | ||
113 | nfserr = nfserrno( nfsd_set_posix_acl( | ||
114 | fh, ACL_TYPE_ACCESS, argp->acl_access) ); | ||
115 | } | ||
116 | if (!nfserr) { | ||
117 | nfserr = nfserrno( nfsd_set_posix_acl( | ||
118 | fh, ACL_TYPE_DEFAULT, argp->acl_default) ); | ||
119 | } | ||
120 | |||
121 | /* argp->acl_{access,default} may have been allocated in | ||
122 | nfssvc_decode_setaclargs. */ | ||
123 | posix_acl_release(argp->acl_access); | ||
124 | posix_acl_release(argp->acl_default); | ||
125 | return nfserr; | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * Check file attributes | ||
130 | */ | ||
131 | static int nfsacld_proc_getattr(struct svc_rqst * rqstp, | ||
132 | struct nfsd_fhandle *argp, struct nfsd_attrstat *resp) | ||
133 | { | ||
134 | dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); | ||
135 | |||
136 | fh_copy(&resp->fh, &argp->fh); | ||
137 | return fh_verify(rqstp, &resp->fh, 0, MAY_NOP); | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Check file access | ||
142 | */ | ||
143 | static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, | ||
144 | struct nfsd3_accessres *resp) | ||
145 | { | ||
146 | int nfserr; | ||
147 | |||
148 | dprintk("nfsd: ACCESS(2acl) %s 0x%x\n", | ||
149 | SVCFH_fmt(&argp->fh), | ||
150 | argp->access); | ||
151 | |||
152 | fh_copy(&resp->fh, &argp->fh); | ||
153 | resp->access = argp->access; | ||
154 | nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); | ||
155 | return nfserr; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * XDR decode functions | ||
160 | */ | ||
161 | static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, | ||
162 | struct nfsd3_getaclargs *argp) | ||
163 | { | ||
164 | if (!(p = nfs2svc_decode_fh(p, &argp->fh))) | ||
165 | return 0; | ||
166 | argp->mask = ntohl(*p); p++; | ||
167 | |||
168 | return xdr_argsize_check(rqstp, p); | ||
169 | } | ||
170 | |||
171 | |||
172 | static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, | ||
173 | struct nfsd3_setaclargs *argp) | ||
174 | { | ||
175 | struct kvec *head = rqstp->rq_arg.head; | ||
176 | unsigned int base; | ||
177 | int n; | ||
178 | |||
179 | if (!(p = nfs2svc_decode_fh(p, &argp->fh))) | ||
180 | return 0; | ||
181 | argp->mask = ntohl(*p++); | ||
182 | if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || | ||
183 | !xdr_argsize_check(rqstp, p)) | ||
184 | return 0; | ||
185 | |||
186 | base = (char *)p - (char *)head->iov_base; | ||
187 | n = nfsacl_decode(&rqstp->rq_arg, base, NULL, | ||
188 | (argp->mask & NFS_ACL) ? | ||
189 | &argp->acl_access : NULL); | ||
190 | if (n > 0) | ||
191 | n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, | ||
192 | (argp->mask & NFS_DFACL) ? | ||
193 | &argp->acl_default : NULL); | ||
194 | return (n > 0); | ||
195 | } | ||
196 | |||
197 | static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p, | ||
198 | struct nfsd_fhandle *argp) | ||
199 | { | ||
200 | if (!(p = nfs2svc_decode_fh(p, &argp->fh))) | ||
201 | return 0; | ||
202 | return xdr_argsize_check(rqstp, p); | ||
203 | } | ||
204 | |||
205 | static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, | ||
206 | struct nfsd3_accessargs *argp) | ||
207 | { | ||
208 | if (!(p = nfs2svc_decode_fh(p, &argp->fh))) | ||
209 | return 0; | ||
210 | argp->access = ntohl(*p++); | ||
211 | |||
212 | return xdr_argsize_check(rqstp, p); | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * XDR encode functions | ||
217 | */ | ||
218 | |||
219 | /* GETACL */ | ||
220 | static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, | ||
221 | struct nfsd3_getaclres *resp) | ||
222 | { | ||
223 | struct dentry *dentry = resp->fh.fh_dentry; | ||
224 | struct inode *inode = dentry->d_inode; | ||
225 | int w = nfsacl_size( | ||
226 | (resp->mask & NFS_ACL) ? resp->acl_access : NULL, | ||
227 | (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); | ||
228 | struct kvec *head = rqstp->rq_res.head; | ||
229 | unsigned int base; | ||
230 | int n; | ||
231 | |||
232 | if (dentry == NULL || dentry->d_inode == NULL) | ||
233 | return 0; | ||
234 | inode = dentry->d_inode; | ||
235 | |||
236 | p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); | ||
237 | *p++ = htonl(resp->mask); | ||
238 | if (!xdr_ressize_check(rqstp, p)) | ||
239 | return 0; | ||
240 | base = (char *)p - (char *)head->iov_base; | ||
241 | |||
242 | rqstp->rq_res.page_len = w; | ||
243 | while (w > 0) { | ||
244 | if (!svc_take_res_page(rqstp)) | ||
245 | return 0; | ||
246 | w -= PAGE_SIZE; | ||
247 | } | ||
248 | |||
249 | n = nfsacl_encode(&rqstp->rq_res, base, inode, | ||
250 | resp->acl_access, | ||
251 | resp->mask & NFS_ACL, 0); | ||
252 | if (n > 0) | ||
253 | n = nfsacl_encode(&rqstp->rq_res, base + n, inode, | ||
254 | resp->acl_default, | ||
255 | resp->mask & NFS_DFACL, | ||
256 | NFS_ACL_DEFAULT); | ||
257 | if (n <= 0) | ||
258 | return 0; | ||
259 | return 1; | ||
260 | } | ||
261 | |||
262 | static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p, | ||
263 | struct nfsd_attrstat *resp) | ||
264 | { | ||
265 | p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); | ||
266 | return xdr_ressize_check(rqstp, p); | ||
267 | } | ||
268 | |||
269 | /* ACCESS */ | ||
270 | static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p, | ||
271 | struct nfsd3_accessres *resp) | ||
272 | { | ||
273 | p = nfs2svc_encode_fattr(rqstp, p, &resp->fh); | ||
274 | *p++ = htonl(resp->access); | ||
275 | return xdr_ressize_check(rqstp, p); | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * XDR release functions | ||
280 | */ | ||
281 | static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p, | ||
282 | struct nfsd3_getaclres *resp) | ||
283 | { | ||
284 | fh_put(&resp->fh); | ||
285 | posix_acl_release(resp->acl_access); | ||
286 | posix_acl_release(resp->acl_default); | ||
287 | return 1; | ||
288 | } | ||
289 | |||
290 | static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p, | ||
291 | struct nfsd_fhandle *resp) | ||
292 | { | ||
293 | fh_put(&resp->fh); | ||
294 | return 1; | ||
295 | } | ||
296 | |||
297 | #define nfsaclsvc_decode_voidargs NULL | ||
298 | #define nfsaclsvc_encode_voidres NULL | ||
299 | #define nfsaclsvc_release_void NULL | ||
300 | #define nfsd3_fhandleargs nfsd_fhandle | ||
301 | #define nfsd3_attrstatres nfsd_attrstat | ||
302 | #define nfsd3_voidres nfsd3_voidargs | ||
303 | struct nfsd3_voidargs { int dummy; }; | ||
304 | |||
305 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
306 | { (svc_procfunc) nfsacld_proc_##name, \ | ||
307 | (kxdrproc_t) nfsaclsvc_decode_##argt##args, \ | ||
308 | (kxdrproc_t) nfsaclsvc_encode_##rest##res, \ | ||
309 | (kxdrproc_t) nfsaclsvc_release_##relt, \ | ||
310 | sizeof(struct nfsd3_##argt##args), \ | ||
311 | sizeof(struct nfsd3_##rest##res), \ | ||
312 | 0, \ | ||
313 | cache, \ | ||
314 | respsize, \ | ||
315 | } | ||
316 | |||
317 | #define ST 1 /* status*/ | ||
318 | #define AT 21 /* attributes */ | ||
319 | #define pAT (1+AT) /* post attributes - conditional */ | ||
320 | #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ | ||
321 | |||
322 | static struct svc_procedure nfsd_acl_procedures2[] = { | ||
323 | PROC(null, void, void, void, RC_NOCACHE, ST), | ||
324 | PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), | ||
325 | PROC(setacl, setacl, attrstat, fhandle, RC_NOCACHE, ST+AT), | ||
326 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | ||
327 | PROC(access, access, access, fhandle, RC_NOCACHE, ST+AT+1), | ||
328 | }; | ||
329 | |||
330 | struct svc_version nfsd_acl_version2 = { | ||
331 | .vs_vers = 2, | ||
332 | .vs_nproc = 5, | ||
333 | .vs_proc = nfsd_acl_procedures2, | ||
334 | .vs_dispatch = nfsd_dispatch, | ||
335 | .vs_xdrsize = NFS3_SVC_XDRSIZE, | ||
336 | }; | ||
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c new file mode 100644 index 000000000000..64ba40572fea --- /dev/null +++ b/fs/nfsd/nfs3acl.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * linux/fs/nfsd/nfs3acl.c | ||
3 | * | ||
4 | * Process version 3 NFSACL requests. | ||
5 | * | ||
6 | * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> | ||
7 | */ | ||
8 | |||
9 | #include <linux/sunrpc/svc.h> | ||
10 | #include <linux/nfs3.h> | ||
11 | #include <linux/nfsd/nfsd.h> | ||
12 | #include <linux/nfsd/cache.h> | ||
13 | #include <linux/nfsd/xdr3.h> | ||
14 | #include <linux/posix_acl.h> | ||
15 | #include <linux/nfsacl.h> | ||
16 | |||
17 | #define RETURN_STATUS(st) { resp->status = (st); return (st); } | ||
18 | |||
19 | /* | ||
20 | * NULL call. | ||
21 | */ | ||
22 | static int | ||
23 | nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) | ||
24 | { | ||
25 | return nfs_ok; | ||
26 | } | ||
27 | |||
28 | /* | ||
29 | * Get the Access and/or Default ACL of a file. | ||
30 | */ | ||
31 | static int nfsd3_proc_getacl(struct svc_rqst * rqstp, | ||
32 | struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) | ||
33 | { | ||
34 | svc_fh *fh; | ||
35 | struct posix_acl *acl; | ||
36 | int nfserr = 0; | ||
37 | |||
38 | fh = fh_copy(&resp->fh, &argp->fh); | ||
39 | if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP))) | ||
40 | RETURN_STATUS(nfserr_inval); | ||
41 | |||
42 | if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | ||
43 | RETURN_STATUS(nfserr_inval); | ||
44 | resp->mask = argp->mask; | ||
45 | |||
46 | if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { | ||
47 | acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS); | ||
48 | if (IS_ERR(acl)) { | ||
49 | int err = PTR_ERR(acl); | ||
50 | |||
51 | if (err == -ENODATA || err == -EOPNOTSUPP) | ||
52 | acl = NULL; | ||
53 | else { | ||
54 | nfserr = nfserrno(err); | ||
55 | goto fail; | ||
56 | } | ||
57 | } | ||
58 | if (acl == NULL) { | ||
59 | /* Solaris returns the inode's minimum ACL. */ | ||
60 | |||
61 | struct inode *inode = fh->fh_dentry->d_inode; | ||
62 | acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | ||
63 | } | ||
64 | resp->acl_access = acl; | ||
65 | } | ||
66 | if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { | ||
67 | /* Check how Solaris handles requests for the Default ACL | ||
68 | of a non-directory! */ | ||
69 | |||
70 | acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT); | ||
71 | if (IS_ERR(acl)) { | ||
72 | int err = PTR_ERR(acl); | ||
73 | |||
74 | if (err == -ENODATA || err == -EOPNOTSUPP) | ||
75 | acl = NULL; | ||
76 | else { | ||
77 | nfserr = nfserrno(err); | ||
78 | goto fail; | ||
79 | } | ||
80 | } | ||
81 | resp->acl_default = acl; | ||
82 | } | ||
83 | |||
84 | /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */ | ||
85 | RETURN_STATUS(0); | ||
86 | |||
87 | fail: | ||
88 | posix_acl_release(resp->acl_access); | ||
89 | posix_acl_release(resp->acl_default); | ||
90 | RETURN_STATUS(nfserr); | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Set the Access and/or Default ACL of a file. | ||
95 | */ | ||
96 | static int nfsd3_proc_setacl(struct svc_rqst * rqstp, | ||
97 | struct nfsd3_setaclargs *argp, | ||
98 | struct nfsd3_attrstat *resp) | ||
99 | { | ||
100 | svc_fh *fh; | ||
101 | int nfserr = 0; | ||
102 | |||
103 | fh = fh_copy(&resp->fh, &argp->fh); | ||
104 | nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); | ||
105 | |||
106 | if (!nfserr) { | ||
107 | nfserr = nfserrno( nfsd_set_posix_acl( | ||
108 | fh, ACL_TYPE_ACCESS, argp->acl_access) ); | ||
109 | } | ||
110 | if (!nfserr) { | ||
111 | nfserr = nfserrno( nfsd_set_posix_acl( | ||
112 | fh, ACL_TYPE_DEFAULT, argp->acl_default) ); | ||
113 | } | ||
114 | |||
115 | /* argp->acl_{access,default} may have been allocated in | ||
116 | nfs3svc_decode_setaclargs. */ | ||
117 | posix_acl_release(argp->acl_access); | ||
118 | posix_acl_release(argp->acl_default); | ||
119 | RETURN_STATUS(nfserr); | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * XDR decode functions | ||
124 | */ | ||
125 | static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p, | ||
126 | struct nfsd3_getaclargs *args) | ||
127 | { | ||
128 | if (!(p = nfs3svc_decode_fh(p, &args->fh))) | ||
129 | return 0; | ||
130 | args->mask = ntohl(*p); p++; | ||
131 | |||
132 | return xdr_argsize_check(rqstp, p); | ||
133 | } | ||
134 | |||
135 | |||
136 | static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p, | ||
137 | struct nfsd3_setaclargs *args) | ||
138 | { | ||
139 | struct kvec *head = rqstp->rq_arg.head; | ||
140 | unsigned int base; | ||
141 | int n; | ||
142 | |||
143 | if (!(p = nfs3svc_decode_fh(p, &args->fh))) | ||
144 | return 0; | ||
145 | args->mask = ntohl(*p++); | ||
146 | if (args->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || | ||
147 | !xdr_argsize_check(rqstp, p)) | ||
148 | return 0; | ||
149 | |||
150 | base = (char *)p - (char *)head->iov_base; | ||
151 | n = nfsacl_decode(&rqstp->rq_arg, base, NULL, | ||
152 | (args->mask & NFS_ACL) ? | ||
153 | &args->acl_access : NULL); | ||
154 | if (n > 0) | ||
155 | n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, | ||
156 | (args->mask & NFS_DFACL) ? | ||
157 | &args->acl_default : NULL); | ||
158 | return (n > 0); | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * XDR encode functions | ||
163 | */ | ||
164 | |||
165 | /* GETACL */ | ||
166 | static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p, | ||
167 | struct nfsd3_getaclres *resp) | ||
168 | { | ||
169 | struct dentry *dentry = resp->fh.fh_dentry; | ||
170 | |||
171 | p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); | ||
172 | if (resp->status == 0 && dentry && dentry->d_inode) { | ||
173 | struct inode *inode = dentry->d_inode; | ||
174 | int w = nfsacl_size( | ||
175 | (resp->mask & NFS_ACL) ? resp->acl_access : NULL, | ||
176 | (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); | ||
177 | struct kvec *head = rqstp->rq_res.head; | ||
178 | unsigned int base; | ||
179 | int n; | ||
180 | |||
181 | *p++ = htonl(resp->mask); | ||
182 | if (!xdr_ressize_check(rqstp, p)) | ||
183 | return 0; | ||
184 | base = (char *)p - (char *)head->iov_base; | ||
185 | |||
186 | rqstp->rq_res.page_len = w; | ||
187 | while (w > 0) { | ||
188 | if (!svc_take_res_page(rqstp)) | ||
189 | return 0; | ||
190 | w -= PAGE_SIZE; | ||
191 | } | ||
192 | |||
193 | n = nfsacl_encode(&rqstp->rq_res, base, inode, | ||
194 | resp->acl_access, | ||
195 | resp->mask & NFS_ACL, 0); | ||
196 | if (n > 0) | ||
197 | n = nfsacl_encode(&rqstp->rq_res, base + n, inode, | ||
198 | resp->acl_default, | ||
199 | resp->mask & NFS_DFACL, | ||
200 | NFS_ACL_DEFAULT); | ||
201 | if (n <= 0) | ||
202 | return 0; | ||
203 | } else | ||
204 | if (!xdr_ressize_check(rqstp, p)) | ||
205 | return 0; | ||
206 | |||
207 | return 1; | ||
208 | } | ||
209 | |||
210 | /* SETACL */ | ||
211 | static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p, | ||
212 | struct nfsd3_attrstat *resp) | ||
213 | { | ||
214 | p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); | ||
215 | |||
216 | return xdr_ressize_check(rqstp, p); | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * XDR release functions | ||
221 | */ | ||
222 | static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p, | ||
223 | struct nfsd3_getaclres *resp) | ||
224 | { | ||
225 | fh_put(&resp->fh); | ||
226 | posix_acl_release(resp->acl_access); | ||
227 | posix_acl_release(resp->acl_default); | ||
228 | return 1; | ||
229 | } | ||
230 | |||
231 | #define nfs3svc_decode_voidargs NULL | ||
232 | #define nfs3svc_release_void NULL | ||
233 | #define nfsd3_setaclres nfsd3_attrstat | ||
234 | #define nfsd3_voidres nfsd3_voidargs | ||
235 | struct nfsd3_voidargs { int dummy; }; | ||
236 | |||
237 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
238 | { (svc_procfunc) nfsd3_proc_##name, \ | ||
239 | (kxdrproc_t) nfs3svc_decode_##argt##args, \ | ||
240 | (kxdrproc_t) nfs3svc_encode_##rest##res, \ | ||
241 | (kxdrproc_t) nfs3svc_release_##relt, \ | ||
242 | sizeof(struct nfsd3_##argt##args), \ | ||
243 | sizeof(struct nfsd3_##rest##res), \ | ||
244 | 0, \ | ||
245 | cache, \ | ||
246 | respsize, \ | ||
247 | } | ||
248 | |||
249 | #define ST 1 /* status*/ | ||
250 | #define AT 21 /* attributes */ | ||
251 | #define pAT (1+AT) /* post attributes - conditional */ | ||
252 | #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ | ||
253 | |||
254 | static struct svc_procedure nfsd_acl_procedures3[] = { | ||
255 | PROC(null, void, void, void, RC_NOCACHE, ST), | ||
256 | PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), | ||
257 | PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT), | ||
258 | }; | ||
259 | |||
260 | struct svc_version nfsd_acl_version3 = { | ||
261 | .vs_vers = 3, | ||
262 | .vs_nproc = 3, | ||
263 | .vs_proc = nfsd_acl_procedures3, | ||
264 | .vs_dispatch = nfsd_dispatch, | ||
265 | .vs_xdrsize = NFS3_SVC_XDRSIZE, | ||
266 | }; | ||
267 | |||
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 11f806835c5a..e0e134d6baba 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -71,6 +71,12 @@ decode_fh(u32 *p, struct svc_fh *fhp) | |||
71 | return p + XDR_QUADLEN(size); | 71 | return p + XDR_QUADLEN(size); |
72 | } | 72 | } |
73 | 73 | ||
74 | /* Helper function for NFSv3 ACL code */ | ||
75 | u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp) | ||
76 | { | ||
77 | return decode_fh(p, fhp); | ||
78 | } | ||
79 | |||
74 | static inline u32 * | 80 | static inline u32 * |
75 | encode_fh(u32 *p, struct svc_fh *fhp) | 81 | encode_fh(u32 *p, struct svc_fh *fhp) |
76 | { | 82 | { |
@@ -233,6 +239,13 @@ encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) | |||
233 | return p; | 239 | return p; |
234 | } | 240 | } |
235 | 241 | ||
242 | /* Helper for NFSv3 ACLs */ | ||
243 | u32 * | ||
244 | nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) | ||
245 | { | ||
246 | return encode_post_op_attr(rqstp, p, fhp); | ||
247 | } | ||
248 | |||
236 | /* | 249 | /* |
237 | * Enocde weak cache consistency data | 250 | * Enocde weak cache consistency data |
238 | */ | 251 | */ |
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 11ebf6c4aa54..4a2105552ac4 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
@@ -125,7 +125,7 @@ static short ace2type(struct nfs4_ace *); | |||
125 | static int _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int); | 125 | static int _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int); |
126 | static struct posix_acl *_nfsv4_to_posix_one(struct nfs4_acl *, unsigned int); | 126 | static struct posix_acl *_nfsv4_to_posix_one(struct nfs4_acl *, unsigned int); |
127 | int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); | 127 | int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); |
128 | int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *); | 128 | static int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *); |
129 | 129 | ||
130 | struct nfs4_acl * | 130 | struct nfs4_acl * |
131 | nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, | 131 | nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, |
@@ -775,7 +775,7 @@ out_err: | |||
775 | return pacl; | 775 | return pacl; |
776 | } | 776 | } |
777 | 777 | ||
778 | int | 778 | static int |
779 | nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl) | 779 | nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl) |
780 | { | 780 | { |
781 | struct list_head *h, *n; | 781 | struct list_head *h, *n; |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 1a55dfcb74bc..583c0710e45e 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -54,7 +54,6 @@ | |||
54 | 54 | ||
55 | /* declarations */ | 55 | /* declarations */ |
56 | static void nfs4_cb_null(struct rpc_task *task); | 56 | static void nfs4_cb_null(struct rpc_task *task); |
57 | extern spinlock_t recall_lock; | ||
58 | 57 | ||
59 | /* Index of predefined Linux callback client operations */ | 58 | /* Index of predefined Linux callback client operations */ |
60 | 59 | ||
@@ -329,12 +328,12 @@ out: | |||
329 | .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \ | 328 | .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \ |
330 | } | 329 | } |
331 | 330 | ||
332 | struct rpc_procinfo nfs4_cb_procedures[] = { | 331 | static struct rpc_procinfo nfs4_cb_procedures[] = { |
333 | PROC(CB_NULL, NULL, enc_cb_null, dec_cb_null), | 332 | PROC(CB_NULL, NULL, enc_cb_null, dec_cb_null), |
334 | PROC(CB_RECALL, COMPOUND, enc_cb_recall, dec_cb_recall), | 333 | PROC(CB_RECALL, COMPOUND, enc_cb_recall, dec_cb_recall), |
335 | }; | 334 | }; |
336 | 335 | ||
337 | struct rpc_version nfs_cb_version4 = { | 336 | static struct rpc_version nfs_cb_version4 = { |
338 | .number = 1, | 337 | .number = 1, |
339 | .nrprocs = sizeof(nfs4_cb_procedures)/sizeof(nfs4_cb_procedures[0]), | 338 | .nrprocs = sizeof(nfs4_cb_procedures)/sizeof(nfs4_cb_procedures[0]), |
340 | .procs = nfs4_cb_procedures | 339 | .procs = nfs4_cb_procedures |
@@ -348,7 +347,7 @@ static struct rpc_version * nfs_cb_version[] = { | |||
348 | /* | 347 | /* |
349 | * Use the SETCLIENTID credential | 348 | * Use the SETCLIENTID credential |
350 | */ | 349 | */ |
351 | struct rpc_cred * | 350 | static struct rpc_cred * |
352 | nfsd4_lookupcred(struct nfs4_client *clp, int taskflags) | 351 | nfsd4_lookupcred(struct nfs4_client *clp, int taskflags) |
353 | { | 352 | { |
354 | struct auth_cred acred; | 353 | struct auth_cred acred; |
@@ -387,9 +386,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
387 | char hostname[32]; | 386 | char hostname[32]; |
388 | int status; | 387 | int status; |
389 | 388 | ||
390 | dprintk("NFSD: probe_callback. cb_parsed %d cb_set %d\n", | 389 | if (atomic_read(&cb->cb_set)) |
391 | cb->cb_parsed, atomic_read(&cb->cb_set)); | ||
392 | if (!cb->cb_parsed || atomic_read(&cb->cb_set)) | ||
393 | return; | 390 | return; |
394 | 391 | ||
395 | /* Initialize address */ | 392 | /* Initialize address */ |
@@ -427,10 +424,10 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
427 | * XXX AUTH_UNIX only - need AUTH_GSS.... | 424 | * XXX AUTH_UNIX only - need AUTH_GSS.... |
428 | */ | 425 | */ |
429 | sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr)); | 426 | sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr)); |
430 | clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX); | 427 | clnt = rpc_new_client(xprt, hostname, program, 1, RPC_AUTH_UNIX); |
431 | if (IS_ERR(clnt)) { | 428 | if (IS_ERR(clnt)) { |
432 | dprintk("NFSD: couldn't create callback client\n"); | 429 | dprintk("NFSD: couldn't create callback client\n"); |
433 | goto out_xprt; | 430 | goto out_err; |
434 | } | 431 | } |
435 | clnt->cl_intr = 0; | 432 | clnt->cl_intr = 0; |
436 | clnt->cl_softrtry = 1; | 433 | clnt->cl_softrtry = 1; |
@@ -465,8 +462,6 @@ out_rpciod: | |||
465 | out_clnt: | 462 | out_clnt: |
466 | rpc_shutdown_client(clnt); | 463 | rpc_shutdown_client(clnt); |
467 | goto out_err; | 464 | goto out_err; |
468 | out_xprt: | ||
469 | xprt_destroy(xprt); | ||
470 | out_err: | 465 | out_err: |
471 | dprintk("NFSD: warning: no callback path to client %.*s\n", | 466 | dprintk("NFSD: warning: no callback path to client %.*s\n", |
472 | (int)clp->cl_name.len, clp->cl_name.data); | 467 | (int)clp->cl_name.len, clp->cl_name.data); |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 4ba540841cf6..5605a26efc57 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
@@ -104,7 +104,7 @@ ent_update(struct ent *new, struct ent *itm) | |||
104 | ent_init(new, itm); | 104 | ent_init(new, itm); |
105 | } | 105 | } |
106 | 106 | ||
107 | void | 107 | static void |
108 | ent_put(struct cache_head *ch, struct cache_detail *cd) | 108 | ent_put(struct cache_head *ch, struct cache_detail *cd) |
109 | { | 109 | { |
110 | if (cache_put(ch, cd)) { | 110 | if (cache_put(ch, cd)) { |
@@ -186,7 +186,7 @@ warn_no_idmapd(struct cache_detail *detail) | |||
186 | static int idtoname_parse(struct cache_detail *, char *, int); | 186 | static int idtoname_parse(struct cache_detail *, char *, int); |
187 | static struct ent *idtoname_lookup(struct ent *, int); | 187 | static struct ent *idtoname_lookup(struct ent *, int); |
188 | 188 | ||
189 | struct cache_detail idtoname_cache = { | 189 | static struct cache_detail idtoname_cache = { |
190 | .hash_size = ENT_HASHMAX, | 190 | .hash_size = ENT_HASHMAX, |
191 | .hash_table = idtoname_table, | 191 | .hash_table = idtoname_table, |
192 | .name = "nfs4.idtoname", | 192 | .name = "nfs4.idtoname", |
@@ -277,7 +277,7 @@ nametoid_hash(struct ent *ent) | |||
277 | return hash_str(ent->name, ENT_HASHBITS); | 277 | return hash_str(ent->name, ENT_HASHBITS); |
278 | } | 278 | } |
279 | 279 | ||
280 | void | 280 | static void |
281 | nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, | 281 | nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, |
282 | int *blen) | 282 | int *blen) |
283 | { | 283 | { |
@@ -317,9 +317,9 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) | |||
317 | } | 317 | } |
318 | 318 | ||
319 | static struct ent *nametoid_lookup(struct ent *, int); | 319 | static struct ent *nametoid_lookup(struct ent *, int); |
320 | int nametoid_parse(struct cache_detail *, char *, int); | 320 | static int nametoid_parse(struct cache_detail *, char *, int); |
321 | 321 | ||
322 | struct cache_detail nametoid_cache = { | 322 | static struct cache_detail nametoid_cache = { |
323 | .hash_size = ENT_HASHMAX, | 323 | .hash_size = ENT_HASHMAX, |
324 | .hash_table = nametoid_table, | 324 | .hash_table = nametoid_table, |
325 | .name = "nfs4.nametoid", | 325 | .name = "nfs4.nametoid", |
@@ -330,7 +330,7 @@ struct cache_detail nametoid_cache = { | |||
330 | .warn_no_listener = warn_no_idmapd, | 330 | .warn_no_listener = warn_no_idmapd, |
331 | }; | 331 | }; |
332 | 332 | ||
333 | int | 333 | static int |
334 | nametoid_parse(struct cache_detail *cd, char *buf, int buflen) | 334 | nametoid_parse(struct cache_detail *cd, char *buf, int buflen) |
335 | { | 335 | { |
336 | struct ent ent, *res; | 336 | struct ent ent, *res; |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index e8158741e8b5..d71f14517b9c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/param.h> | 45 | #include <linux/param.h> |
46 | #include <linux/major.h> | 46 | #include <linux/major.h> |
47 | #include <linux/slab.h> | 47 | #include <linux/slab.h> |
48 | #include <linux/file.h> | ||
48 | 49 | ||
49 | #include <linux/sunrpc/svc.h> | 50 | #include <linux/sunrpc/svc.h> |
50 | #include <linux/nfsd/nfsd.h> | 51 | #include <linux/nfsd/nfsd.h> |
@@ -198,6 +199,11 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
198 | if (status) | 199 | if (status) |
199 | goto out; | 200 | goto out; |
200 | switch (open->op_claim_type) { | 201 | switch (open->op_claim_type) { |
202 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | ||
203 | status = nfserr_inval; | ||
204 | if (open->op_create) | ||
205 | goto out; | ||
206 | /* fall through */ | ||
201 | case NFS4_OPEN_CLAIM_NULL: | 207 | case NFS4_OPEN_CLAIM_NULL: |
202 | /* | 208 | /* |
203 | * (1) set CURRENT_FH to the file being opened, | 209 | * (1) set CURRENT_FH to the file being opened, |
@@ -220,7 +226,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
220 | if (status) | 226 | if (status) |
221 | goto out; | 227 | goto out; |
222 | break; | 228 | break; |
223 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | ||
224 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: | 229 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: |
225 | printk("NFSD: unsupported OPEN claim type %d\n", | 230 | printk("NFSD: unsupported OPEN claim type %d\n", |
226 | open->op_claim_type); | 231 | open->op_claim_type); |
@@ -473,26 +478,27 @@ static inline int | |||
473 | nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) | 478 | nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) |
474 | { | 479 | { |
475 | int status; | 480 | int status; |
476 | struct file *filp = NULL; | ||
477 | 481 | ||
478 | /* no need to check permission - this will be done in nfsd_read() */ | 482 | /* no need to check permission - this will be done in nfsd_read() */ |
479 | 483 | ||
484 | read->rd_filp = NULL; | ||
480 | if (read->rd_offset >= OFFSET_MAX) | 485 | if (read->rd_offset >= OFFSET_MAX) |
481 | return nfserr_inval; | 486 | return nfserr_inval; |
482 | 487 | ||
483 | nfs4_lock_state(); | 488 | nfs4_lock_state(); |
484 | /* check stateid */ | 489 | /* check stateid */ |
485 | if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, | 490 | if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, |
486 | CHECK_FH | RD_STATE, &filp))) { | 491 | CHECK_FH | RD_STATE, &read->rd_filp))) { |
487 | dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); | 492 | dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); |
488 | goto out; | 493 | goto out; |
489 | } | 494 | } |
495 | if (read->rd_filp) | ||
496 | get_file(read->rd_filp); | ||
490 | status = nfs_ok; | 497 | status = nfs_ok; |
491 | out: | 498 | out: |
492 | nfs4_unlock_state(); | 499 | nfs4_unlock_state(); |
493 | read->rd_rqstp = rqstp; | 500 | read->rd_rqstp = rqstp; |
494 | read->rd_fhp = current_fh; | 501 | read->rd_fhp = current_fh; |
495 | read->rd_filp = filp; | ||
496 | return status; | 502 | return status; |
497 | } | 503 | } |
498 | 504 | ||
@@ -532,6 +538,8 @@ nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_rem | |||
532 | { | 538 | { |
533 | int status; | 539 | int status; |
534 | 540 | ||
541 | if (nfs4_in_grace()) | ||
542 | return nfserr_grace; | ||
535 | status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen); | 543 | status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen); |
536 | if (status == nfserr_symlink) | 544 | if (status == nfserr_symlink) |
537 | return nfserr_notdir; | 545 | return nfserr_notdir; |
@@ -550,6 +558,9 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, | |||
550 | 558 | ||
551 | if (!save_fh->fh_dentry) | 559 | if (!save_fh->fh_dentry) |
552 | return status; | 560 | return status; |
561 | if (nfs4_in_grace() && !(save_fh->fh_export->ex_flags | ||
562 | & NFSEXP_NOSUBTREECHECK)) | ||
563 | return nfserr_grace; | ||
553 | status = nfsd_rename(rqstp, save_fh, rename->rn_sname, | 564 | status = nfsd_rename(rqstp, save_fh, rename->rn_sname, |
554 | rename->rn_snamelen, current_fh, | 565 | rename->rn_snamelen, current_fh, |
555 | rename->rn_tname, rename->rn_tnamelen); | 566 | rename->rn_tname, rename->rn_tnamelen); |
@@ -624,6 +635,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
624 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); | 635 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); |
625 | goto out; | 636 | goto out; |
626 | } | 637 | } |
638 | if (filp) | ||
639 | get_file(filp); | ||
627 | nfs4_unlock_state(); | 640 | nfs4_unlock_state(); |
628 | 641 | ||
629 | write->wr_bytes_written = write->wr_buflen; | 642 | write->wr_bytes_written = write->wr_buflen; |
@@ -635,6 +648,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
635 | status = nfsd_write(rqstp, current_fh, filp, write->wr_offset, | 648 | status = nfsd_write(rqstp, current_fh, filp, write->wr_offset, |
636 | write->wr_vec, write->wr_vlen, write->wr_buflen, | 649 | write->wr_vec, write->wr_vlen, write->wr_buflen, |
637 | &write->wr_how_written); | 650 | &write->wr_how_written); |
651 | if (filp) | ||
652 | fput(filp); | ||
638 | 653 | ||
639 | if (status == nfserr_symlink) | 654 | if (status == nfserr_symlink) |
640 | status = nfserr_inval; | 655 | status = nfserr_inval; |
@@ -923,6 +938,9 @@ encode_op: | |||
923 | nfs4_put_stateowner(replay_owner); | 938 | nfs4_put_stateowner(replay_owner); |
924 | replay_owner = NULL; | 939 | replay_owner = NULL; |
925 | } | 940 | } |
941 | /* XXX Ugh, we need to get rid of this kind of special case: */ | ||
942 | if (op->opnum == OP_READ && op->u.read.rd_filp) | ||
943 | fput(op->u.read.rd_filp); | ||
926 | } | 944 | } |
927 | 945 | ||
928 | out: | 946 | out: |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c new file mode 100644 index 000000000000..095f1740f3ae --- /dev/null +++ b/fs/nfsd/nfs4recover.c | |||
@@ -0,0 +1,431 @@ | |||
1 | /* | ||
2 | * linux/fs/nfsd/nfs4recover.c | ||
3 | * | ||
4 | * Copyright (c) 2004 The Regents of the University of Michigan. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Andy Adamson <andros@citi.umich.edu> | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions | ||
11 | * are met: | ||
12 | * | ||
13 | * 1. Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer. | ||
15 | * 2. Redistributions in binary form must reproduce the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer in the | ||
17 | * documentation and/or other materials provided with the distribution. | ||
18 | * 3. Neither the name of the University nor the names of its | ||
19 | * contributors may be used to endorse or promote products derived | ||
20 | * from this software without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
23 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
24 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
25 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
31 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | |||
37 | #include <linux/sunrpc/svc.h> | ||
38 | #include <linux/nfsd/nfsd.h> | ||
39 | #include <linux/nfs4.h> | ||
40 | #include <linux/nfsd/state.h> | ||
41 | #include <linux/nfsd/xdr4.h> | ||
42 | #include <linux/param.h> | ||
43 | #include <linux/file.h> | ||
44 | #include <linux/namei.h> | ||
45 | #include <asm/uaccess.h> | ||
46 | #include <asm/scatterlist.h> | ||
47 | #include <linux/crypto.h> | ||
48 | |||
49 | |||
50 | #define NFSDDBG_FACILITY NFSDDBG_PROC | ||
51 | |||
52 | /* Globals */ | ||
53 | static struct nameidata rec_dir; | ||
54 | static int rec_dir_init = 0; | ||
55 | |||
56 | static void | ||
57 | nfs4_save_user(uid_t *saveuid, gid_t *savegid) | ||
58 | { | ||
59 | *saveuid = current->fsuid; | ||
60 | *savegid = current->fsgid; | ||
61 | current->fsuid = 0; | ||
62 | current->fsgid = 0; | ||
63 | } | ||
64 | |||
65 | static void | ||
66 | nfs4_reset_user(uid_t saveuid, gid_t savegid) | ||
67 | { | ||
68 | current->fsuid = saveuid; | ||
69 | current->fsgid = savegid; | ||
70 | } | ||
71 | |||
72 | static void | ||
73 | md5_to_hex(char *out, char *md5) | ||
74 | { | ||
75 | int i; | ||
76 | |||
77 | for (i=0; i<16; i++) { | ||
78 | unsigned char c = md5[i]; | ||
79 | |||
80 | *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); | ||
81 | *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); | ||
82 | } | ||
83 | *out = '\0'; | ||
84 | } | ||
85 | |||
86 | int | ||
87 | nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) | ||
88 | { | ||
89 | struct xdr_netobj cksum; | ||
90 | struct crypto_tfm *tfm; | ||
91 | struct scatterlist sg[1]; | ||
92 | int status = nfserr_resource; | ||
93 | |||
94 | dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", | ||
95 | clname->len, clname->data); | ||
96 | tfm = crypto_alloc_tfm("md5", 0); | ||
97 | if (tfm == NULL) | ||
98 | goto out; | ||
99 | cksum.len = crypto_tfm_alg_digestsize(tfm); | ||
100 | cksum.data = kmalloc(cksum.len, GFP_KERNEL); | ||
101 | if (cksum.data == NULL) | ||
102 | goto out; | ||
103 | crypto_digest_init(tfm); | ||
104 | |||
105 | sg[0].page = virt_to_page(clname->data); | ||
106 | sg[0].offset = offset_in_page(clname->data); | ||
107 | sg[0].length = clname->len; | ||
108 | |||
109 | crypto_digest_update(tfm, sg, 1); | ||
110 | crypto_digest_final(tfm, cksum.data); | ||
111 | |||
112 | md5_to_hex(dname, cksum.data); | ||
113 | |||
114 | kfree(cksum.data); | ||
115 | status = nfs_ok; | ||
116 | out: | ||
117 | if (tfm) | ||
118 | crypto_free_tfm(tfm); | ||
119 | return status; | ||
120 | } | ||
121 | |||
122 | static int | ||
123 | nfsd4_rec_fsync(struct dentry *dentry) | ||
124 | { | ||
125 | struct file *filp; | ||
126 | int status = nfs_ok; | ||
127 | |||
128 | dprintk("NFSD: nfs4_fsync_rec_dir\n"); | ||
129 | filp = dentry_open(dget(dentry), mntget(rec_dir.mnt), O_RDWR); | ||
130 | if (IS_ERR(filp)) { | ||
131 | status = PTR_ERR(filp); | ||
132 | goto out; | ||
133 | } | ||
134 | if (filp->f_op && filp->f_op->fsync) | ||
135 | status = filp->f_op->fsync(filp, filp->f_dentry, 0); | ||
136 | fput(filp); | ||
137 | out: | ||
138 | if (status) | ||
139 | printk("nfsd4: unable to sync recovery directory\n"); | ||
140 | return status; | ||
141 | } | ||
142 | |||
143 | int | ||
144 | nfsd4_create_clid_dir(struct nfs4_client *clp) | ||
145 | { | ||
146 | char *dname = clp->cl_recdir; | ||
147 | struct dentry *dentry; | ||
148 | uid_t uid; | ||
149 | gid_t gid; | ||
150 | int status; | ||
151 | |||
152 | dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); | ||
153 | |||
154 | if (!rec_dir_init || clp->cl_firststate) | ||
155 | return 0; | ||
156 | |||
157 | nfs4_save_user(&uid, &gid); | ||
158 | |||
159 | /* lock the parent */ | ||
160 | down(&rec_dir.dentry->d_inode->i_sem); | ||
161 | |||
162 | dentry = lookup_one_len(dname, rec_dir.dentry, HEXDIR_LEN-1); | ||
163 | if (IS_ERR(dentry)) { | ||
164 | status = PTR_ERR(dentry); | ||
165 | goto out_unlock; | ||
166 | } | ||
167 | status = -EEXIST; | ||
168 | if (dentry->d_inode) { | ||
169 | dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n"); | ||
170 | goto out_put; | ||
171 | } | ||
172 | status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU); | ||
173 | out_put: | ||
174 | dput(dentry); | ||
175 | out_unlock: | ||
176 | up(&rec_dir.dentry->d_inode->i_sem); | ||
177 | if (status == 0) { | ||
178 | clp->cl_firststate = 1; | ||
179 | status = nfsd4_rec_fsync(rec_dir.dentry); | ||
180 | } | ||
181 | nfs4_reset_user(uid, gid); | ||
182 | dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status); | ||
183 | return status; | ||
184 | } | ||
185 | |||
186 | typedef int (recdir_func)(struct dentry *, struct dentry *); | ||
187 | |||
188 | struct dentry_list { | ||
189 | struct dentry *dentry; | ||
190 | struct list_head list; | ||
191 | }; | ||
192 | |||
193 | struct dentry_list_arg { | ||
194 | struct list_head dentries; | ||
195 | struct dentry *parent; | ||
196 | }; | ||
197 | |||
198 | static int | ||
199 | nfsd4_build_dentrylist(void *arg, const char *name, int namlen, | ||
200 | loff_t offset, ino_t ino, unsigned int d_type) | ||
201 | { | ||
202 | struct dentry_list_arg *dla = arg; | ||
203 | struct list_head *dentries = &dla->dentries; | ||
204 | struct dentry *parent = dla->parent; | ||
205 | struct dentry *dentry; | ||
206 | struct dentry_list *child; | ||
207 | |||
208 | if (name && isdotent(name, namlen)) | ||
209 | return nfs_ok; | ||
210 | dentry = lookup_one_len(name, parent, namlen); | ||
211 | if (IS_ERR(dentry)) | ||
212 | return PTR_ERR(dentry); | ||
213 | child = kmalloc(sizeof(*child), GFP_KERNEL); | ||
214 | if (child == NULL) | ||
215 | return -ENOMEM; | ||
216 | child->dentry = dentry; | ||
217 | list_add(&child->list, dentries); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int | ||
222 | nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) | ||
223 | { | ||
224 | struct file *filp; | ||
225 | struct dentry_list_arg dla = { | ||
226 | .parent = dir, | ||
227 | }; | ||
228 | struct list_head *dentries = &dla.dentries; | ||
229 | struct dentry_list *child; | ||
230 | uid_t uid; | ||
231 | gid_t gid; | ||
232 | int status; | ||
233 | |||
234 | if (!rec_dir_init) | ||
235 | return 0; | ||
236 | |||
237 | nfs4_save_user(&uid, &gid); | ||
238 | |||
239 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), | ||
240 | O_RDWR); | ||
241 | status = PTR_ERR(filp); | ||
242 | if (IS_ERR(filp)) | ||
243 | goto out; | ||
244 | INIT_LIST_HEAD(dentries); | ||
245 | status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla); | ||
246 | fput(filp); | ||
247 | while (!list_empty(dentries)) { | ||
248 | child = list_entry(dentries->next, struct dentry_list, list); | ||
249 | status = f(dir, child->dentry); | ||
250 | if (status) | ||
251 | goto out; | ||
252 | list_del(&child->list); | ||
253 | dput(child->dentry); | ||
254 | kfree(child); | ||
255 | } | ||
256 | out: | ||
257 | while (!list_empty(dentries)) { | ||
258 | child = list_entry(dentries->next, struct dentry_list, list); | ||
259 | list_del(&child->list); | ||
260 | dput(child->dentry); | ||
261 | kfree(child); | ||
262 | } | ||
263 | nfs4_reset_user(uid, gid); | ||
264 | return status; | ||
265 | } | ||
266 | |||
267 | static int | ||
268 | nfsd4_remove_clid_file(struct dentry *dir, struct dentry *dentry) | ||
269 | { | ||
270 | int status; | ||
271 | |||
272 | if (!S_ISREG(dir->d_inode->i_mode)) { | ||
273 | printk("nfsd4: non-file found in client recovery directory\n"); | ||
274 | return -EINVAL; | ||
275 | } | ||
276 | down(&dir->d_inode->i_sem); | ||
277 | status = vfs_unlink(dir->d_inode, dentry); | ||
278 | up(&dir->d_inode->i_sem); | ||
279 | return status; | ||
280 | } | ||
281 | |||
282 | static int | ||
283 | nfsd4_clear_clid_dir(struct dentry *dir, struct dentry *dentry) | ||
284 | { | ||
285 | int status; | ||
286 | |||
287 | /* For now this directory should already be empty, but we empty it of | ||
288 | * any regular files anyway, just in case the directory was created by | ||
289 | * a kernel from the future.... */ | ||
290 | nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file); | ||
291 | down(&dir->d_inode->i_sem); | ||
292 | status = vfs_rmdir(dir->d_inode, dentry); | ||
293 | up(&dir->d_inode->i_sem); | ||
294 | return status; | ||
295 | } | ||
296 | |||
297 | static int | ||
298 | nfsd4_unlink_clid_dir(char *name, int namlen) | ||
299 | { | ||
300 | struct dentry *dentry; | ||
301 | int status; | ||
302 | |||
303 | dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); | ||
304 | |||
305 | dentry = lookup_one_len(name, rec_dir.dentry, namlen); | ||
306 | if (IS_ERR(dentry)) { | ||
307 | status = PTR_ERR(dentry); | ||
308 | return status; | ||
309 | } | ||
310 | status = -ENOENT; | ||
311 | if (!dentry->d_inode) | ||
312 | goto out; | ||
313 | |||
314 | status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry); | ||
315 | out: | ||
316 | dput(dentry); | ||
317 | return status; | ||
318 | } | ||
319 | |||
320 | void | ||
321 | nfsd4_remove_clid_dir(struct nfs4_client *clp) | ||
322 | { | ||
323 | uid_t uid; | ||
324 | gid_t gid; | ||
325 | int status; | ||
326 | |||
327 | if (!rec_dir_init || !clp->cl_firststate) | ||
328 | return; | ||
329 | |||
330 | nfs4_save_user(&uid, &gid); | ||
331 | status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); | ||
332 | nfs4_reset_user(uid, gid); | ||
333 | if (status == 0) | ||
334 | status = nfsd4_rec_fsync(rec_dir.dentry); | ||
335 | if (status) | ||
336 | printk("NFSD: Failed to remove expired client state directory" | ||
337 | " %.*s\n", HEXDIR_LEN, clp->cl_recdir); | ||
338 | return; | ||
339 | } | ||
340 | |||
341 | static int | ||
342 | purge_old(struct dentry *parent, struct dentry *child) | ||
343 | { | ||
344 | int status; | ||
345 | |||
346 | if (nfs4_has_reclaimed_state(child->d_name.name)) | ||
347 | return nfs_ok; | ||
348 | |||
349 | status = nfsd4_clear_clid_dir(parent, child); | ||
350 | if (status) | ||
351 | printk("failed to remove client recovery directory %s\n", | ||
352 | child->d_name.name); | ||
353 | /* Keep trying, success or failure: */ | ||
354 | return nfs_ok; | ||
355 | } | ||
356 | |||
357 | void | ||
358 | nfsd4_recdir_purge_old(void) { | ||
359 | int status; | ||
360 | |||
361 | if (!rec_dir_init) | ||
362 | return; | ||
363 | status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old); | ||
364 | if (status == 0) | ||
365 | status = nfsd4_rec_fsync(rec_dir.dentry); | ||
366 | if (status) | ||
367 | printk("nfsd4: failed to purge old clients from recovery" | ||
368 | " directory %s\n", rec_dir.dentry->d_name.name); | ||
369 | return; | ||
370 | } | ||
371 | |||
372 | static int | ||
373 | load_recdir(struct dentry *parent, struct dentry *child) | ||
374 | { | ||
375 | if (child->d_name.len != HEXDIR_LEN - 1) { | ||
376 | printk("nfsd4: illegal name %s in recovery directory\n", | ||
377 | child->d_name.name); | ||
378 | /* Keep trying; maybe the others are OK: */ | ||
379 | return nfs_ok; | ||
380 | } | ||
381 | nfs4_client_to_reclaim(child->d_name.name); | ||
382 | return nfs_ok; | ||
383 | } | ||
384 | |||
385 | int | ||
386 | nfsd4_recdir_load(void) { | ||
387 | int status; | ||
388 | |||
389 | status = nfsd4_list_rec_dir(rec_dir.dentry, load_recdir); | ||
390 | if (status) | ||
391 | printk("nfsd4: failed loading clients from recovery" | ||
392 | " directory %s\n", rec_dir.dentry->d_name.name); | ||
393 | return status; | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * Hold reference to the recovery directory. | ||
398 | */ | ||
399 | |||
400 | void | ||
401 | nfsd4_init_recdir(char *rec_dirname) | ||
402 | { | ||
403 | uid_t uid = 0; | ||
404 | gid_t gid = 0; | ||
405 | int status; | ||
406 | |||
407 | printk("NFSD: Using %s as the NFSv4 state recovery directory\n", | ||
408 | rec_dirname); | ||
409 | |||
410 | BUG_ON(rec_dir_init); | ||
411 | |||
412 | nfs4_save_user(&uid, &gid); | ||
413 | |||
414 | status = path_lookup(rec_dirname, LOOKUP_FOLLOW, &rec_dir); | ||
415 | if (status == -ENOENT) | ||
416 | printk("NFSD: recovery directory %s doesn't exist\n", | ||
417 | rec_dirname); | ||
418 | |||
419 | if (!status) | ||
420 | rec_dir_init = 1; | ||
421 | nfs4_reset_user(uid, gid); | ||
422 | } | ||
423 | |||
424 | void | ||
425 | nfsd4_shutdown_recdir(void) | ||
426 | { | ||
427 | if (!rec_dir_init) | ||
428 | return; | ||
429 | rec_dir_init = 0; | ||
430 | path_release(&rec_dir); | ||
431 | } | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 75e8b137580c..89e36526d7f2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -48,39 +48,32 @@ | |||
48 | #include <linux/nfs4.h> | 48 | #include <linux/nfs4.h> |
49 | #include <linux/nfsd/state.h> | 49 | #include <linux/nfsd/state.h> |
50 | #include <linux/nfsd/xdr4.h> | 50 | #include <linux/nfsd/xdr4.h> |
51 | #include <linux/namei.h> | ||
51 | 52 | ||
52 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 53 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
53 | 54 | ||
54 | /* Globals */ | 55 | /* Globals */ |
55 | static time_t lease_time = 90; /* default lease time */ | 56 | static time_t lease_time = 90; /* default lease time */ |
56 | static time_t old_lease_time = 90; /* past incarnation lease time */ | 57 | static time_t user_lease_time = 90; |
57 | static u32 nfs4_reclaim_init = 0; | 58 | static time_t boot_time; |
58 | time_t boot_time; | 59 | static int in_grace = 1; |
59 | static time_t grace_end = 0; | ||
60 | static u32 current_clientid = 1; | 60 | static u32 current_clientid = 1; |
61 | static u32 current_ownerid = 1; | 61 | static u32 current_ownerid = 1; |
62 | static u32 current_fileid = 1; | 62 | static u32 current_fileid = 1; |
63 | static u32 current_delegid = 1; | 63 | static u32 current_delegid = 1; |
64 | static u32 nfs4_init; | 64 | static u32 nfs4_init; |
65 | stateid_t zerostateid; /* bits all 0 */ | 65 | static stateid_t zerostateid; /* bits all 0 */ |
66 | stateid_t onestateid; /* bits all 1 */ | 66 | static stateid_t onestateid; /* bits all 1 */ |
67 | 67 | ||
68 | /* debug counters */ | 68 | #define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t))) |
69 | u32 list_add_perfile = 0; | 69 | #define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) |
70 | u32 list_del_perfile = 0; | ||
71 | u32 add_perclient = 0; | ||
72 | u32 del_perclient = 0; | ||
73 | u32 alloc_file = 0; | ||
74 | u32 free_file = 0; | ||
75 | u32 vfsopen = 0; | ||
76 | u32 vfsclose = 0; | ||
77 | u32 alloc_delegation= 0; | ||
78 | u32 free_delegation= 0; | ||
79 | 70 | ||
80 | /* forward declarations */ | 71 | /* forward declarations */ |
81 | struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); | 72 | static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); |
82 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); | 73 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); |
83 | static void release_stateid_lockowners(struct nfs4_stateid *open_stp); | 74 | static void release_stateid_lockowners(struct nfs4_stateid *open_stp); |
75 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | ||
76 | static void nfs4_set_recdir(char *recdir); | ||
84 | 77 | ||
85 | /* Locking: | 78 | /* Locking: |
86 | * | 79 | * |
@@ -90,6 +83,11 @@ static void release_stateid_lockowners(struct nfs4_stateid *open_stp); | |||
90 | */ | 83 | */ |
91 | static DECLARE_MUTEX(client_sema); | 84 | static DECLARE_MUTEX(client_sema); |
92 | 85 | ||
86 | static kmem_cache_t *stateowner_slab = NULL; | ||
87 | static kmem_cache_t *file_slab = NULL; | ||
88 | static kmem_cache_t *stateid_slab = NULL; | ||
89 | static kmem_cache_t *deleg_slab = NULL; | ||
90 | |||
93 | void | 91 | void |
94 | nfs4_lock_state(void) | 92 | nfs4_lock_state(void) |
95 | { | 93 | { |
@@ -118,16 +116,36 @@ opaque_hashval(const void *ptr, int nbytes) | |||
118 | /* forward declarations */ | 116 | /* forward declarations */ |
119 | static void release_stateowner(struct nfs4_stateowner *sop); | 117 | static void release_stateowner(struct nfs4_stateowner *sop); |
120 | static void release_stateid(struct nfs4_stateid *stp, int flags); | 118 | static void release_stateid(struct nfs4_stateid *stp, int flags); |
121 | static void release_file(struct nfs4_file *fp); | ||
122 | 119 | ||
123 | /* | 120 | /* |
124 | * Delegation state | 121 | * Delegation state |
125 | */ | 122 | */ |
126 | 123 | ||
127 | /* recall_lock protects the del_recall_lru */ | 124 | /* recall_lock protects the del_recall_lru */ |
128 | spinlock_t recall_lock; | 125 | static spinlock_t recall_lock = SPIN_LOCK_UNLOCKED; |
129 | static struct list_head del_recall_lru; | 126 | static struct list_head del_recall_lru; |
130 | 127 | ||
128 | static void | ||
129 | free_nfs4_file(struct kref *kref) | ||
130 | { | ||
131 | struct nfs4_file *fp = container_of(kref, struct nfs4_file, fi_ref); | ||
132 | list_del(&fp->fi_hash); | ||
133 | iput(fp->fi_inode); | ||
134 | kmem_cache_free(file_slab, fp); | ||
135 | } | ||
136 | |||
137 | static inline void | ||
138 | put_nfs4_file(struct nfs4_file *fi) | ||
139 | { | ||
140 | kref_put(&fi->fi_ref, free_nfs4_file); | ||
141 | } | ||
142 | |||
143 | static inline void | ||
144 | get_nfs4_file(struct nfs4_file *fi) | ||
145 | { | ||
146 | kref_get(&fi->fi_ref); | ||
147 | } | ||
148 | |||
131 | static struct nfs4_delegation * | 149 | static struct nfs4_delegation * |
132 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) | 150 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) |
133 | { | 151 | { |
@@ -136,13 +154,14 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
136 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; | 154 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; |
137 | 155 | ||
138 | dprintk("NFSD alloc_init_deleg\n"); | 156 | dprintk("NFSD alloc_init_deleg\n"); |
139 | if ((dp = kmalloc(sizeof(struct nfs4_delegation), | 157 | dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); |
140 | GFP_KERNEL)) == NULL) | 158 | if (dp == NULL) |
141 | return dp; | 159 | return dp; |
142 | INIT_LIST_HEAD(&dp->dl_del_perfile); | 160 | INIT_LIST_HEAD(&dp->dl_perfile); |
143 | INIT_LIST_HEAD(&dp->dl_del_perclnt); | 161 | INIT_LIST_HEAD(&dp->dl_perclnt); |
144 | INIT_LIST_HEAD(&dp->dl_recall_lru); | 162 | INIT_LIST_HEAD(&dp->dl_recall_lru); |
145 | dp->dl_client = clp; | 163 | dp->dl_client = clp; |
164 | get_nfs4_file(fp); | ||
146 | dp->dl_file = fp; | 165 | dp->dl_file = fp; |
147 | dp->dl_flock = NULL; | 166 | dp->dl_flock = NULL; |
148 | get_file(stp->st_vfs_file); | 167 | get_file(stp->st_vfs_file); |
@@ -160,9 +179,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
160 | current_fh->fh_handle.fh_size); | 179 | current_fh->fh_handle.fh_size); |
161 | dp->dl_time = 0; | 180 | dp->dl_time = 0; |
162 | atomic_set(&dp->dl_count, 1); | 181 | atomic_set(&dp->dl_count, 1); |
163 | list_add(&dp->dl_del_perfile, &fp->fi_del_perfile); | 182 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
164 | list_add(&dp->dl_del_perclnt, &clp->cl_del_perclnt); | 183 | list_add(&dp->dl_perclnt, &clp->cl_delegations); |
165 | alloc_delegation++; | ||
166 | return dp; | 184 | return dp; |
167 | } | 185 | } |
168 | 186 | ||
@@ -171,8 +189,8 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
171 | { | 189 | { |
172 | if (atomic_dec_and_test(&dp->dl_count)) { | 190 | if (atomic_dec_and_test(&dp->dl_count)) { |
173 | dprintk("NFSD: freeing dp %p\n",dp); | 191 | dprintk("NFSD: freeing dp %p\n",dp); |
174 | kfree(dp); | 192 | put_nfs4_file(dp->dl_file); |
175 | free_delegation++; | 193 | kmem_cache_free(deleg_slab, dp); |
176 | } | 194 | } |
177 | } | 195 | } |
178 | 196 | ||
@@ -193,15 +211,14 @@ nfs4_close_delegation(struct nfs4_delegation *dp) | |||
193 | if (dp->dl_flock) | 211 | if (dp->dl_flock) |
194 | setlease(filp, F_UNLCK, &dp->dl_flock); | 212 | setlease(filp, F_UNLCK, &dp->dl_flock); |
195 | nfsd_close(filp); | 213 | nfsd_close(filp); |
196 | vfsclose++; | ||
197 | } | 214 | } |
198 | 215 | ||
199 | /* Called under the state lock. */ | 216 | /* Called under the state lock. */ |
200 | static void | 217 | static void |
201 | unhash_delegation(struct nfs4_delegation *dp) | 218 | unhash_delegation(struct nfs4_delegation *dp) |
202 | { | 219 | { |
203 | list_del_init(&dp->dl_del_perfile); | 220 | list_del_init(&dp->dl_perfile); |
204 | list_del_init(&dp->dl_del_perclnt); | 221 | list_del_init(&dp->dl_perclnt); |
205 | spin_lock(&recall_lock); | 222 | spin_lock(&recall_lock); |
206 | list_del_init(&dp->dl_recall_lru); | 223 | list_del_init(&dp->dl_recall_lru); |
207 | spin_unlock(&recall_lock); | 224 | spin_unlock(&recall_lock); |
@@ -220,8 +237,8 @@ unhash_delegation(struct nfs4_delegation *dp) | |||
220 | 237 | ||
221 | #define clientid_hashval(id) \ | 238 | #define clientid_hashval(id) \ |
222 | ((id) & CLIENT_HASH_MASK) | 239 | ((id) & CLIENT_HASH_MASK) |
223 | #define clientstr_hashval(name, namelen) \ | 240 | #define clientstr_hashval(name) \ |
224 | (opaque_hashval((name), (namelen)) & CLIENT_HASH_MASK) | 241 | (opaque_hashval((name), 8) & CLIENT_HASH_MASK) |
225 | /* | 242 | /* |
226 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot | 243 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot |
227 | * used in reboot/reset lease grace period processing | 244 | * used in reboot/reset lease grace period processing |
@@ -331,11 +348,11 @@ expire_client(struct nfs4_client *clp) | |||
331 | 348 | ||
332 | INIT_LIST_HEAD(&reaplist); | 349 | INIT_LIST_HEAD(&reaplist); |
333 | spin_lock(&recall_lock); | 350 | spin_lock(&recall_lock); |
334 | while (!list_empty(&clp->cl_del_perclnt)) { | 351 | while (!list_empty(&clp->cl_delegations)) { |
335 | dp = list_entry(clp->cl_del_perclnt.next, struct nfs4_delegation, dl_del_perclnt); | 352 | dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); |
336 | dprintk("NFSD: expire client. dp %p, fp %p\n", dp, | 353 | dprintk("NFSD: expire client. dp %p, fp %p\n", dp, |
337 | dp->dl_flock); | 354 | dp->dl_flock); |
338 | list_del_init(&dp->dl_del_perclnt); | 355 | list_del_init(&dp->dl_perclnt); |
339 | list_move(&dp->dl_recall_lru, &reaplist); | 356 | list_move(&dp->dl_recall_lru, &reaplist); |
340 | } | 357 | } |
341 | spin_unlock(&recall_lock); | 358 | spin_unlock(&recall_lock); |
@@ -347,26 +364,26 @@ expire_client(struct nfs4_client *clp) | |||
347 | list_del(&clp->cl_idhash); | 364 | list_del(&clp->cl_idhash); |
348 | list_del(&clp->cl_strhash); | 365 | list_del(&clp->cl_strhash); |
349 | list_del(&clp->cl_lru); | 366 | list_del(&clp->cl_lru); |
350 | while (!list_empty(&clp->cl_perclient)) { | 367 | while (!list_empty(&clp->cl_openowners)) { |
351 | sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient); | 368 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); |
352 | release_stateowner(sop); | 369 | release_stateowner(sop); |
353 | } | 370 | } |
354 | put_nfs4_client(clp); | 371 | put_nfs4_client(clp); |
355 | } | 372 | } |
356 | 373 | ||
357 | static struct nfs4_client * | 374 | static struct nfs4_client * |
358 | create_client(struct xdr_netobj name) { | 375 | create_client(struct xdr_netobj name, char *recdir) { |
359 | struct nfs4_client *clp; | 376 | struct nfs4_client *clp; |
360 | 377 | ||
361 | if (!(clp = alloc_client(name))) | 378 | if (!(clp = alloc_client(name))) |
362 | goto out; | 379 | goto out; |
380 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | ||
363 | atomic_set(&clp->cl_count, 1); | 381 | atomic_set(&clp->cl_count, 1); |
364 | atomic_set(&clp->cl_callback.cb_set, 0); | 382 | atomic_set(&clp->cl_callback.cb_set, 0); |
365 | clp->cl_callback.cb_parsed = 0; | ||
366 | INIT_LIST_HEAD(&clp->cl_idhash); | 383 | INIT_LIST_HEAD(&clp->cl_idhash); |
367 | INIT_LIST_HEAD(&clp->cl_strhash); | 384 | INIT_LIST_HEAD(&clp->cl_strhash); |
368 | INIT_LIST_HEAD(&clp->cl_perclient); | 385 | INIT_LIST_HEAD(&clp->cl_openowners); |
369 | INIT_LIST_HEAD(&clp->cl_del_perclnt); | 386 | INIT_LIST_HEAD(&clp->cl_delegations); |
370 | INIT_LIST_HEAD(&clp->cl_lru); | 387 | INIT_LIST_HEAD(&clp->cl_lru); |
371 | out: | 388 | out: |
372 | return clp; | 389 | return clp; |
@@ -392,11 +409,9 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) { | |||
392 | get_group_info(target->cr_group_info); | 409 | get_group_info(target->cr_group_info); |
393 | } | 410 | } |
394 | 411 | ||
395 | static int | 412 | static inline int |
396 | cmp_name(struct xdr_netobj *n1, struct xdr_netobj *n2) { | 413 | same_name(const char *n1, const char *n2) { |
397 | if (!n1 || !n2) | 414 | return 0 == memcmp(n1, n2, HEXDIR_LEN); |
398 | return 0; | ||
399 | return((n1->len == n2->len) && !memcmp(n1->data, n2->data, n2->len)); | ||
400 | } | 415 | } |
401 | 416 | ||
402 | static int | 417 | static int |
@@ -446,7 +461,7 @@ check_name(struct xdr_netobj name) { | |||
446 | return 1; | 461 | return 1; |
447 | } | 462 | } |
448 | 463 | ||
449 | void | 464 | static void |
450 | add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) | 465 | add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) |
451 | { | 466 | { |
452 | unsigned int idhashval; | 467 | unsigned int idhashval; |
@@ -458,7 +473,7 @@ add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) | |||
458 | clp->cl_time = get_seconds(); | 473 | clp->cl_time = get_seconds(); |
459 | } | 474 | } |
460 | 475 | ||
461 | void | 476 | static void |
462 | move_to_confirmed(struct nfs4_client *clp) | 477 | move_to_confirmed(struct nfs4_client *clp) |
463 | { | 478 | { |
464 | unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 479 | unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
@@ -468,8 +483,7 @@ move_to_confirmed(struct nfs4_client *clp) | |||
468 | list_del_init(&clp->cl_strhash); | 483 | list_del_init(&clp->cl_strhash); |
469 | list_del_init(&clp->cl_idhash); | 484 | list_del_init(&clp->cl_idhash); |
470 | list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); | 485 | list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); |
471 | strhashval = clientstr_hashval(clp->cl_name.data, | 486 | strhashval = clientstr_hashval(clp->cl_recdir); |
472 | clp->cl_name.len); | ||
473 | list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); | 487 | list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); |
474 | renew_client(clp); | 488 | renew_client(clp); |
475 | } | 489 | } |
@@ -500,6 +514,30 @@ find_unconfirmed_client(clientid_t *clid) | |||
500 | return NULL; | 514 | return NULL; |
501 | } | 515 | } |
502 | 516 | ||
517 | static struct nfs4_client * | ||
518 | find_confirmed_client_by_str(const char *dname, unsigned int hashval) | ||
519 | { | ||
520 | struct nfs4_client *clp; | ||
521 | |||
522 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { | ||
523 | if (same_name(clp->cl_recdir, dname)) | ||
524 | return clp; | ||
525 | } | ||
526 | return NULL; | ||
527 | } | ||
528 | |||
529 | static struct nfs4_client * | ||
530 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) | ||
531 | { | ||
532 | struct nfs4_client *clp; | ||
533 | |||
534 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { | ||
535 | if (same_name(clp->cl_recdir, dname)) | ||
536 | return clp; | ||
537 | } | ||
538 | return NULL; | ||
539 | } | ||
540 | |||
503 | /* a helper function for parse_callback */ | 541 | /* a helper function for parse_callback */ |
504 | static int | 542 | static int |
505 | parse_octet(unsigned int *lenp, char **addrp) | 543 | parse_octet(unsigned int *lenp, char **addrp) |
@@ -534,7 +572,7 @@ parse_octet(unsigned int *lenp, char **addrp) | |||
534 | } | 572 | } |
535 | 573 | ||
536 | /* parse and set the setclientid ipv4 callback address */ | 574 | /* parse and set the setclientid ipv4 callback address */ |
537 | int | 575 | static int |
538 | parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp) | 576 | parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp) |
539 | { | 577 | { |
540 | int temp = 0; | 578 | int temp = 0; |
@@ -570,7 +608,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne | |||
570 | return 1; | 608 | return 1; |
571 | } | 609 | } |
572 | 610 | ||
573 | void | 611 | static void |
574 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | 612 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) |
575 | { | 613 | { |
576 | struct nfs4_callback *cb = &clp->cl_callback; | 614 | struct nfs4_callback *cb = &clp->cl_callback; |
@@ -584,14 +622,12 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | |||
584 | goto out_err; | 622 | goto out_err; |
585 | cb->cb_prog = se->se_callback_prog; | 623 | cb->cb_prog = se->se_callback_prog; |
586 | cb->cb_ident = se->se_callback_ident; | 624 | cb->cb_ident = se->se_callback_ident; |
587 | cb->cb_parsed = 1; | ||
588 | return; | 625 | return; |
589 | out_err: | 626 | out_err: |
590 | printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " | 627 | printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " |
591 | "will not receive delegations\n", | 628 | "will not receive delegations\n", |
592 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | 629 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); |
593 | 630 | ||
594 | cb->cb_parsed = 0; | ||
595 | return; | 631 | return; |
596 | } | 632 | } |
597 | 633 | ||
@@ -638,59 +674,43 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
638 | }; | 674 | }; |
639 | nfs4_verifier clverifier = setclid->se_verf; | 675 | nfs4_verifier clverifier = setclid->se_verf; |
640 | unsigned int strhashval; | 676 | unsigned int strhashval; |
641 | struct nfs4_client * conf, * unconf, * new, * clp; | 677 | struct nfs4_client *conf, *unconf, *new; |
642 | int status; | 678 | int status; |
679 | char dname[HEXDIR_LEN]; | ||
643 | 680 | ||
644 | status = nfserr_inval; | 681 | status = nfserr_inval; |
645 | if (!check_name(clname)) | 682 | if (!check_name(clname)) |
646 | goto out; | 683 | goto out; |
647 | 684 | ||
685 | status = nfs4_make_rec_clidname(dname, &clname); | ||
686 | if (status) | ||
687 | goto out; | ||
688 | |||
648 | /* | 689 | /* |
649 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | 690 | * XXX The Duplicate Request Cache (DRC) has been checked (??) |
650 | * We get here on a DRC miss. | 691 | * We get here on a DRC miss. |
651 | */ | 692 | */ |
652 | 693 | ||
653 | strhashval = clientstr_hashval(clname.data, clname.len); | 694 | strhashval = clientstr_hashval(dname); |
654 | 695 | ||
655 | conf = NULL; | ||
656 | nfs4_lock_state(); | 696 | nfs4_lock_state(); |
657 | list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) { | 697 | conf = find_confirmed_client_by_str(dname, strhashval); |
658 | if (!cmp_name(&clp->cl_name, &clname)) | 698 | if (conf) { |
659 | continue; | ||
660 | /* | 699 | /* |
661 | * CASE 0: | 700 | * CASE 0: |
662 | * clname match, confirmed, different principal | 701 | * clname match, confirmed, different principal |
663 | * or different ip_address | 702 | * or different ip_address |
664 | */ | 703 | */ |
665 | status = nfserr_clid_inuse; | 704 | status = nfserr_clid_inuse; |
666 | if (!cmp_creds(&clp->cl_cred,&rqstp->rq_cred)) { | 705 | if (!cmp_creds(&conf->cl_cred, &rqstp->rq_cred) |
667 | printk("NFSD: setclientid: string in use by client" | 706 | || conf->cl_addr != ip_addr) { |
668 | "(clientid %08x/%08x)\n", | ||
669 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | ||
670 | goto out; | ||
671 | } | ||
672 | if (clp->cl_addr != ip_addr) { | ||
673 | printk("NFSD: setclientid: string in use by client" | 707 | printk("NFSD: setclientid: string in use by client" |
674 | "(clientid %08x/%08x)\n", | 708 | "(clientid %08x/%08x)\n", |
675 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | 709 | conf->cl_clientid.cl_boot, conf->cl_clientid.cl_id); |
676 | goto out; | 710 | goto out; |
677 | } | 711 | } |
678 | |||
679 | /* | ||
680 | * cl_name match from a previous SETCLIENTID operation | ||
681 | * XXX check for additional matches? | ||
682 | */ | ||
683 | conf = clp; | ||
684 | break; | ||
685 | } | ||
686 | unconf = NULL; | ||
687 | list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) { | ||
688 | if (!cmp_name(&clp->cl_name, &clname)) | ||
689 | continue; | ||
690 | /* cl_name match from a previous SETCLIENTID operation */ | ||
691 | unconf = clp; | ||
692 | break; | ||
693 | } | 712 | } |
713 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | ||
694 | status = nfserr_resource; | 714 | status = nfserr_resource; |
695 | if (!conf) { | 715 | if (!conf) { |
696 | /* | 716 | /* |
@@ -699,7 +719,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
699 | */ | 719 | */ |
700 | if (unconf) | 720 | if (unconf) |
701 | expire_client(unconf); | 721 | expire_client(unconf); |
702 | if (!(new = create_client(clname))) | 722 | new = create_client(clname, dname); |
723 | if (new == NULL) | ||
703 | goto out; | 724 | goto out; |
704 | copy_verf(new, &clverifier); | 725 | copy_verf(new, &clverifier); |
705 | new->cl_addr = ip_addr; | 726 | new->cl_addr = ip_addr; |
@@ -722,12 +743,16 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
722 | * nfs4_client, but with the new callback info and a | 743 | * nfs4_client, but with the new callback info and a |
723 | * new cl_confirm | 744 | * new cl_confirm |
724 | */ | 745 | */ |
725 | if ((unconf) && | 746 | if (unconf) { |
726 | cmp_verf(&unconf->cl_verifier, &conf->cl_verifier) && | 747 | /* Note this is removing unconfirmed {*x***}, |
727 | cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) { | 748 | * which is stronger than RFC recommended {vxc**}. |
728 | expire_client(unconf); | 749 | * This has the advantage that there is at most |
750 | * one {*x***} in either list at any time. | ||
751 | */ | ||
752 | expire_client(unconf); | ||
729 | } | 753 | } |
730 | if (!(new = create_client(clname))) | 754 | new = create_client(clname, dname); |
755 | if (new == NULL) | ||
731 | goto out; | 756 | goto out; |
732 | copy_verf(new,&conf->cl_verifier); | 757 | copy_verf(new,&conf->cl_verifier); |
733 | new->cl_addr = ip_addr; | 758 | new->cl_addr = ip_addr; |
@@ -745,7 +770,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
745 | * using input clverifier, clname, and callback info | 770 | * using input clverifier, clname, and callback info |
746 | * and generate a new cl_clientid and cl_confirm. | 771 | * and generate a new cl_clientid and cl_confirm. |
747 | */ | 772 | */ |
748 | if (!(new = create_client(clname))) | 773 | new = create_client(clname, dname); |
774 | if (new == NULL) | ||
749 | goto out; | 775 | goto out; |
750 | copy_verf(new,&clverifier); | 776 | copy_verf(new,&clverifier); |
751 | new->cl_addr = ip_addr; | 777 | new->cl_addr = ip_addr; |
@@ -771,7 +797,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
771 | * new cl_verifier and a new cl_confirm | 797 | * new cl_verifier and a new cl_confirm |
772 | */ | 798 | */ |
773 | expire_client(unconf); | 799 | expire_client(unconf); |
774 | if (!(new = create_client(clname))) | 800 | new = create_client(clname, dname); |
801 | if (new == NULL) | ||
775 | goto out; | 802 | goto out; |
776 | copy_verf(new,&clverifier); | 803 | copy_verf(new,&clverifier); |
777 | new->cl_addr = ip_addr; | 804 | new->cl_addr = ip_addr; |
@@ -807,7 +834,7 @@ int | |||
807 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm) | 834 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm) |
808 | { | 835 | { |
809 | u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; | 836 | u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; |
810 | struct nfs4_client *clp, *conf = NULL, *unconf = NULL; | 837 | struct nfs4_client *conf, *unconf; |
811 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 838 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
812 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 839 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
813 | int status; | 840 | int status; |
@@ -820,102 +847,90 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi | |||
820 | */ | 847 | */ |
821 | 848 | ||
822 | nfs4_lock_state(); | 849 | nfs4_lock_state(); |
823 | clp = find_confirmed_client(clid); | 850 | |
824 | if (clp) { | 851 | conf = find_confirmed_client(clid); |
825 | status = nfserr_inval; | 852 | unconf = find_unconfirmed_client(clid); |
826 | /* | 853 | |
827 | * Found a record for this clientid. If the IP addresses | 854 | status = nfserr_clid_inuse; |
828 | * don't match, return ERR_INVAL just as if the record had | 855 | if (conf && conf->cl_addr != ip_addr) |
829 | * not been found. | 856 | goto out; |
830 | */ | 857 | if (unconf && unconf->cl_addr != ip_addr) |
831 | if (clp->cl_addr != ip_addr) { | 858 | goto out; |
832 | printk("NFSD: setclientid: string in use by client" | 859 | |
833 | "(clientid %08x/%08x)\n", | ||
834 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | ||
835 | goto out; | ||
836 | } | ||
837 | conf = clp; | ||
838 | } | ||
839 | clp = find_unconfirmed_client(clid); | ||
840 | if (clp) { | ||
841 | status = nfserr_inval; | ||
842 | if (clp->cl_addr != ip_addr) { | ||
843 | printk("NFSD: setclientid: string in use by client" | ||
844 | "(clientid %08x/%08x)\n", | ||
845 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | ||
846 | goto out; | ||
847 | } | ||
848 | unconf = clp; | ||
849 | } | ||
850 | /* CASE 1: | ||
851 | * unconf record that matches input clientid and input confirm. | ||
852 | * conf record that matches input clientid. | ||
853 | * conf and unconf records match names, verifiers | ||
854 | */ | ||
855 | if ((conf && unconf) && | 860 | if ((conf && unconf) && |
856 | (cmp_verf(&unconf->cl_confirm, &confirm)) && | 861 | (cmp_verf(&unconf->cl_confirm, &confirm)) && |
857 | (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) && | 862 | (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) && |
858 | (cmp_name(&conf->cl_name,&unconf->cl_name)) && | 863 | (same_name(conf->cl_recdir,unconf->cl_recdir)) && |
859 | (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) { | 864 | (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) { |
865 | /* CASE 1: | ||
866 | * unconf record that matches input clientid and input confirm. | ||
867 | * conf record that matches input clientid. | ||
868 | * conf and unconf records match names, verifiers | ||
869 | */ | ||
860 | if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) | 870 | if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) |
861 | status = nfserr_clid_inuse; | 871 | status = nfserr_clid_inuse; |
862 | else { | 872 | else { |
863 | expire_client(conf); | 873 | /* XXX: We just turn off callbacks until we can handle |
864 | clp = unconf; | 874 | * change request correctly. */ |
865 | move_to_confirmed(unconf); | 875 | atomic_set(&conf->cl_callback.cb_set, 0); |
876 | gen_confirm(conf); | ||
877 | expire_client(unconf); | ||
866 | status = nfs_ok; | 878 | status = nfs_ok; |
879 | |||
867 | } | 880 | } |
868 | goto out; | 881 | } else if ((conf && !unconf) || |
869 | } | ||
870 | /* CASE 2: | ||
871 | * conf record that matches input clientid. | ||
872 | * if unconf record that matches input clientid, then unconf->cl_name | ||
873 | * or unconf->cl_verifier don't match the conf record. | ||
874 | */ | ||
875 | if ((conf && !unconf) || | ||
876 | ((conf && unconf) && | 882 | ((conf && unconf) && |
877 | (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) || | 883 | (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) || |
878 | !cmp_name(&conf->cl_name, &unconf->cl_name)))) { | 884 | !same_name(conf->cl_recdir, unconf->cl_recdir)))) { |
879 | if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) { | 885 | /* CASE 2: |
886 | * conf record that matches input clientid. | ||
887 | * if unconf record matches input clientid, then | ||
888 | * unconf->cl_name or unconf->cl_verifier don't match the | ||
889 | * conf record. | ||
890 | */ | ||
891 | if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) | ||
880 | status = nfserr_clid_inuse; | 892 | status = nfserr_clid_inuse; |
881 | } else { | 893 | else |
882 | clp = conf; | ||
883 | status = nfs_ok; | 894 | status = nfs_ok; |
884 | } | 895 | } else if (!conf && unconf |
885 | goto out; | 896 | && cmp_verf(&unconf->cl_confirm, &confirm)) { |
886 | } | 897 | /* CASE 3: |
887 | /* CASE 3: | 898 | * conf record not found. |
888 | * conf record not found. | 899 | * unconf record found. |
889 | * unconf record found. | 900 | * unconf->cl_confirm matches input confirm |
890 | * unconf->cl_confirm matches input confirm | 901 | */ |
891 | */ | ||
892 | if (!conf && unconf && cmp_verf(&unconf->cl_confirm, &confirm)) { | ||
893 | if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) { | 902 | if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) { |
894 | status = nfserr_clid_inuse; | 903 | status = nfserr_clid_inuse; |
895 | } else { | 904 | } else { |
896 | status = nfs_ok; | 905 | unsigned int hash = |
897 | clp = unconf; | 906 | clientstr_hashval(unconf->cl_recdir); |
907 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | ||
908 | hash); | ||
909 | if (conf) { | ||
910 | nfsd4_remove_clid_dir(conf); | ||
911 | expire_client(conf); | ||
912 | } | ||
898 | move_to_confirmed(unconf); | 913 | move_to_confirmed(unconf); |
914 | conf = unconf; | ||
915 | status = nfs_ok; | ||
899 | } | 916 | } |
900 | goto out; | 917 | } else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) |
901 | } | 918 | && (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, |
902 | /* CASE 4: | 919 | &confirm)))) { |
903 | * conf record not found, or if conf, then conf->cl_confirm does not | 920 | /* CASE 4: |
904 | * match input confirm. | 921 | * conf record not found, or if conf, conf->cl_confirm does not |
905 | * unconf record not found, or if unconf, then unconf->cl_confirm | 922 | * match input confirm. |
906 | * does not match input confirm. | 923 | * unconf record not found, or if unconf, unconf->cl_confirm |
907 | */ | 924 | * does not match input confirm. |
908 | if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) && | 925 | */ |
909 | (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, &confirm)))) { | ||
910 | status = nfserr_stale_clientid; | 926 | status = nfserr_stale_clientid; |
911 | goto out; | 927 | } else { |
928 | /* check that we have hit one of the cases...*/ | ||
929 | status = nfserr_clid_inuse; | ||
912 | } | 930 | } |
913 | /* check that we have hit one of the cases...*/ | ||
914 | status = nfserr_inval; | ||
915 | goto out; | ||
916 | out: | 931 | out: |
917 | if (!status) | 932 | if (!status) |
918 | nfsd4_probe_callback(clp); | 933 | nfsd4_probe_callback(conf); |
919 | nfs4_unlock_state(); | 934 | nfs4_unlock_state(); |
920 | return status; | 935 | return status; |
921 | } | 936 | } |
@@ -961,60 +976,65 @@ alloc_init_file(struct inode *ino) | |||
961 | struct nfs4_file *fp; | 976 | struct nfs4_file *fp; |
962 | unsigned int hashval = file_hashval(ino); | 977 | unsigned int hashval = file_hashval(ino); |
963 | 978 | ||
964 | if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) { | 979 | fp = kmem_cache_alloc(file_slab, GFP_KERNEL); |
980 | if (fp) { | ||
981 | kref_init(&fp->fi_ref); | ||
965 | INIT_LIST_HEAD(&fp->fi_hash); | 982 | INIT_LIST_HEAD(&fp->fi_hash); |
966 | INIT_LIST_HEAD(&fp->fi_perfile); | 983 | INIT_LIST_HEAD(&fp->fi_stateids); |
967 | INIT_LIST_HEAD(&fp->fi_del_perfile); | 984 | INIT_LIST_HEAD(&fp->fi_delegations); |
968 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | 985 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); |
969 | fp->fi_inode = igrab(ino); | 986 | fp->fi_inode = igrab(ino); |
970 | fp->fi_id = current_fileid++; | 987 | fp->fi_id = current_fileid++; |
971 | alloc_file++; | ||
972 | return fp; | 988 | return fp; |
973 | } | 989 | } |
974 | return NULL; | 990 | return NULL; |
975 | } | 991 | } |
976 | 992 | ||
977 | static void | 993 | static void |
978 | release_all_files(void) | 994 | nfsd4_free_slab(kmem_cache_t **slab) |
979 | { | 995 | { |
980 | int i; | 996 | int status; |
981 | struct nfs4_file *fp; | ||
982 | 997 | ||
983 | for (i=0;i<FILE_HASH_SIZE;i++) { | 998 | if (*slab == NULL) |
984 | while (!list_empty(&file_hashtbl[i])) { | 999 | return; |
985 | fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash); | 1000 | status = kmem_cache_destroy(*slab); |
986 | /* this should never be more than once... */ | 1001 | *slab = NULL; |
987 | if (!list_empty(&fp->fi_perfile) || !list_empty(&fp->fi_del_perfile)) { | 1002 | WARN_ON(status); |
988 | printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp); | ||
989 | } | ||
990 | release_file(fp); | ||
991 | } | ||
992 | } | ||
993 | } | 1003 | } |
994 | 1004 | ||
995 | kmem_cache_t *stateowner_slab = NULL; | 1005 | static void |
1006 | nfsd4_free_slabs(void) | ||
1007 | { | ||
1008 | nfsd4_free_slab(&stateowner_slab); | ||
1009 | nfsd4_free_slab(&file_slab); | ||
1010 | nfsd4_free_slab(&stateid_slab); | ||
1011 | nfsd4_free_slab(&deleg_slab); | ||
1012 | } | ||
996 | 1013 | ||
997 | static int | 1014 | static int |
998 | nfsd4_init_slabs(void) | 1015 | nfsd4_init_slabs(void) |
999 | { | 1016 | { |
1000 | stateowner_slab = kmem_cache_create("nfsd4_stateowners", | 1017 | stateowner_slab = kmem_cache_create("nfsd4_stateowners", |
1001 | sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL); | 1018 | sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL); |
1002 | if (stateowner_slab == NULL) { | 1019 | if (stateowner_slab == NULL) |
1003 | dprintk("nfsd4: out of memory while initializing nfsv4\n"); | 1020 | goto out_nomem; |
1004 | return -ENOMEM; | 1021 | file_slab = kmem_cache_create("nfsd4_files", |
1005 | } | 1022 | sizeof(struct nfs4_file), 0, 0, NULL, NULL); |
1023 | if (file_slab == NULL) | ||
1024 | goto out_nomem; | ||
1025 | stateid_slab = kmem_cache_create("nfsd4_stateids", | ||
1026 | sizeof(struct nfs4_stateid), 0, 0, NULL, NULL); | ||
1027 | if (stateid_slab == NULL) | ||
1028 | goto out_nomem; | ||
1029 | deleg_slab = kmem_cache_create("nfsd4_delegations", | ||
1030 | sizeof(struct nfs4_delegation), 0, 0, NULL, NULL); | ||
1031 | if (deleg_slab == NULL) | ||
1032 | goto out_nomem; | ||
1006 | return 0; | 1033 | return 0; |
1007 | } | 1034 | out_nomem: |
1008 | 1035 | nfsd4_free_slabs(); | |
1009 | static void | 1036 | dprintk("nfsd4: out of memory while initializing nfsv4\n"); |
1010 | nfsd4_free_slabs(void) | 1037 | return -ENOMEM; |
1011 | { | ||
1012 | int status = 0; | ||
1013 | |||
1014 | if (stateowner_slab) | ||
1015 | status = kmem_cache_destroy(stateowner_slab); | ||
1016 | stateowner_slab = NULL; | ||
1017 | BUG_ON(status); | ||
1018 | } | 1038 | } |
1019 | 1039 | ||
1020 | void | 1040 | void |
@@ -1055,14 +1075,13 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
1055 | INIT_LIST_HEAD(&sop->so_idhash); | 1075 | INIT_LIST_HEAD(&sop->so_idhash); |
1056 | INIT_LIST_HEAD(&sop->so_strhash); | 1076 | INIT_LIST_HEAD(&sop->so_strhash); |
1057 | INIT_LIST_HEAD(&sop->so_perclient); | 1077 | INIT_LIST_HEAD(&sop->so_perclient); |
1058 | INIT_LIST_HEAD(&sop->so_perfilestate); | 1078 | INIT_LIST_HEAD(&sop->so_stateids); |
1059 | INIT_LIST_HEAD(&sop->so_perlockowner); /* not used */ | 1079 | INIT_LIST_HEAD(&sop->so_perstateid); /* not used */ |
1060 | INIT_LIST_HEAD(&sop->so_close_lru); | 1080 | INIT_LIST_HEAD(&sop->so_close_lru); |
1061 | sop->so_time = 0; | 1081 | sop->so_time = 0; |
1062 | list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]); | 1082 | list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]); |
1063 | list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]); | 1083 | list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]); |
1064 | list_add(&sop->so_perclient, &clp->cl_perclient); | 1084 | list_add(&sop->so_perclient, &clp->cl_openowners); |
1065 | add_perclient++; | ||
1066 | sop->so_is_open_owner = 1; | 1085 | sop->so_is_open_owner = 1; |
1067 | sop->so_id = current_ownerid++; | 1086 | sop->so_id = current_ownerid++; |
1068 | sop->so_client = clp; | 1087 | sop->so_client = clp; |
@@ -1080,10 +1099,10 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp) | |||
1080 | { | 1099 | { |
1081 | struct nfs4_stateowner *lock_sop; | 1100 | struct nfs4_stateowner *lock_sop; |
1082 | 1101 | ||
1083 | while (!list_empty(&open_stp->st_perlockowner)) { | 1102 | while (!list_empty(&open_stp->st_lockowners)) { |
1084 | lock_sop = list_entry(open_stp->st_perlockowner.next, | 1103 | lock_sop = list_entry(open_stp->st_lockowners.next, |
1085 | struct nfs4_stateowner, so_perlockowner); | 1104 | struct nfs4_stateowner, so_perstateid); |
1086 | /* list_del(&open_stp->st_perlockowner); */ | 1105 | /* list_del(&open_stp->st_lockowners); */ |
1087 | BUG_ON(lock_sop->so_is_open_owner); | 1106 | BUG_ON(lock_sop->so_is_open_owner); |
1088 | release_stateowner(lock_sop); | 1107 | release_stateowner(lock_sop); |
1089 | } | 1108 | } |
@@ -1096,14 +1115,12 @@ unhash_stateowner(struct nfs4_stateowner *sop) | |||
1096 | 1115 | ||
1097 | list_del(&sop->so_idhash); | 1116 | list_del(&sop->so_idhash); |
1098 | list_del(&sop->so_strhash); | 1117 | list_del(&sop->so_strhash); |
1099 | if (sop->so_is_open_owner) { | 1118 | if (sop->so_is_open_owner) |
1100 | list_del(&sop->so_perclient); | 1119 | list_del(&sop->so_perclient); |
1101 | del_perclient++; | 1120 | list_del(&sop->so_perstateid); |
1102 | } | 1121 | while (!list_empty(&sop->so_stateids)) { |
1103 | list_del(&sop->so_perlockowner); | 1122 | stp = list_entry(sop->so_stateids.next, |
1104 | while (!list_empty(&sop->so_perfilestate)) { | 1123 | struct nfs4_stateid, st_perstateowner); |
1105 | stp = list_entry(sop->so_perfilestate.next, | ||
1106 | struct nfs4_stateid, st_perfilestate); | ||
1107 | if (sop->so_is_open_owner) | 1124 | if (sop->so_is_open_owner) |
1108 | release_stateid(stp, OPEN_STATE); | 1125 | release_stateid(stp, OPEN_STATE); |
1109 | else | 1126 | else |
@@ -1125,14 +1142,14 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
1125 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); | 1142 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); |
1126 | 1143 | ||
1127 | INIT_LIST_HEAD(&stp->st_hash); | 1144 | INIT_LIST_HEAD(&stp->st_hash); |
1128 | INIT_LIST_HEAD(&stp->st_perfilestate); | 1145 | INIT_LIST_HEAD(&stp->st_perstateowner); |
1129 | INIT_LIST_HEAD(&stp->st_perlockowner); | 1146 | INIT_LIST_HEAD(&stp->st_lockowners); |
1130 | INIT_LIST_HEAD(&stp->st_perfile); | 1147 | INIT_LIST_HEAD(&stp->st_perfile); |
1131 | list_add(&stp->st_hash, &stateid_hashtbl[hashval]); | 1148 | list_add(&stp->st_hash, &stateid_hashtbl[hashval]); |
1132 | list_add(&stp->st_perfilestate, &sop->so_perfilestate); | 1149 | list_add(&stp->st_perstateowner, &sop->so_stateids); |
1133 | list_add_perfile++; | 1150 | list_add(&stp->st_perfile, &fp->fi_stateids); |
1134 | list_add(&stp->st_perfile, &fp->fi_perfile); | ||
1135 | stp->st_stateowner = sop; | 1151 | stp->st_stateowner = sop; |
1152 | get_nfs4_file(fp); | ||
1136 | stp->st_file = fp; | 1153 | stp->st_file = fp; |
1137 | stp->st_stateid.si_boot = boot_time; | 1154 | stp->st_stateid.si_boot = boot_time; |
1138 | stp->st_stateid.si_stateownerid = sop->so_id; | 1155 | stp->st_stateid.si_stateownerid = sop->so_id; |
@@ -1150,30 +1167,20 @@ release_stateid(struct nfs4_stateid *stp, int flags) | |||
1150 | struct file *filp = stp->st_vfs_file; | 1167 | struct file *filp = stp->st_vfs_file; |
1151 | 1168 | ||
1152 | list_del(&stp->st_hash); | 1169 | list_del(&stp->st_hash); |
1153 | list_del_perfile++; | ||
1154 | list_del(&stp->st_perfile); | 1170 | list_del(&stp->st_perfile); |
1155 | list_del(&stp->st_perfilestate); | 1171 | list_del(&stp->st_perstateowner); |
1156 | if (flags & OPEN_STATE) { | 1172 | if (flags & OPEN_STATE) { |
1157 | release_stateid_lockowners(stp); | 1173 | release_stateid_lockowners(stp); |
1158 | stp->st_vfs_file = NULL; | 1174 | stp->st_vfs_file = NULL; |
1159 | nfsd_close(filp); | 1175 | nfsd_close(filp); |
1160 | vfsclose++; | ||
1161 | } else if (flags & LOCK_STATE) | 1176 | } else if (flags & LOCK_STATE) |
1162 | locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); | 1177 | locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); |
1163 | kfree(stp); | 1178 | put_nfs4_file(stp->st_file); |
1179 | kmem_cache_free(stateid_slab, stp); | ||
1164 | stp = NULL; | 1180 | stp = NULL; |
1165 | } | 1181 | } |
1166 | 1182 | ||
1167 | static void | 1183 | static void |
1168 | release_file(struct nfs4_file *fp) | ||
1169 | { | ||
1170 | free_file++; | ||
1171 | list_del(&fp->fi_hash); | ||
1172 | iput(fp->fi_inode); | ||
1173 | kfree(fp); | ||
1174 | } | ||
1175 | |||
1176 | void | ||
1177 | move_to_close_lru(struct nfs4_stateowner *sop) | 1184 | move_to_close_lru(struct nfs4_stateowner *sop) |
1178 | { | 1185 | { |
1179 | dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop); | 1186 | dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop); |
@@ -1183,11 +1190,10 @@ move_to_close_lru(struct nfs4_stateowner *sop) | |||
1183 | sop->so_time = get_seconds(); | 1190 | sop->so_time = get_seconds(); |
1184 | } | 1191 | } |
1185 | 1192 | ||
1186 | void | 1193 | static void |
1187 | release_state_owner(struct nfs4_stateid *stp, int flag) | 1194 | release_state_owner(struct nfs4_stateid *stp, int flag) |
1188 | { | 1195 | { |
1189 | struct nfs4_stateowner *sop = stp->st_stateowner; | 1196 | struct nfs4_stateowner *sop = stp->st_stateowner; |
1190 | struct nfs4_file *fp = stp->st_file; | ||
1191 | 1197 | ||
1192 | dprintk("NFSD: release_state_owner\n"); | 1198 | dprintk("NFSD: release_state_owner\n"); |
1193 | release_stateid(stp, flag); | 1199 | release_stateid(stp, flag); |
@@ -1196,12 +1202,8 @@ release_state_owner(struct nfs4_stateid *stp, int flag) | |||
1196 | * released by the laundromat service after the lease period | 1202 | * released by the laundromat service after the lease period |
1197 | * to enable us to handle CLOSE replay | 1203 | * to enable us to handle CLOSE replay |
1198 | */ | 1204 | */ |
1199 | if (sop->so_confirmed && list_empty(&sop->so_perfilestate)) | 1205 | if (sop->so_confirmed && list_empty(&sop->so_stateids)) |
1200 | move_to_close_lru(sop); | 1206 | move_to_close_lru(sop); |
1201 | /* unused nfs4_file's are releseed. XXX slab cache? */ | ||
1202 | if (list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile)) { | ||
1203 | release_file(fp); | ||
1204 | } | ||
1205 | } | 1207 | } |
1206 | 1208 | ||
1207 | static int | 1209 | static int |
@@ -1231,8 +1233,10 @@ find_file(struct inode *ino) | |||
1231 | struct nfs4_file *fp; | 1233 | struct nfs4_file *fp; |
1232 | 1234 | ||
1233 | list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { | 1235 | list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { |
1234 | if (fp->fi_inode == ino) | 1236 | if (fp->fi_inode == ino) { |
1237 | get_nfs4_file(fp); | ||
1235 | return fp; | 1238 | return fp; |
1239 | } | ||
1236 | } | 1240 | } |
1237 | return NULL; | 1241 | return NULL; |
1238 | } | 1242 | } |
@@ -1240,7 +1244,7 @@ find_file(struct inode *ino) | |||
1240 | #define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0) | 1244 | #define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0) |
1241 | #define TEST_DENY(x) ((x >= 0 || x < 5)?1:0) | 1245 | #define TEST_DENY(x) ((x >= 0 || x < 5)?1:0) |
1242 | 1246 | ||
1243 | void | 1247 | static void |
1244 | set_access(unsigned int *access, unsigned long bmap) { | 1248 | set_access(unsigned int *access, unsigned long bmap) { |
1245 | int i; | 1249 | int i; |
1246 | 1250 | ||
@@ -1251,7 +1255,7 @@ set_access(unsigned int *access, unsigned long bmap) { | |||
1251 | } | 1255 | } |
1252 | } | 1256 | } |
1253 | 1257 | ||
1254 | void | 1258 | static void |
1255 | set_deny(unsigned int *deny, unsigned long bmap) { | 1259 | set_deny(unsigned int *deny, unsigned long bmap) { |
1256 | int i; | 1260 | int i; |
1257 | 1261 | ||
@@ -1277,25 +1281,30 @@ test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | |||
1277 | * Called to check deny when READ with all zero stateid or | 1281 | * Called to check deny when READ with all zero stateid or |
1278 | * WRITE with all zero or all one stateid | 1282 | * WRITE with all zero or all one stateid |
1279 | */ | 1283 | */ |
1280 | int | 1284 | static int |
1281 | nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) | 1285 | nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) |
1282 | { | 1286 | { |
1283 | struct inode *ino = current_fh->fh_dentry->d_inode; | 1287 | struct inode *ino = current_fh->fh_dentry->d_inode; |
1284 | struct nfs4_file *fp; | 1288 | struct nfs4_file *fp; |
1285 | struct nfs4_stateid *stp; | 1289 | struct nfs4_stateid *stp; |
1290 | int ret; | ||
1286 | 1291 | ||
1287 | dprintk("NFSD: nfs4_share_conflict\n"); | 1292 | dprintk("NFSD: nfs4_share_conflict\n"); |
1288 | 1293 | ||
1289 | fp = find_file(ino); | 1294 | fp = find_file(ino); |
1290 | if (fp) { | 1295 | if (!fp) |
1296 | return nfs_ok; | ||
1297 | ret = nfserr_share_denied; | ||
1291 | /* Search for conflicting share reservations */ | 1298 | /* Search for conflicting share reservations */ |
1292 | list_for_each_entry(stp, &fp->fi_perfile, st_perfile) { | 1299 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { |
1293 | if (test_bit(deny_type, &stp->st_deny_bmap) || | 1300 | if (test_bit(deny_type, &stp->st_deny_bmap) || |
1294 | test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) | 1301 | test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) |
1295 | return nfserr_share_denied; | 1302 | goto out; |
1296 | } | ||
1297 | } | 1303 | } |
1298 | return nfs_ok; | 1304 | ret = nfs_ok; |
1305 | out: | ||
1306 | put_nfs4_file(fp); | ||
1307 | return ret; | ||
1299 | } | 1308 | } |
1300 | 1309 | ||
1301 | static inline void | 1310 | static inline void |
@@ -1427,7 +1436,7 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | |||
1427 | return -EAGAIN; | 1436 | return -EAGAIN; |
1428 | } | 1437 | } |
1429 | 1438 | ||
1430 | struct lock_manager_operations nfsd_lease_mng_ops = { | 1439 | static struct lock_manager_operations nfsd_lease_mng_ops = { |
1431 | .fl_break = nfsd_break_deleg_cb, | 1440 | .fl_break = nfsd_break_deleg_cb, |
1432 | .fl_release_private = nfsd_release_deleg_cb, | 1441 | .fl_release_private = nfsd_release_deleg_cb, |
1433 | .fl_copy_lock = nfsd_copy_lock_deleg_cb, | 1442 | .fl_copy_lock = nfsd_copy_lock_deleg_cb, |
@@ -1526,6 +1535,51 @@ out: | |||
1526 | return status; | 1535 | return status; |
1527 | } | 1536 | } |
1528 | 1537 | ||
1538 | static inline int | ||
1539 | nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) | ||
1540 | { | ||
1541 | if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) | ||
1542 | return nfserr_openmode; | ||
1543 | else | ||
1544 | return nfs_ok; | ||
1545 | } | ||
1546 | |||
1547 | static struct nfs4_delegation * | ||
1548 | find_delegation_file(struct nfs4_file *fp, stateid_t *stid) | ||
1549 | { | ||
1550 | struct nfs4_delegation *dp; | ||
1551 | |||
1552 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) { | ||
1553 | if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) | ||
1554 | return dp; | ||
1555 | } | ||
1556 | return NULL; | ||
1557 | } | ||
1558 | |||
1559 | static int | ||
1560 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, | ||
1561 | struct nfs4_delegation **dp) | ||
1562 | { | ||
1563 | int flags; | ||
1564 | int status = nfserr_bad_stateid; | ||
1565 | |||
1566 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); | ||
1567 | if (*dp == NULL) | ||
1568 | goto out; | ||
1569 | flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ? | ||
1570 | RD_STATE : WR_STATE; | ||
1571 | status = nfs4_check_delegmode(*dp, flags); | ||
1572 | if (status) | ||
1573 | *dp = NULL; | ||
1574 | out: | ||
1575 | if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR) | ||
1576 | return nfs_ok; | ||
1577 | if (status) | ||
1578 | return status; | ||
1579 | open->op_stateowner->so_confirmed = 1; | ||
1580 | return nfs_ok; | ||
1581 | } | ||
1582 | |||
1529 | static int | 1583 | static int |
1530 | nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp) | 1584 | nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp) |
1531 | { | 1585 | { |
@@ -1533,7 +1587,7 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_state | |||
1533 | int status = nfserr_share_denied; | 1587 | int status = nfserr_share_denied; |
1534 | struct nfs4_stateowner *sop = open->op_stateowner; | 1588 | struct nfs4_stateowner *sop = open->op_stateowner; |
1535 | 1589 | ||
1536 | list_for_each_entry(local, &fp->fi_perfile, st_perfile) { | 1590 | list_for_each_entry(local, &fp->fi_stateids, st_perfile) { |
1537 | /* ignore lock owners */ | 1591 | /* ignore lock owners */ |
1538 | if (local->st_stateowner->so_is_open_owner == 0) | 1592 | if (local->st_stateowner->so_is_open_owner == 0) |
1539 | continue; | 1593 | continue; |
@@ -1549,25 +1603,37 @@ out: | |||
1549 | return status; | 1603 | return status; |
1550 | } | 1604 | } |
1551 | 1605 | ||
1606 | static inline struct nfs4_stateid * | ||
1607 | nfs4_alloc_stateid(void) | ||
1608 | { | ||
1609 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); | ||
1610 | } | ||
1611 | |||
1552 | static int | 1612 | static int |
1553 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, | 1613 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, |
1614 | struct nfs4_delegation *dp, | ||
1554 | struct svc_fh *cur_fh, int flags) | 1615 | struct svc_fh *cur_fh, int flags) |
1555 | { | 1616 | { |
1556 | struct nfs4_stateid *stp; | 1617 | struct nfs4_stateid *stp; |
1557 | int status; | ||
1558 | 1618 | ||
1559 | stp = kmalloc(sizeof(struct nfs4_stateid), GFP_KERNEL); | 1619 | stp = nfs4_alloc_stateid(); |
1560 | if (stp == NULL) | 1620 | if (stp == NULL) |
1561 | return nfserr_resource; | 1621 | return nfserr_resource; |
1562 | 1622 | ||
1563 | status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, &stp->st_vfs_file); | 1623 | if (dp) { |
1564 | if (status) { | 1624 | get_file(dp->dl_vfs_file); |
1565 | if (status == nfserr_dropit) | 1625 | stp->st_vfs_file = dp->dl_vfs_file; |
1566 | status = nfserr_jukebox; | 1626 | } else { |
1567 | kfree(stp); | 1627 | int status; |
1568 | return status; | 1628 | status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, |
1629 | &stp->st_vfs_file); | ||
1630 | if (status) { | ||
1631 | if (status == nfserr_dropit) | ||
1632 | status = nfserr_jukebox; | ||
1633 | kmem_cache_free(stateid_slab, stp); | ||
1634 | return status; | ||
1635 | } | ||
1569 | } | 1636 | } |
1570 | vfsopen++; | ||
1571 | *stpp = stp; | 1637 | *stpp = stp; |
1572 | return 0; | 1638 | return 0; |
1573 | } | 1639 | } |
@@ -1628,6 +1694,7 @@ nfs4_set_claim_prev(struct nfsd4_open *open, int *status) | |||
1628 | *status = nfserr_reclaim_bad; | 1694 | *status = nfserr_reclaim_bad; |
1629 | else { | 1695 | else { |
1630 | open->op_stateowner->so_confirmed = 1; | 1696 | open->op_stateowner->so_confirmed = 1; |
1697 | open->op_stateowner->so_client->cl_firststate = 1; | ||
1631 | open->op_stateowner->so_seqid--; | 1698 | open->op_stateowner->so_seqid--; |
1632 | } | 1699 | } |
1633 | } | 1700 | } |
@@ -1646,14 +1713,30 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
1646 | int status, flag = 0; | 1713 | int status, flag = 0; |
1647 | 1714 | ||
1648 | flag = NFS4_OPEN_DELEGATE_NONE; | 1715 | flag = NFS4_OPEN_DELEGATE_NONE; |
1649 | if (open->op_claim_type != NFS4_OPEN_CLAIM_NULL | 1716 | open->op_recall = 0; |
1650 | || !atomic_read(&cb->cb_set) || !sop->so_confirmed) | 1717 | switch (open->op_claim_type) { |
1651 | goto out; | 1718 | case NFS4_OPEN_CLAIM_PREVIOUS: |
1652 | 1719 | if (!atomic_read(&cb->cb_set)) | |
1653 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 1720 | open->op_recall = 1; |
1654 | flag = NFS4_OPEN_DELEGATE_WRITE; | 1721 | flag = open->op_delegate_type; |
1655 | else | 1722 | if (flag == NFS4_OPEN_DELEGATE_NONE) |
1656 | flag = NFS4_OPEN_DELEGATE_READ; | 1723 | goto out; |
1724 | break; | ||
1725 | case NFS4_OPEN_CLAIM_NULL: | ||
1726 | /* Let's not give out any delegations till everyone's | ||
1727 | * had the chance to reclaim theirs.... */ | ||
1728 | if (nfs4_in_grace()) | ||
1729 | goto out; | ||
1730 | if (!atomic_read(&cb->cb_set) || !sop->so_confirmed) | ||
1731 | goto out; | ||
1732 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | ||
1733 | flag = NFS4_OPEN_DELEGATE_WRITE; | ||
1734 | else | ||
1735 | flag = NFS4_OPEN_DELEGATE_READ; | ||
1736 | break; | ||
1737 | default: | ||
1738 | goto out; | ||
1739 | } | ||
1657 | 1740 | ||
1658 | dp = alloc_init_deleg(sop->so_client, stp, fh, flag); | 1741 | dp = alloc_init_deleg(sop->so_client, stp, fh, flag); |
1659 | if (dp == NULL) { | 1742 | if (dp == NULL) { |
@@ -1687,6 +1770,10 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
1687 | dp->dl_stateid.si_fileid, | 1770 | dp->dl_stateid.si_fileid, |
1688 | dp->dl_stateid.si_generation); | 1771 | dp->dl_stateid.si_generation); |
1689 | out: | 1772 | out: |
1773 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS | ||
1774 | && flag == NFS4_OPEN_DELEGATE_NONE | ||
1775 | && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | ||
1776 | printk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
1690 | open->op_delegate_type = flag; | 1777 | open->op_delegate_type = flag; |
1691 | } | 1778 | } |
1692 | 1779 | ||
@@ -1699,6 +1786,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1699 | struct nfs4_file *fp = NULL; | 1786 | struct nfs4_file *fp = NULL; |
1700 | struct inode *ino = current_fh->fh_dentry->d_inode; | 1787 | struct inode *ino = current_fh->fh_dentry->d_inode; |
1701 | struct nfs4_stateid *stp = NULL; | 1788 | struct nfs4_stateid *stp = NULL; |
1789 | struct nfs4_delegation *dp = NULL; | ||
1702 | int status; | 1790 | int status; |
1703 | 1791 | ||
1704 | status = nfserr_inval; | 1792 | status = nfserr_inval; |
@@ -1713,7 +1801,13 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1713 | if (fp) { | 1801 | if (fp) { |
1714 | if ((status = nfs4_check_open(fp, open, &stp))) | 1802 | if ((status = nfs4_check_open(fp, open, &stp))) |
1715 | goto out; | 1803 | goto out; |
1804 | status = nfs4_check_deleg(fp, open, &dp); | ||
1805 | if (status) | ||
1806 | goto out; | ||
1716 | } else { | 1807 | } else { |
1808 | status = nfserr_bad_stateid; | ||
1809 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | ||
1810 | goto out; | ||
1717 | status = nfserr_resource; | 1811 | status = nfserr_resource; |
1718 | fp = alloc_init_file(ino); | 1812 | fp = alloc_init_file(ino); |
1719 | if (fp == NULL) | 1813 | if (fp == NULL) |
@@ -1736,7 +1830,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1736 | flags = MAY_WRITE; | 1830 | flags = MAY_WRITE; |
1737 | else | 1831 | else |
1738 | flags = MAY_READ; | 1832 | flags = MAY_READ; |
1739 | if ((status = nfs4_new_open(rqstp, &stp, current_fh, flags))) | 1833 | status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags); |
1834 | if (status) | ||
1740 | goto out; | 1835 | goto out; |
1741 | init_stateid(stp, fp, open); | 1836 | init_stateid(stp, fp, open); |
1742 | status = nfsd4_truncate(rqstp, current_fh, open); | 1837 | status = nfsd4_truncate(rqstp, current_fh, open); |
@@ -1759,10 +1854,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1759 | stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid, | 1854 | stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid, |
1760 | stp->st_stateid.si_fileid, stp->st_stateid.si_generation); | 1855 | stp->st_stateid.si_fileid, stp->st_stateid.si_generation); |
1761 | out: | 1856 | out: |
1762 | /* take the opportunity to clean up unused state */ | 1857 | if (fp) |
1763 | if (fp && list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile)) | 1858 | put_nfs4_file(fp); |
1764 | release_file(fp); | ||
1765 | |||
1766 | /* CLAIM_PREVIOUS has different error returns */ | 1859 | /* CLAIM_PREVIOUS has different error returns */ |
1767 | nfs4_set_claim_prev(open, &status); | 1860 | nfs4_set_claim_prev(open, &status); |
1768 | /* | 1861 | /* |
@@ -1775,6 +1868,7 @@ out: | |||
1775 | return status; | 1868 | return status; |
1776 | } | 1869 | } |
1777 | 1870 | ||
1871 | static struct workqueue_struct *laundry_wq; | ||
1778 | static struct work_struct laundromat_work; | 1872 | static struct work_struct laundromat_work; |
1779 | static void laundromat_main(void *); | 1873 | static void laundromat_main(void *); |
1780 | static DECLARE_WORK(laundromat_work, laundromat_main, NULL); | 1874 | static DECLARE_WORK(laundromat_work, laundromat_main, NULL); |
@@ -1800,7 +1894,7 @@ nfsd4_renew(clientid_t *clid) | |||
1800 | } | 1894 | } |
1801 | renew_client(clp); | 1895 | renew_client(clp); |
1802 | status = nfserr_cb_path_down; | 1896 | status = nfserr_cb_path_down; |
1803 | if (!list_empty(&clp->cl_del_perclnt) | 1897 | if (!list_empty(&clp->cl_delegations) |
1804 | && !atomic_read(&clp->cl_callback.cb_set)) | 1898 | && !atomic_read(&clp->cl_callback.cb_set)) |
1805 | goto out; | 1899 | goto out; |
1806 | status = nfs_ok; | 1900 | status = nfs_ok; |
@@ -1809,7 +1903,15 @@ out: | |||
1809 | return status; | 1903 | return status; |
1810 | } | 1904 | } |
1811 | 1905 | ||
1812 | time_t | 1906 | static void |
1907 | end_grace(void) | ||
1908 | { | ||
1909 | dprintk("NFSD: end of grace period\n"); | ||
1910 | nfsd4_recdir_purge_old(); | ||
1911 | in_grace = 0; | ||
1912 | } | ||
1913 | |||
1914 | static time_t | ||
1813 | nfs4_laundromat(void) | 1915 | nfs4_laundromat(void) |
1814 | { | 1916 | { |
1815 | struct nfs4_client *clp; | 1917 | struct nfs4_client *clp; |
@@ -1823,6 +1925,8 @@ nfs4_laundromat(void) | |||
1823 | nfs4_lock_state(); | 1925 | nfs4_lock_state(); |
1824 | 1926 | ||
1825 | dprintk("NFSD: laundromat service - starting\n"); | 1927 | dprintk("NFSD: laundromat service - starting\n"); |
1928 | if (in_grace) | ||
1929 | end_grace(); | ||
1826 | list_for_each_safe(pos, next, &client_lru) { | 1930 | list_for_each_safe(pos, next, &client_lru) { |
1827 | clp = list_entry(pos, struct nfs4_client, cl_lru); | 1931 | clp = list_entry(pos, struct nfs4_client, cl_lru); |
1828 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { | 1932 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { |
@@ -1833,6 +1937,7 @@ nfs4_laundromat(void) | |||
1833 | } | 1937 | } |
1834 | dprintk("NFSD: purging unused client (clientid %08x)\n", | 1938 | dprintk("NFSD: purging unused client (clientid %08x)\n", |
1835 | clp->cl_clientid.cl_id); | 1939 | clp->cl_clientid.cl_id); |
1940 | nfsd4_remove_clid_dir(clp); | ||
1836 | expire_client(clp); | 1941 | expire_client(clp); |
1837 | } | 1942 | } |
1838 | INIT_LIST_HEAD(&reaplist); | 1943 | INIT_LIST_HEAD(&reaplist); |
@@ -1882,13 +1987,13 @@ laundromat_main(void *not_used) | |||
1882 | 1987 | ||
1883 | t = nfs4_laundromat(); | 1988 | t = nfs4_laundromat(); |
1884 | dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); | 1989 | dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); |
1885 | schedule_delayed_work(&laundromat_work, t*HZ); | 1990 | queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); |
1886 | } | 1991 | } |
1887 | 1992 | ||
1888 | /* search ownerid_hashtbl[] and close_lru for stateid owner | 1993 | /* search ownerid_hashtbl[] and close_lru for stateid owner |
1889 | * (stateid->si_stateownerid) | 1994 | * (stateid->si_stateownerid) |
1890 | */ | 1995 | */ |
1891 | struct nfs4_stateowner * | 1996 | static struct nfs4_stateowner * |
1892 | find_openstateowner_id(u32 st_id, int flags) { | 1997 | find_openstateowner_id(u32 st_id, int flags) { |
1893 | struct nfs4_stateowner *local = NULL; | 1998 | struct nfs4_stateowner *local = NULL; |
1894 | 1999 | ||
@@ -1949,15 +2054,6 @@ out: | |||
1949 | } | 2054 | } |
1950 | 2055 | ||
1951 | static inline int | 2056 | static inline int |
1952 | nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) | ||
1953 | { | ||
1954 | if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) | ||
1955 | return nfserr_openmode; | ||
1956 | else | ||
1957 | return nfs_ok; | ||
1958 | } | ||
1959 | |||
1960 | static inline int | ||
1961 | check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) | 2057 | check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) |
1962 | { | 2058 | { |
1963 | /* Trying to call delegreturn with a special stateid? Yuch: */ | 2059 | /* Trying to call delegreturn with a special stateid? Yuch: */ |
@@ -2071,7 +2167,7 @@ out: | |||
2071 | /* | 2167 | /* |
2072 | * Checks for sequence id mutating operations. | 2168 | * Checks for sequence id mutating operations. |
2073 | */ | 2169 | */ |
2074 | int | 2170 | static int |
2075 | nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid) | 2171 | nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid) |
2076 | { | 2172 | { |
2077 | int status; | 2173 | int status; |
@@ -2230,6 +2326,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs | |||
2230 | stp->st_stateid.si_stateownerid, | 2326 | stp->st_stateid.si_stateownerid, |
2231 | stp->st_stateid.si_fileid, | 2327 | stp->st_stateid.si_fileid, |
2232 | stp->st_stateid.si_generation); | 2328 | stp->st_stateid.si_generation); |
2329 | |||
2330 | nfsd4_create_clid_dir(sop->so_client); | ||
2233 | out: | 2331 | out: |
2234 | if (oc->oc_stateowner) | 2332 | if (oc->oc_stateowner) |
2235 | nfs4_get_stateowner(oc->oc_stateowner); | 2333 | nfs4_get_stateowner(oc->oc_stateowner); |
@@ -2387,7 +2485,7 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE]; | |||
2387 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; | 2485 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; |
2388 | static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; | 2486 | static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; |
2389 | 2487 | ||
2390 | struct nfs4_stateid * | 2488 | static struct nfs4_stateid * |
2391 | find_stateid(stateid_t *stid, int flags) | 2489 | find_stateid(stateid_t *stid, int flags) |
2392 | { | 2490 | { |
2393 | struct nfs4_stateid *local = NULL; | 2491 | struct nfs4_stateid *local = NULL; |
@@ -2419,25 +2517,19 @@ find_stateid(stateid_t *stid, int flags) | |||
2419 | static struct nfs4_delegation * | 2517 | static struct nfs4_delegation * |
2420 | find_delegation_stateid(struct inode *ino, stateid_t *stid) | 2518 | find_delegation_stateid(struct inode *ino, stateid_t *stid) |
2421 | { | 2519 | { |
2422 | struct nfs4_delegation *dp = NULL; | 2520 | struct nfs4_file *fp; |
2423 | struct nfs4_file *fp = NULL; | 2521 | struct nfs4_delegation *dl; |
2424 | u32 st_id; | ||
2425 | 2522 | ||
2426 | dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n", | 2523 | dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n", |
2427 | stid->si_boot, stid->si_stateownerid, | 2524 | stid->si_boot, stid->si_stateownerid, |
2428 | stid->si_fileid, stid->si_generation); | 2525 | stid->si_fileid, stid->si_generation); |
2429 | 2526 | ||
2430 | st_id = stid->si_stateownerid; | ||
2431 | fp = find_file(ino); | 2527 | fp = find_file(ino); |
2432 | if (fp) { | 2528 | if (!fp) |
2433 | list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) { | 2529 | return NULL; |
2434 | if(dp->dl_stateid.si_stateownerid == st_id) { | 2530 | dl = find_delegation_file(fp, stid); |
2435 | dprintk("NFSD: find_delegation dp %p\n",dp); | 2531 | put_nfs4_file(fp); |
2436 | return dp; | 2532 | return dl; |
2437 | } | ||
2438 | } | ||
2439 | } | ||
2440 | return NULL; | ||
2441 | } | 2533 | } |
2442 | 2534 | ||
2443 | /* | 2535 | /* |
@@ -2457,7 +2549,7 @@ nfs4_transform_lock_offset(struct file_lock *lock) | |||
2457 | lock->fl_end = OFFSET_MAX; | 2549 | lock->fl_end = OFFSET_MAX; |
2458 | } | 2550 | } |
2459 | 2551 | ||
2460 | int | 2552 | static int |
2461 | nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval) | 2553 | nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval) |
2462 | { | 2554 | { |
2463 | struct nfs4_stateowner *local = NULL; | 2555 | struct nfs4_stateowner *local = NULL; |
@@ -2498,22 +2590,6 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) | |||
2498 | } | 2590 | } |
2499 | 2591 | ||
2500 | static struct nfs4_stateowner * | 2592 | static struct nfs4_stateowner * |
2501 | find_lockstateowner(struct xdr_netobj *owner, clientid_t *clid) | ||
2502 | { | ||
2503 | struct nfs4_stateowner *local = NULL; | ||
2504 | int i; | ||
2505 | |||
2506 | for (i = 0; i < LOCK_HASH_SIZE; i++) { | ||
2507 | list_for_each_entry(local, &lock_ownerid_hashtbl[i], so_idhash) { | ||
2508 | if (!cmp_owner_str(local, owner, clid)) | ||
2509 | continue; | ||
2510 | return local; | ||
2511 | } | ||
2512 | } | ||
2513 | return NULL; | ||
2514 | } | ||
2515 | |||
2516 | static struct nfs4_stateowner * | ||
2517 | find_lockstateowner_str(struct inode *inode, clientid_t *clid, | 2593 | find_lockstateowner_str(struct inode *inode, clientid_t *clid, |
2518 | struct xdr_netobj *owner) | 2594 | struct xdr_netobj *owner) |
2519 | { | 2595 | { |
@@ -2548,13 +2624,13 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
2548 | INIT_LIST_HEAD(&sop->so_idhash); | 2624 | INIT_LIST_HEAD(&sop->so_idhash); |
2549 | INIT_LIST_HEAD(&sop->so_strhash); | 2625 | INIT_LIST_HEAD(&sop->so_strhash); |
2550 | INIT_LIST_HEAD(&sop->so_perclient); | 2626 | INIT_LIST_HEAD(&sop->so_perclient); |
2551 | INIT_LIST_HEAD(&sop->so_perfilestate); | 2627 | INIT_LIST_HEAD(&sop->so_stateids); |
2552 | INIT_LIST_HEAD(&sop->so_perlockowner); | 2628 | INIT_LIST_HEAD(&sop->so_perstateid); |
2553 | INIT_LIST_HEAD(&sop->so_close_lru); /* not used */ | 2629 | INIT_LIST_HEAD(&sop->so_close_lru); /* not used */ |
2554 | sop->so_time = 0; | 2630 | sop->so_time = 0; |
2555 | list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]); | 2631 | list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]); |
2556 | list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]); | 2632 | list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]); |
2557 | list_add(&sop->so_perlockowner, &open_stp->st_perlockowner); | 2633 | list_add(&sop->so_perstateid, &open_stp->st_lockowners); |
2558 | sop->so_is_open_owner = 0; | 2634 | sop->so_is_open_owner = 0; |
2559 | sop->so_id = current_ownerid++; | 2635 | sop->so_id = current_ownerid++; |
2560 | sop->so_client = clp; | 2636 | sop->so_client = clp; |
@@ -2567,24 +2643,24 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
2567 | return sop; | 2643 | return sop; |
2568 | } | 2644 | } |
2569 | 2645 | ||
2570 | struct nfs4_stateid * | 2646 | static struct nfs4_stateid * |
2571 | alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp) | 2647 | alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp) |
2572 | { | 2648 | { |
2573 | struct nfs4_stateid *stp; | 2649 | struct nfs4_stateid *stp; |
2574 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); | 2650 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); |
2575 | 2651 | ||
2576 | if ((stp = kmalloc(sizeof(struct nfs4_stateid), | 2652 | stp = nfs4_alloc_stateid(); |
2577 | GFP_KERNEL)) == NULL) | 2653 | if (stp == NULL) |
2578 | goto out; | 2654 | goto out; |
2579 | INIT_LIST_HEAD(&stp->st_hash); | 2655 | INIT_LIST_HEAD(&stp->st_hash); |
2580 | INIT_LIST_HEAD(&stp->st_perfile); | 2656 | INIT_LIST_HEAD(&stp->st_perfile); |
2581 | INIT_LIST_HEAD(&stp->st_perfilestate); | 2657 | INIT_LIST_HEAD(&stp->st_perstateowner); |
2582 | INIT_LIST_HEAD(&stp->st_perlockowner); /* not used */ | 2658 | INIT_LIST_HEAD(&stp->st_lockowners); /* not used */ |
2583 | list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]); | 2659 | list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]); |
2584 | list_add(&stp->st_perfile, &fp->fi_perfile); | 2660 | list_add(&stp->st_perfile, &fp->fi_stateids); |
2585 | list_add_perfile++; | 2661 | list_add(&stp->st_perstateowner, &sop->so_stateids); |
2586 | list_add(&stp->st_perfilestate, &sop->so_perfilestate); | ||
2587 | stp->st_stateowner = sop; | 2662 | stp->st_stateowner = sop; |
2663 | get_nfs4_file(fp); | ||
2588 | stp->st_file = fp; | 2664 | stp->st_file = fp; |
2589 | stp->st_stateid.si_boot = boot_time; | 2665 | stp->st_stateid.si_boot = boot_time; |
2590 | stp->st_stateid.si_stateownerid = sop->so_id; | 2666 | stp->st_stateid.si_stateownerid = sop->so_id; |
@@ -2598,7 +2674,7 @@ out: | |||
2598 | return stp; | 2674 | return stp; |
2599 | } | 2675 | } |
2600 | 2676 | ||
2601 | int | 2677 | static int |
2602 | check_lock_length(u64 offset, u64 length) | 2678 | check_lock_length(u64 offset, u64 length) |
2603 | { | 2679 | { |
2604 | return ((length == 0) || ((length != ~(u64)0) && | 2680 | return ((length == 0) || ((length != ~(u64)0) && |
@@ -2611,7 +2687,7 @@ check_lock_length(u64 offset, u64 length) | |||
2611 | int | 2687 | int |
2612 | nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) | 2688 | nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) |
2613 | { | 2689 | { |
2614 | struct nfs4_stateowner *lock_sop = NULL, *open_sop = NULL; | 2690 | struct nfs4_stateowner *open_sop = NULL; |
2615 | struct nfs4_stateid *lock_stp; | 2691 | struct nfs4_stateid *lock_stp; |
2616 | struct file *filp; | 2692 | struct file *filp; |
2617 | struct file_lock file_lock; | 2693 | struct file_lock file_lock; |
@@ -2670,16 +2746,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2670 | strhashval = lock_ownerstr_hashval(fp->fi_inode, | 2746 | strhashval = lock_ownerstr_hashval(fp->fi_inode, |
2671 | open_sop->so_client->cl_clientid.cl_id, | 2747 | open_sop->so_client->cl_clientid.cl_id, |
2672 | &lock->v.new.owner); | 2748 | &lock->v.new.owner); |
2673 | /* | 2749 | /* XXX: Do we need to check for duplicate stateowners on |
2674 | * If we already have this lock owner, the client is in | 2750 | * the same file, or should they just be allowed (and |
2675 | * error (or our bookeeping is wrong!) | 2751 | * create new stateids)? */ |
2676 | * for asking for a 'new lock'. | ||
2677 | */ | ||
2678 | status = nfserr_bad_stateid; | ||
2679 | lock_sop = find_lockstateowner(&lock->v.new.owner, | ||
2680 | &lock->v.new.clientid); | ||
2681 | if (lock_sop) | ||
2682 | goto out; | ||
2683 | status = nfserr_resource; | 2752 | status = nfserr_resource; |
2684 | if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock))) | 2753 | if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock))) |
2685 | goto out; | 2754 | goto out; |
@@ -2970,8 +3039,11 @@ int | |||
2970 | nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) | 3039 | nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) |
2971 | { | 3040 | { |
2972 | clientid_t *clid = &rlockowner->rl_clientid; | 3041 | clientid_t *clid = &rlockowner->rl_clientid; |
2973 | struct nfs4_stateowner *local = NULL; | 3042 | struct nfs4_stateowner *sop; |
3043 | struct nfs4_stateid *stp; | ||
2974 | struct xdr_netobj *owner = &rlockowner->rl_owner; | 3044 | struct xdr_netobj *owner = &rlockowner->rl_owner; |
3045 | struct list_head matches; | ||
3046 | int i; | ||
2975 | int status; | 3047 | int status; |
2976 | 3048 | ||
2977 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", | 3049 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", |
@@ -2987,22 +3059,32 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner * | |||
2987 | 3059 | ||
2988 | nfs4_lock_state(); | 3060 | nfs4_lock_state(); |
2989 | 3061 | ||
2990 | status = nfs_ok; | 3062 | status = nfserr_locks_held; |
2991 | local = find_lockstateowner(owner, clid); | 3063 | /* XXX: we're doing a linear search through all the lockowners. |
2992 | if (local) { | 3064 | * Yipes! For now we'll just hope clients aren't really using |
2993 | struct nfs4_stateid *stp; | 3065 | * release_lockowner much, but eventually we have to fix these |
2994 | 3066 | * data structures. */ | |
2995 | /* check for any locks held by any stateid | 3067 | INIT_LIST_HEAD(&matches); |
2996 | * associated with the (lock) stateowner */ | 3068 | for (i = 0; i < LOCK_HASH_SIZE; i++) { |
2997 | status = nfserr_locks_held; | 3069 | list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) { |
2998 | list_for_each_entry(stp, &local->so_perfilestate, | 3070 | if (!cmp_owner_str(sop, owner, clid)) |
2999 | st_perfilestate) { | 3071 | continue; |
3000 | if (check_for_locks(stp->st_vfs_file, local)) | 3072 | list_for_each_entry(stp, &sop->so_stateids, |
3001 | goto out; | 3073 | st_perstateowner) { |
3074 | if (check_for_locks(stp->st_vfs_file, sop)) | ||
3075 | goto out; | ||
3076 | /* Note: so_perclient unused for lockowners, | ||
3077 | * so it's OK to fool with here. */ | ||
3078 | list_add(&sop->so_perclient, &matches); | ||
3079 | } | ||
3002 | } | 3080 | } |
3003 | /* no locks held by (lock) stateowner */ | 3081 | } |
3004 | status = nfs_ok; | 3082 | /* Clients probably won't expect us to return with some (but not all) |
3005 | release_stateowner(local); | 3083 | * of the lockowner state released; so don't release any until all |
3084 | * have been checked. */ | ||
3085 | status = nfs_ok; | ||
3086 | list_for_each_entry(sop, &matches, so_perclient) { | ||
3087 | release_stateowner(sop); | ||
3006 | } | 3088 | } |
3007 | out: | 3089 | out: |
3008 | nfs4_unlock_state(); | 3090 | nfs4_unlock_state(); |
@@ -3010,39 +3092,38 @@ out: | |||
3010 | } | 3092 | } |
3011 | 3093 | ||
3012 | static inline struct nfs4_client_reclaim * | 3094 | static inline struct nfs4_client_reclaim * |
3013 | alloc_reclaim(int namelen) | 3095 | alloc_reclaim(void) |
3014 | { | 3096 | { |
3015 | struct nfs4_client_reclaim *crp = NULL; | 3097 | return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); |
3098 | } | ||
3016 | 3099 | ||
3017 | crp = kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); | 3100 | int |
3018 | if (!crp) | 3101 | nfs4_has_reclaimed_state(const char *name) |
3019 | return NULL; | 3102 | { |
3020 | crp->cr_name.data = kmalloc(namelen, GFP_KERNEL); | 3103 | unsigned int strhashval = clientstr_hashval(name); |
3021 | if (!crp->cr_name.data) { | 3104 | struct nfs4_client *clp; |
3022 | kfree(crp); | 3105 | |
3023 | return NULL; | 3106 | clp = find_confirmed_client_by_str(name, strhashval); |
3024 | } | 3107 | return clp ? 1 : 0; |
3025 | return crp; | ||
3026 | } | 3108 | } |
3027 | 3109 | ||
3028 | /* | 3110 | /* |
3029 | * failure => all reset bets are off, nfserr_no_grace... | 3111 | * failure => all reset bets are off, nfserr_no_grace... |
3030 | */ | 3112 | */ |
3031 | static int | 3113 | int |
3032 | nfs4_client_to_reclaim(char *name, int namlen) | 3114 | nfs4_client_to_reclaim(const char *name) |
3033 | { | 3115 | { |
3034 | unsigned int strhashval; | 3116 | unsigned int strhashval; |
3035 | struct nfs4_client_reclaim *crp = NULL; | 3117 | struct nfs4_client_reclaim *crp = NULL; |
3036 | 3118 | ||
3037 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", namlen, name); | 3119 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); |
3038 | crp = alloc_reclaim(namlen); | 3120 | crp = alloc_reclaim(); |
3039 | if (!crp) | 3121 | if (!crp) |
3040 | return 0; | 3122 | return 0; |
3041 | strhashval = clientstr_hashval(name, namlen); | 3123 | strhashval = clientstr_hashval(name); |
3042 | INIT_LIST_HEAD(&crp->cr_strhash); | 3124 | INIT_LIST_HEAD(&crp->cr_strhash); |
3043 | list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); | 3125 | list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); |
3044 | memcpy(crp->cr_name.data, name, namlen); | 3126 | memcpy(crp->cr_recdir, name, HEXDIR_LEN); |
3045 | crp->cr_name.len = namlen; | ||
3046 | reclaim_str_hashtbl_size++; | 3127 | reclaim_str_hashtbl_size++; |
3047 | return 1; | 3128 | return 1; |
3048 | } | 3129 | } |
@@ -3053,13 +3134,11 @@ nfs4_release_reclaim(void) | |||
3053 | struct nfs4_client_reclaim *crp = NULL; | 3134 | struct nfs4_client_reclaim *crp = NULL; |
3054 | int i; | 3135 | int i; |
3055 | 3136 | ||
3056 | BUG_ON(!nfs4_reclaim_init); | ||
3057 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | 3137 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
3058 | while (!list_empty(&reclaim_str_hashtbl[i])) { | 3138 | while (!list_empty(&reclaim_str_hashtbl[i])) { |
3059 | crp = list_entry(reclaim_str_hashtbl[i].next, | 3139 | crp = list_entry(reclaim_str_hashtbl[i].next, |
3060 | struct nfs4_client_reclaim, cr_strhash); | 3140 | struct nfs4_client_reclaim, cr_strhash); |
3061 | list_del(&crp->cr_strhash); | 3141 | list_del(&crp->cr_strhash); |
3062 | kfree(crp->cr_name.data); | ||
3063 | kfree(crp); | 3142 | kfree(crp); |
3064 | reclaim_str_hashtbl_size--; | 3143 | reclaim_str_hashtbl_size--; |
3065 | } | 3144 | } |
@@ -3069,7 +3148,7 @@ nfs4_release_reclaim(void) | |||
3069 | 3148 | ||
3070 | /* | 3149 | /* |
3071 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ | 3150 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ |
3072 | struct nfs4_client_reclaim * | 3151 | static struct nfs4_client_reclaim * |
3073 | nfs4_find_reclaim_client(clientid_t *clid) | 3152 | nfs4_find_reclaim_client(clientid_t *clid) |
3074 | { | 3153 | { |
3075 | unsigned int strhashval; | 3154 | unsigned int strhashval; |
@@ -3082,13 +3161,14 @@ nfs4_find_reclaim_client(clientid_t *clid) | |||
3082 | if (clp == NULL) | 3161 | if (clp == NULL) |
3083 | return NULL; | 3162 | return NULL; |
3084 | 3163 | ||
3085 | dprintk("NFSD: nfs4_find_reclaim_client for %.*s\n", | 3164 | dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n", |
3086 | clp->cl_name.len, clp->cl_name.data); | 3165 | clp->cl_name.len, clp->cl_name.data, |
3166 | clp->cl_recdir); | ||
3087 | 3167 | ||
3088 | /* find clp->cl_name in reclaim_str_hashtbl */ | 3168 | /* find clp->cl_name in reclaim_str_hashtbl */ |
3089 | strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len); | 3169 | strhashval = clientstr_hashval(clp->cl_recdir); |
3090 | list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { | 3170 | list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { |
3091 | if (cmp_name(&crp->cr_name, &clp->cl_name)) { | 3171 | if (same_name(crp->cr_recdir, clp->cl_recdir)) { |
3092 | return crp; | 3172 | return crp; |
3093 | } | 3173 | } |
3094 | } | 3174 | } |
@@ -3101,30 +3181,16 @@ nfs4_find_reclaim_client(clientid_t *clid) | |||
3101 | int | 3181 | int |
3102 | nfs4_check_open_reclaim(clientid_t *clid) | 3182 | nfs4_check_open_reclaim(clientid_t *clid) |
3103 | { | 3183 | { |
3104 | struct nfs4_client_reclaim *crp; | 3184 | return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; |
3105 | |||
3106 | if ((crp = nfs4_find_reclaim_client(clid)) == NULL) | ||
3107 | return nfserr_reclaim_bad; | ||
3108 | return nfs_ok; | ||
3109 | } | 3185 | } |
3110 | 3186 | ||
3187 | /* initialization to perform at module load time: */ | ||
3111 | 3188 | ||
3112 | /* | 3189 | void |
3113 | * Start and stop routines | 3190 | nfs4_state_init(void) |
3114 | */ | ||
3115 | |||
3116 | static void | ||
3117 | __nfs4_state_init(void) | ||
3118 | { | 3191 | { |
3119 | int i; | 3192 | int i; |
3120 | time_t grace_time; | ||
3121 | 3193 | ||
3122 | if (!nfs4_reclaim_init) { | ||
3123 | for (i = 0; i < CLIENT_HASH_SIZE; i++) | ||
3124 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
3125 | reclaim_str_hashtbl_size = 0; | ||
3126 | nfs4_reclaim_init = 1; | ||
3127 | } | ||
3128 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | 3194 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
3129 | INIT_LIST_HEAD(&conf_id_hashtbl[i]); | 3195 | INIT_LIST_HEAD(&conf_id_hashtbl[i]); |
3130 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); | 3196 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); |
@@ -3146,26 +3212,46 @@ __nfs4_state_init(void) | |||
3146 | INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]); | 3212 | INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]); |
3147 | INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); | 3213 | INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); |
3148 | } | 3214 | } |
3149 | memset(&zerostateid, 0, sizeof(stateid_t)); | ||
3150 | memset(&onestateid, ~0, sizeof(stateid_t)); | 3215 | memset(&onestateid, ~0, sizeof(stateid_t)); |
3151 | |||
3152 | INIT_LIST_HEAD(&close_lru); | 3216 | INIT_LIST_HEAD(&close_lru); |
3153 | INIT_LIST_HEAD(&client_lru); | 3217 | INIT_LIST_HEAD(&client_lru); |
3154 | INIT_LIST_HEAD(&del_recall_lru); | 3218 | INIT_LIST_HEAD(&del_recall_lru); |
3155 | spin_lock_init(&recall_lock); | 3219 | for (i = 0; i < CLIENT_HASH_SIZE; i++) |
3220 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
3221 | reclaim_str_hashtbl_size = 0; | ||
3222 | } | ||
3223 | |||
3224 | static void | ||
3225 | nfsd4_load_reboot_recovery_data(void) | ||
3226 | { | ||
3227 | int status; | ||
3228 | |||
3229 | nfs4_lock_state(); | ||
3230 | nfsd4_init_recdir(user_recovery_dirname); | ||
3231 | status = nfsd4_recdir_load(); | ||
3232 | nfs4_unlock_state(); | ||
3233 | if (status) | ||
3234 | printk("NFSD: Failure reading reboot recovery data\n"); | ||
3235 | } | ||
3236 | |||
3237 | /* initialization to perform when the nfsd service is started: */ | ||
3238 | |||
3239 | static void | ||
3240 | __nfs4_state_start(void) | ||
3241 | { | ||
3242 | time_t grace_time; | ||
3243 | |||
3156 | boot_time = get_seconds(); | 3244 | boot_time = get_seconds(); |
3157 | grace_time = max(old_lease_time, lease_time); | 3245 | grace_time = max(user_lease_time, lease_time); |
3158 | if (reclaim_str_hashtbl_size == 0) | 3246 | lease_time = user_lease_time; |
3159 | grace_time = 0; | 3247 | in_grace = 1; |
3160 | if (grace_time) | 3248 | printk("NFSD: starting %ld-second grace period\n", grace_time); |
3161 | printk("NFSD: starting %ld-second grace period\n", grace_time); | 3249 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
3162 | grace_end = boot_time + grace_time; | 3250 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time*HZ); |
3163 | INIT_WORK(&laundromat_work,laundromat_main, NULL); | ||
3164 | schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ); | ||
3165 | } | 3251 | } |
3166 | 3252 | ||
3167 | int | 3253 | int |
3168 | nfs4_state_init(void) | 3254 | nfs4_state_start(void) |
3169 | { | 3255 | { |
3170 | int status; | 3256 | int status; |
3171 | 3257 | ||
@@ -3174,7 +3260,8 @@ nfs4_state_init(void) | |||
3174 | status = nfsd4_init_slabs(); | 3260 | status = nfsd4_init_slabs(); |
3175 | if (status) | 3261 | if (status) |
3176 | return status; | 3262 | return status; |
3177 | __nfs4_state_init(); | 3263 | nfsd4_load_reboot_recovery_data(); |
3264 | __nfs4_state_start(); | ||
3178 | nfs4_init = 1; | 3265 | nfs4_init = 1; |
3179 | return 0; | 3266 | return 0; |
3180 | } | 3267 | } |
@@ -3182,14 +3269,7 @@ nfs4_state_init(void) | |||
3182 | int | 3269 | int |
3183 | nfs4_in_grace(void) | 3270 | nfs4_in_grace(void) |
3184 | { | 3271 | { |
3185 | return get_seconds() < grace_end; | 3272 | return in_grace; |
3186 | } | ||
3187 | |||
3188 | void | ||
3189 | set_no_grace(void) | ||
3190 | { | ||
3191 | printk("NFSD: ERROR in reboot recovery. State reclaims will fail.\n"); | ||
3192 | grace_end = get_seconds(); | ||
3193 | } | 3273 | } |
3194 | 3274 | ||
3195 | time_t | 3275 | time_t |
@@ -3236,21 +3316,11 @@ __nfs4_state_shutdown(void) | |||
3236 | unhash_delegation(dp); | 3316 | unhash_delegation(dp); |
3237 | } | 3317 | } |
3238 | 3318 | ||
3239 | release_all_files(); | ||
3240 | cancel_delayed_work(&laundromat_work); | 3319 | cancel_delayed_work(&laundromat_work); |
3241 | flush_scheduled_work(); | 3320 | flush_workqueue(laundry_wq); |
3321 | destroy_workqueue(laundry_wq); | ||
3322 | nfsd4_shutdown_recdir(); | ||
3242 | nfs4_init = 0; | 3323 | nfs4_init = 0; |
3243 | dprintk("NFSD: list_add_perfile %d list_del_perfile %d\n", | ||
3244 | list_add_perfile, list_del_perfile); | ||
3245 | dprintk("NFSD: add_perclient %d del_perclient %d\n", | ||
3246 | add_perclient, del_perclient); | ||
3247 | dprintk("NFSD: alloc_file %d free_file %d\n", | ||
3248 | alloc_file, free_file); | ||
3249 | dprintk("NFSD: vfsopen %d vfsclose %d\n", | ||
3250 | vfsopen, vfsclose); | ||
3251 | dprintk("NFSD: alloc_delegation %d free_delegation %d\n", | ||
3252 | alloc_delegation, free_delegation); | ||
3253 | |||
3254 | } | 3324 | } |
3255 | 3325 | ||
3256 | void | 3326 | void |
@@ -3263,56 +3333,48 @@ nfs4_state_shutdown(void) | |||
3263 | nfs4_unlock_state(); | 3333 | nfs4_unlock_state(); |
3264 | } | 3334 | } |
3265 | 3335 | ||
3336 | static void | ||
3337 | nfs4_set_recdir(char *recdir) | ||
3338 | { | ||
3339 | nfs4_lock_state(); | ||
3340 | strcpy(user_recovery_dirname, recdir); | ||
3341 | nfs4_unlock_state(); | ||
3342 | } | ||
3343 | |||
3344 | /* | ||
3345 | * Change the NFSv4 recovery directory to recdir. | ||
3346 | */ | ||
3347 | int | ||
3348 | nfs4_reset_recoverydir(char *recdir) | ||
3349 | { | ||
3350 | int status; | ||
3351 | struct nameidata nd; | ||
3352 | |||
3353 | status = path_lookup(recdir, LOOKUP_FOLLOW, &nd); | ||
3354 | if (status) | ||
3355 | return status; | ||
3356 | status = -ENOTDIR; | ||
3357 | if (S_ISDIR(nd.dentry->d_inode->i_mode)) { | ||
3358 | nfs4_set_recdir(recdir); | ||
3359 | status = 0; | ||
3360 | } | ||
3361 | path_release(&nd); | ||
3362 | return status; | ||
3363 | } | ||
3364 | |||
3266 | /* | 3365 | /* |
3267 | * Called when leasetime is changed. | 3366 | * Called when leasetime is changed. |
3268 | * | 3367 | * |
3269 | * if nfsd is not started, simply set the global lease. | 3368 | * The only way the protocol gives us to handle on-the-fly lease changes is to |
3270 | * | 3369 | * simulate a reboot. Instead of doing that, we just wait till the next time |
3271 | * if nfsd(s) are running, lease change requires nfsv4 state to be reset. | 3370 | * we start to register any changes in lease time. If the administrator |
3272 | * e.g: boot_time is reset, existing nfs4_client structs are | 3371 | * really wants to change the lease time *now*, they can go ahead and bring |
3273 | * used to fill reclaim_str_hashtbl, then all state (except for the | 3372 | * nfsd down and then back up again after changing the lease time. |
3274 | * reclaim_str_hashtbl) is re-initialized. | ||
3275 | * | ||
3276 | * if the old lease time is greater than the new lease time, the grace | ||
3277 | * period needs to be set to the old lease time to allow clients to reclaim | ||
3278 | * their state. XXX - we may want to set the grace period == lease time | ||
3279 | * after an initial grace period == old lease time | ||
3280 | * | ||
3281 | * if an error occurs in this process, the new lease is set, but the server | ||
3282 | * will not honor OPEN or LOCK reclaims, and will return nfserr_no_grace | ||
3283 | * which means OPEN/LOCK/READ/WRITE will fail during grace period. | ||
3284 | * | ||
3285 | * clients will attempt to reset all state with SETCLIENTID/CONFIRM, and | ||
3286 | * OPEN and LOCK reclaims. | ||
3287 | */ | 3373 | */ |
3288 | void | 3374 | void |
3289 | nfs4_reset_lease(time_t leasetime) | 3375 | nfs4_reset_lease(time_t leasetime) |
3290 | { | 3376 | { |
3291 | struct nfs4_client *clp; | 3377 | lock_kernel(); |
3292 | int i; | 3378 | user_lease_time = leasetime; |
3293 | 3379 | unlock_kernel(); | |
3294 | printk("NFSD: New leasetime %ld\n",leasetime); | ||
3295 | if (!nfs4_init) | ||
3296 | return; | ||
3297 | nfs4_lock_state(); | ||
3298 | old_lease_time = lease_time; | ||
3299 | lease_time = leasetime; | ||
3300 | |||
3301 | nfs4_release_reclaim(); | ||
3302 | |||
3303 | /* populate reclaim_str_hashtbl with current confirmed nfs4_clientid */ | ||
3304 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
3305 | list_for_each_entry(clp, &conf_id_hashtbl[i], cl_idhash) { | ||
3306 | if (!nfs4_client_to_reclaim(clp->cl_name.data, | ||
3307 | clp->cl_name.len)) { | ||
3308 | nfs4_release_reclaim(); | ||
3309 | goto init_state; | ||
3310 | } | ||
3311 | } | ||
3312 | } | ||
3313 | init_state: | ||
3314 | __nfs4_state_shutdown(); | ||
3315 | __nfs4_state_init(); | ||
3316 | nfs4_unlock_state(); | ||
3317 | } | 3380 | } |
3318 | |||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 36a058a112d5..91fb171d2ace 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -136,7 +136,7 @@ xdr_error: \ | |||
136 | } \ | 136 | } \ |
137 | } while (0) | 137 | } while (0) |
138 | 138 | ||
139 | u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) | 139 | static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) |
140 | { | 140 | { |
141 | /* We want more bytes than seem to be available. | 141 | /* We want more bytes than seem to be available. |
142 | * Maybe we need a new page, maybe we have just run out | 142 | * Maybe we need a new page, maybe we have just run out |
@@ -190,7 +190,7 @@ defer_free(struct nfsd4_compoundargs *argp, | |||
190 | return 0; | 190 | return 0; |
191 | } | 191 | } |
192 | 192 | ||
193 | char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes) | 193 | static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes) |
194 | { | 194 | { |
195 | void *new = NULL; | 195 | void *new = NULL; |
196 | if (p == argp->tmp) { | 196 | if (p == argp->tmp) { |
@@ -1366,7 +1366,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1366 | if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { | 1366 | if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { |
1367 | if ((buflen -= 4) < 0) | 1367 | if ((buflen -= 4) < 0) |
1368 | goto out_resource; | 1368 | goto out_resource; |
1369 | WRITE32( NFS4_FH_NOEXPIRE_WITH_OPEN | NFS4_FH_VOL_RENAME ); | 1369 | if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) |
1370 | WRITE32(NFS4_FH_VOLATILE_ANY); | ||
1371 | else | ||
1372 | WRITE32(NFS4_FH_VOLATILE_ANY|NFS4_FH_VOL_RENAME); | ||
1370 | } | 1373 | } |
1371 | if (bmval0 & FATTR4_WORD0_CHANGE) { | 1374 | if (bmval0 & FATTR4_WORD0_CHANGE) { |
1372 | /* | 1375 | /* |
@@ -1969,7 +1972,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open | |||
1969 | case NFS4_OPEN_DELEGATE_READ: | 1972 | case NFS4_OPEN_DELEGATE_READ: |
1970 | RESERVE_SPACE(20 + sizeof(stateid_t)); | 1973 | RESERVE_SPACE(20 + sizeof(stateid_t)); |
1971 | WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t)); | 1974 | WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t)); |
1972 | WRITE32(0); | 1975 | WRITE32(open->op_recall); |
1973 | 1976 | ||
1974 | /* | 1977 | /* |
1975 | * TODO: ACE's in delegations | 1978 | * TODO: ACE's in delegations |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 161afdcb8f7d..841c562991e8 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -51,6 +51,7 @@ enum { | |||
51 | NFSD_Fh, | 51 | NFSD_Fh, |
52 | NFSD_Threads, | 52 | NFSD_Threads, |
53 | NFSD_Leasetime, | 53 | NFSD_Leasetime, |
54 | NFSD_RecoveryDir, | ||
54 | }; | 55 | }; |
55 | 56 | ||
56 | /* | 57 | /* |
@@ -66,6 +67,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size); | |||
66 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); | 67 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); |
67 | static ssize_t write_threads(struct file *file, char *buf, size_t size); | 68 | static ssize_t write_threads(struct file *file, char *buf, size_t size); |
68 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size); | 69 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size); |
70 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); | ||
69 | 71 | ||
70 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { | 72 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { |
71 | [NFSD_Svc] = write_svc, | 73 | [NFSD_Svc] = write_svc, |
@@ -78,6 +80,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { | |||
78 | [NFSD_Fh] = write_filehandle, | 80 | [NFSD_Fh] = write_filehandle, |
79 | [NFSD_Threads] = write_threads, | 81 | [NFSD_Threads] = write_threads, |
80 | [NFSD_Leasetime] = write_leasetime, | 82 | [NFSD_Leasetime] = write_leasetime, |
83 | [NFSD_RecoveryDir] = write_recoverydir, | ||
81 | }; | 84 | }; |
82 | 85 | ||
83 | static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) | 86 | static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) |
@@ -349,6 +352,25 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size) | |||
349 | return strlen(buf); | 352 | return strlen(buf); |
350 | } | 353 | } |
351 | 354 | ||
355 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) | ||
356 | { | ||
357 | char *mesg = buf; | ||
358 | char *recdir; | ||
359 | int len, status; | ||
360 | |||
361 | if (size > PATH_MAX || buf[size-1] != '\n') | ||
362 | return -EINVAL; | ||
363 | buf[size-1] = 0; | ||
364 | |||
365 | recdir = mesg; | ||
366 | len = qword_get(&mesg, recdir, size); | ||
367 | if (len <= 0) | ||
368 | return -EINVAL; | ||
369 | |||
370 | status = nfs4_reset_recoverydir(recdir); | ||
371 | return strlen(buf); | ||
372 | } | ||
373 | |||
352 | /*----------------------------------------------------------------------------*/ | 374 | /*----------------------------------------------------------------------------*/ |
353 | /* | 375 | /* |
354 | * populating the filesystem. | 376 | * populating the filesystem. |
@@ -369,6 +391,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | |||
369 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, | 391 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, |
370 | #ifdef CONFIG_NFSD_V4 | 392 | #ifdef CONFIG_NFSD_V4 |
371 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, | 393 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, |
394 | [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, | ||
372 | #endif | 395 | #endif |
373 | /* last one */ {""} | 396 | /* last one */ {""} |
374 | }; | 397 | }; |
@@ -397,9 +420,8 @@ static int __init init_nfsd(void) | |||
397 | nfsd_cache_init(); /* RPC reply cache */ | 420 | nfsd_cache_init(); /* RPC reply cache */ |
398 | nfsd_export_init(); /* Exports table */ | 421 | nfsd_export_init(); /* Exports table */ |
399 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ | 422 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ |
400 | #ifdef CONFIG_NFSD_V4 | 423 | nfs4_state_init(); /* NFSv4 locking state */ |
401 | nfsd_idmap_init(); /* Name to ID mapping */ | 424 | nfsd_idmap_init(); /* Name to ID mapping */ |
402 | #endif /* CONFIG_NFSD_V4 */ | ||
403 | if (proc_mkdir("fs/nfs", NULL)) { | 425 | if (proc_mkdir("fs/nfs", NULL)) { |
404 | struct proc_dir_entry *entry; | 426 | struct proc_dir_entry *entry; |
405 | entry = create_proc_entry("fs/nfs/exports", 0, NULL); | 427 | entry = create_proc_entry("fs/nfs/exports", 0, NULL); |
@@ -426,9 +448,7 @@ static void __exit exit_nfsd(void) | |||
426 | remove_proc_entry("fs/nfs", NULL); | 448 | remove_proc_entry("fs/nfs", NULL); |
427 | nfsd_stat_shutdown(); | 449 | nfsd_stat_shutdown(); |
428 | nfsd_lockd_shutdown(); | 450 | nfsd_lockd_shutdown(); |
429 | #ifdef CONFIG_NFSD_V4 | ||
430 | nfsd_idmap_shutdown(); | 451 | nfsd_idmap_shutdown(); |
431 | #endif /* CONFIG_NFSD_V4 */ | ||
432 | unregister_filesystem(&nfsd_fs_type); | 452 | unregister_filesystem(&nfsd_fs_type); |
433 | } | 453 | } |
434 | 454 | ||
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 757f9d208034..0aa1b9603d7f 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -591,6 +591,7 @@ nfserrno (int errno) | |||
591 | { nfserr_dropit, -ENOMEM }, | 591 | { nfserr_dropit, -ENOMEM }, |
592 | { nfserr_badname, -ESRCH }, | 592 | { nfserr_badname, -ESRCH }, |
593 | { nfserr_io, -ETXTBSY }, | 593 | { nfserr_io, -ETXTBSY }, |
594 | { nfserr_notsupp, -EOPNOTSUPP }, | ||
594 | { -1, -EIO } | 595 | { -1, -EIO } |
595 | }; | 596 | }; |
596 | int i; | 597 | int i; |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 02ded7cfbdcf..07b9a065e9da 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/nfsd/stats.h> | 31 | #include <linux/nfsd/stats.h> |
32 | #include <linux/nfsd/cache.h> | 32 | #include <linux/nfsd/cache.h> |
33 | #include <linux/lockd/bind.h> | 33 | #include <linux/lockd/bind.h> |
34 | #include <linux/nfsacl.h> | ||
34 | 35 | ||
35 | #define NFSDDBG_FACILITY NFSDDBG_SVC | 36 | #define NFSDDBG_FACILITY NFSDDBG_SVC |
36 | 37 | ||
@@ -94,7 +95,7 @@ nfsd_svc(unsigned short port, int nrservs) | |||
94 | error = nfsd_racache_init(2*nrservs); | 95 | error = nfsd_racache_init(2*nrservs); |
95 | if (error<0) | 96 | if (error<0) |
96 | goto out; | 97 | goto out; |
97 | error = nfs4_state_init(); | 98 | error = nfs4_state_start(); |
98 | if (error<0) | 99 | if (error<0) |
99 | goto out; | 100 | goto out; |
100 | if (!nfsd_serv) { | 101 | if (!nfsd_serv) { |
@@ -362,6 +363,32 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp) | |||
362 | return 1; | 363 | return 1; |
363 | } | 364 | } |
364 | 365 | ||
366 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||
367 | static struct svc_stat nfsd_acl_svcstats; | ||
368 | static struct svc_version * nfsd_acl_version[] = { | ||
369 | [2] = &nfsd_acl_version2, | ||
370 | [3] = &nfsd_acl_version3, | ||
371 | }; | ||
372 | |||
373 | #define NFSD_ACL_NRVERS (sizeof(nfsd_acl_version)/sizeof(nfsd_acl_version[0])) | ||
374 | static struct svc_program nfsd_acl_program = { | ||
375 | .pg_prog = NFS_ACL_PROGRAM, | ||
376 | .pg_nvers = NFSD_ACL_NRVERS, | ||
377 | .pg_vers = nfsd_acl_version, | ||
378 | .pg_name = "nfsd", | ||
379 | .pg_class = "nfsd", | ||
380 | .pg_stats = &nfsd_acl_svcstats, | ||
381 | }; | ||
382 | |||
383 | static struct svc_stat nfsd_acl_svcstats = { | ||
384 | .program = &nfsd_acl_program, | ||
385 | }; | ||
386 | |||
387 | #define nfsd_acl_program_p &nfsd_acl_program | ||
388 | #else | ||
389 | #define nfsd_acl_program_p NULL | ||
390 | #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ | ||
391 | |||
365 | extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; | 392 | extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; |
366 | 393 | ||
367 | static struct svc_version * nfsd_version[] = { | 394 | static struct svc_version * nfsd_version[] = { |
@@ -376,6 +403,7 @@ static struct svc_version * nfsd_version[] = { | |||
376 | 403 | ||
377 | #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) | 404 | #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) |
378 | struct svc_program nfsd_program = { | 405 | struct svc_program nfsd_program = { |
406 | .pg_next = nfsd_acl_program_p, | ||
379 | .pg_prog = NFS_PROGRAM, /* program number */ | 407 | .pg_prog = NFS_PROGRAM, /* program number */ |
380 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ | 408 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ |
381 | .pg_vers = nfsd_version, /* version table */ | 409 | .pg_vers = nfsd_version, /* version table */ |
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 948b08287c99..b45999ff33e6 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
@@ -49,6 +49,12 @@ decode_fh(u32 *p, struct svc_fh *fhp) | |||
49 | return p + (NFS_FHSIZE >> 2); | 49 | return p + (NFS_FHSIZE >> 2); |
50 | } | 50 | } |
51 | 51 | ||
52 | /* Helper function for NFSv2 ACL code */ | ||
53 | u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp) | ||
54 | { | ||
55 | return decode_fh(p, fhp); | ||
56 | } | ||
57 | |||
52 | static inline u32 * | 58 | static inline u32 * |
53 | encode_fh(u32 *p, struct svc_fh *fhp) | 59 | encode_fh(u32 *p, struct svc_fh *fhp) |
54 | { | 60 | { |
@@ -190,6 +196,11 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) | |||
190 | return p; | 196 | return p; |
191 | } | 197 | } |
192 | 198 | ||
199 | /* Helper function for NFSv2 ACL code */ | ||
200 | u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp) | ||
201 | { | ||
202 | return encode_fattr(rqstp, p, fhp); | ||
203 | } | ||
193 | 204 | ||
194 | /* | 205 | /* |
195 | * XDR decode functions | 206 | * XDR decode functions |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index e3e9d217236e..de340ffd33c3 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -46,10 +46,10 @@ | |||
46 | #include <linux/nfsd/nfsfh.h> | 46 | #include <linux/nfsd/nfsfh.h> |
47 | #include <linux/quotaops.h> | 47 | #include <linux/quotaops.h> |
48 | #include <linux/dnotify.h> | 48 | #include <linux/dnotify.h> |
49 | #ifdef CONFIG_NFSD_V4 | 49 | #include <linux/xattr_acl.h> |
50 | #include <linux/posix_acl.h> | 50 | #include <linux/posix_acl.h> |
51 | #ifdef CONFIG_NFSD_V4 | ||
51 | #include <linux/posix_acl_xattr.h> | 52 | #include <linux/posix_acl_xattr.h> |
52 | #include <linux/xattr_acl.h> | ||
53 | #include <linux/xattr.h> | 53 | #include <linux/xattr.h> |
54 | #include <linux/nfs4.h> | 54 | #include <linux/nfs4.h> |
55 | #include <linux/nfs4_acl.h> | 55 | #include <linux/nfs4_acl.h> |
@@ -424,13 +424,13 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
424 | goto out_nfserr; | 424 | goto out_nfserr; |
425 | 425 | ||
426 | if (pacl) { | 426 | if (pacl) { |
427 | error = set_nfsv4_acl_one(dentry, pacl, XATTR_NAME_ACL_ACCESS); | 427 | error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); |
428 | if (error < 0) | 428 | if (error < 0) |
429 | goto out_nfserr; | 429 | goto out_nfserr; |
430 | } | 430 | } |
431 | 431 | ||
432 | if (dpacl) { | 432 | if (dpacl) { |
433 | error = set_nfsv4_acl_one(dentry, dpacl, XATTR_NAME_ACL_DEFAULT); | 433 | error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); |
434 | if (error < 0) | 434 | if (error < 0) |
435 | goto out_nfserr; | 435 | goto out_nfserr; |
436 | } | 436 | } |
@@ -497,7 +497,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac | |||
497 | struct posix_acl *pacl = NULL, *dpacl = NULL; | 497 | struct posix_acl *pacl = NULL, *dpacl = NULL; |
498 | unsigned int flags = 0; | 498 | unsigned int flags = 0; |
499 | 499 | ||
500 | pacl = _get_posix_acl(dentry, XATTR_NAME_ACL_ACCESS); | 500 | pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS); |
501 | if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA) | 501 | if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA) |
502 | pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); | 502 | pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); |
503 | if (IS_ERR(pacl)) { | 503 | if (IS_ERR(pacl)) { |
@@ -507,7 +507,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac | |||
507 | } | 507 | } |
508 | 508 | ||
509 | if (S_ISDIR(inode->i_mode)) { | 509 | if (S_ISDIR(inode->i_mode)) { |
510 | dpacl = _get_posix_acl(dentry, XATTR_NAME_ACL_DEFAULT); | 510 | dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT); |
511 | if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA) | 511 | if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA) |
512 | dpacl = NULL; | 512 | dpacl = NULL; |
513 | else if (IS_ERR(dpacl)) { | 513 | else if (IS_ERR(dpacl)) { |
@@ -1857,3 +1857,107 @@ nfsd_racache_init(int cache_size) | |||
1857 | nfsdstats.ra_size = cache_size; | 1857 | nfsdstats.ra_size = cache_size; |
1858 | return 0; | 1858 | return 0; |
1859 | } | 1859 | } |
1860 | |||
1861 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||
1862 | struct posix_acl * | ||
1863 | nfsd_get_posix_acl(struct svc_fh *fhp, int type) | ||
1864 | { | ||
1865 | struct inode *inode = fhp->fh_dentry->d_inode; | ||
1866 | char *name; | ||
1867 | void *value = NULL; | ||
1868 | ssize_t size; | ||
1869 | struct posix_acl *acl; | ||
1870 | |||
1871 | if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr) | ||
1872 | return ERR_PTR(-EOPNOTSUPP); | ||
1873 | switch(type) { | ||
1874 | case ACL_TYPE_ACCESS: | ||
1875 | name = XATTR_NAME_ACL_ACCESS; | ||
1876 | break; | ||
1877 | case ACL_TYPE_DEFAULT: | ||
1878 | name = XATTR_NAME_ACL_DEFAULT; | ||
1879 | break; | ||
1880 | default: | ||
1881 | return ERR_PTR(-EOPNOTSUPP); | ||
1882 | } | ||
1883 | |||
1884 | size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0); | ||
1885 | |||
1886 | if (size < 0) { | ||
1887 | acl = ERR_PTR(size); | ||
1888 | goto getout; | ||
1889 | } else if (size > 0) { | ||
1890 | value = kmalloc(size, GFP_KERNEL); | ||
1891 | if (!value) { | ||
1892 | acl = ERR_PTR(-ENOMEM); | ||
1893 | goto getout; | ||
1894 | } | ||
1895 | size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size); | ||
1896 | if (size < 0) { | ||
1897 | acl = ERR_PTR(size); | ||
1898 | goto getout; | ||
1899 | } | ||
1900 | } | ||
1901 | acl = posix_acl_from_xattr(value, size); | ||
1902 | |||
1903 | getout: | ||
1904 | kfree(value); | ||
1905 | return acl; | ||
1906 | } | ||
1907 | |||
1908 | int | ||
1909 | nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) | ||
1910 | { | ||
1911 | struct inode *inode = fhp->fh_dentry->d_inode; | ||
1912 | char *name; | ||
1913 | void *value = NULL; | ||
1914 | size_t size; | ||
1915 | int error; | ||
1916 | |||
1917 | if (!IS_POSIXACL(inode) || !inode->i_op || | ||
1918 | !inode->i_op->setxattr || !inode->i_op->removexattr) | ||
1919 | return -EOPNOTSUPP; | ||
1920 | switch(type) { | ||
1921 | case ACL_TYPE_ACCESS: | ||
1922 | name = XATTR_NAME_ACL_ACCESS; | ||
1923 | break; | ||
1924 | case ACL_TYPE_DEFAULT: | ||
1925 | name = XATTR_NAME_ACL_DEFAULT; | ||
1926 | break; | ||
1927 | default: | ||
1928 | return -EOPNOTSUPP; | ||
1929 | } | ||
1930 | |||
1931 | if (acl && acl->a_count) { | ||
1932 | size = xattr_acl_size(acl->a_count); | ||
1933 | value = kmalloc(size, GFP_KERNEL); | ||
1934 | if (!value) | ||
1935 | return -ENOMEM; | ||
1936 | size = posix_acl_to_xattr(acl, value, size); | ||
1937 | if (size < 0) { | ||
1938 | error = size; | ||
1939 | goto getout; | ||
1940 | } | ||
1941 | } else | ||
1942 | size = 0; | ||
1943 | |||
1944 | if (!fhp->fh_locked) | ||
1945 | fh_lock(fhp); /* unlocking is done automatically */ | ||
1946 | if (size) | ||
1947 | error = inode->i_op->setxattr(fhp->fh_dentry, name, | ||
1948 | value, size, 0); | ||
1949 | else { | ||
1950 | if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT) | ||
1951 | error = 0; | ||
1952 | else { | ||
1953 | error = inode->i_op->removexattr(fhp->fh_dentry, name); | ||
1954 | if (error == -ENODATA) | ||
1955 | error = 0; | ||
1956 | } | ||
1957 | } | ||
1958 | |||
1959 | getout: | ||
1960 | kfree(value); | ||
1961 | return error; | ||
1962 | } | ||
1963 | #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ | ||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/vfs.h> | 21 | #include <linux/vfs.h> |
22 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/personality.h> | ||
24 | #include <linux/pagemap.h> | 25 | #include <linux/pagemap.h> |
25 | #include <linux/syscalls.h> | 26 | #include <linux/syscalls.h> |
26 | 27 | ||
@@ -807,7 +808,9 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | |||
807 | 808 | ||
808 | /* NB: we're sure to have correct a_ops only after f_op->open */ | 809 | /* NB: we're sure to have correct a_ops only after f_op->open */ |
809 | if (f->f_flags & O_DIRECT) { | 810 | if (f->f_flags & O_DIRECT) { |
810 | if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) { | 811 | if (!f->f_mapping->a_ops || |
812 | ((!f->f_mapping->a_ops->direct_IO) && | ||
813 | (!f->f_mapping->a_ops->get_xip_page))) { | ||
811 | fput(f); | 814 | fput(f); |
812 | f = ERR_PTR(-EINVAL); | 815 | f = ERR_PTR(-EINVAL); |
813 | } | 816 | } |
@@ -933,31 +936,27 @@ EXPORT_SYMBOL(fd_install); | |||
933 | asmlinkage long sys_open(const char __user * filename, int flags, int mode) | 936 | asmlinkage long sys_open(const char __user * filename, int flags, int mode) |
934 | { | 937 | { |
935 | char * tmp; | 938 | char * tmp; |
936 | int fd, error; | 939 | int fd; |
940 | |||
941 | if (force_o_largefile()) | ||
942 | flags |= O_LARGEFILE; | ||
937 | 943 | ||
938 | #if BITS_PER_LONG != 32 | ||
939 | flags |= O_LARGEFILE; | ||
940 | #endif | ||
941 | tmp = getname(filename); | 944 | tmp = getname(filename); |
942 | fd = PTR_ERR(tmp); | 945 | fd = PTR_ERR(tmp); |
943 | if (!IS_ERR(tmp)) { | 946 | if (!IS_ERR(tmp)) { |
944 | fd = get_unused_fd(); | 947 | fd = get_unused_fd(); |
945 | if (fd >= 0) { | 948 | if (fd >= 0) { |
946 | struct file *f = filp_open(tmp, flags, mode); | 949 | struct file *f = filp_open(tmp, flags, mode); |
947 | error = PTR_ERR(f); | 950 | if (IS_ERR(f)) { |
948 | if (IS_ERR(f)) | 951 | put_unused_fd(fd); |
949 | goto out_error; | 952 | fd = PTR_ERR(f); |
950 | fd_install(fd, f); | 953 | } else { |
954 | fd_install(fd, f); | ||
955 | } | ||
951 | } | 956 | } |
952 | out: | ||
953 | putname(tmp); | 957 | putname(tmp); |
954 | } | 958 | } |
955 | return fd; | 959 | return fd; |
956 | |||
957 | out_error: | ||
958 | put_unused_fd(fd); | ||
959 | fd = error; | ||
960 | goto out; | ||
961 | } | 960 | } |
962 | EXPORT_SYMBOL_GPL(sys_open); | 961 | EXPORT_SYMBOL_GPL(sys_open); |
963 | 962 | ||
@@ -980,23 +979,15 @@ asmlinkage long sys_creat(const char __user * pathname, int mode) | |||
980 | */ | 979 | */ |
981 | int filp_close(struct file *filp, fl_owner_t id) | 980 | int filp_close(struct file *filp, fl_owner_t id) |
982 | { | 981 | { |
983 | int retval; | 982 | int retval = 0; |
984 | |||
985 | /* Report and clear outstanding errors */ | ||
986 | retval = filp->f_error; | ||
987 | if (retval) | ||
988 | filp->f_error = 0; | ||
989 | 983 | ||
990 | if (!file_count(filp)) { | 984 | if (!file_count(filp)) { |
991 | printk(KERN_ERR "VFS: Close: file count is 0\n"); | 985 | printk(KERN_ERR "VFS: Close: file count is 0\n"); |
992 | return retval; | 986 | return 0; |
993 | } | 987 | } |
994 | 988 | ||
995 | if (filp->f_op && filp->f_op->flush) { | 989 | if (filp->f_op && filp->f_op->flush) |
996 | int err = filp->f_op->flush(filp); | 990 | retval = filp->f_op->flush(filp); |
997 | if (!retval) | ||
998 | retval = err; | ||
999 | } | ||
1000 | 991 | ||
1001 | dnotify_flush(filp, id); | 992 | dnotify_flush(filp, id); |
1002 | locks_remove_posix(filp, id); | 993 | locks_remove_posix(filp, id); |
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile index 4c83c17969e1..66d5cc26fafb 100644 --- a/fs/partitions/Makefile +++ b/fs/partitions/Makefile | |||
@@ -17,4 +17,3 @@ obj-$(CONFIG_SUN_PARTITION) += sun.o | |||
17 | obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o | 17 | obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o |
18 | obj-$(CONFIG_IBM_PARTITION) += ibm.o | 18 | obj-$(CONFIG_IBM_PARTITION) += ibm.o |
19 | obj-$(CONFIG_EFI_PARTITION) += efi.o | 19 | obj-$(CONFIG_EFI_PARTITION) += efi.o |
20 | obj-$(CONFIG_NEC98_PARTITION) += nec98.o msdos.o | ||
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 2cab98a9a621..77e178f13162 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -79,9 +79,6 @@ static int (*check_part[])(struct parsed_partitions *, struct block_device *) = | |||
79 | #ifdef CONFIG_LDM_PARTITION | 79 | #ifdef CONFIG_LDM_PARTITION |
80 | ldm_partition, /* this must come before msdos */ | 80 | ldm_partition, /* this must come before msdos */ |
81 | #endif | 81 | #endif |
82 | #ifdef CONFIG_NEC98_PARTITION | ||
83 | nec98_partition, /* must be come before `msdos_partition' */ | ||
84 | #endif | ||
85 | #ifdef CONFIG_MSDOS_PARTITION | 82 | #ifdef CONFIG_MSDOS_PARTITION |
86 | msdos_partition, | 83 | msdos_partition, |
87 | #endif | 84 | #endif |
diff --git a/fs/partitions/check.h b/fs/partitions/check.h index 43adcc68e471..17ae8ecd9e8b 100644 --- a/fs/partitions/check.h +++ b/fs/partitions/check.h | |||
@@ -30,7 +30,3 @@ put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size) | |||
30 | 30 | ||
31 | extern int warn_no_part; | 31 | extern int warn_no_part; |
32 | 32 | ||
33 | extern void parse_bsd(struct parsed_partitions *state, | ||
34 | struct block_device *bdev, u32 offset, u32 size, | ||
35 | int origin, char *flavour, int max_partitions); | ||
36 | |||
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 584a27b2bbd5..9935d254186e 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c | |||
@@ -202,12 +202,12 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, | |||
202 | #endif | 202 | #endif |
203 | } | 203 | } |
204 | 204 | ||
205 | #if defined(CONFIG_BSD_DISKLABEL) || defined(CONFIG_NEC98_PARTITION) | 205 | #if defined(CONFIG_BSD_DISKLABEL) |
206 | /* | 206 | /* |
207 | * Create devices for BSD partitions listed in a disklabel, under a | 207 | * Create devices for BSD partitions listed in a disklabel, under a |
208 | * dos-like partition. See parse_extended() for more information. | 208 | * dos-like partition. See parse_extended() for more information. |
209 | */ | 209 | */ |
210 | void | 210 | static void |
211 | parse_bsd(struct parsed_partitions *state, struct block_device *bdev, | 211 | parse_bsd(struct parsed_partitions *state, struct block_device *bdev, |
212 | u32 offset, u32 size, int origin, char *flavour, | 212 | u32 offset, u32 size, int origin, char *flavour, |
213 | int max_partitions) | 213 | int max_partitions) |
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 738b9b602932..7431d7ba2d09 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile | |||
@@ -11,4 +11,5 @@ proc-y += inode.o root.o base.o generic.o array.o \ | |||
11 | kmsg.o proc_tty.o proc_misc.o | 11 | kmsg.o proc_tty.o proc_misc.o |
12 | 12 | ||
13 | proc-$(CONFIG_PROC_KCORE) += kcore.o | 13 | proc-$(CONFIG_PROC_KCORE) += kcore.o |
14 | proc-$(CONFIG_PROC_VMCORE) += vmcore.o | ||
14 | proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o | 15 | proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o |
diff --git a/fs/proc/base.c b/fs/proc/base.c index e31903aadd96..ace151fa4878 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -314,7 +314,7 @@ static int may_ptrace_attach(struct task_struct *task) | |||
314 | (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) | 314 | (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) |
315 | goto out; | 315 | goto out; |
316 | rmb(); | 316 | rmb(); |
317 | if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE)) | 317 | if (task->mm->dumpable != 1 && !capable(CAP_SYS_PTRACE)) |
318 | goto out; | 318 | goto out; |
319 | if (security_ptrace(current, task)) | 319 | if (security_ptrace(current, task)) |
320 | goto out; | 320 | goto out; |
@@ -1113,7 +1113,9 @@ static int task_dumpable(struct task_struct *task) | |||
1113 | if (mm) | 1113 | if (mm) |
1114 | dumpable = mm->dumpable; | 1114 | dumpable = mm->dumpable; |
1115 | task_unlock(task); | 1115 | task_unlock(task); |
1116 | return dumpable; | 1116 | if(dumpable == 1) |
1117 | return 1; | ||
1118 | return 0; | ||
1117 | } | 1119 | } |
1118 | 1120 | ||
1119 | 1121 | ||
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 67423c696c0a..6fd57f154197 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
@@ -12,15 +12,8 @@ | |||
12 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
13 | 13 | ||
14 | #ifndef HAVE_ARCH_DEVTREE_FIXUPS | 14 | #ifndef HAVE_ARCH_DEVTREE_FIXUPS |
15 | static inline void set_node_proc_entry(struct device_node *np, struct proc_dir_entry *de) | 15 | static inline void set_node_proc_entry(struct device_node *np, |
16 | { | 16 | struct proc_dir_entry *de) |
17 | } | ||
18 | |||
19 | static void inline set_node_name_link(struct device_node *np, struct proc_dir_entry *de) | ||
20 | { | ||
21 | } | ||
22 | |||
23 | static void inline set_node_addr_link(struct device_node *np, struct proc_dir_entry *de) | ||
24 | { | 17 | { |
25 | } | 18 | } |
26 | #endif | 19 | #endif |
@@ -58,89 +51,67 @@ static int property_read_proc(char *page, char **start, off_t off, | |||
58 | /* | 51 | /* |
59 | * Process a node, adding entries for its children and its properties. | 52 | * Process a node, adding entries for its children and its properties. |
60 | */ | 53 | */ |
61 | void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *de) | 54 | void proc_device_tree_add_node(struct device_node *np, |
55 | struct proc_dir_entry *de) | ||
62 | { | 56 | { |
63 | struct property *pp; | 57 | struct property *pp; |
64 | struct proc_dir_entry *ent; | 58 | struct proc_dir_entry *ent; |
65 | struct device_node *child, *sib; | 59 | struct device_node *child; |
66 | const char *p, *at; | 60 | struct proc_dir_entry *list = NULL, **lastp; |
67 | int l; | 61 | const char *p; |
68 | struct proc_dir_entry *list, **lastp, *al; | ||
69 | 62 | ||
70 | set_node_proc_entry(np, de); | 63 | set_node_proc_entry(np, de); |
71 | lastp = &list; | 64 | lastp = &list; |
72 | for (pp = np->properties; pp != 0; pp = pp->next) { | 65 | for (child = NULL; (child = of_get_next_child(np, child));) { |
73 | /* | ||
74 | * Unfortunately proc_register puts each new entry | ||
75 | * at the beginning of the list. So we rearrange them. | ||
76 | */ | ||
77 | ent = create_proc_read_entry(pp->name, strncmp(pp->name, "security-", 9) ? | ||
78 | S_IRUGO : S_IRUSR, de, property_read_proc, pp); | ||
79 | if (ent == 0) | ||
80 | break; | ||
81 | if (!strncmp(pp->name, "security-", 9)) | ||
82 | ent->size = 0; /* don't leak number of password chars */ | ||
83 | else | ||
84 | ent->size = pp->length; | ||
85 | *lastp = ent; | ||
86 | lastp = &ent->next; | ||
87 | } | ||
88 | child = NULL; | ||
89 | while ((child = of_get_next_child(np, child))) { | ||
90 | p = strrchr(child->full_name, '/'); | 66 | p = strrchr(child->full_name, '/'); |
91 | if (!p) | 67 | if (!p) |
92 | p = child->full_name; | 68 | p = child->full_name; |
93 | else | 69 | else |
94 | ++p; | 70 | ++p; |
95 | /* chop off '@0' if the name ends with that */ | ||
96 | l = strlen(p); | ||
97 | if (l > 2 && p[l-2] == '@' && p[l-1] == '0') | ||
98 | l -= 2; | ||
99 | ent = proc_mkdir(p, de); | 71 | ent = proc_mkdir(p, de); |
100 | if (ent == 0) | 72 | if (ent == 0) |
101 | break; | 73 | break; |
102 | *lastp = ent; | 74 | *lastp = ent; |
75 | ent->next = NULL; | ||
103 | lastp = &ent->next; | 76 | lastp = &ent->next; |
104 | proc_device_tree_add_node(child, ent); | 77 | proc_device_tree_add_node(child, ent); |
105 | 78 | } | |
106 | /* | 79 | of_node_put(child); |
107 | * If we left the address part on the name, consider | 80 | for (pp = np->properties; pp != 0; pp = pp->next) { |
108 | * adding symlinks from the name and address parts. | ||
109 | */ | ||
110 | if (p[l] != 0 || (at = strchr(p, '@')) == 0) | ||
111 | continue; | ||
112 | |||
113 | /* | 81 | /* |
114 | * If this is the first node with a given name property, | 82 | * Yet another Apple device-tree bogosity: on some machines, |
115 | * add a symlink with the name property as its name. | 83 | * they have properties & nodes with the same name. Those |
84 | * properties are quite unimportant for us though, thus we | ||
85 | * simply "skip" them here, but we do have to check. | ||
116 | */ | 86 | */ |
117 | sib = NULL; | 87 | for (ent = list; ent != NULL; ent = ent->next) |
118 | while ((sib = of_get_next_child(np, sib)) && sib != child) | 88 | if (!strcmp(ent->name, pp->name)) |
119 | if (sib->name && strcmp(sib->name, child->name) == 0) | ||
120 | break; | ||
121 | if (sib == child && strncmp(p, child->name, l) != 0) { | ||
122 | al = proc_symlink(child->name, de, ent->name); | ||
123 | if (al == 0) { | ||
124 | of_node_put(sib); | ||
125 | break; | 89 | break; |
126 | } | 90 | if (ent != NULL) { |
127 | set_node_name_link(child, al); | 91 | printk(KERN_WARNING "device-tree: property \"%s\" name" |
128 | *lastp = al; | 92 | " conflicts with node in %s\n", pp->name, |
129 | lastp = &al->next; | 93 | np->full_name); |
94 | continue; | ||
130 | } | 95 | } |
131 | of_node_put(sib); | 96 | |
132 | /* | 97 | /* |
133 | * Add another directory with the @address part as its name. | 98 | * Unfortunately proc_register puts each new entry |
99 | * at the beginning of the list. So we rearrange them. | ||
134 | */ | 100 | */ |
135 | al = proc_symlink(at, de, ent->name); | 101 | ent = create_proc_read_entry(pp->name, |
136 | if (al == 0) | 102 | strncmp(pp->name, "security-", 9) |
103 | ? S_IRUGO : S_IRUSR, de, | ||
104 | property_read_proc, pp); | ||
105 | if (ent == 0) | ||
137 | break; | 106 | break; |
138 | set_node_addr_link(child, al); | 107 | if (!strncmp(pp->name, "security-", 9)) |
139 | *lastp = al; | 108 | ent->size = 0; /* don't leak number of password chars */ |
140 | lastp = &al->next; | 109 | else |
110 | ent->size = pp->length; | ||
111 | ent->next = NULL; | ||
112 | *lastp = ent; | ||
113 | lastp = &ent->next; | ||
141 | } | 114 | } |
142 | of_node_put(child); | ||
143 | *lastp = NULL; | ||
144 | de->subdir = list; | 115 | de->subdir = list; |
145 | } | 116 | } |
146 | 117 | ||
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index a60a3b3d8a7b..a3453555a94e 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/jiffies.h> | 44 | #include <linux/jiffies.h> |
45 | #include <linux/sysrq.h> | 45 | #include <linux/sysrq.h> |
46 | #include <linux/vmalloc.h> | 46 | #include <linux/vmalloc.h> |
47 | #include <linux/crash_dump.h> | ||
47 | #include <asm/uaccess.h> | 48 | #include <asm/uaccess.h> |
48 | #include <asm/pgtable.h> | 49 | #include <asm/pgtable.h> |
49 | #include <asm/io.h> | 50 | #include <asm/io.h> |
@@ -219,6 +220,19 @@ static struct file_operations fragmentation_file_operations = { | |||
219 | .release = seq_release, | 220 | .release = seq_release, |
220 | }; | 221 | }; |
221 | 222 | ||
223 | extern struct seq_operations zoneinfo_op; | ||
224 | static int zoneinfo_open(struct inode *inode, struct file *file) | ||
225 | { | ||
226 | return seq_open(file, &zoneinfo_op); | ||
227 | } | ||
228 | |||
229 | static struct file_operations proc_zoneinfo_file_operations = { | ||
230 | .open = zoneinfo_open, | ||
231 | .read = seq_read, | ||
232 | .llseek = seq_lseek, | ||
233 | .release = seq_release, | ||
234 | }; | ||
235 | |||
222 | static int version_read_proc(char *page, char **start, off_t off, | 236 | static int version_read_proc(char *page, char **start, off_t off, |
223 | int count, int *eof, void *data) | 237 | int count, int *eof, void *data) |
224 | { | 238 | { |
@@ -438,7 +452,7 @@ static int devices_read_proc(char *page, char **start, off_t off, | |||
438 | int count, int *eof, void *data) | 452 | int count, int *eof, void *data) |
439 | { | 453 | { |
440 | int len = get_chrdev_list(page); | 454 | int len = get_chrdev_list(page); |
441 | len += get_blkdev_list(page+len); | 455 | len += get_blkdev_list(page+len, len); |
442 | return proc_calc_metrics(page, start, off, count, eof, len); | 456 | return proc_calc_metrics(page, start, off, count, eof, len); |
443 | } | 457 | } |
444 | 458 | ||
@@ -589,6 +603,7 @@ void __init proc_misc_init(void) | |||
589 | create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); | 603 | create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); |
590 | create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); | 604 | create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); |
591 | create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); | 605 | create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); |
606 | create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations); | ||
592 | create_seq_entry("diskstats", 0, &proc_diskstats_operations); | 607 | create_seq_entry("diskstats", 0, &proc_diskstats_operations); |
593 | #ifdef CONFIG_MODULES | 608 | #ifdef CONFIG_MODULES |
594 | create_seq_entry("modules", 0, &proc_modules_operations); | 609 | create_seq_entry("modules", 0, &proc_modules_operations); |
@@ -604,6 +619,11 @@ void __init proc_misc_init(void) | |||
604 | (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; | 619 | (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; |
605 | } | 620 | } |
606 | #endif | 621 | #endif |
622 | #ifdef CONFIG_PROC_VMCORE | ||
623 | proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL); | ||
624 | if (proc_vmcore) | ||
625 | proc_vmcore->proc_fops = &proc_vmcore_operations; | ||
626 | #endif | ||
607 | #ifdef CONFIG_MAGIC_SYSRQ | 627 | #ifdef CONFIG_MAGIC_SYSRQ |
608 | entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL); | 628 | entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL); |
609 | if (entry) | 629 | if (entry) |
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c new file mode 100644 index 000000000000..3b2e7b69e63a --- /dev/null +++ b/fs/proc/vmcore.c | |||
@@ -0,0 +1,669 @@ | |||
1 | /* | ||
2 | * fs/proc/vmcore.c Interface for accessing the crash | ||
3 | * dump from the system's previous life. | ||
4 | * Heavily borrowed from fs/proc/kcore.c | ||
5 | * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) | ||
6 | * Copyright (C) IBM Corporation, 2004. All rights reserved | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/proc_fs.h> | ||
13 | #include <linux/user.h> | ||
14 | #include <linux/a.out.h> | ||
15 | #include <linux/elf.h> | ||
16 | #include <linux/elfcore.h> | ||
17 | #include <linux/proc_fs.h> | ||
18 | #include <linux/highmem.h> | ||
19 | #include <linux/bootmem.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/crash_dump.h> | ||
22 | #include <linux/list.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | #include <asm/io.h> | ||
25 | |||
26 | /* List representing chunks of contiguous memory areas and their offsets in | ||
27 | * vmcore file. | ||
28 | */ | ||
29 | static LIST_HEAD(vmcore_list); | ||
30 | |||
31 | /* Stores the pointer to the buffer containing kernel elf core headers. */ | ||
32 | static char *elfcorebuf; | ||
33 | static size_t elfcorebuf_sz; | ||
34 | |||
35 | /* Total size of vmcore file. */ | ||
36 | static u64 vmcore_size; | ||
37 | |||
38 | struct proc_dir_entry *proc_vmcore = NULL; | ||
39 | |||
40 | /* Reads a page from the oldmem device from given offset. */ | ||
41 | static ssize_t read_from_oldmem(char *buf, size_t count, | ||
42 | loff_t *ppos, int userbuf) | ||
43 | { | ||
44 | unsigned long pfn, offset; | ||
45 | size_t nr_bytes; | ||
46 | ssize_t read = 0, tmp; | ||
47 | |||
48 | if (!count) | ||
49 | return 0; | ||
50 | |||
51 | offset = (unsigned long)(*ppos % PAGE_SIZE); | ||
52 | pfn = (unsigned long)(*ppos / PAGE_SIZE); | ||
53 | if (pfn > saved_max_pfn) | ||
54 | return -EINVAL; | ||
55 | |||
56 | do { | ||
57 | if (count > (PAGE_SIZE - offset)) | ||
58 | nr_bytes = PAGE_SIZE - offset; | ||
59 | else | ||
60 | nr_bytes = count; | ||
61 | |||
62 | tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf); | ||
63 | if (tmp < 0) | ||
64 | return tmp; | ||
65 | *ppos += nr_bytes; | ||
66 | count -= nr_bytes; | ||
67 | buf += nr_bytes; | ||
68 | read += nr_bytes; | ||
69 | ++pfn; | ||
70 | offset = 0; | ||
71 | } while (count); | ||
72 | |||
73 | return read; | ||
74 | } | ||
75 | |||
76 | /* Maps vmcore file offset to respective physical address in memroy. */ | ||
77 | static u64 map_offset_to_paddr(loff_t offset, struct list_head *vc_list, | ||
78 | struct vmcore **m_ptr) | ||
79 | { | ||
80 | struct vmcore *m; | ||
81 | u64 paddr; | ||
82 | |||
83 | list_for_each_entry(m, vc_list, list) { | ||
84 | u64 start, end; | ||
85 | start = m->offset; | ||
86 | end = m->offset + m->size - 1; | ||
87 | if (offset >= start && offset <= end) { | ||
88 | paddr = m->paddr + offset - start; | ||
89 | *m_ptr = m; | ||
90 | return paddr; | ||
91 | } | ||
92 | } | ||
93 | *m_ptr = NULL; | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* Read from the ELF header and then the crash dump. On error, negative value is | ||
98 | * returned otherwise number of bytes read are returned. | ||
99 | */ | ||
100 | static ssize_t read_vmcore(struct file *file, char __user *buffer, | ||
101 | size_t buflen, loff_t *fpos) | ||
102 | { | ||
103 | ssize_t acc = 0, tmp; | ||
104 | size_t tsz, nr_bytes; | ||
105 | u64 start; | ||
106 | struct vmcore *curr_m = NULL; | ||
107 | |||
108 | if (buflen == 0 || *fpos >= vmcore_size) | ||
109 | return 0; | ||
110 | |||
111 | /* trim buflen to not go beyond EOF */ | ||
112 | if (buflen > vmcore_size - *fpos) | ||
113 | buflen = vmcore_size - *fpos; | ||
114 | |||
115 | /* Read ELF core header */ | ||
116 | if (*fpos < elfcorebuf_sz) { | ||
117 | tsz = elfcorebuf_sz - *fpos; | ||
118 | if (buflen < tsz) | ||
119 | tsz = buflen; | ||
120 | if (copy_to_user(buffer, elfcorebuf + *fpos, tsz)) | ||
121 | return -EFAULT; | ||
122 | buflen -= tsz; | ||
123 | *fpos += tsz; | ||
124 | buffer += tsz; | ||
125 | acc += tsz; | ||
126 | |||
127 | /* leave now if filled buffer already */ | ||
128 | if (buflen == 0) | ||
129 | return acc; | ||
130 | } | ||
131 | |||
132 | start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m); | ||
133 | if (!curr_m) | ||
134 | return -EINVAL; | ||
135 | if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) | ||
136 | tsz = buflen; | ||
137 | |||
138 | /* Calculate left bytes in current memory segment. */ | ||
139 | nr_bytes = (curr_m->size - (start - curr_m->paddr)); | ||
140 | if (tsz > nr_bytes) | ||
141 | tsz = nr_bytes; | ||
142 | |||
143 | while (buflen) { | ||
144 | tmp = read_from_oldmem(buffer, tsz, &start, 1); | ||
145 | if (tmp < 0) | ||
146 | return tmp; | ||
147 | buflen -= tsz; | ||
148 | *fpos += tsz; | ||
149 | buffer += tsz; | ||
150 | acc += tsz; | ||
151 | if (start >= (curr_m->paddr + curr_m->size)) { | ||
152 | if (curr_m->list.next == &vmcore_list) | ||
153 | return acc; /*EOF*/ | ||
154 | curr_m = list_entry(curr_m->list.next, | ||
155 | struct vmcore, list); | ||
156 | start = curr_m->paddr; | ||
157 | } | ||
158 | if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) | ||
159 | tsz = buflen; | ||
160 | /* Calculate left bytes in current memory segment. */ | ||
161 | nr_bytes = (curr_m->size - (start - curr_m->paddr)); | ||
162 | if (tsz > nr_bytes) | ||
163 | tsz = nr_bytes; | ||
164 | } | ||
165 | return acc; | ||
166 | } | ||
167 | |||
168 | static int open_vmcore(struct inode *inode, struct file *filp) | ||
169 | { | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | struct file_operations proc_vmcore_operations = { | ||
174 | .read = read_vmcore, | ||
175 | .open = open_vmcore, | ||
176 | }; | ||
177 | |||
178 | static struct vmcore* __init get_new_element(void) | ||
179 | { | ||
180 | struct vmcore *p; | ||
181 | |||
182 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
183 | if (p) | ||
184 | memset(p, 0, sizeof(*p)); | ||
185 | return p; | ||
186 | } | ||
187 | |||
188 | static u64 __init get_vmcore_size_elf64(char *elfptr) | ||
189 | { | ||
190 | int i; | ||
191 | u64 size; | ||
192 | Elf64_Ehdr *ehdr_ptr; | ||
193 | Elf64_Phdr *phdr_ptr; | ||
194 | |||
195 | ehdr_ptr = (Elf64_Ehdr *)elfptr; | ||
196 | phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); | ||
197 | size = sizeof(Elf64_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr)); | ||
198 | for (i = 0; i < ehdr_ptr->e_phnum; i++) { | ||
199 | size += phdr_ptr->p_memsz; | ||
200 | phdr_ptr++; | ||
201 | } | ||
202 | return size; | ||
203 | } | ||
204 | |||
205 | static u64 __init get_vmcore_size_elf32(char *elfptr) | ||
206 | { | ||
207 | int i; | ||
208 | u64 size; | ||
209 | Elf32_Ehdr *ehdr_ptr; | ||
210 | Elf32_Phdr *phdr_ptr; | ||
211 | |||
212 | ehdr_ptr = (Elf32_Ehdr *)elfptr; | ||
213 | phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); | ||
214 | size = sizeof(Elf32_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr)); | ||
215 | for (i = 0; i < ehdr_ptr->e_phnum; i++) { | ||
216 | size += phdr_ptr->p_memsz; | ||
217 | phdr_ptr++; | ||
218 | } | ||
219 | return size; | ||
220 | } | ||
221 | |||
222 | /* Merges all the PT_NOTE headers into one. */ | ||
223 | static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz, | ||
224 | struct list_head *vc_list) | ||
225 | { | ||
226 | int i, nr_ptnote=0, rc=0; | ||
227 | char *tmp; | ||
228 | Elf64_Ehdr *ehdr_ptr; | ||
229 | Elf64_Phdr phdr, *phdr_ptr; | ||
230 | Elf64_Nhdr *nhdr_ptr; | ||
231 | u64 phdr_sz = 0, note_off; | ||
232 | |||
233 | ehdr_ptr = (Elf64_Ehdr *)elfptr; | ||
234 | phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); | ||
235 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | ||
236 | int j; | ||
237 | void *notes_section; | ||
238 | struct vmcore *new; | ||
239 | u64 offset, max_sz, sz, real_sz = 0; | ||
240 | if (phdr_ptr->p_type != PT_NOTE) | ||
241 | continue; | ||
242 | nr_ptnote++; | ||
243 | max_sz = phdr_ptr->p_memsz; | ||
244 | offset = phdr_ptr->p_offset; | ||
245 | notes_section = kmalloc(max_sz, GFP_KERNEL); | ||
246 | if (!notes_section) | ||
247 | return -ENOMEM; | ||
248 | rc = read_from_oldmem(notes_section, max_sz, &offset, 0); | ||
249 | if (rc < 0) { | ||
250 | kfree(notes_section); | ||
251 | return rc; | ||
252 | } | ||
253 | nhdr_ptr = notes_section; | ||
254 | for (j = 0; j < max_sz; j += sz) { | ||
255 | if (nhdr_ptr->n_namesz == 0) | ||
256 | break; | ||
257 | sz = sizeof(Elf64_Nhdr) + | ||
258 | ((nhdr_ptr->n_namesz + 3) & ~3) + | ||
259 | ((nhdr_ptr->n_descsz + 3) & ~3); | ||
260 | real_sz += sz; | ||
261 | nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz); | ||
262 | } | ||
263 | |||
264 | /* Add this contiguous chunk of notes section to vmcore list.*/ | ||
265 | new = get_new_element(); | ||
266 | if (!new) { | ||
267 | kfree(notes_section); | ||
268 | return -ENOMEM; | ||
269 | } | ||
270 | new->paddr = phdr_ptr->p_offset; | ||
271 | new->size = real_sz; | ||
272 | list_add_tail(&new->list, vc_list); | ||
273 | phdr_sz += real_sz; | ||
274 | kfree(notes_section); | ||
275 | } | ||
276 | |||
277 | /* Prepare merged PT_NOTE program header. */ | ||
278 | phdr.p_type = PT_NOTE; | ||
279 | phdr.p_flags = 0; | ||
280 | note_off = sizeof(Elf64_Ehdr) + | ||
281 | (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr); | ||
282 | phdr.p_offset = note_off; | ||
283 | phdr.p_vaddr = phdr.p_paddr = 0; | ||
284 | phdr.p_filesz = phdr.p_memsz = phdr_sz; | ||
285 | phdr.p_align = 0; | ||
286 | |||
287 | /* Add merged PT_NOTE program header*/ | ||
288 | tmp = elfptr + sizeof(Elf64_Ehdr); | ||
289 | memcpy(tmp, &phdr, sizeof(phdr)); | ||
290 | tmp += sizeof(phdr); | ||
291 | |||
292 | /* Remove unwanted PT_NOTE program headers. */ | ||
293 | i = (nr_ptnote - 1) * sizeof(Elf64_Phdr); | ||
294 | *elfsz = *elfsz - i; | ||
295 | memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf64_Ehdr)-sizeof(Elf64_Phdr))); | ||
296 | |||
297 | /* Modify e_phnum to reflect merged headers. */ | ||
298 | ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | /* Merges all the PT_NOTE headers into one. */ | ||
304 | static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz, | ||
305 | struct list_head *vc_list) | ||
306 | { | ||
307 | int i, nr_ptnote=0, rc=0; | ||
308 | char *tmp; | ||
309 | Elf32_Ehdr *ehdr_ptr; | ||
310 | Elf32_Phdr phdr, *phdr_ptr; | ||
311 | Elf32_Nhdr *nhdr_ptr; | ||
312 | u64 phdr_sz = 0, note_off; | ||
313 | |||
314 | ehdr_ptr = (Elf32_Ehdr *)elfptr; | ||
315 | phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); | ||
316 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | ||
317 | int j; | ||
318 | void *notes_section; | ||
319 | struct vmcore *new; | ||
320 | u64 offset, max_sz, sz, real_sz = 0; | ||
321 | if (phdr_ptr->p_type != PT_NOTE) | ||
322 | continue; | ||
323 | nr_ptnote++; | ||
324 | max_sz = phdr_ptr->p_memsz; | ||
325 | offset = phdr_ptr->p_offset; | ||
326 | notes_section = kmalloc(max_sz, GFP_KERNEL); | ||
327 | if (!notes_section) | ||
328 | return -ENOMEM; | ||
329 | rc = read_from_oldmem(notes_section, max_sz, &offset, 0); | ||
330 | if (rc < 0) { | ||
331 | kfree(notes_section); | ||
332 | return rc; | ||
333 | } | ||
334 | nhdr_ptr = notes_section; | ||
335 | for (j = 0; j < max_sz; j += sz) { | ||
336 | if (nhdr_ptr->n_namesz == 0) | ||
337 | break; | ||
338 | sz = sizeof(Elf32_Nhdr) + | ||
339 | ((nhdr_ptr->n_namesz + 3) & ~3) + | ||
340 | ((nhdr_ptr->n_descsz + 3) & ~3); | ||
341 | real_sz += sz; | ||
342 | nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz); | ||
343 | } | ||
344 | |||
345 | /* Add this contiguous chunk of notes section to vmcore list.*/ | ||
346 | new = get_new_element(); | ||
347 | if (!new) { | ||
348 | kfree(notes_section); | ||
349 | return -ENOMEM; | ||
350 | } | ||
351 | new->paddr = phdr_ptr->p_offset; | ||
352 | new->size = real_sz; | ||
353 | list_add_tail(&new->list, vc_list); | ||
354 | phdr_sz += real_sz; | ||
355 | kfree(notes_section); | ||
356 | } | ||
357 | |||
358 | /* Prepare merged PT_NOTE program header. */ | ||
359 | phdr.p_type = PT_NOTE; | ||
360 | phdr.p_flags = 0; | ||
361 | note_off = sizeof(Elf32_Ehdr) + | ||
362 | (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr); | ||
363 | phdr.p_offset = note_off; | ||
364 | phdr.p_vaddr = phdr.p_paddr = 0; | ||
365 | phdr.p_filesz = phdr.p_memsz = phdr_sz; | ||
366 | phdr.p_align = 0; | ||
367 | |||
368 | /* Add merged PT_NOTE program header*/ | ||
369 | tmp = elfptr + sizeof(Elf32_Ehdr); | ||
370 | memcpy(tmp, &phdr, sizeof(phdr)); | ||
371 | tmp += sizeof(phdr); | ||
372 | |||
373 | /* Remove unwanted PT_NOTE program headers. */ | ||
374 | i = (nr_ptnote - 1) * sizeof(Elf32_Phdr); | ||
375 | *elfsz = *elfsz - i; | ||
376 | memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf32_Ehdr)-sizeof(Elf32_Phdr))); | ||
377 | |||
378 | /* Modify e_phnum to reflect merged headers. */ | ||
379 | ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1; | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /* Add memory chunks represented by program headers to vmcore list. Also update | ||
385 | * the new offset fields of exported program headers. */ | ||
386 | static int __init process_ptload_program_headers_elf64(char *elfptr, | ||
387 | size_t elfsz, | ||
388 | struct list_head *vc_list) | ||
389 | { | ||
390 | int i; | ||
391 | Elf64_Ehdr *ehdr_ptr; | ||
392 | Elf64_Phdr *phdr_ptr; | ||
393 | loff_t vmcore_off; | ||
394 | struct vmcore *new; | ||
395 | |||
396 | ehdr_ptr = (Elf64_Ehdr *)elfptr; | ||
397 | phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */ | ||
398 | |||
399 | /* First program header is PT_NOTE header. */ | ||
400 | vmcore_off = sizeof(Elf64_Ehdr) + | ||
401 | (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr) + | ||
402 | phdr_ptr->p_memsz; /* Note sections */ | ||
403 | |||
404 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | ||
405 | if (phdr_ptr->p_type != PT_LOAD) | ||
406 | continue; | ||
407 | |||
408 | /* Add this contiguous chunk of memory to vmcore list.*/ | ||
409 | new = get_new_element(); | ||
410 | if (!new) | ||
411 | return -ENOMEM; | ||
412 | new->paddr = phdr_ptr->p_offset; | ||
413 | new->size = phdr_ptr->p_memsz; | ||
414 | list_add_tail(&new->list, vc_list); | ||
415 | |||
416 | /* Update the program header offset. */ | ||
417 | phdr_ptr->p_offset = vmcore_off; | ||
418 | vmcore_off = vmcore_off + phdr_ptr->p_memsz; | ||
419 | } | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int __init process_ptload_program_headers_elf32(char *elfptr, | ||
424 | size_t elfsz, | ||
425 | struct list_head *vc_list) | ||
426 | { | ||
427 | int i; | ||
428 | Elf32_Ehdr *ehdr_ptr; | ||
429 | Elf32_Phdr *phdr_ptr; | ||
430 | loff_t vmcore_off; | ||
431 | struct vmcore *new; | ||
432 | |||
433 | ehdr_ptr = (Elf32_Ehdr *)elfptr; | ||
434 | phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */ | ||
435 | |||
436 | /* First program header is PT_NOTE header. */ | ||
437 | vmcore_off = sizeof(Elf32_Ehdr) + | ||
438 | (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr) + | ||
439 | phdr_ptr->p_memsz; /* Note sections */ | ||
440 | |||
441 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | ||
442 | if (phdr_ptr->p_type != PT_LOAD) | ||
443 | continue; | ||
444 | |||
445 | /* Add this contiguous chunk of memory to vmcore list.*/ | ||
446 | new = get_new_element(); | ||
447 | if (!new) | ||
448 | return -ENOMEM; | ||
449 | new->paddr = phdr_ptr->p_offset; | ||
450 | new->size = phdr_ptr->p_memsz; | ||
451 | list_add_tail(&new->list, vc_list); | ||
452 | |||
453 | /* Update the program header offset */ | ||
454 | phdr_ptr->p_offset = vmcore_off; | ||
455 | vmcore_off = vmcore_off + phdr_ptr->p_memsz; | ||
456 | } | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | /* Sets offset fields of vmcore elements. */ | ||
461 | static void __init set_vmcore_list_offsets_elf64(char *elfptr, | ||
462 | struct list_head *vc_list) | ||
463 | { | ||
464 | loff_t vmcore_off; | ||
465 | Elf64_Ehdr *ehdr_ptr; | ||
466 | struct vmcore *m; | ||
467 | |||
468 | ehdr_ptr = (Elf64_Ehdr *)elfptr; | ||
469 | |||
470 | /* Skip Elf header and program headers. */ | ||
471 | vmcore_off = sizeof(Elf64_Ehdr) + | ||
472 | (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr); | ||
473 | |||
474 | list_for_each_entry(m, vc_list, list) { | ||
475 | m->offset = vmcore_off; | ||
476 | vmcore_off += m->size; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | /* Sets offset fields of vmcore elements. */ | ||
481 | static void __init set_vmcore_list_offsets_elf32(char *elfptr, | ||
482 | struct list_head *vc_list) | ||
483 | { | ||
484 | loff_t vmcore_off; | ||
485 | Elf32_Ehdr *ehdr_ptr; | ||
486 | struct vmcore *m; | ||
487 | |||
488 | ehdr_ptr = (Elf32_Ehdr *)elfptr; | ||
489 | |||
490 | /* Skip Elf header and program headers. */ | ||
491 | vmcore_off = sizeof(Elf32_Ehdr) + | ||
492 | (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr); | ||
493 | |||
494 | list_for_each_entry(m, vc_list, list) { | ||
495 | m->offset = vmcore_off; | ||
496 | vmcore_off += m->size; | ||
497 | } | ||
498 | } | ||
499 | |||
500 | static int __init parse_crash_elf64_headers(void) | ||
501 | { | ||
502 | int rc=0; | ||
503 | Elf64_Ehdr ehdr; | ||
504 | u64 addr; | ||
505 | |||
506 | addr = elfcorehdr_addr; | ||
507 | |||
508 | /* Read Elf header */ | ||
509 | rc = read_from_oldmem((char*)&ehdr, sizeof(Elf64_Ehdr), &addr, 0); | ||
510 | if (rc < 0) | ||
511 | return rc; | ||
512 | |||
513 | /* Do some basic Verification. */ | ||
514 | if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || | ||
515 | (ehdr.e_type != ET_CORE) || | ||
516 | !elf_check_arch(&ehdr) || | ||
517 | ehdr.e_ident[EI_CLASS] != ELFCLASS64 || | ||
518 | ehdr.e_ident[EI_VERSION] != EV_CURRENT || | ||
519 | ehdr.e_version != EV_CURRENT || | ||
520 | ehdr.e_ehsize != sizeof(Elf64_Ehdr) || | ||
521 | ehdr.e_phentsize != sizeof(Elf64_Phdr) || | ||
522 | ehdr.e_phnum == 0) { | ||
523 | printk(KERN_WARNING "Warning: Core image elf header is not" | ||
524 | "sane\n"); | ||
525 | return -EINVAL; | ||
526 | } | ||
527 | |||
528 | /* Read in all elf headers. */ | ||
529 | elfcorebuf_sz = sizeof(Elf64_Ehdr) + ehdr.e_phnum * sizeof(Elf64_Phdr); | ||
530 | elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL); | ||
531 | if (!elfcorebuf) | ||
532 | return -ENOMEM; | ||
533 | addr = elfcorehdr_addr; | ||
534 | rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0); | ||
535 | if (rc < 0) { | ||
536 | kfree(elfcorebuf); | ||
537 | return rc; | ||
538 | } | ||
539 | |||
540 | /* Merge all PT_NOTE headers into one. */ | ||
541 | rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list); | ||
542 | if (rc) { | ||
543 | kfree(elfcorebuf); | ||
544 | return rc; | ||
545 | } | ||
546 | rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz, | ||
547 | &vmcore_list); | ||
548 | if (rc) { | ||
549 | kfree(elfcorebuf); | ||
550 | return rc; | ||
551 | } | ||
552 | set_vmcore_list_offsets_elf64(elfcorebuf, &vmcore_list); | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | static int __init parse_crash_elf32_headers(void) | ||
557 | { | ||
558 | int rc=0; | ||
559 | Elf32_Ehdr ehdr; | ||
560 | u64 addr; | ||
561 | |||
562 | addr = elfcorehdr_addr; | ||
563 | |||
564 | /* Read Elf header */ | ||
565 | rc = read_from_oldmem((char*)&ehdr, sizeof(Elf32_Ehdr), &addr, 0); | ||
566 | if (rc < 0) | ||
567 | return rc; | ||
568 | |||
569 | /* Do some basic Verification. */ | ||
570 | if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || | ||
571 | (ehdr.e_type != ET_CORE) || | ||
572 | !elf_check_arch(&ehdr) || | ||
573 | ehdr.e_ident[EI_CLASS] != ELFCLASS32|| | ||
574 | ehdr.e_ident[EI_VERSION] != EV_CURRENT || | ||
575 | ehdr.e_version != EV_CURRENT || | ||
576 | ehdr.e_ehsize != sizeof(Elf32_Ehdr) || | ||
577 | ehdr.e_phentsize != sizeof(Elf32_Phdr) || | ||
578 | ehdr.e_phnum == 0) { | ||
579 | printk(KERN_WARNING "Warning: Core image elf header is not" | ||
580 | "sane\n"); | ||
581 | return -EINVAL; | ||
582 | } | ||
583 | |||
584 | /* Read in all elf headers. */ | ||
585 | elfcorebuf_sz = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr); | ||
586 | elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL); | ||
587 | if (!elfcorebuf) | ||
588 | return -ENOMEM; | ||
589 | addr = elfcorehdr_addr; | ||
590 | rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0); | ||
591 | if (rc < 0) { | ||
592 | kfree(elfcorebuf); | ||
593 | return rc; | ||
594 | } | ||
595 | |||
596 | /* Merge all PT_NOTE headers into one. */ | ||
597 | rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list); | ||
598 | if (rc) { | ||
599 | kfree(elfcorebuf); | ||
600 | return rc; | ||
601 | } | ||
602 | rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz, | ||
603 | &vmcore_list); | ||
604 | if (rc) { | ||
605 | kfree(elfcorebuf); | ||
606 | return rc; | ||
607 | } | ||
608 | set_vmcore_list_offsets_elf32(elfcorebuf, &vmcore_list); | ||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static int __init parse_crash_elf_headers(void) | ||
613 | { | ||
614 | unsigned char e_ident[EI_NIDENT]; | ||
615 | u64 addr; | ||
616 | int rc=0; | ||
617 | |||
618 | addr = elfcorehdr_addr; | ||
619 | rc = read_from_oldmem(e_ident, EI_NIDENT, &addr, 0); | ||
620 | if (rc < 0) | ||
621 | return rc; | ||
622 | if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) { | ||
623 | printk(KERN_WARNING "Warning: Core image elf header" | ||
624 | " not found\n"); | ||
625 | return -EINVAL; | ||
626 | } | ||
627 | |||
628 | if (e_ident[EI_CLASS] == ELFCLASS64) { | ||
629 | rc = parse_crash_elf64_headers(); | ||
630 | if (rc) | ||
631 | return rc; | ||
632 | |||
633 | /* Determine vmcore size. */ | ||
634 | vmcore_size = get_vmcore_size_elf64(elfcorebuf); | ||
635 | } else if (e_ident[EI_CLASS] == ELFCLASS32) { | ||
636 | rc = parse_crash_elf32_headers(); | ||
637 | if (rc) | ||
638 | return rc; | ||
639 | |||
640 | /* Determine vmcore size. */ | ||
641 | vmcore_size = get_vmcore_size_elf32(elfcorebuf); | ||
642 | } else { | ||
643 | printk(KERN_WARNING "Warning: Core image elf header is not" | ||
644 | " sane\n"); | ||
645 | return -EINVAL; | ||
646 | } | ||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | /* Init function for vmcore module. */ | ||
651 | static int __init vmcore_init(void) | ||
652 | { | ||
653 | int rc = 0; | ||
654 | |||
655 | /* If elfcorehdr= has been passed in cmdline, then capture the dump.*/ | ||
656 | if (!(elfcorehdr_addr < ELFCORE_ADDR_MAX)) | ||
657 | return rc; | ||
658 | rc = parse_crash_elf_headers(); | ||
659 | if (rc) { | ||
660 | printk(KERN_WARNING "Kdump: vmcore not initialized\n"); | ||
661 | return rc; | ||
662 | } | ||
663 | |||
664 | /* Initialize /proc/vmcore size if proc is already up. */ | ||
665 | if (proc_vmcore) | ||
666 | proc_vmcore->size = vmcore_size; | ||
667 | return 0; | ||
668 | } | ||
669 | module_init(vmcore_init) | ||
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c index cd66147cca04..7a8f5595c26f 100644 --- a/fs/qnx4/dir.c +++ b/fs/qnx4/dir.c | |||
@@ -61,7 +61,7 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
61 | ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1; | 61 | ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1; |
62 | else { | 62 | else { |
63 | le = (struct qnx4_link_info*)de; | 63 | le = (struct qnx4_link_info*)de; |
64 | ino = ( le->dl_inode_blk - 1 ) * | 64 | ino = ( le32_to_cpu(le->dl_inode_blk) - 1 ) * |
65 | QNX4_INODES_PER_BLOCK + | 65 | QNX4_INODES_PER_BLOCK + |
66 | le->dl_inode_ndx; | 66 | le->dl_inode_ndx; |
67 | } | 67 | } |
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index aa92d6b76a9a..b79162a35478 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c | |||
@@ -236,7 +236,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock ) | |||
236 | struct buffer_head *bh = NULL; | 236 | struct buffer_head *bh = NULL; |
237 | struct qnx4_xblk *xblk = NULL; | 237 | struct qnx4_xblk *xblk = NULL; |
238 | struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode); | 238 | struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode); |
239 | qnx4_nxtnt_t nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts); | 239 | u16 nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts); |
240 | 240 | ||
241 | if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) { | 241 | if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) { |
242 | // iblock is in the first extent. This is easy. | 242 | // iblock is in the first extent. This is easy. |
@@ -372,7 +372,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) | |||
372 | printk("qnx4: unable to read the superblock\n"); | 372 | printk("qnx4: unable to read the superblock\n"); |
373 | goto outnobh; | 373 | goto outnobh; |
374 | } | 374 | } |
375 | if ( le32_to_cpu( *(__u32*)bh->b_data ) != QNX4_SUPER_MAGIC ) { | 375 | if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) { |
376 | if (!silent) | 376 | if (!silent) |
377 | printk("qnx4: wrong fsid in superblock.\n"); | 377 | printk("qnx4: wrong fsid in superblock.\n"); |
378 | goto out; | 378 | goto out; |
diff --git a/fs/quota.c b/fs/quota.c index 3f0333a51a23..f5d1cff55196 100644 --- a/fs/quota.c +++ b/fs/quota.c | |||
@@ -149,36 +149,6 @@ static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t | |||
149 | return error; | 149 | return error; |
150 | } | 150 | } |
151 | 151 | ||
152 | static struct super_block *get_super_to_sync(int type) | ||
153 | { | ||
154 | struct list_head *head; | ||
155 | int cnt, dirty; | ||
156 | |||
157 | restart: | ||
158 | spin_lock(&sb_lock); | ||
159 | list_for_each(head, &super_blocks) { | ||
160 | struct super_block *sb = list_entry(head, struct super_block, s_list); | ||
161 | |||
162 | /* This test just improves performance so it needn't be reliable... */ | ||
163 | for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) | ||
164 | if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) | ||
165 | && info_any_dirty(&sb_dqopt(sb)->info[cnt])) | ||
166 | dirty = 1; | ||
167 | if (!dirty) | ||
168 | continue; | ||
169 | sb->s_count++; | ||
170 | spin_unlock(&sb_lock); | ||
171 | down_read(&sb->s_umount); | ||
172 | if (!sb->s_root) { | ||
173 | drop_super(sb); | ||
174 | goto restart; | ||
175 | } | ||
176 | return sb; | ||
177 | } | ||
178 | spin_unlock(&sb_lock); | ||
179 | return NULL; | ||
180 | } | ||
181 | |||
182 | static void quota_sync_sb(struct super_block *sb, int type) | 152 | static void quota_sync_sb(struct super_block *sb, int type) |
183 | { | 153 | { |
184 | int cnt; | 154 | int cnt; |
@@ -219,17 +189,35 @@ static void quota_sync_sb(struct super_block *sb, int type) | |||
219 | 189 | ||
220 | void sync_dquots(struct super_block *sb, int type) | 190 | void sync_dquots(struct super_block *sb, int type) |
221 | { | 191 | { |
192 | int cnt, dirty; | ||
193 | |||
222 | if (sb) { | 194 | if (sb) { |
223 | if (sb->s_qcop->quota_sync) | 195 | if (sb->s_qcop->quota_sync) |
224 | quota_sync_sb(sb, type); | 196 | quota_sync_sb(sb, type); |
197 | return; | ||
225 | } | 198 | } |
226 | else { | 199 | |
227 | while ((sb = get_super_to_sync(type)) != NULL) { | 200 | spin_lock(&sb_lock); |
228 | if (sb->s_qcop->quota_sync) | 201 | restart: |
229 | quota_sync_sb(sb, type); | 202 | list_for_each_entry(sb, &super_blocks, s_list) { |
230 | drop_super(sb); | 203 | /* This test just improves performance so it needn't be reliable... */ |
231 | } | 204 | for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) |
205 | if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) | ||
206 | && info_any_dirty(&sb_dqopt(sb)->info[cnt])) | ||
207 | dirty = 1; | ||
208 | if (!dirty) | ||
209 | continue; | ||
210 | sb->s_count++; | ||
211 | spin_unlock(&sb_lock); | ||
212 | down_read(&sb->s_umount); | ||
213 | if (sb->s_root && sb->s_qcop->quota_sync) | ||
214 | quota_sync_sb(sb, type); | ||
215 | up_read(&sb->s_umount); | ||
216 | spin_lock(&sb_lock); | ||
217 | if (__put_super_and_need_restart(sb)) | ||
218 | goto restart; | ||
232 | } | 219 | } |
220 | spin_unlock(&sb_lock); | ||
233 | } | 221 | } |
234 | 222 | ||
235 | /* Copy parameters and call proper function */ | 223 | /* Copy parameters and call proper function */ |
diff --git a/fs/read_write.c b/fs/read_write.c index c4c2bee373ed..9292f5fa4d62 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -203,6 +203,16 @@ Einval: | |||
203 | return -EINVAL; | 203 | return -EINVAL; |
204 | } | 204 | } |
205 | 205 | ||
206 | static void wait_on_retry_sync_kiocb(struct kiocb *iocb) | ||
207 | { | ||
208 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
209 | if (!kiocbIsKicked(iocb)) | ||
210 | schedule(); | ||
211 | else | ||
212 | kiocbClearKicked(iocb); | ||
213 | __set_current_state(TASK_RUNNING); | ||
214 | } | ||
215 | |||
206 | ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) | 216 | ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) |
207 | { | 217 | { |
208 | struct kiocb kiocb; | 218 | struct kiocb kiocb; |
@@ -210,7 +220,10 @@ ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *pp | |||
210 | 220 | ||
211 | init_sync_kiocb(&kiocb, filp); | 221 | init_sync_kiocb(&kiocb, filp); |
212 | kiocb.ki_pos = *ppos; | 222 | kiocb.ki_pos = *ppos; |
213 | ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos); | 223 | while (-EIOCBRETRY == |
224 | (ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos))) | ||
225 | wait_on_retry_sync_kiocb(&kiocb); | ||
226 | |||
214 | if (-EIOCBQUEUED == ret) | 227 | if (-EIOCBQUEUED == ret) |
215 | ret = wait_on_sync_kiocb(&kiocb); | 228 | ret = wait_on_sync_kiocb(&kiocb); |
216 | *ppos = kiocb.ki_pos; | 229 | *ppos = kiocb.ki_pos; |
@@ -258,7 +271,10 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof | |||
258 | 271 | ||
259 | init_sync_kiocb(&kiocb, filp); | 272 | init_sync_kiocb(&kiocb, filp); |
260 | kiocb.ki_pos = *ppos; | 273 | kiocb.ki_pos = *ppos; |
261 | ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos); | 274 | while (-EIOCBRETRY == |
275 | (ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos))) | ||
276 | wait_on_retry_sync_kiocb(&kiocb); | ||
277 | |||
262 | if (-EIOCBQUEUED == ret) | 278 | if (-EIOCBQUEUED == ret) |
263 | ret = wait_on_sync_kiocb(&kiocb); | 279 | ret = wait_on_sync_kiocb(&kiocb); |
264 | *ppos = kiocb.ki_pos; | 280 | *ppos = kiocb.ki_pos; |
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 2230afff1870..12e91209544e 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c | |||
@@ -201,7 +201,7 @@ static int reiserfs_allocate_blocks_for_region( | |||
201 | /* If we came here, it means we absolutely need to open a transaction, | 201 | /* If we came here, it means we absolutely need to open a transaction, |
202 | since we need to allocate some blocks */ | 202 | since we need to allocate some blocks */ |
203 | reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that. | 203 | reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that. |
204 | res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS); // Wish I know if this number enough | 204 | res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb)); // Wish I know if this number enough |
205 | if (res) | 205 | if (res) |
206 | goto error_exit; | 206 | goto error_exit; |
207 | reiserfs_update_inode_transaction(inode) ; | 207 | reiserfs_update_inode_transaction(inode) ; |
@@ -576,7 +576,7 @@ error_exit: | |||
576 | int err; | 576 | int err; |
577 | // update any changes we made to blk count | 577 | // update any changes we made to blk count |
578 | reiserfs_update_sd(th, inode); | 578 | reiserfs_update_sd(th, inode); |
579 | err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS); | 579 | err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb)); |
580 | if (err) | 580 | if (err) |
581 | res = err; | 581 | res = err; |
582 | } | 582 | } |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 2711dff1b7b4..289d864fe731 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -28,7 +28,7 @@ static int reiserfs_prepare_write(struct file *f, struct page *page, | |||
28 | void reiserfs_delete_inode (struct inode * inode) | 28 | void reiserfs_delete_inode (struct inode * inode) |
29 | { | 29 | { |
30 | /* We need blocks for transaction + (user+group) quota update (possibly delete) */ | 30 | /* We need blocks for transaction + (user+group) quota update (possibly delete) */ |
31 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS; | 31 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); |
32 | struct reiserfs_transaction_handle th ; | 32 | struct reiserfs_transaction_handle th ; |
33 | 33 | ||
34 | reiserfs_write_lock(inode->i_sb); | 34 | reiserfs_write_lock(inode->i_sb); |
@@ -254,6 +254,7 @@ static int _get_block_create_0 (struct inode * inode, long block, | |||
254 | char * p = NULL; | 254 | char * p = NULL; |
255 | int chars; | 255 | int chars; |
256 | int ret ; | 256 | int ret ; |
257 | int result ; | ||
257 | int done = 0 ; | 258 | int done = 0 ; |
258 | unsigned long offset ; | 259 | unsigned long offset ; |
259 | 260 | ||
@@ -262,10 +263,13 @@ static int _get_block_create_0 (struct inode * inode, long block, | |||
262 | (loff_t)block * inode->i_sb->s_blocksize + 1, TYPE_ANY, 3); | 263 | (loff_t)block * inode->i_sb->s_blocksize + 1, TYPE_ANY, 3); |
263 | 264 | ||
264 | research: | 265 | research: |
265 | if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND) { | 266 | result = search_for_position_by_key (inode->i_sb, &key, &path) ; |
267 | if (result != POSITION_FOUND) { | ||
266 | pathrelse (&path); | 268 | pathrelse (&path); |
267 | if (p) | 269 | if (p) |
268 | kunmap(bh_result->b_page) ; | 270 | kunmap(bh_result->b_page) ; |
271 | if (result == IO_ERROR) | ||
272 | return -EIO; | ||
269 | // We do not return -ENOENT if there is a hole but page is uptodate, because it means | 273 | // We do not return -ENOENT if there is a hole but page is uptodate, because it means |
270 | // That there is some MMAPED data associated with it that is yet to be written to disk. | 274 | // That there is some MMAPED data associated with it that is yet to be written to disk. |
271 | if ((args & GET_BLOCK_NO_HOLE) && !PageUptodate(bh_result->b_page) ) { | 275 | if ((args & GET_BLOCK_NO_HOLE) && !PageUptodate(bh_result->b_page) ) { |
@@ -382,8 +386,9 @@ research: | |||
382 | 386 | ||
383 | // update key to look for the next piece | 387 | // update key to look for the next piece |
384 | set_cpu_key_k_offset (&key, cpu_key_k_offset (&key) + chars); | 388 | set_cpu_key_k_offset (&key, cpu_key_k_offset (&key) + chars); |
385 | if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND) | 389 | result = search_for_position_by_key (inode->i_sb, &key, &path); |
386 | // we read something from tail, even if now we got IO_ERROR | 390 | if (result != POSITION_FOUND) |
391 | // i/o error most likely | ||
387 | break; | 392 | break; |
388 | bh = get_last_bh (&path); | 393 | bh = get_last_bh (&path); |
389 | ih = get_ih (&path); | 394 | ih = get_ih (&path); |
@@ -394,6 +399,10 @@ research: | |||
394 | 399 | ||
395 | finished: | 400 | finished: |
396 | pathrelse (&path); | 401 | pathrelse (&path); |
402 | |||
403 | if (result == IO_ERROR) | ||
404 | return -EIO; | ||
405 | |||
397 | /* this buffer has valid data, but isn't valid for io. mapping it to | 406 | /* this buffer has valid data, but isn't valid for io. mapping it to |
398 | * block #0 tells the rest of reiserfs it just has a tail in it | 407 | * block #0 tells the rest of reiserfs it just has a tail in it |
399 | */ | 408 | */ |
@@ -591,7 +600,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block, | |||
591 | XXX in practically impossible worst case direct2indirect() | 600 | XXX in practically impossible worst case direct2indirect() |
592 | can incur (much) more than 3 balancings. | 601 | can incur (much) more than 3 balancings. |
593 | quota update for user, group */ | 602 | quota update for user, group */ |
594 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS; | 603 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); |
595 | int version; | 604 | int version; |
596 | int dangle = 1; | 605 | int dangle = 1; |
597 | loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ; | 606 | loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ; |
@@ -2796,12 +2805,15 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { | |||
2796 | 2805 | ||
2797 | if (!error) { | 2806 | if (!error) { |
2798 | struct reiserfs_transaction_handle th; | 2807 | struct reiserfs_transaction_handle th; |
2808 | int jbegin_count = 2*(REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb)+REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb))+2; | ||
2799 | 2809 | ||
2800 | /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ | 2810 | /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ |
2801 | journal_begin(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2); | 2811 | error = journal_begin(&th, inode->i_sb, jbegin_count); |
2812 | if (error) | ||
2813 | goto out; | ||
2802 | error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; | 2814 | error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; |
2803 | if (error) { | 2815 | if (error) { |
2804 | journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2); | 2816 | journal_end(&th, inode->i_sb, jbegin_count); |
2805 | goto out; | 2817 | goto out; |
2806 | } | 2818 | } |
2807 | /* Update corresponding info in inode so that everything is in | 2819 | /* Update corresponding info in inode so that everything is in |
@@ -2811,7 +2823,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { | |||
2811 | if (attr->ia_valid & ATTR_GID) | 2823 | if (attr->ia_valid & ATTR_GID) |
2812 | inode->i_gid = attr->ia_gid; | 2824 | inode->i_gid = attr->ia_gid; |
2813 | mark_inode_dirty(inode); | 2825 | mark_inode_dirty(inode); |
2814 | journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2); | 2826 | error = journal_end(&th, inode->i_sb, jbegin_count); |
2815 | } | 2827 | } |
2816 | } | 2828 | } |
2817 | if (!error) | 2829 | if (!error) |
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 3072cfdee959..7b87707acc36 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c | |||
@@ -2631,6 +2631,8 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup | |||
2631 | int retval; | 2631 | int retval; |
2632 | 2632 | ||
2633 | reiserfs_check_lock_depth(p_s_sb, "journal_begin") ; | 2633 | reiserfs_check_lock_depth(p_s_sb, "journal_begin") ; |
2634 | if (nblocks > journal->j_trans_max) | ||
2635 | BUG(); | ||
2634 | 2636 | ||
2635 | PROC_INFO_INC( p_s_sb, journal.journal_being ); | 2637 | PROC_INFO_INC( p_s_sb, journal.journal_being ); |
2636 | /* set here for journal_join */ | 2638 | /* set here for journal_join */ |
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 7d4dc5f5aa8b..4a333255f27a 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c | |||
@@ -586,7 +586,7 @@ static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode, | |||
586 | int retval; | 586 | int retval; |
587 | struct inode * inode; | 587 | struct inode * inode; |
588 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | 588 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ |
589 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 589 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); |
590 | struct reiserfs_transaction_handle th ; | 590 | struct reiserfs_transaction_handle th ; |
591 | int locked; | 591 | int locked; |
592 | 592 | ||
@@ -653,7 +653,7 @@ static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, | |||
653 | struct inode * inode; | 653 | struct inode * inode; |
654 | struct reiserfs_transaction_handle th ; | 654 | struct reiserfs_transaction_handle th ; |
655 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | 655 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ |
656 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 656 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); |
657 | int locked; | 657 | int locked; |
658 | 658 | ||
659 | if (!new_valid_dev(rdev)) | 659 | if (!new_valid_dev(rdev)) |
@@ -727,7 +727,7 @@ static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode) | |||
727 | struct inode * inode; | 727 | struct inode * inode; |
728 | struct reiserfs_transaction_handle th ; | 728 | struct reiserfs_transaction_handle th ; |
729 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | 729 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ |
730 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 730 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); |
731 | int locked; | 731 | int locked; |
732 | 732 | ||
733 | #ifdef DISPLACE_NEW_PACKING_LOCALITIES | 733 | #ifdef DISPLACE_NEW_PACKING_LOCALITIES |
@@ -829,8 +829,10 @@ static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry) | |||
829 | 829 | ||
830 | 830 | ||
831 | /* we will be doing 2 balancings and update 2 stat data, we change quotas | 831 | /* we will be doing 2 balancings and update 2 stat data, we change quotas |
832 | * of the owner of the directory and of the owner of the parent directory */ | 832 | * of the owner of the directory and of the owner of the parent directory. |
833 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 833 | * The quota structure is possibly deleted only on last iput => outside |
834 | * of this transaction */ | ||
835 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); | ||
834 | 836 | ||
835 | reiserfs_write_lock(dir->i_sb); | 837 | reiserfs_write_lock(dir->i_sb); |
836 | retval = journal_begin(&th, dir->i_sb, jbegin_count) ; | 838 | retval = journal_begin(&th, dir->i_sb, jbegin_count) ; |
@@ -913,9 +915,10 @@ static int reiserfs_unlink (struct inode * dir, struct dentry *dentry) | |||
913 | inode = dentry->d_inode; | 915 | inode = dentry->d_inode; |
914 | 916 | ||
915 | /* in this transaction we can be doing at max two balancings and update | 917 | /* in this transaction we can be doing at max two balancings and update |
916 | two stat datas, we change quotas of the owner of the directory and of | 918 | * two stat datas, we change quotas of the owner of the directory and of |
917 | the owner of the parent directory */ | 919 | * the owner of the parent directory. The quota structure is possibly |
918 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 920 | * deleted only on iput => outside of this transaction */ |
921 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); | ||
919 | 922 | ||
920 | reiserfs_write_lock(dir->i_sb); | 923 | reiserfs_write_lock(dir->i_sb); |
921 | retval = journal_begin(&th, dir->i_sb, jbegin_count) ; | 924 | retval = journal_begin(&th, dir->i_sb, jbegin_count) ; |
@@ -1000,7 +1003,7 @@ static int reiserfs_symlink (struct inode * parent_dir, | |||
1000 | struct reiserfs_transaction_handle th ; | 1003 | struct reiserfs_transaction_handle th ; |
1001 | int mode = S_IFLNK | S_IRWXUGO; | 1004 | int mode = S_IFLNK | S_IRWXUGO; |
1002 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | 1005 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ |
1003 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 1006 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(parent_dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(parent_dir->i_sb)); |
1004 | 1007 | ||
1005 | if (!(inode = new_inode(parent_dir->i_sb))) { | 1008 | if (!(inode = new_inode(parent_dir->i_sb))) { |
1006 | return -ENOMEM ; | 1009 | return -ENOMEM ; |
@@ -1076,7 +1079,7 @@ static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct | |||
1076 | struct inode *inode = old_dentry->d_inode; | 1079 | struct inode *inode = old_dentry->d_inode; |
1077 | struct reiserfs_transaction_handle th ; | 1080 | struct reiserfs_transaction_handle th ; |
1078 | /* We need blocks for transaction + update of quotas for the owners of the directory */ | 1081 | /* We need blocks for transaction + update of quotas for the owners of the directory */ |
1079 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * REISERFS_QUOTA_TRANS_BLOCKS; | 1082 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); |
1080 | 1083 | ||
1081 | reiserfs_write_lock(dir->i_sb); | 1084 | reiserfs_write_lock(dir->i_sb); |
1082 | if (inode->i_nlink >= REISERFS_LINK_MAX) { | 1085 | if (inode->i_nlink >= REISERFS_LINK_MAX) { |
@@ -1196,7 +1199,7 @@ static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
1196 | pointed initially and (5) maybe block containing ".." of | 1199 | pointed initially and (5) maybe block containing ".." of |
1197 | renamed directory | 1200 | renamed directory |
1198 | quota updates: two parent directories */ | 1201 | quota updates: two parent directories */ |
1199 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 5 + 4 * REISERFS_QUOTA_TRANS_BLOCKS; | 1202 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 5 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(old_dir->i_sb); |
1200 | 1203 | ||
1201 | old_inode = old_dentry->d_inode; | 1204 | old_inode = old_dentry->d_inode; |
1202 | new_dentry_inode = new_dentry->d_inode; | 1205 | new_dentry_inode = new_dentry->d_inode; |
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index c47f8fd31a2d..63158491e152 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c | |||
@@ -223,7 +223,7 @@ extern struct tree_balance * cur_tb; | |||
223 | const struct reiserfs_key MIN_KEY = {0, 0, {{0, 0},}}; | 223 | const struct reiserfs_key MIN_KEY = {0, 0, {{0, 0},}}; |
224 | 224 | ||
225 | /* Maximal possible key. It is never in the tree. */ | 225 | /* Maximal possible key. It is never in the tree. */ |
226 | const struct reiserfs_key MAX_KEY = { | 226 | static const struct reiserfs_key MAX_KEY = { |
227 | __constant_cpu_to_le32(0xffffffff), | 227 | __constant_cpu_to_le32(0xffffffff), |
228 | __constant_cpu_to_le32(0xffffffff), | 228 | __constant_cpu_to_le32(0xffffffff), |
229 | {{__constant_cpu_to_le32(0xffffffff), | 229 | {{__constant_cpu_to_le32(0xffffffff), |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index b35b87744983..660aefca1fd2 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -866,8 +866,9 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st | |||
866 | {"jdev", .arg_required = 'j', .values = NULL}, | 866 | {"jdev", .arg_required = 'j', .values = NULL}, |
867 | {"nolargeio", .arg_required = 'w', .values = NULL}, | 867 | {"nolargeio", .arg_required = 'w', .values = NULL}, |
868 | {"commit", .arg_required = 'c', .values = NULL}, | 868 | {"commit", .arg_required = 'c', .values = NULL}, |
869 | {"usrquota",}, | 869 | {"usrquota", .setmask = 1<<REISERFS_QUOTA}, |
870 | {"grpquota",}, | 870 | {"grpquota", .setmask = 1<<REISERFS_QUOTA}, |
871 | {"noquota", .clrmask = 1<<REISERFS_QUOTA}, | ||
871 | {"errors", .arg_required = 'e', .values = error_actions}, | 872 | {"errors", .arg_required = 'e', .values = error_actions}, |
872 | {"usrjquota", .arg_required = 'u'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL}, | 873 | {"usrjquota", .arg_required = 'u'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL}, |
873 | {"grpjquota", .arg_required = 'g'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL}, | 874 | {"grpjquota", .arg_required = 'g'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL}, |
@@ -964,6 +965,7 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st | |||
964 | return 0; | 965 | return 0; |
965 | } | 966 | } |
966 | strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg); | 967 | strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg); |
968 | *mount_options |= 1<<REISERFS_QUOTA; | ||
967 | } | 969 | } |
968 | else { | 970 | else { |
969 | if (REISERFS_SB(s)->s_qf_names[qtype]) { | 971 | if (REISERFS_SB(s)->s_qf_names[qtype]) { |
@@ -995,7 +997,13 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st | |||
995 | reiserfs_warning(s, "reiserfs_parse_options: journalled quota format not specified."); | 997 | reiserfs_warning(s, "reiserfs_parse_options: journalled quota format not specified."); |
996 | return 0; | 998 | return 0; |
997 | } | 999 | } |
1000 | /* This checking is not precise wrt the quota type but for our purposes it is sufficient */ | ||
1001 | if (!(*mount_options & (1<<REISERFS_QUOTA)) && sb_any_quota_enabled(s)) { | ||
1002 | reiserfs_warning(s, "reiserfs_parse_options: quota options must be present when quota is turned on."); | ||
1003 | return 0; | ||
1004 | } | ||
998 | #endif | 1005 | #endif |
1006 | |||
999 | return 1; | 1007 | return 1; |
1000 | } | 1008 | } |
1001 | 1009 | ||
@@ -1105,6 +1113,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a | |||
1105 | safe_mask |= 1 << REISERFS_ERROR_RO; | 1113 | safe_mask |= 1 << REISERFS_ERROR_RO; |
1106 | safe_mask |= 1 << REISERFS_ERROR_CONTINUE; | 1114 | safe_mask |= 1 << REISERFS_ERROR_CONTINUE; |
1107 | safe_mask |= 1 << REISERFS_ERROR_PANIC; | 1115 | safe_mask |= 1 << REISERFS_ERROR_PANIC; |
1116 | safe_mask |= 1 << REISERFS_QUOTA; | ||
1108 | 1117 | ||
1109 | /* Update the bitmask, taking care to keep | 1118 | /* Update the bitmask, taking care to keep |
1110 | * the bits we're not allowed to change here */ | 1119 | * the bits we're not allowed to change here */ |
@@ -1841,13 +1850,18 @@ static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf) | |||
1841 | static int reiserfs_dquot_initialize(struct inode *inode, int type) | 1850 | static int reiserfs_dquot_initialize(struct inode *inode, int type) |
1842 | { | 1851 | { |
1843 | struct reiserfs_transaction_handle th; | 1852 | struct reiserfs_transaction_handle th; |
1844 | int ret; | 1853 | int ret, err; |
1845 | 1854 | ||
1846 | /* We may create quota structure so we need to reserve enough blocks */ | 1855 | /* We may create quota structure so we need to reserve enough blocks */ |
1847 | reiserfs_write_lock(inode->i_sb); | 1856 | reiserfs_write_lock(inode->i_sb); |
1848 | journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); | 1857 | ret = journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb)); |
1858 | if (ret) | ||
1859 | goto out; | ||
1849 | ret = dquot_initialize(inode, type); | 1860 | ret = dquot_initialize(inode, type); |
1850 | journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); | 1861 | err = journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb)); |
1862 | if (!ret && err) | ||
1863 | ret = err; | ||
1864 | out: | ||
1851 | reiserfs_write_unlock(inode->i_sb); | 1865 | reiserfs_write_unlock(inode->i_sb); |
1852 | return ret; | 1866 | return ret; |
1853 | } | 1867 | } |
@@ -1855,13 +1869,18 @@ static int reiserfs_dquot_initialize(struct inode *inode, int type) | |||
1855 | static int reiserfs_dquot_drop(struct inode *inode) | 1869 | static int reiserfs_dquot_drop(struct inode *inode) |
1856 | { | 1870 | { |
1857 | struct reiserfs_transaction_handle th; | 1871 | struct reiserfs_transaction_handle th; |
1858 | int ret; | 1872 | int ret, err; |
1859 | 1873 | ||
1860 | /* We may delete quota structure so we need to reserve enough blocks */ | 1874 | /* We may delete quota structure so we need to reserve enough blocks */ |
1861 | reiserfs_write_lock(inode->i_sb); | 1875 | reiserfs_write_lock(inode->i_sb); |
1862 | journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); | 1876 | ret = journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)); |
1877 | if (ret) | ||
1878 | goto out; | ||
1863 | ret = dquot_drop(inode); | 1879 | ret = dquot_drop(inode); |
1864 | journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); | 1880 | err = journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)); |
1881 | if (!ret && err) | ||
1882 | ret = err; | ||
1883 | out: | ||
1865 | reiserfs_write_unlock(inode->i_sb); | 1884 | reiserfs_write_unlock(inode->i_sb); |
1866 | return ret; | 1885 | return ret; |
1867 | } | 1886 | } |
@@ -1869,12 +1888,17 @@ static int reiserfs_dquot_drop(struct inode *inode) | |||
1869 | static int reiserfs_write_dquot(struct dquot *dquot) | 1888 | static int reiserfs_write_dquot(struct dquot *dquot) |
1870 | { | 1889 | { |
1871 | struct reiserfs_transaction_handle th; | 1890 | struct reiserfs_transaction_handle th; |
1872 | int ret; | 1891 | int ret, err; |
1873 | 1892 | ||
1874 | reiserfs_write_lock(dquot->dq_sb); | 1893 | reiserfs_write_lock(dquot->dq_sb); |
1875 | journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS); | 1894 | ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); |
1895 | if (ret) | ||
1896 | goto out; | ||
1876 | ret = dquot_commit(dquot); | 1897 | ret = dquot_commit(dquot); |
1877 | journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS); | 1898 | err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); |
1899 | if (!ret && err) | ||
1900 | ret = err; | ||
1901 | out: | ||
1878 | reiserfs_write_unlock(dquot->dq_sb); | 1902 | reiserfs_write_unlock(dquot->dq_sb); |
1879 | return ret; | 1903 | return ret; |
1880 | } | 1904 | } |
@@ -1882,12 +1906,17 @@ static int reiserfs_write_dquot(struct dquot *dquot) | |||
1882 | static int reiserfs_acquire_dquot(struct dquot *dquot) | 1906 | static int reiserfs_acquire_dquot(struct dquot *dquot) |
1883 | { | 1907 | { |
1884 | struct reiserfs_transaction_handle th; | 1908 | struct reiserfs_transaction_handle th; |
1885 | int ret; | 1909 | int ret, err; |
1886 | 1910 | ||
1887 | reiserfs_write_lock(dquot->dq_sb); | 1911 | reiserfs_write_lock(dquot->dq_sb); |
1888 | journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); | 1912 | ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); |
1913 | if (ret) | ||
1914 | goto out; | ||
1889 | ret = dquot_acquire(dquot); | 1915 | ret = dquot_acquire(dquot); |
1890 | journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); | 1916 | err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); |
1917 | if (!ret && err) | ||
1918 | ret = err; | ||
1919 | out: | ||
1891 | reiserfs_write_unlock(dquot->dq_sb); | 1920 | reiserfs_write_unlock(dquot->dq_sb); |
1892 | return ret; | 1921 | return ret; |
1893 | } | 1922 | } |
@@ -1895,12 +1924,17 @@ static int reiserfs_acquire_dquot(struct dquot *dquot) | |||
1895 | static int reiserfs_release_dquot(struct dquot *dquot) | 1924 | static int reiserfs_release_dquot(struct dquot *dquot) |
1896 | { | 1925 | { |
1897 | struct reiserfs_transaction_handle th; | 1926 | struct reiserfs_transaction_handle th; |
1898 | int ret; | 1927 | int ret, err; |
1899 | 1928 | ||
1900 | reiserfs_write_lock(dquot->dq_sb); | 1929 | reiserfs_write_lock(dquot->dq_sb); |
1901 | journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); | 1930 | ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); |
1931 | if (ret) | ||
1932 | goto out; | ||
1902 | ret = dquot_release(dquot); | 1933 | ret = dquot_release(dquot); |
1903 | journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); | 1934 | err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); |
1935 | if (!ret && err) | ||
1936 | ret = err; | ||
1937 | out: | ||
1904 | reiserfs_write_unlock(dquot->dq_sb); | 1938 | reiserfs_write_unlock(dquot->dq_sb); |
1905 | return ret; | 1939 | return ret; |
1906 | } | 1940 | } |
@@ -1920,39 +1954,29 @@ static int reiserfs_mark_dquot_dirty(struct dquot *dquot) | |||
1920 | static int reiserfs_write_info(struct super_block *sb, int type) | 1954 | static int reiserfs_write_info(struct super_block *sb, int type) |
1921 | { | 1955 | { |
1922 | struct reiserfs_transaction_handle th; | 1956 | struct reiserfs_transaction_handle th; |
1923 | int ret; | 1957 | int ret, err; |
1924 | 1958 | ||
1925 | /* Data block + inode block */ | 1959 | /* Data block + inode block */ |
1926 | reiserfs_write_lock(sb); | 1960 | reiserfs_write_lock(sb); |
1927 | journal_begin(&th, sb, 2); | 1961 | ret = journal_begin(&th, sb, 2); |
1962 | if (ret) | ||
1963 | goto out; | ||
1928 | ret = dquot_commit_info(sb, type); | 1964 | ret = dquot_commit_info(sb, type); |
1929 | journal_end(&th, sb, 2); | 1965 | err = journal_end(&th, sb, 2); |
1966 | if (!ret && err) | ||
1967 | ret = err; | ||
1968 | out: | ||
1930 | reiserfs_write_unlock(sb); | 1969 | reiserfs_write_unlock(sb); |
1931 | return ret; | 1970 | return ret; |
1932 | } | 1971 | } |
1933 | 1972 | ||
1934 | /* | 1973 | /* |
1935 | * Turn on quotas during mount time - we need to find | 1974 | * Turn on quotas during mount time - we need to find the quota file and such... |
1936 | * the quota file and such... | ||
1937 | */ | 1975 | */ |
1938 | static int reiserfs_quota_on_mount(struct super_block *sb, int type) | 1976 | static int reiserfs_quota_on_mount(struct super_block *sb, int type) |
1939 | { | 1977 | { |
1940 | int err; | 1978 | return vfs_quota_on_mount(sb, REISERFS_SB(sb)->s_qf_names[type], |
1941 | struct dentry *dentry; | 1979 | REISERFS_SB(sb)->s_jquota_fmt, type); |
1942 | struct qstr name = { .name = REISERFS_SB(sb)->s_qf_names[type], | ||
1943 | .hash = 0, | ||
1944 | .len = strlen(REISERFS_SB(sb)->s_qf_names[type])}; | ||
1945 | |||
1946 | dentry = lookup_hash(&name, sb->s_root); | ||
1947 | if (IS_ERR(dentry)) | ||
1948 | return PTR_ERR(dentry); | ||
1949 | err = vfs_quota_on_mount(type, REISERFS_SB(sb)->s_jquota_fmt, dentry); | ||
1950 | /* Now invalidate and put the dentry - quota got its own reference | ||
1951 | * to inode and dentry has at least wrong hash so we had better | ||
1952 | * throw it away */ | ||
1953 | d_invalidate(dentry); | ||
1954 | dput(dentry); | ||
1955 | return err; | ||
1956 | } | 1980 | } |
1957 | 1981 | ||
1958 | /* | 1982 | /* |
@@ -1963,6 +1987,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, ch | |||
1963 | int err; | 1987 | int err; |
1964 | struct nameidata nd; | 1988 | struct nameidata nd; |
1965 | 1989 | ||
1990 | if (!(REISERFS_SB(sb)->s_mount_opt & (1<<REISERFS_QUOTA))) | ||
1991 | return -EINVAL; | ||
1966 | err = path_lookup(path, LOOKUP_FOLLOW, &nd); | 1992 | err = path_lookup(path, LOOKUP_FOLLOW, &nd); |
1967 | if (err) | 1993 | if (err) |
1968 | return err; | 1994 | return err; |
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index e302071903a1..c312881c5f53 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c | |||
@@ -4,7 +4,7 @@ | |||
4 | #include <linux/errno.h> | 4 | #include <linux/errno.h> |
5 | #include <linux/pagemap.h> | 5 | #include <linux/pagemap.h> |
6 | #include <linux/xattr.h> | 6 | #include <linux/xattr.h> |
7 | #include <linux/xattr_acl.h> | 7 | #include <linux/posix_acl_xattr.h> |
8 | #include <linux/reiserfs_xattr.h> | 8 | #include <linux/reiserfs_xattr.h> |
9 | #include <linux/reiserfs_acl.h> | 9 | #include <linux/reiserfs_acl.h> |
10 | #include <asm/uaccess.h> | 10 | #include <asm/uaccess.h> |
@@ -192,11 +192,11 @@ reiserfs_get_acl(struct inode *inode, int type) | |||
192 | 192 | ||
193 | switch (type) { | 193 | switch (type) { |
194 | case ACL_TYPE_ACCESS: | 194 | case ACL_TYPE_ACCESS: |
195 | name = XATTR_NAME_ACL_ACCESS; | 195 | name = POSIX_ACL_XATTR_ACCESS; |
196 | p_acl = &reiserfs_i->i_acl_access; | 196 | p_acl = &reiserfs_i->i_acl_access; |
197 | break; | 197 | break; |
198 | case ACL_TYPE_DEFAULT: | 198 | case ACL_TYPE_DEFAULT: |
199 | name = XATTR_NAME_ACL_DEFAULT; | 199 | name = POSIX_ACL_XATTR_DEFAULT; |
200 | p_acl = &reiserfs_i->i_acl_default; | 200 | p_acl = &reiserfs_i->i_acl_default; |
201 | break; | 201 | break; |
202 | default: | 202 | default: |
@@ -260,7 +260,7 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
260 | 260 | ||
261 | switch (type) { | 261 | switch (type) { |
262 | case ACL_TYPE_ACCESS: | 262 | case ACL_TYPE_ACCESS: |
263 | name = XATTR_NAME_ACL_ACCESS; | 263 | name = POSIX_ACL_XATTR_ACCESS; |
264 | p_acl = &reiserfs_i->i_acl_access; | 264 | p_acl = &reiserfs_i->i_acl_access; |
265 | if (acl) { | 265 | if (acl) { |
266 | mode_t mode = inode->i_mode; | 266 | mode_t mode = inode->i_mode; |
@@ -275,7 +275,7 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
275 | } | 275 | } |
276 | break; | 276 | break; |
277 | case ACL_TYPE_DEFAULT: | 277 | case ACL_TYPE_DEFAULT: |
278 | name = XATTR_NAME_ACL_DEFAULT; | 278 | name = POSIX_ACL_XATTR_DEFAULT; |
279 | p_acl = &reiserfs_i->i_acl_default; | 279 | p_acl = &reiserfs_i->i_acl_default; |
280 | if (!S_ISDIR (inode->i_mode)) | 280 | if (!S_ISDIR (inode->i_mode)) |
281 | return acl ? -EACCES : 0; | 281 | return acl ? -EACCES : 0; |
@@ -468,7 +468,7 @@ static int | |||
468 | posix_acl_access_get(struct inode *inode, const char *name, | 468 | posix_acl_access_get(struct inode *inode, const char *name, |
469 | void *buffer, size_t size) | 469 | void *buffer, size_t size) |
470 | { | 470 | { |
471 | if (strlen(name) != sizeof(XATTR_NAME_ACL_ACCESS)-1) | 471 | if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1) |
472 | return -EINVAL; | 472 | return -EINVAL; |
473 | return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); | 473 | return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); |
474 | } | 474 | } |
@@ -477,7 +477,7 @@ static int | |||
477 | posix_acl_access_set(struct inode *inode, const char *name, | 477 | posix_acl_access_set(struct inode *inode, const char *name, |
478 | const void *value, size_t size, int flags) | 478 | const void *value, size_t size, int flags) |
479 | { | 479 | { |
480 | if (strlen(name) != sizeof(XATTR_NAME_ACL_ACCESS)-1) | 480 | if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1) |
481 | return -EINVAL; | 481 | return -EINVAL; |
482 | return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); | 482 | return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); |
483 | } | 483 | } |
@@ -487,7 +487,7 @@ posix_acl_access_del (struct inode *inode, const char *name) | |||
487 | { | 487 | { |
488 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); | 488 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); |
489 | struct posix_acl **acl = &reiserfs_i->i_acl_access; | 489 | struct posix_acl **acl = &reiserfs_i->i_acl_access; |
490 | if (strlen(name) != sizeof(XATTR_NAME_ACL_ACCESS)-1) | 490 | if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1) |
491 | return -EINVAL; | 491 | return -EINVAL; |
492 | if (!IS_ERR (*acl) && *acl) { | 492 | if (!IS_ERR (*acl) && *acl) { |
493 | posix_acl_release (*acl); | 493 | posix_acl_release (*acl); |
@@ -510,7 +510,7 @@ posix_acl_access_list (struct inode *inode, const char *name, int namelen, char | |||
510 | } | 510 | } |
511 | 511 | ||
512 | struct reiserfs_xattr_handler posix_acl_access_handler = { | 512 | struct reiserfs_xattr_handler posix_acl_access_handler = { |
513 | .prefix = XATTR_NAME_ACL_ACCESS, | 513 | .prefix = POSIX_ACL_XATTR_ACCESS, |
514 | .get = posix_acl_access_get, | 514 | .get = posix_acl_access_get, |
515 | .set = posix_acl_access_set, | 515 | .set = posix_acl_access_set, |
516 | .del = posix_acl_access_del, | 516 | .del = posix_acl_access_del, |
@@ -521,7 +521,7 @@ static int | |||
521 | posix_acl_default_get (struct inode *inode, const char *name, | 521 | posix_acl_default_get (struct inode *inode, const char *name, |
522 | void *buffer, size_t size) | 522 | void *buffer, size_t size) |
523 | { | 523 | { |
524 | if (strlen(name) != sizeof(XATTR_NAME_ACL_DEFAULT)-1) | 524 | if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1) |
525 | return -EINVAL; | 525 | return -EINVAL; |
526 | return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); | 526 | return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); |
527 | } | 527 | } |
@@ -530,7 +530,7 @@ static int | |||
530 | posix_acl_default_set(struct inode *inode, const char *name, | 530 | posix_acl_default_set(struct inode *inode, const char *name, |
531 | const void *value, size_t size, int flags) | 531 | const void *value, size_t size, int flags) |
532 | { | 532 | { |
533 | if (strlen(name) != sizeof(XATTR_NAME_ACL_DEFAULT)-1) | 533 | if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1) |
534 | return -EINVAL; | 534 | return -EINVAL; |
535 | return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); | 535 | return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); |
536 | } | 536 | } |
@@ -540,7 +540,7 @@ posix_acl_default_del (struct inode *inode, const char *name) | |||
540 | { | 540 | { |
541 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); | 541 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); |
542 | struct posix_acl **acl = &reiserfs_i->i_acl_default; | 542 | struct posix_acl **acl = &reiserfs_i->i_acl_default; |
543 | if (strlen(name) != sizeof(XATTR_NAME_ACL_DEFAULT)-1) | 543 | if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1) |
544 | return -EINVAL; | 544 | return -EINVAL; |
545 | if (!IS_ERR (*acl) && *acl) { | 545 | if (!IS_ERR (*acl) && *acl) { |
546 | posix_acl_release (*acl); | 546 | posix_acl_release (*acl); |
@@ -563,7 +563,7 @@ posix_acl_default_list (struct inode *inode, const char *name, int namelen, char | |||
563 | } | 563 | } |
564 | 564 | ||
565 | struct reiserfs_xattr_handler posix_acl_default_handler = { | 565 | struct reiserfs_xattr_handler posix_acl_default_handler = { |
566 | .prefix = XATTR_NAME_ACL_DEFAULT, | 566 | .prefix = POSIX_ACL_XATTR_DEFAULT, |
567 | .get = posix_acl_default_get, | 567 | .get = posix_acl_default_get, |
568 | .set = posix_acl_default_set, | 568 | .set = posix_acl_default_set, |
569 | .del = posix_acl_default_del, | 569 | .del = posix_acl_default_del, |
diff --git a/fs/super.c b/fs/super.c index 3a1b8ca04ba6..25bc1ec6bc5d 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -341,20 +341,22 @@ static inline void write_super(struct super_block *sb) | |||
341 | */ | 341 | */ |
342 | void sync_supers(void) | 342 | void sync_supers(void) |
343 | { | 343 | { |
344 | struct super_block * sb; | 344 | struct super_block *sb; |
345 | restart: | 345 | |
346 | spin_lock(&sb_lock); | 346 | spin_lock(&sb_lock); |
347 | sb = sb_entry(super_blocks.next); | 347 | restart: |
348 | while (sb != sb_entry(&super_blocks)) | 348 | list_for_each_entry(sb, &super_blocks, s_list) { |
349 | if (sb->s_dirt) { | 349 | if (sb->s_dirt) { |
350 | sb->s_count++; | 350 | sb->s_count++; |
351 | spin_unlock(&sb_lock); | 351 | spin_unlock(&sb_lock); |
352 | down_read(&sb->s_umount); | 352 | down_read(&sb->s_umount); |
353 | write_super(sb); | 353 | write_super(sb); |
354 | drop_super(sb); | 354 | up_read(&sb->s_umount); |
355 | goto restart; | 355 | spin_lock(&sb_lock); |
356 | } else | 356 | if (__put_super_and_need_restart(sb)) |
357 | sb = sb_entry(sb->s_list.next); | 357 | goto restart; |
358 | } | ||
359 | } | ||
358 | spin_unlock(&sb_lock); | 360 | spin_unlock(&sb_lock); |
359 | } | 361 | } |
360 | 362 | ||
@@ -381,20 +383,16 @@ void sync_filesystems(int wait) | |||
381 | 383 | ||
382 | down(&mutex); /* Could be down_interruptible */ | 384 | down(&mutex); /* Could be down_interruptible */ |
383 | spin_lock(&sb_lock); | 385 | spin_lock(&sb_lock); |
384 | for (sb = sb_entry(super_blocks.next); sb != sb_entry(&super_blocks); | 386 | list_for_each_entry(sb, &super_blocks, s_list) { |
385 | sb = sb_entry(sb->s_list.next)) { | ||
386 | if (!sb->s_op->sync_fs) | 387 | if (!sb->s_op->sync_fs) |
387 | continue; | 388 | continue; |
388 | if (sb->s_flags & MS_RDONLY) | 389 | if (sb->s_flags & MS_RDONLY) |
389 | continue; | 390 | continue; |
390 | sb->s_need_sync_fs = 1; | 391 | sb->s_need_sync_fs = 1; |
391 | } | 392 | } |
392 | spin_unlock(&sb_lock); | ||
393 | 393 | ||
394 | restart: | 394 | restart: |
395 | spin_lock(&sb_lock); | 395 | list_for_each_entry(sb, &super_blocks, s_list) { |
396 | for (sb = sb_entry(super_blocks.next); sb != sb_entry(&super_blocks); | ||
397 | sb = sb_entry(sb->s_list.next)) { | ||
398 | if (!sb->s_need_sync_fs) | 396 | if (!sb->s_need_sync_fs) |
399 | continue; | 397 | continue; |
400 | sb->s_need_sync_fs = 0; | 398 | sb->s_need_sync_fs = 0; |
@@ -405,8 +403,11 @@ restart: | |||
405 | down_read(&sb->s_umount); | 403 | down_read(&sb->s_umount); |
406 | if (sb->s_root && (wait || sb->s_dirt)) | 404 | if (sb->s_root && (wait || sb->s_dirt)) |
407 | sb->s_op->sync_fs(sb, wait); | 405 | sb->s_op->sync_fs(sb, wait); |
408 | drop_super(sb); | 406 | up_read(&sb->s_umount); |
409 | goto restart; | 407 | /* restart only when sb is no longer on the list */ |
408 | spin_lock(&sb_lock); | ||
409 | if (__put_super_and_need_restart(sb)) | ||
410 | goto restart; | ||
410 | } | 411 | } |
411 | spin_unlock(&sb_lock); | 412 | spin_unlock(&sb_lock); |
412 | up(&mutex); | 413 | up(&mutex); |
@@ -422,21 +423,25 @@ restart: | |||
422 | 423 | ||
423 | struct super_block * get_super(struct block_device *bdev) | 424 | struct super_block * get_super(struct block_device *bdev) |
424 | { | 425 | { |
425 | struct list_head *p; | 426 | struct super_block *sb; |
427 | |||
426 | if (!bdev) | 428 | if (!bdev) |
427 | return NULL; | 429 | return NULL; |
428 | rescan: | 430 | |
429 | spin_lock(&sb_lock); | 431 | spin_lock(&sb_lock); |
430 | list_for_each(p, &super_blocks) { | 432 | rescan: |
431 | struct super_block *s = sb_entry(p); | 433 | list_for_each_entry(sb, &super_blocks, s_list) { |
432 | if (s->s_bdev == bdev) { | 434 | if (sb->s_bdev == bdev) { |
433 | s->s_count++; | 435 | sb->s_count++; |
434 | spin_unlock(&sb_lock); | 436 | spin_unlock(&sb_lock); |
435 | down_read(&s->s_umount); | 437 | down_read(&sb->s_umount); |
436 | if (s->s_root) | 438 | if (sb->s_root) |
437 | return s; | 439 | return sb; |
438 | drop_super(s); | 440 | up_read(&sb->s_umount); |
439 | goto rescan; | 441 | /* restart only when sb is no longer on the list */ |
442 | spin_lock(&sb_lock); | ||
443 | if (__put_super_and_need_restart(sb)) | ||
444 | goto rescan; | ||
440 | } | 445 | } |
441 | } | 446 | } |
442 | spin_unlock(&sb_lock); | 447 | spin_unlock(&sb_lock); |
@@ -447,20 +452,22 @@ EXPORT_SYMBOL(get_super); | |||
447 | 452 | ||
448 | struct super_block * user_get_super(dev_t dev) | 453 | struct super_block * user_get_super(dev_t dev) |
449 | { | 454 | { |
450 | struct list_head *p; | 455 | struct super_block *sb; |
451 | 456 | ||
452 | rescan: | ||
453 | spin_lock(&sb_lock); | 457 | spin_lock(&sb_lock); |
454 | list_for_each(p, &super_blocks) { | 458 | rescan: |
455 | struct super_block *s = sb_entry(p); | 459 | list_for_each_entry(sb, &super_blocks, s_list) { |
456 | if (s->s_dev == dev) { | 460 | if (sb->s_dev == dev) { |
457 | s->s_count++; | 461 | sb->s_count++; |
458 | spin_unlock(&sb_lock); | 462 | spin_unlock(&sb_lock); |
459 | down_read(&s->s_umount); | 463 | down_read(&sb->s_umount); |
460 | if (s->s_root) | 464 | if (sb->s_root) |
461 | return s; | 465 | return sb; |
462 | drop_super(s); | 466 | up_read(&sb->s_umount); |
463 | goto rescan; | 467 | /* restart only when sb is no longer on the list */ |
468 | spin_lock(&sb_lock); | ||
469 | if (__put_super_and_need_restart(sb)) | ||
470 | goto rescan; | ||
464 | } | 471 | } |
465 | } | 472 | } |
466 | spin_unlock(&sb_lock); | 473 | spin_unlock(&sb_lock); |
@@ -835,6 +842,7 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data) | |||
835 | mnt->mnt_parent = mnt; | 842 | mnt->mnt_parent = mnt; |
836 | mnt->mnt_namespace = current->namespace; | 843 | mnt->mnt_namespace = current->namespace; |
837 | up_write(&sb->s_umount); | 844 | up_write(&sb->s_umount); |
845 | free_secdata(secdata); | ||
838 | put_filesystem(type); | 846 | put_filesystem(type); |
839 | return mnt; | 847 | return mnt; |
840 | out_sb: | 848 | out_sb: |
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index d4aaa88d0214..78899eeab974 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c | |||
@@ -25,7 +25,7 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) | |||
25 | struct kobject * kobj = to_kobj(dentry->d_parent); | 25 | struct kobject * kobj = to_kobj(dentry->d_parent); |
26 | 26 | ||
27 | if (!attr->read) | 27 | if (!attr->read) |
28 | return -EINVAL; | 28 | return -EIO; |
29 | 29 | ||
30 | return attr->read(kobj, buffer, off, count); | 30 | return attr->read(kobj, buffer, off, count); |
31 | } | 31 | } |
@@ -71,7 +71,7 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) | |||
71 | struct kobject *kobj = to_kobj(dentry->d_parent); | 71 | struct kobject *kobj = to_kobj(dentry->d_parent); |
72 | 72 | ||
73 | if (!attr->write) | 73 | if (!attr->write) |
74 | return -EINVAL; | 74 | return -EIO; |
75 | 75 | ||
76 | return attr->write(kobj, buffer, offset, count); | 76 | return attr->write(kobj, buffer, offset, count); |
77 | } | 77 | } |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index fe198210bc2d..59734ba1ee60 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/mount.h> | 8 | #include <linux/mount.h> |
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/kobject.h> | 10 | #include <linux/kobject.h> |
11 | #include <linux/namei.h> | ||
11 | #include "sysfs.h" | 12 | #include "sysfs.h" |
12 | 13 | ||
13 | DECLARE_RWSEM(sysfs_rename_sem); | 14 | DECLARE_RWSEM(sysfs_rename_sem); |
@@ -99,20 +100,21 @@ static int create_dir(struct kobject * k, struct dentry * p, | |||
99 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; | 100 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; |
100 | 101 | ||
101 | down(&p->d_inode->i_sem); | 102 | down(&p->d_inode->i_sem); |
102 | *d = sysfs_get_dentry(p,n); | 103 | *d = lookup_one_len(n, p, strlen(n)); |
103 | if (!IS_ERR(*d)) { | 104 | if (!IS_ERR(*d)) { |
104 | error = sysfs_create(*d, mode, init_dir); | 105 | error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR); |
105 | if (!error) { | 106 | if (!error) { |
106 | error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, | 107 | error = sysfs_create(*d, mode, init_dir); |
107 | SYSFS_DIR); | ||
108 | if (!error) { | 108 | if (!error) { |
109 | p->d_inode->i_nlink++; | 109 | p->d_inode->i_nlink++; |
110 | (*d)->d_op = &sysfs_dentry_ops; | 110 | (*d)->d_op = &sysfs_dentry_ops; |
111 | d_rehash(*d); | 111 | d_rehash(*d); |
112 | } | 112 | } |
113 | } | 113 | } |
114 | if (error && (error != -EEXIST)) | 114 | if (error && (error != -EEXIST)) { |
115 | sysfs_put((*d)->d_fsdata); | ||
115 | d_drop(*d); | 116 | d_drop(*d); |
117 | } | ||
116 | dput(*d); | 118 | dput(*d); |
117 | } else | 119 | } else |
118 | error = PTR_ERR(*d); | 120 | error = PTR_ERR(*d); |
@@ -171,17 +173,19 @@ static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry) | |||
171 | init = init_file; | 173 | init = init_file; |
172 | } | 174 | } |
173 | 175 | ||
176 | dentry->d_fsdata = sysfs_get(sd); | ||
177 | sd->s_dentry = dentry; | ||
174 | error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init); | 178 | error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init); |
175 | if (error) | 179 | if (error) { |
180 | sysfs_put(sd); | ||
176 | return error; | 181 | return error; |
182 | } | ||
177 | 183 | ||
178 | if (bin_attr) { | 184 | if (bin_attr) { |
179 | dentry->d_inode->i_size = bin_attr->size; | 185 | dentry->d_inode->i_size = bin_attr->size; |
180 | dentry->d_inode->i_fop = &bin_fops; | 186 | dentry->d_inode->i_fop = &bin_fops; |
181 | } | 187 | } |
182 | dentry->d_op = &sysfs_dentry_ops; | 188 | dentry->d_op = &sysfs_dentry_ops; |
183 | dentry->d_fsdata = sysfs_get(sd); | ||
184 | sd->s_dentry = dentry; | ||
185 | d_rehash(dentry); | 189 | d_rehash(dentry); |
186 | 190 | ||
187 | return 0; | 191 | return 0; |
@@ -191,13 +195,15 @@ static int sysfs_attach_link(struct sysfs_dirent * sd, struct dentry * dentry) | |||
191 | { | 195 | { |
192 | int err = 0; | 196 | int err = 0; |
193 | 197 | ||
198 | dentry->d_fsdata = sysfs_get(sd); | ||
199 | sd->s_dentry = dentry; | ||
194 | err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink); | 200 | err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink); |
195 | if (!err) { | 201 | if (!err) { |
196 | dentry->d_op = &sysfs_dentry_ops; | 202 | dentry->d_op = &sysfs_dentry_ops; |
197 | dentry->d_fsdata = sysfs_get(sd); | ||
198 | sd->s_dentry = dentry; | ||
199 | d_rehash(dentry); | 203 | d_rehash(dentry); |
200 | } | 204 | } else |
205 | sysfs_put(sd); | ||
206 | |||
201 | return err; | 207 | return err; |
202 | } | 208 | } |
203 | 209 | ||
@@ -228,6 +234,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
228 | 234 | ||
229 | struct inode_operations sysfs_dir_inode_operations = { | 235 | struct inode_operations sysfs_dir_inode_operations = { |
230 | .lookup = sysfs_lookup, | 236 | .lookup = sysfs_lookup, |
237 | .setattr = sysfs_setattr, | ||
231 | }; | 238 | }; |
232 | 239 | ||
233 | static void remove_dir(struct dentry * d) | 240 | static void remove_dir(struct dentry * d) |
@@ -309,7 +316,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) | |||
309 | 316 | ||
310 | down(&parent->d_inode->i_sem); | 317 | down(&parent->d_inode->i_sem); |
311 | 318 | ||
312 | new_dentry = sysfs_get_dentry(parent, new_name); | 319 | new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); |
313 | if (!IS_ERR(new_dentry)) { | 320 | if (!IS_ERR(new_dentry)) { |
314 | if (!new_dentry->d_inode) { | 321 | if (!new_dentry->d_inode) { |
315 | error = kobject_set_name(kobj, "%s", new_name); | 322 | error = kobject_set_name(kobj, "%s", new_name); |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 364208071e17..d72c1ce48559 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/module.h> | 5 | #include <linux/module.h> |
6 | #include <linux/dnotify.h> | 6 | #include <linux/dnotify.h> |
7 | #include <linux/kobject.h> | 7 | #include <linux/kobject.h> |
8 | #include <linux/namei.h> | ||
8 | #include <asm/uaccess.h> | 9 | #include <asm/uaccess.h> |
9 | #include <asm/semaphore.h> | 10 | #include <asm/semaphore.h> |
10 | 11 | ||
@@ -13,7 +14,7 @@ | |||
13 | #define to_subsys(k) container_of(k,struct subsystem,kset.kobj) | 14 | #define to_subsys(k) container_of(k,struct subsystem,kset.kobj) |
14 | #define to_sattr(a) container_of(a,struct subsys_attribute,attr) | 15 | #define to_sattr(a) container_of(a,struct subsys_attribute,attr) |
15 | 16 | ||
16 | /** | 17 | /* |
17 | * Subsystem file operations. | 18 | * Subsystem file operations. |
18 | * These operations allow subsystems to have files that can be | 19 | * These operations allow subsystems to have files that can be |
19 | * read/written. | 20 | * read/written. |
@@ -23,7 +24,7 @@ subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page) | |||
23 | { | 24 | { |
24 | struct subsystem * s = to_subsys(kobj); | 25 | struct subsystem * s = to_subsys(kobj); |
25 | struct subsys_attribute * sattr = to_sattr(attr); | 26 | struct subsys_attribute * sattr = to_sattr(attr); |
26 | ssize_t ret = 0; | 27 | ssize_t ret = -EIO; |
27 | 28 | ||
28 | if (sattr->show) | 29 | if (sattr->show) |
29 | ret = sattr->show(s,page); | 30 | ret = sattr->show(s,page); |
@@ -36,7 +37,7 @@ subsys_attr_store(struct kobject * kobj, struct attribute * attr, | |||
36 | { | 37 | { |
37 | struct subsystem * s = to_subsys(kobj); | 38 | struct subsystem * s = to_subsys(kobj); |
38 | struct subsys_attribute * sattr = to_sattr(attr); | 39 | struct subsys_attribute * sattr = to_sattr(attr); |
39 | ssize_t ret = 0; | 40 | ssize_t ret = -EIO; |
40 | 41 | ||
41 | if (sattr->store) | 42 | if (sattr->store) |
42 | ret = sattr->store(s,page,count); | 43 | ret = sattr->store(s,page,count); |
@@ -182,7 +183,7 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t | |||
182 | return -ENOMEM; | 183 | return -ENOMEM; |
183 | 184 | ||
184 | if (count >= PAGE_SIZE) | 185 | if (count >= PAGE_SIZE) |
185 | count = PAGE_SIZE - 1; | 186 | count = PAGE_SIZE; |
186 | error = copy_from_user(buffer->page,buf,count); | 187 | error = copy_from_user(buffer->page,buf,count); |
187 | buffer->needs_read_fill = 1; | 188 | buffer->needs_read_fill = 1; |
188 | return error ? -EFAULT : count; | 189 | return error ? -EFAULT : count; |
@@ -191,8 +192,9 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t | |||
191 | 192 | ||
192 | /** | 193 | /** |
193 | * flush_write_buffer - push buffer to kobject. | 194 | * flush_write_buffer - push buffer to kobject. |
194 | * @file: file pointer. | 195 | * @dentry: dentry to the attribute |
195 | * @buffer: data buffer for file. | 196 | * @buffer: data buffer for file. |
197 | * @count: number of bytes | ||
196 | * | 198 | * |
197 | * Get the correct pointers for the kobject and the attribute we're | 199 | * Get the correct pointers for the kobject and the attribute we're |
198 | * dealing with, then call the store() method for the attribute, | 200 | * dealing with, then call the store() method for the attribute, |
@@ -400,7 +402,7 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr) | |||
400 | int res = -ENOENT; | 402 | int res = -ENOENT; |
401 | 403 | ||
402 | down(&dir->d_inode->i_sem); | 404 | down(&dir->d_inode->i_sem); |
403 | victim = sysfs_get_dentry(dir, attr->name); | 405 | victim = lookup_one_len(attr->name, dir, strlen(attr->name)); |
404 | if (!IS_ERR(victim)) { | 406 | if (!IS_ERR(victim)) { |
405 | /* make sure dentry is really there */ | 407 | /* make sure dentry is really there */ |
406 | if (victim->d_inode && | 408 | if (victim->d_inode && |
@@ -443,7 +445,7 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) | |||
443 | int res = -ENOENT; | 445 | int res = -ENOENT; |
444 | 446 | ||
445 | down(&dir->d_inode->i_sem); | 447 | down(&dir->d_inode->i_sem); |
446 | victim = sysfs_get_dentry(dir, attr->name); | 448 | victim = lookup_one_len(attr->name, dir, strlen(attr->name)); |
447 | if (!IS_ERR(victim)) { | 449 | if (!IS_ERR(victim)) { |
448 | if (victim->d_inode && | 450 | if (victim->d_inode && |
449 | (victim->d_parent->d_inode == dir->d_inode)) { | 451 | (victim->d_parent->d_inode == dir->d_inode)) { |
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index f11ac5ea7021..122145b0895c 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/kobject.h> | 11 | #include <linux/kobject.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/dcache.h> | 13 | #include <linux/dcache.h> |
14 | #include <linux/namei.h> | ||
14 | #include <linux/err.h> | 15 | #include <linux/err.h> |
15 | #include "sysfs.h" | 16 | #include "sysfs.h" |
16 | 17 | ||
@@ -68,7 +69,8 @@ void sysfs_remove_group(struct kobject * kobj, | |||
68 | struct dentry * dir; | 69 | struct dentry * dir; |
69 | 70 | ||
70 | if (grp->name) | 71 | if (grp->name) |
71 | dir = sysfs_get_dentry(kobj->dentry,grp->name); | 72 | dir = lookup_one_len(grp->name, kobj->dentry, |
73 | strlen(grp->name)); | ||
72 | else | 74 | else |
73 | dir = dget(kobj->dentry); | 75 | dir = dget(kobj->dentry); |
74 | 76 | ||
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index aff7b2dfa8ee..8de13bafaa76 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -26,18 +26,107 @@ static struct backing_dev_info sysfs_backing_dev_info = { | |||
26 | .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, | 26 | .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | struct inode * sysfs_new_inode(mode_t mode) | 29 | static struct inode_operations sysfs_inode_operations ={ |
30 | .setattr = sysfs_setattr, | ||
31 | }; | ||
32 | |||
33 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | ||
34 | { | ||
35 | struct inode * inode = dentry->d_inode; | ||
36 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
37 | struct iattr * sd_iattr; | ||
38 | unsigned int ia_valid = iattr->ia_valid; | ||
39 | int error; | ||
40 | |||
41 | if (!sd) | ||
42 | return -EINVAL; | ||
43 | |||
44 | sd_iattr = sd->s_iattr; | ||
45 | |||
46 | error = inode_change_ok(inode, iattr); | ||
47 | if (error) | ||
48 | return error; | ||
49 | |||
50 | error = inode_setattr(inode, iattr); | ||
51 | if (error) | ||
52 | return error; | ||
53 | |||
54 | if (!sd_iattr) { | ||
55 | /* setting attributes for the first time, allocate now */ | ||
56 | sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL); | ||
57 | if (!sd_iattr) | ||
58 | return -ENOMEM; | ||
59 | /* assign default attributes */ | ||
60 | memset(sd_iattr, 0, sizeof(struct iattr)); | ||
61 | sd_iattr->ia_mode = sd->s_mode; | ||
62 | sd_iattr->ia_uid = 0; | ||
63 | sd_iattr->ia_gid = 0; | ||
64 | sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; | ||
65 | sd->s_iattr = sd_iattr; | ||
66 | } | ||
67 | |||
68 | /* attributes were changed atleast once in past */ | ||
69 | |||
70 | if (ia_valid & ATTR_UID) | ||
71 | sd_iattr->ia_uid = iattr->ia_uid; | ||
72 | if (ia_valid & ATTR_GID) | ||
73 | sd_iattr->ia_gid = iattr->ia_gid; | ||
74 | if (ia_valid & ATTR_ATIME) | ||
75 | sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, | ||
76 | inode->i_sb->s_time_gran); | ||
77 | if (ia_valid & ATTR_MTIME) | ||
78 | sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, | ||
79 | inode->i_sb->s_time_gran); | ||
80 | if (ia_valid & ATTR_CTIME) | ||
81 | sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, | ||
82 | inode->i_sb->s_time_gran); | ||
83 | if (ia_valid & ATTR_MODE) { | ||
84 | umode_t mode = iattr->ia_mode; | ||
85 | |||
86 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
87 | mode &= ~S_ISGID; | ||
88 | sd_iattr->ia_mode = mode; | ||
89 | } | ||
90 | |||
91 | return error; | ||
92 | } | ||
93 | |||
94 | static inline void set_default_inode_attr(struct inode * inode, mode_t mode) | ||
95 | { | ||
96 | inode->i_mode = mode; | ||
97 | inode->i_uid = 0; | ||
98 | inode->i_gid = 0; | ||
99 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
100 | } | ||
101 | |||
102 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | ||
103 | { | ||
104 | inode->i_mode = iattr->ia_mode; | ||
105 | inode->i_uid = iattr->ia_uid; | ||
106 | inode->i_gid = iattr->ia_gid; | ||
107 | inode->i_atime = iattr->ia_atime; | ||
108 | inode->i_mtime = iattr->ia_mtime; | ||
109 | inode->i_ctime = iattr->ia_ctime; | ||
110 | } | ||
111 | |||
112 | struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd) | ||
30 | { | 113 | { |
31 | struct inode * inode = new_inode(sysfs_sb); | 114 | struct inode * inode = new_inode(sysfs_sb); |
32 | if (inode) { | 115 | if (inode) { |
33 | inode->i_mode = mode; | ||
34 | inode->i_uid = 0; | ||
35 | inode->i_gid = 0; | ||
36 | inode->i_blksize = PAGE_CACHE_SIZE; | 116 | inode->i_blksize = PAGE_CACHE_SIZE; |
37 | inode->i_blocks = 0; | 117 | inode->i_blocks = 0; |
38 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
39 | inode->i_mapping->a_ops = &sysfs_aops; | 118 | inode->i_mapping->a_ops = &sysfs_aops; |
40 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; | 119 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; |
120 | inode->i_op = &sysfs_inode_operations; | ||
121 | |||
122 | if (sd->s_iattr) { | ||
123 | /* sysfs_dirent has non-default attributes | ||
124 | * get them for the new inode from persistent copy | ||
125 | * in sysfs_dirent | ||
126 | */ | ||
127 | set_inode_attr(inode, sd->s_iattr); | ||
128 | } else | ||
129 | set_default_inode_attr(inode, mode); | ||
41 | } | 130 | } |
42 | return inode; | 131 | return inode; |
43 | } | 132 | } |
@@ -48,7 +137,8 @@ int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) | |||
48 | struct inode * inode = NULL; | 137 | struct inode * inode = NULL; |
49 | if (dentry) { | 138 | if (dentry) { |
50 | if (!dentry->d_inode) { | 139 | if (!dentry->d_inode) { |
51 | if ((inode = sysfs_new_inode(mode))) { | 140 | struct sysfs_dirent * sd = dentry->d_fsdata; |
141 | if ((inode = sysfs_new_inode(mode, sd))) { | ||
52 | if (dentry->d_parent && dentry->d_parent->d_inode) { | 142 | if (dentry->d_parent && dentry->d_parent->d_inode) { |
53 | struct inode *p_inode = dentry->d_parent->d_inode; | 143 | struct inode *p_inode = dentry->d_parent->d_inode; |
54 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; | 144 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; |
@@ -76,16 +166,6 @@ int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) | |||
76 | return error; | 166 | return error; |
77 | } | 167 | } |
78 | 168 | ||
79 | struct dentry * sysfs_get_dentry(struct dentry * parent, const char * name) | ||
80 | { | ||
81 | struct qstr qstr; | ||
82 | |||
83 | qstr.name = name; | ||
84 | qstr.len = strlen(name); | ||
85 | qstr.hash = full_name_hash(name,qstr.len); | ||
86 | return lookup_hash(&qstr,parent); | ||
87 | } | ||
88 | |||
89 | /* | 169 | /* |
90 | * Get the name for corresponding element represented by the given sysfs_dirent | 170 | * Get the name for corresponding element represented by the given sysfs_dirent |
91 | */ | 171 | */ |
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 5c805bb1a4b7..f1117e885bd6 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -28,6 +28,7 @@ static struct sysfs_dirent sysfs_root = { | |||
28 | .s_children = LIST_HEAD_INIT(sysfs_root.s_children), | 28 | .s_children = LIST_HEAD_INIT(sysfs_root.s_children), |
29 | .s_element = NULL, | 29 | .s_element = NULL, |
30 | .s_type = SYSFS_ROOT, | 30 | .s_type = SYSFS_ROOT, |
31 | .s_iattr = NULL, | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | 34 | static int sysfs_fill_super(struct super_block *sb, void *data, int silent) |
@@ -42,7 +43,8 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | |||
42 | sb->s_time_gran = 1; | 43 | sb->s_time_gran = 1; |
43 | sysfs_sb = sb; | 44 | sysfs_sb = sb; |
44 | 45 | ||
45 | inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO); | 46 | inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, |
47 | &sysfs_root); | ||
46 | if (inode) { | 48 | if (inode) { |
47 | inode->i_op = &sysfs_dir_inode_operations; | 49 | inode->i_op = &sysfs_dir_inode_operations; |
48 | inode->i_fop = &sysfs_dir_operations; | 50 | inode->i_fop = &sysfs_dir_operations; |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index dfdf70174354..fae57c83a722 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -43,7 +43,7 @@ static void fill_object_path(struct kobject * kobj, char * buffer, int length) | |||
43 | } | 43 | } |
44 | } | 44 | } |
45 | 45 | ||
46 | static int sysfs_add_link(struct dentry * parent, char * name, struct kobject * target) | 46 | static int sysfs_add_link(struct dentry * parent, const char * name, struct kobject * target) |
47 | { | 47 | { |
48 | struct sysfs_dirent * parent_sd = parent->d_fsdata; | 48 | struct sysfs_dirent * parent_sd = parent->d_fsdata; |
49 | struct sysfs_symlink * sl; | 49 | struct sysfs_symlink * sl; |
@@ -79,7 +79,7 @@ exit1: | |||
79 | * @target: object we're pointing to. | 79 | * @target: object we're pointing to. |
80 | * @name: name of the symlink. | 80 | * @name: name of the symlink. |
81 | */ | 81 | */ |
82 | int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name) | 82 | int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) |
83 | { | 83 | { |
84 | struct dentry * dentry = kobj->dentry; | 84 | struct dentry * dentry = kobj->dentry; |
85 | int error = 0; | 85 | int error = 0; |
@@ -99,13 +99,13 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * nam | |||
99 | * @name: name of the symlink to remove. | 99 | * @name: name of the symlink to remove. |
100 | */ | 100 | */ |
101 | 101 | ||
102 | void sysfs_remove_link(struct kobject * kobj, char * name) | 102 | void sysfs_remove_link(struct kobject * kobj, const char * name) |
103 | { | 103 | { |
104 | sysfs_hash_and_remove(kobj->dentry,name); | 104 | sysfs_hash_and_remove(kobj->dentry,name); |
105 | } | 105 | } |
106 | 106 | ||
107 | static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target, | 107 | static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target, |
108 | char *path) | 108 | char *path) |
109 | { | 109 | { |
110 | char * s; | 110 | char * s; |
111 | int depth, size; | 111 | int depth, size; |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index a8a24a0c0b3b..3f8953e0e5d0 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -2,12 +2,11 @@ | |||
2 | extern struct vfsmount * sysfs_mount; | 2 | extern struct vfsmount * sysfs_mount; |
3 | extern kmem_cache_t *sysfs_dir_cachep; | 3 | extern kmem_cache_t *sysfs_dir_cachep; |
4 | 4 | ||
5 | extern struct inode * sysfs_new_inode(mode_t mode); | 5 | extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); |
6 | extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); | 6 | extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); |
7 | 7 | ||
8 | extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, | 8 | extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, |
9 | umode_t, int); | 9 | umode_t, int); |
10 | extern struct dentry * sysfs_get_dentry(struct dentry *, const char *); | ||
11 | 10 | ||
12 | extern int sysfs_add_file(struct dentry *, const struct attribute *, int); | 11 | extern int sysfs_add_file(struct dentry *, const struct attribute *, int); |
13 | extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); | 12 | extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); |
@@ -17,6 +16,7 @@ extern void sysfs_remove_subdir(struct dentry *); | |||
17 | 16 | ||
18 | extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd); | 17 | extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd); |
19 | extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent); | 18 | extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent); |
19 | extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | ||
20 | 20 | ||
21 | extern struct rw_semaphore sysfs_rename_sem; | 21 | extern struct rw_semaphore sysfs_rename_sem; |
22 | extern struct super_block * sysfs_sb; | 22 | extern struct super_block * sysfs_sb; |
@@ -75,6 +75,7 @@ static inline void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
75 | kobject_put(sl->target_kobj); | 75 | kobject_put(sl->target_kobj); |
76 | kfree(sl); | 76 | kfree(sl); |
77 | } | 77 | } |
78 | kfree(sd->s_iattr); | ||
78 | kmem_cache_free(sysfs_dir_cachep, sd); | 79 | kmem_cache_free(sysfs_dir_cachep, sd); |
79 | } | 80 | } |
80 | 81 | ||
diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c index 457a8fe28575..85d8dbe843f1 100644 --- a/fs/udf/udftime.c +++ b/fs/udf/udftime.c | |||
@@ -46,7 +46,7 @@ | |||
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | /* How many days come before each month (0-12). */ | 48 | /* How many days come before each month (0-12). */ |
49 | const unsigned short int __mon_yday[2][13] = | 49 | static const unsigned short int __mon_yday[2][13] = |
50 | { | 50 | { |
51 | /* Normal years. */ | 51 | /* Normal years. */ |
52 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | 52 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, |
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 9278e9aba9ba..a3a4b5aaf5d9 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -149,11 +149,12 @@ linvfs_unwritten_convert( | |||
149 | */ | 149 | */ |
150 | STATIC void | 150 | STATIC void |
151 | linvfs_unwritten_convert_direct( | 151 | linvfs_unwritten_convert_direct( |
152 | struct inode *inode, | 152 | struct kiocb *iocb, |
153 | loff_t offset, | 153 | loff_t offset, |
154 | ssize_t size, | 154 | ssize_t size, |
155 | void *private) | 155 | void *private) |
156 | { | 156 | { |
157 | struct inode *inode = iocb->ki_filp->f_dentry->d_inode; | ||
157 | ASSERT(!private || inode == (struct inode *)private); | 158 | ASSERT(!private || inode == (struct inode *)private); |
158 | 159 | ||
159 | /* private indicates an unwritten extent lay beneath this IO */ | 160 | /* private indicates an unwritten extent lay beneath this IO */ |
@@ -886,7 +887,6 @@ xfs_page_state_convert( | |||
886 | SetPageUptodate(page); | 887 | SetPageUptodate(page); |
887 | 888 | ||
888 | if (startio) { | 889 | if (startio) { |
889 | WARN_ON(page_dirty); | ||
890 | xfs_submit_page(page, wbc, bh_arr, cnt, 0, !page_dirty); | 890 | xfs_submit_page(page, wbc, bh_arr, cnt, 0, !page_dirty); |
891 | } | 891 | } |
892 | 892 | ||
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 997963e53622..df0cba239dd5 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
@@ -61,12 +61,13 @@ | |||
61 | * File wide globals | 61 | * File wide globals |
62 | */ | 62 | */ |
63 | 63 | ||
64 | STATIC kmem_cache_t *pagebuf_cache; | 64 | STATIC kmem_cache_t *pagebuf_zone; |
65 | STATIC kmem_shaker_t pagebuf_shake; | 65 | STATIC kmem_shaker_t pagebuf_shake; |
66 | STATIC int pagebuf_daemon_wakeup(int, unsigned int); | 66 | STATIC int xfsbufd_wakeup(int, unsigned int); |
67 | STATIC void pagebuf_delwri_queue(xfs_buf_t *, int); | 67 | STATIC void pagebuf_delwri_queue(xfs_buf_t *, int); |
68 | STATIC struct workqueue_struct *pagebuf_logio_workqueue; | 68 | |
69 | STATIC struct workqueue_struct *pagebuf_dataio_workqueue; | 69 | STATIC struct workqueue_struct *xfslogd_workqueue; |
70 | STATIC struct workqueue_struct *xfsdatad_workqueue; | ||
70 | 71 | ||
71 | /* | 72 | /* |
72 | * Pagebuf debugging | 73 | * Pagebuf debugging |
@@ -123,9 +124,9 @@ ktrace_t *pagebuf_trace_buf; | |||
123 | 124 | ||
124 | 125 | ||
125 | #define pagebuf_allocate(flags) \ | 126 | #define pagebuf_allocate(flags) \ |
126 | kmem_zone_alloc(pagebuf_cache, pb_to_km(flags)) | 127 | kmem_zone_alloc(pagebuf_zone, pb_to_km(flags)) |
127 | #define pagebuf_deallocate(pb) \ | 128 | #define pagebuf_deallocate(pb) \ |
128 | kmem_zone_free(pagebuf_cache, (pb)); | 129 | kmem_zone_free(pagebuf_zone, (pb)); |
129 | 130 | ||
130 | /* | 131 | /* |
131 | * Page Region interfaces. | 132 | * Page Region interfaces. |
@@ -425,7 +426,7 @@ _pagebuf_lookup_pages( | |||
425 | __FUNCTION__, gfp_mask); | 426 | __FUNCTION__, gfp_mask); |
426 | 427 | ||
427 | XFS_STATS_INC(pb_page_retries); | 428 | XFS_STATS_INC(pb_page_retries); |
428 | pagebuf_daemon_wakeup(0, gfp_mask); | 429 | xfsbufd_wakeup(0, gfp_mask); |
429 | blk_congestion_wait(WRITE, HZ/50); | 430 | blk_congestion_wait(WRITE, HZ/50); |
430 | goto retry; | 431 | goto retry; |
431 | } | 432 | } |
@@ -1136,8 +1137,8 @@ pagebuf_iodone( | |||
1136 | if ((pb->pb_iodone) || (pb->pb_flags & PBF_ASYNC)) { | 1137 | if ((pb->pb_iodone) || (pb->pb_flags & PBF_ASYNC)) { |
1137 | if (schedule) { | 1138 | if (schedule) { |
1138 | INIT_WORK(&pb->pb_iodone_work, pagebuf_iodone_work, pb); | 1139 | INIT_WORK(&pb->pb_iodone_work, pagebuf_iodone_work, pb); |
1139 | queue_work(dataio ? pagebuf_dataio_workqueue : | 1140 | queue_work(dataio ? xfsdatad_workqueue : |
1140 | pagebuf_logio_workqueue, &pb->pb_iodone_work); | 1141 | xfslogd_workqueue, &pb->pb_iodone_work); |
1141 | } else { | 1142 | } else { |
1142 | pagebuf_iodone_work(pb); | 1143 | pagebuf_iodone_work(pb); |
1143 | } | 1144 | } |
@@ -1562,16 +1563,6 @@ xfs_free_buftarg( | |||
1562 | kmem_free(btp, sizeof(*btp)); | 1563 | kmem_free(btp, sizeof(*btp)); |
1563 | } | 1564 | } |
1564 | 1565 | ||
1565 | void | ||
1566 | xfs_incore_relse( | ||
1567 | xfs_buftarg_t *btp, | ||
1568 | int delwri_only, | ||
1569 | int wait) | ||
1570 | { | ||
1571 | invalidate_bdev(btp->pbr_bdev, 1); | ||
1572 | truncate_inode_pages(btp->pbr_mapping, 0LL); | ||
1573 | } | ||
1574 | |||
1575 | STATIC int | 1566 | STATIC int |
1576 | xfs_setsize_buftarg_flags( | 1567 | xfs_setsize_buftarg_flags( |
1577 | xfs_buftarg_t *btp, | 1568 | xfs_buftarg_t *btp, |
@@ -1742,27 +1733,27 @@ pagebuf_runall_queues( | |||
1742 | } | 1733 | } |
1743 | 1734 | ||
1744 | /* Defines for pagebuf daemon */ | 1735 | /* Defines for pagebuf daemon */ |
1745 | STATIC DECLARE_COMPLETION(pagebuf_daemon_done); | 1736 | STATIC DECLARE_COMPLETION(xfsbufd_done); |
1746 | STATIC struct task_struct *pagebuf_daemon_task; | 1737 | STATIC struct task_struct *xfsbufd_task; |
1747 | STATIC int pagebuf_daemon_active; | 1738 | STATIC int xfsbufd_active; |
1748 | STATIC int force_flush; | 1739 | STATIC int xfsbufd_force_flush; |
1749 | STATIC int force_sleep; | 1740 | STATIC int xfsbufd_force_sleep; |
1750 | 1741 | ||
1751 | STATIC int | 1742 | STATIC int |
1752 | pagebuf_daemon_wakeup( | 1743 | xfsbufd_wakeup( |
1753 | int priority, | 1744 | int priority, |
1754 | unsigned int mask) | 1745 | unsigned int mask) |
1755 | { | 1746 | { |
1756 | if (force_sleep) | 1747 | if (xfsbufd_force_sleep) |
1757 | return 0; | 1748 | return 0; |
1758 | force_flush = 1; | 1749 | xfsbufd_force_flush = 1; |
1759 | barrier(); | 1750 | barrier(); |
1760 | wake_up_process(pagebuf_daemon_task); | 1751 | wake_up_process(xfsbufd_task); |
1761 | return 0; | 1752 | return 0; |
1762 | } | 1753 | } |
1763 | 1754 | ||
1764 | STATIC int | 1755 | STATIC int |
1765 | pagebuf_daemon( | 1756 | xfsbufd( |
1766 | void *data) | 1757 | void *data) |
1767 | { | 1758 | { |
1768 | struct list_head tmp; | 1759 | struct list_head tmp; |
@@ -1774,17 +1765,17 @@ pagebuf_daemon( | |||
1774 | daemonize("xfsbufd"); | 1765 | daemonize("xfsbufd"); |
1775 | current->flags |= PF_MEMALLOC; | 1766 | current->flags |= PF_MEMALLOC; |
1776 | 1767 | ||
1777 | pagebuf_daemon_task = current; | 1768 | xfsbufd_task = current; |
1778 | pagebuf_daemon_active = 1; | 1769 | xfsbufd_active = 1; |
1779 | barrier(); | 1770 | barrier(); |
1780 | 1771 | ||
1781 | INIT_LIST_HEAD(&tmp); | 1772 | INIT_LIST_HEAD(&tmp); |
1782 | do { | 1773 | do { |
1783 | if (unlikely(current->flags & PF_FREEZE)) { | 1774 | if (unlikely(freezing(current))) { |
1784 | force_sleep = 1; | 1775 | xfsbufd_force_sleep = 1; |
1785 | refrigerator(PF_FREEZE); | 1776 | refrigerator(); |
1786 | } else { | 1777 | } else { |
1787 | force_sleep = 0; | 1778 | xfsbufd_force_sleep = 0; |
1788 | } | 1779 | } |
1789 | 1780 | ||
1790 | set_current_state(TASK_INTERRUPTIBLE); | 1781 | set_current_state(TASK_INTERRUPTIBLE); |
@@ -1797,7 +1788,7 @@ pagebuf_daemon( | |||
1797 | ASSERT(pb->pb_flags & PBF_DELWRI); | 1788 | ASSERT(pb->pb_flags & PBF_DELWRI); |
1798 | 1789 | ||
1799 | if (!pagebuf_ispin(pb) && !pagebuf_cond_lock(pb)) { | 1790 | if (!pagebuf_ispin(pb) && !pagebuf_cond_lock(pb)) { |
1800 | if (!force_flush && | 1791 | if (!xfsbufd_force_flush && |
1801 | time_before(jiffies, | 1792 | time_before(jiffies, |
1802 | pb->pb_queuetime + age)) { | 1793 | pb->pb_queuetime + age)) { |
1803 | pagebuf_unlock(pb); | 1794 | pagebuf_unlock(pb); |
@@ -1824,10 +1815,10 @@ pagebuf_daemon( | |||
1824 | if (as_list_len > 0) | 1815 | if (as_list_len > 0) |
1825 | purge_addresses(); | 1816 | purge_addresses(); |
1826 | 1817 | ||
1827 | force_flush = 0; | 1818 | xfsbufd_force_flush = 0; |
1828 | } while (pagebuf_daemon_active); | 1819 | } while (xfsbufd_active); |
1829 | 1820 | ||
1830 | complete_and_exit(&pagebuf_daemon_done, 0); | 1821 | complete_and_exit(&xfsbufd_done, 0); |
1831 | } | 1822 | } |
1832 | 1823 | ||
1833 | /* | 1824 | /* |
@@ -1844,8 +1835,8 @@ xfs_flush_buftarg( | |||
1844 | xfs_buf_t *pb, *n; | 1835 | xfs_buf_t *pb, *n; |
1845 | int pincount = 0; | 1836 | int pincount = 0; |
1846 | 1837 | ||
1847 | pagebuf_runall_queues(pagebuf_dataio_workqueue); | 1838 | pagebuf_runall_queues(xfsdatad_workqueue); |
1848 | pagebuf_runall_queues(pagebuf_logio_workqueue); | 1839 | pagebuf_runall_queues(xfslogd_workqueue); |
1849 | 1840 | ||
1850 | INIT_LIST_HEAD(&tmp); | 1841 | INIT_LIST_HEAD(&tmp); |
1851 | spin_lock(&pbd_delwrite_lock); | 1842 | spin_lock(&pbd_delwrite_lock); |
@@ -1898,43 +1889,43 @@ xfs_flush_buftarg( | |||
1898 | } | 1889 | } |
1899 | 1890 | ||
1900 | STATIC int | 1891 | STATIC int |
1901 | pagebuf_daemon_start(void) | 1892 | xfs_buf_daemons_start(void) |
1902 | { | 1893 | { |
1903 | int rval; | 1894 | int error = -ENOMEM; |
1904 | 1895 | ||
1905 | pagebuf_logio_workqueue = create_workqueue("xfslogd"); | 1896 | xfslogd_workqueue = create_workqueue("xfslogd"); |
1906 | if (!pagebuf_logio_workqueue) | 1897 | if (!xfslogd_workqueue) |
1907 | return -ENOMEM; | 1898 | goto out; |
1908 | 1899 | ||
1909 | pagebuf_dataio_workqueue = create_workqueue("xfsdatad"); | 1900 | xfsdatad_workqueue = create_workqueue("xfsdatad"); |
1910 | if (!pagebuf_dataio_workqueue) { | 1901 | if (!xfsdatad_workqueue) |
1911 | destroy_workqueue(pagebuf_logio_workqueue); | 1902 | goto out_destroy_xfslogd_workqueue; |
1912 | return -ENOMEM; | ||
1913 | } | ||
1914 | 1903 | ||
1915 | rval = kernel_thread(pagebuf_daemon, NULL, CLONE_FS|CLONE_FILES); | 1904 | error = kernel_thread(xfsbufd, NULL, CLONE_FS|CLONE_FILES); |
1916 | if (rval < 0) { | 1905 | if (error < 0) |
1917 | destroy_workqueue(pagebuf_logio_workqueue); | 1906 | goto out_destroy_xfsdatad_workqueue; |
1918 | destroy_workqueue(pagebuf_dataio_workqueue); | 1907 | return 0; |
1919 | } | ||
1920 | 1908 | ||
1921 | return rval; | 1909 | out_destroy_xfsdatad_workqueue: |
1910 | destroy_workqueue(xfsdatad_workqueue); | ||
1911 | out_destroy_xfslogd_workqueue: | ||
1912 | destroy_workqueue(xfslogd_workqueue); | ||
1913 | out: | ||
1914 | return error; | ||
1922 | } | 1915 | } |
1923 | 1916 | ||
1924 | /* | 1917 | /* |
1925 | * pagebuf_daemon_stop | ||
1926 | * | ||
1927 | * Note: do not mark as __exit, it is called from pagebuf_terminate. | 1918 | * Note: do not mark as __exit, it is called from pagebuf_terminate. |
1928 | */ | 1919 | */ |
1929 | STATIC void | 1920 | STATIC void |
1930 | pagebuf_daemon_stop(void) | 1921 | xfs_buf_daemons_stop(void) |
1931 | { | 1922 | { |
1932 | pagebuf_daemon_active = 0; | 1923 | xfsbufd_active = 0; |
1933 | barrier(); | 1924 | barrier(); |
1934 | wait_for_completion(&pagebuf_daemon_done); | 1925 | wait_for_completion(&xfsbufd_done); |
1935 | 1926 | ||
1936 | destroy_workqueue(pagebuf_logio_workqueue); | 1927 | destroy_workqueue(xfslogd_workqueue); |
1937 | destroy_workqueue(pagebuf_dataio_workqueue); | 1928 | destroy_workqueue(xfsdatad_workqueue); |
1938 | } | 1929 | } |
1939 | 1930 | ||
1940 | /* | 1931 | /* |
@@ -1944,27 +1935,37 @@ pagebuf_daemon_stop(void) | |||
1944 | int __init | 1935 | int __init |
1945 | pagebuf_init(void) | 1936 | pagebuf_init(void) |
1946 | { | 1937 | { |
1947 | pagebuf_cache = kmem_cache_create("xfs_buf_t", sizeof(xfs_buf_t), 0, | 1938 | int error = -ENOMEM; |
1948 | SLAB_HWCACHE_ALIGN, NULL, NULL); | 1939 | |
1949 | if (pagebuf_cache == NULL) { | 1940 | pagebuf_zone = kmem_zone_init(sizeof(xfs_buf_t), "xfs_buf"); |
1950 | printk("XFS: couldn't init xfs_buf_t cache\n"); | 1941 | if (!pagebuf_zone) |
1951 | pagebuf_terminate(); | 1942 | goto out; |
1952 | return -ENOMEM; | ||
1953 | } | ||
1954 | 1943 | ||
1955 | #ifdef PAGEBUF_TRACE | 1944 | #ifdef PAGEBUF_TRACE |
1956 | pagebuf_trace_buf = ktrace_alloc(PAGEBUF_TRACE_SIZE, KM_SLEEP); | 1945 | pagebuf_trace_buf = ktrace_alloc(PAGEBUF_TRACE_SIZE, KM_SLEEP); |
1957 | #endif | 1946 | #endif |
1958 | 1947 | ||
1959 | pagebuf_daemon_start(); | 1948 | error = xfs_buf_daemons_start(); |
1949 | if (error) | ||
1950 | goto out_free_buf_zone; | ||
1960 | 1951 | ||
1961 | pagebuf_shake = kmem_shake_register(pagebuf_daemon_wakeup); | 1952 | pagebuf_shake = kmem_shake_register(xfsbufd_wakeup); |
1962 | if (pagebuf_shake == NULL) { | 1953 | if (!pagebuf_shake) { |
1963 | pagebuf_terminate(); | 1954 | error = -ENOMEM; |
1964 | return -ENOMEM; | 1955 | goto out_stop_daemons; |
1965 | } | 1956 | } |
1966 | 1957 | ||
1967 | return 0; | 1958 | return 0; |
1959 | |||
1960 | out_stop_daemons: | ||
1961 | xfs_buf_daemons_stop(); | ||
1962 | out_free_buf_zone: | ||
1963 | #ifdef PAGEBUF_TRACE | ||
1964 | ktrace_free(pagebuf_trace_buf); | ||
1965 | #endif | ||
1966 | kmem_zone_destroy(pagebuf_zone); | ||
1967 | out: | ||
1968 | return error; | ||
1968 | } | 1969 | } |
1969 | 1970 | ||
1970 | 1971 | ||
@@ -1976,12 +1977,12 @@ pagebuf_init(void) | |||
1976 | void | 1977 | void |
1977 | pagebuf_terminate(void) | 1978 | pagebuf_terminate(void) |
1978 | { | 1979 | { |
1979 | pagebuf_daemon_stop(); | 1980 | xfs_buf_daemons_stop(); |
1980 | 1981 | ||
1981 | #ifdef PAGEBUF_TRACE | 1982 | #ifdef PAGEBUF_TRACE |
1982 | ktrace_free(pagebuf_trace_buf); | 1983 | ktrace_free(pagebuf_trace_buf); |
1983 | #endif | 1984 | #endif |
1984 | 1985 | ||
1985 | kmem_zone_destroy(pagebuf_cache); | 1986 | kmem_zone_destroy(pagebuf_zone); |
1986 | kmem_shake_deregister(pagebuf_shake); | 1987 | kmem_shake_deregister(pagebuf_shake); |
1987 | } | 1988 | } |
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index 74deed8e6d90..3f8f69a66aea 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h | |||
@@ -576,7 +576,6 @@ extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *, int); | |||
576 | extern void xfs_free_buftarg(xfs_buftarg_t *, int); | 576 | extern void xfs_free_buftarg(xfs_buftarg_t *, int); |
577 | extern void xfs_wait_buftarg(xfs_buftarg_t *); | 577 | extern void xfs_wait_buftarg(xfs_buftarg_t *); |
578 | extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); | 578 | extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); |
579 | extern void xfs_incore_relse(xfs_buftarg_t *, int, int); | ||
580 | extern int xfs_flush_buftarg(xfs_buftarg_t *, int); | 579 | extern int xfs_flush_buftarg(xfs_buftarg_t *, int); |
581 | 580 | ||
582 | #define xfs_getsize_buftarg(buftarg) \ | 581 | #define xfs_getsize_buftarg(buftarg) \ |
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index d0d412afd261..f1ce4323f56e 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
@@ -57,7 +57,9 @@ | |||
57 | #include <linux/smp_lock.h> | 57 | #include <linux/smp_lock.h> |
58 | 58 | ||
59 | static struct vm_operations_struct linvfs_file_vm_ops; | 59 | static struct vm_operations_struct linvfs_file_vm_ops; |
60 | 60 | #ifdef CONFIG_XFS_DMAPI | |
61 | static struct vm_operations_struct linvfs_dmapi_file_vm_ops; | ||
62 | #endif | ||
61 | 63 | ||
62 | STATIC inline ssize_t | 64 | STATIC inline ssize_t |
63 | __linvfs_read( | 65 | __linvfs_read( |
@@ -388,6 +390,14 @@ done: | |||
388 | return -error; | 390 | return -error; |
389 | } | 391 | } |
390 | 392 | ||
393 | #ifdef CONFIG_XFS_DMAPI | ||
394 | STATIC void | ||
395 | linvfs_mmap_close( | ||
396 | struct vm_area_struct *vma) | ||
397 | { | ||
398 | xfs_dm_mm_put(vma); | ||
399 | } | ||
400 | #endif /* CONFIG_XFS_DMAPI */ | ||
391 | 401 | ||
392 | STATIC int | 402 | STATIC int |
393 | linvfs_file_mmap( | 403 | linvfs_file_mmap( |
@@ -399,16 +409,19 @@ linvfs_file_mmap( | |||
399 | vattr_t va = { .va_mask = XFS_AT_UPDATIME }; | 409 | vattr_t va = { .va_mask = XFS_AT_UPDATIME }; |
400 | int error; | 410 | int error; |
401 | 411 | ||
412 | vma->vm_ops = &linvfs_file_vm_ops; | ||
413 | |||
402 | if (vp->v_vfsp->vfs_flag & VFS_DMI) { | 414 | if (vp->v_vfsp->vfs_flag & VFS_DMI) { |
403 | xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp); | 415 | xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp); |
404 | 416 | ||
405 | error = -XFS_SEND_MMAP(mp, vma, 0); | 417 | error = -XFS_SEND_MMAP(mp, vma, 0); |
406 | if (error) | 418 | if (error) |
407 | return error; | 419 | return error; |
420 | #ifdef CONFIG_XFS_DMAPI | ||
421 | vma->vm_ops = &linvfs_dmapi_file_vm_ops; | ||
422 | #endif | ||
408 | } | 423 | } |
409 | 424 | ||
410 | vma->vm_ops = &linvfs_file_vm_ops; | ||
411 | |||
412 | VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error); | 425 | VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error); |
413 | if (!error) | 426 | if (!error) |
414 | vn_revalidate(vp); /* update Linux inode flags */ | 427 | vn_revalidate(vp); /* update Linux inode flags */ |
@@ -565,7 +578,7 @@ struct file_operations linvfs_file_operations = { | |||
565 | .sendfile = linvfs_sendfile, | 578 | .sendfile = linvfs_sendfile, |
566 | .unlocked_ioctl = linvfs_ioctl, | 579 | .unlocked_ioctl = linvfs_ioctl, |
567 | #ifdef CONFIG_COMPAT | 580 | #ifdef CONFIG_COMPAT |
568 | .compat_ioctl = xfs_compat_ioctl, | 581 | .compat_ioctl = linvfs_compat_ioctl, |
569 | #endif | 582 | #endif |
570 | .mmap = linvfs_file_mmap, | 583 | .mmap = linvfs_file_mmap, |
571 | .open = linvfs_open, | 584 | .open = linvfs_open, |
@@ -587,7 +600,7 @@ struct file_operations linvfs_invis_file_operations = { | |||
587 | .sendfile = linvfs_sendfile, | 600 | .sendfile = linvfs_sendfile, |
588 | .unlocked_ioctl = linvfs_ioctl_invis, | 601 | .unlocked_ioctl = linvfs_ioctl_invis, |
589 | #ifdef CONFIG_COMPAT | 602 | #ifdef CONFIG_COMPAT |
590 | .compat_ioctl = xfs_compat_invis_ioctl, | 603 | .compat_ioctl = linvfs_compat_invis_ioctl, |
591 | #endif | 604 | #endif |
592 | .mmap = linvfs_file_mmap, | 605 | .mmap = linvfs_file_mmap, |
593 | .open = linvfs_open, | 606 | .open = linvfs_open, |
@@ -600,13 +613,24 @@ struct file_operations linvfs_dir_operations = { | |||
600 | .read = generic_read_dir, | 613 | .read = generic_read_dir, |
601 | .readdir = linvfs_readdir, | 614 | .readdir = linvfs_readdir, |
602 | .unlocked_ioctl = linvfs_ioctl, | 615 | .unlocked_ioctl = linvfs_ioctl, |
616 | #ifdef CONFIG_COMPAT | ||
617 | .compat_ioctl = linvfs_compat_ioctl, | ||
618 | #endif | ||
603 | .fsync = linvfs_fsync, | 619 | .fsync = linvfs_fsync, |
604 | }; | 620 | }; |
605 | 621 | ||
606 | static struct vm_operations_struct linvfs_file_vm_ops = { | 622 | static struct vm_operations_struct linvfs_file_vm_ops = { |
607 | .nopage = filemap_nopage, | 623 | .nopage = filemap_nopage, |
608 | .populate = filemap_populate, | 624 | .populate = filemap_populate, |
625 | }; | ||
626 | |||
627 | #ifdef CONFIG_XFS_DMAPI | ||
628 | static struct vm_operations_struct linvfs_dmapi_file_vm_ops = { | ||
629 | .close = linvfs_mmap_close, | ||
630 | .nopage = filemap_nopage, | ||
631 | .populate = filemap_populate, | ||
609 | #ifdef HAVE_VMOP_MPROTECT | 632 | #ifdef HAVE_VMOP_MPROTECT |
610 | .mprotect = linvfs_mprotect, | 633 | .mprotect = linvfs_mprotect, |
611 | #endif | 634 | #endif |
612 | }; | 635 | }; |
636 | #endif /* CONFIG_XFS_DMAPI */ | ||
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 69809eef8a54..05a447e51cc0 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c | |||
@@ -1174,7 +1174,8 @@ xfs_ioc_xattr( | |||
1174 | 1174 | ||
1175 | switch (cmd) { | 1175 | switch (cmd) { |
1176 | case XFS_IOC_FSGETXATTR: { | 1176 | case XFS_IOC_FSGETXATTR: { |
1177 | va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS; | 1177 | va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ |
1178 | XFS_AT_NEXTENTS | XFS_AT_PROJID; | ||
1178 | VOP_GETATTR(vp, &va, 0, NULL, error); | 1179 | VOP_GETATTR(vp, &va, 0, NULL, error); |
1179 | if (error) | 1180 | if (error) |
1180 | return -error; | 1181 | return -error; |
@@ -1182,6 +1183,7 @@ xfs_ioc_xattr( | |||
1182 | fa.fsx_xflags = va.va_xflags; | 1183 | fa.fsx_xflags = va.va_xflags; |
1183 | fa.fsx_extsize = va.va_extsize; | 1184 | fa.fsx_extsize = va.va_extsize; |
1184 | fa.fsx_nextents = va.va_nextents; | 1185 | fa.fsx_nextents = va.va_nextents; |
1186 | fa.fsx_projid = va.va_projid; | ||
1185 | 1187 | ||
1186 | if (copy_to_user(arg, &fa, sizeof(fa))) | 1188 | if (copy_to_user(arg, &fa, sizeof(fa))) |
1187 | return -XFS_ERROR(EFAULT); | 1189 | return -XFS_ERROR(EFAULT); |
@@ -1196,9 +1198,10 @@ xfs_ioc_xattr( | |||
1196 | if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) | 1198 | if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) |
1197 | attr_flags |= ATTR_NONBLOCK; | 1199 | attr_flags |= ATTR_NONBLOCK; |
1198 | 1200 | ||
1199 | va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE; | 1201 | va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID; |
1200 | va.va_xflags = fa.fsx_xflags; | 1202 | va.va_xflags = fa.fsx_xflags; |
1201 | va.va_extsize = fa.fsx_extsize; | 1203 | va.va_extsize = fa.fsx_extsize; |
1204 | va.va_projid = fa.fsx_projid; | ||
1202 | 1205 | ||
1203 | VOP_SETATTR(vp, &va, attr_flags, NULL, error); | 1206 | VOP_SETATTR(vp, &va, attr_flags, NULL, error); |
1204 | if (!error) | 1207 | if (!error) |
@@ -1207,7 +1210,8 @@ xfs_ioc_xattr( | |||
1207 | } | 1210 | } |
1208 | 1211 | ||
1209 | case XFS_IOC_FSGETXATTRA: { | 1212 | case XFS_IOC_FSGETXATTRA: { |
1210 | va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS; | 1213 | va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ |
1214 | XFS_AT_ANEXTENTS | XFS_AT_PROJID; | ||
1211 | VOP_GETATTR(vp, &va, 0, NULL, error); | 1215 | VOP_GETATTR(vp, &va, 0, NULL, error); |
1212 | if (error) | 1216 | if (error) |
1213 | return -error; | 1217 | return -error; |
@@ -1215,6 +1219,7 @@ xfs_ioc_xattr( | |||
1215 | fa.fsx_xflags = va.va_xflags; | 1219 | fa.fsx_xflags = va.va_xflags; |
1216 | fa.fsx_extsize = va.va_extsize; | 1220 | fa.fsx_extsize = va.va_extsize; |
1217 | fa.fsx_nextents = va.va_anextents; | 1221 | fa.fsx_nextents = va.va_anextents; |
1222 | fa.fsx_projid = va.va_projid; | ||
1218 | 1223 | ||
1219 | if (copy_to_user(arg, &fa, sizeof(fa))) | 1224 | if (copy_to_user(arg, &fa, sizeof(fa))) |
1220 | return -XFS_ERROR(EFAULT); | 1225 | return -XFS_ERROR(EFAULT); |
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 7a12c83184f5..0f8f1384eb36 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. | 2 | * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of version 2 of the GNU General Public License as | 5 | * under the terms of version 2 of the GNU General Public License as |
@@ -58,8 +58,9 @@ typedef struct xfs_fsop_bulkreq32 { | |||
58 | __s32 ocount; /* output count pointer */ | 58 | __s32 ocount; /* output count pointer */ |
59 | } xfs_fsop_bulkreq32_t; | 59 | } xfs_fsop_bulkreq32_t; |
60 | 60 | ||
61 | static unsigned long | 61 | STATIC unsigned long |
62 | xfs_ioctl32_bulkstat(unsigned long arg) | 62 | xfs_ioctl32_bulkstat( |
63 | unsigned long arg) | ||
63 | { | 64 | { |
64 | xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg; | 65 | xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg; |
65 | xfs_fsop_bulkreq_t __user *p = compat_alloc_user_space(sizeof(*p)); | 66 | xfs_fsop_bulkreq_t __user *p = compat_alloc_user_space(sizeof(*p)); |
@@ -78,11 +79,11 @@ xfs_ioctl32_bulkstat(unsigned long arg) | |||
78 | } | 79 | } |
79 | #endif | 80 | #endif |
80 | 81 | ||
81 | static long | 82 | STATIC long |
82 | __xfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg) | 83 | __linvfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg) |
83 | { | 84 | { |
84 | int error; | 85 | int error; |
85 | struct inode *inode = f->f_dentry->d_inode; | 86 | struct inode *inode = f->f_dentry->d_inode; |
86 | vnode_t *vp = LINVFS_GET_VP(inode); | 87 | vnode_t *vp = LINVFS_GET_VP(inode); |
87 | 88 | ||
88 | switch (cmd) { | 89 | switch (cmd) { |
@@ -152,12 +153,20 @@ __xfs_compat_ioctl(int mode, struct file *f, unsigned cmd, unsigned long arg) | |||
152 | return error; | 153 | return error; |
153 | } | 154 | } |
154 | 155 | ||
155 | long xfs_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg) | 156 | long |
157 | linvfs_compat_ioctl( | ||
158 | struct file *f, | ||
159 | unsigned cmd, | ||
160 | unsigned long arg) | ||
156 | { | 161 | { |
157 | return __xfs_compat_ioctl(0, f, cmd, arg); | 162 | return __linvfs_compat_ioctl(0, f, cmd, arg); |
158 | } | 163 | } |
159 | 164 | ||
160 | long xfs_compat_invis_ioctl(struct file *f, unsigned cmd, unsigned long arg) | 165 | long |
166 | linvfs_compat_invis_ioctl( | ||
167 | struct file *f, | ||
168 | unsigned cmd, | ||
169 | unsigned long arg) | ||
161 | { | 170 | { |
162 | return __xfs_compat_ioctl(IO_INVIS, f, cmd, arg); | 171 | return __linvfs_compat_ioctl(IO_INVIS, f, cmd, arg); |
163 | } | 172 | } |
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.h b/fs/xfs/linux-2.6/xfs_ioctl32.h index 779f69a48116..c874793a1dc9 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.h +++ b/fs/xfs/linux-2.6/xfs_ioctl32.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. | 2 | * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of version 2 of the GNU General Public License as | 5 | * under the terms of version 2 of the GNU General Public License as |
@@ -30,5 +30,5 @@ | |||
30 | * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ | 30 | * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ |
31 | */ | 31 | */ |
32 | 32 | ||
33 | long xfs_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg); | 33 | long linvfs_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg); |
34 | long xfs_compat_invis_ioctl(struct file *f, unsigned cmd, unsigned long arg); | 34 | long linvfs_compat_invis_ioctl(struct file *f, unsigned cmd, unsigned long arg); |
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index 71bb41019a12..42dc5e4662ed 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h | |||
@@ -145,10 +145,10 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh) | |||
145 | #define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val | 145 | #define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val |
146 | #define xfs_rotorstep xfs_params.rotorstep.val | 146 | #define xfs_rotorstep xfs_params.rotorstep.val |
147 | 147 | ||
148 | #ifndef __smp_processor_id | 148 | #ifndef raw_smp_processor_id |
149 | #define __smp_processor_id() smp_processor_id() | 149 | #define raw_smp_processor_id() smp_processor_id() |
150 | #endif | 150 | #endif |
151 | #define current_cpu() __smp_processor_id() | 151 | #define current_cpu() raw_smp_processor_id() |
152 | #define current_pid() (current->pid) | 152 | #define current_pid() (current->pid) |
153 | #define current_fsuid(cred) (current->fsuid) | 153 | #define current_fsuid(cred) (current->fsuid) |
154 | #define current_fsgid(cred) (current->fsgid) | 154 | #define current_fsgid(cred) (current->fsgid) |
@@ -230,8 +230,10 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh) | |||
230 | * field (see the QCMD macro in quota.h). These macros help keep the | 230 | * field (see the QCMD macro in quota.h). These macros help keep the |
231 | * code portable - they are not visible from the syscall interface. | 231 | * code portable - they are not visible from the syscall interface. |
232 | */ | 232 | */ |
233 | #define Q_XSETGQLIM XQM_CMD(0x8) /* set groups disk limits */ | 233 | #define Q_XSETGQLIM XQM_CMD(8) /* set groups disk limits */ |
234 | #define Q_XGETGQUOTA XQM_CMD(0x9) /* get groups disk limits */ | 234 | #define Q_XGETGQUOTA XQM_CMD(9) /* get groups disk limits */ |
235 | #define Q_XSETPQLIM XQM_CMD(10) /* set projects disk limits */ | ||
236 | #define Q_XGETPQUOTA XQM_CMD(11) /* get projects disk limits */ | ||
235 | 237 | ||
236 | /* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */ | 238 | /* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */ |
237 | /* we may well need to fine-tune this if it ever becomes an issue. */ | 239 | /* we may well need to fine-tune this if it ever becomes an issue. */ |
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index aa9daaea6c34..acab58c48043 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c | |||
@@ -209,30 +209,6 @@ unlock: | |||
209 | return (-status); | 209 | return (-status); |
210 | } | 210 | } |
211 | 211 | ||
212 | /* | ||
213 | * xfs_inval_cached_pages | ||
214 | * | ||
215 | * This routine is responsible for keeping direct I/O and buffered I/O | ||
216 | * somewhat coherent. From here we make sure that we're at least | ||
217 | * temporarily holding the inode I/O lock exclusively and then call | ||
218 | * the page cache to flush and invalidate any cached pages. If there | ||
219 | * are no cached pages this routine will be very quick. | ||
220 | */ | ||
221 | void | ||
222 | xfs_inval_cached_pages( | ||
223 | vnode_t *vp, | ||
224 | xfs_iocore_t *io, | ||
225 | xfs_off_t offset, | ||
226 | int write, | ||
227 | int relock) | ||
228 | { | ||
229 | if (VN_CACHED(vp)) { | ||
230 | xfs_inval_cached_trace(io, offset, -1, ctooff(offtoct(offset)), -1); | ||
231 | VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(offset)), -1, FI_REMAPF_LOCKED); | ||
232 | } | ||
233 | |||
234 | } | ||
235 | |||
236 | ssize_t /* bytes read, or (-) error */ | 212 | ssize_t /* bytes read, or (-) error */ |
237 | xfs_read( | 213 | xfs_read( |
238 | bhv_desc_t *bdp, | 214 | bhv_desc_t *bdp, |
@@ -304,10 +280,11 @@ xfs_read( | |||
304 | if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && | 280 | if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && |
305 | !(ioflags & IO_INVIS)) { | 281 | !(ioflags & IO_INVIS)) { |
306 | vrwlock_t locktype = VRWLOCK_READ; | 282 | vrwlock_t locktype = VRWLOCK_READ; |
283 | int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags); | ||
307 | 284 | ||
308 | ret = -XFS_SEND_DATA(mp, DM_EVENT_READ, | 285 | ret = -XFS_SEND_DATA(mp, DM_EVENT_READ, |
309 | BHV_TO_VNODE(bdp), *offset, size, | 286 | BHV_TO_VNODE(bdp), *offset, size, |
310 | FILP_DELAY_FLAG(file), &locktype); | 287 | dmflags, &locktype); |
311 | if (ret) { | 288 | if (ret) { |
312 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | 289 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); |
313 | goto unlock_isem; | 290 | goto unlock_isem; |
@@ -867,11 +844,15 @@ retry: | |||
867 | !(ioflags & IO_INVIS)) { | 844 | !(ioflags & IO_INVIS)) { |
868 | 845 | ||
869 | xfs_rwunlock(bdp, locktype); | 846 | xfs_rwunlock(bdp, locktype); |
847 | if (need_isem) | ||
848 | up(&inode->i_sem); | ||
870 | error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp, | 849 | error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp, |
871 | DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL, | 850 | DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL, |
872 | 0, 0, 0); /* Delay flag intentionally unused */ | 851 | 0, 0, 0); /* Delay flag intentionally unused */ |
873 | if (error) | 852 | if (error) |
874 | goto out_unlock_isem; | 853 | goto out_nounlocks; |
854 | if (need_isem) | ||
855 | down(&inode->i_sem); | ||
875 | xfs_rwlock(bdp, locktype); | 856 | xfs_rwlock(bdp, locktype); |
876 | pos = xip->i_d.di_size; | 857 | pos = xip->i_d.di_size; |
877 | ret = 0; | 858 | ret = 0; |
@@ -986,6 +967,7 @@ retry: | |||
986 | out_unlock_isem: | 967 | out_unlock_isem: |
987 | if (need_isem) | 968 | if (need_isem) |
988 | up(&inode->i_sem); | 969 | up(&inode->i_sem); |
970 | out_nounlocks: | ||
989 | return -error; | 971 | return -error; |
990 | } | 972 | } |
991 | 973 | ||
diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index d723e35254a0..f197a720e394 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h | |||
@@ -94,8 +94,6 @@ extern int xfs_bdstrat_cb(struct xfs_buf *); | |||
94 | 94 | ||
95 | extern int xfs_zero_eof(struct vnode *, struct xfs_iocore *, xfs_off_t, | 95 | extern int xfs_zero_eof(struct vnode *, struct xfs_iocore *, xfs_off_t, |
96 | xfs_fsize_t, xfs_fsize_t); | 96 | xfs_fsize_t, xfs_fsize_t); |
97 | extern void xfs_inval_cached_pages(struct vnode *, struct xfs_iocore *, | ||
98 | xfs_off_t, int, int); | ||
99 | extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *, | 97 | extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *, |
100 | const struct iovec *, unsigned int, | 98 | const struct iovec *, unsigned int, |
101 | loff_t *, int, struct cred *); | 99 | loff_t *, int, struct cred *); |
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 53dc658cafa6..f6dd7de25927 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. | 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of version 2 of the GNU General Public License as | 5 | * under the terms of version 2 of the GNU General Public License as |
@@ -66,7 +66,6 @@ | |||
66 | #include "xfs_buf_item.h" | 66 | #include "xfs_buf_item.h" |
67 | #include "xfs_utils.h" | 67 | #include "xfs_utils.h" |
68 | #include "xfs_version.h" | 68 | #include "xfs_version.h" |
69 | #include "xfs_ioctl32.h" | ||
70 | 69 | ||
71 | #include <linux/namei.h> | 70 | #include <linux/namei.h> |
72 | #include <linux/init.h> | 71 | #include <linux/init.h> |
@@ -484,7 +483,7 @@ xfssyncd( | |||
484 | set_current_state(TASK_INTERRUPTIBLE); | 483 | set_current_state(TASK_INTERRUPTIBLE); |
485 | timeleft = schedule_timeout(timeleft); | 484 | timeleft = schedule_timeout(timeleft); |
486 | /* swsusp */ | 485 | /* swsusp */ |
487 | try_to_freeze(PF_FREEZE); | 486 | try_to_freeze(); |
488 | if (vfsp->vfs_flag & VFS_UMOUNT) | 487 | if (vfsp->vfs_flag & VFS_UMOUNT) |
489 | break; | 488 | break; |
490 | 489 | ||
@@ -591,8 +590,10 @@ linvfs_sync_super( | |||
591 | int error; | 590 | int error; |
592 | int flags = SYNC_FSDATA; | 591 | int flags = SYNC_FSDATA; |
593 | 592 | ||
594 | if (wait) | 593 | if (unlikely(sb->s_frozen == SB_FREEZE_WRITE)) |
595 | flags |= SYNC_WAIT; | 594 | flags = SYNC_QUIESCE; |
595 | else | ||
596 | flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0); | ||
596 | 597 | ||
597 | VFS_SYNC(vfsp, flags, NULL, error); | 598 | VFS_SYNC(vfsp, flags, NULL, error); |
598 | sb->s_dirt = 0; | 599 | sb->s_dirt = 0; |
@@ -702,7 +703,8 @@ linvfs_getxquota( | |||
702 | struct vfs *vfsp = LINVFS_GET_VFS(sb); | 703 | struct vfs *vfsp = LINVFS_GET_VFS(sb); |
703 | int error, getmode; | 704 | int error, getmode; |
704 | 705 | ||
705 | getmode = (type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETQUOTA; | 706 | getmode = (type == USRQUOTA) ? Q_XGETQUOTA : |
707 | ((type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETPQUOTA); | ||
706 | VFS_QUOTACTL(vfsp, getmode, id, (caddr_t)fdq, error); | 708 | VFS_QUOTACTL(vfsp, getmode, id, (caddr_t)fdq, error); |
707 | return -error; | 709 | return -error; |
708 | } | 710 | } |
@@ -717,7 +719,8 @@ linvfs_setxquota( | |||
717 | struct vfs *vfsp = LINVFS_GET_VFS(sb); | 719 | struct vfs *vfsp = LINVFS_GET_VFS(sb); |
718 | int error, setmode; | 720 | int error, setmode; |
719 | 721 | ||
720 | setmode = (type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETQLIM; | 722 | setmode = (type == USRQUOTA) ? Q_XSETQLIM : |
723 | ((type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETPQLIM); | ||
721 | VFS_QUOTACTL(vfsp, setmode, id, (caddr_t)fdq, error); | 724 | VFS_QUOTACTL(vfsp, setmode, id, (caddr_t)fdq, error); |
722 | return -error; | 725 | return -error; |
723 | } | 726 | } |
diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h index 76493991578f..7ee1f714e9ba 100644 --- a/fs/xfs/linux-2.6/xfs_vfs.h +++ b/fs/xfs/linux-2.6/xfs_vfs.h | |||
@@ -107,6 +107,7 @@ typedef enum { | |||
107 | #define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */ | 107 | #define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */ |
108 | #define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */ | 108 | #define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */ |
109 | #define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */ | 109 | #define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */ |
110 | #define SYNC_QUIESCE 0x0100 /* quiesce fileystem for a snapshot */ | ||
110 | 111 | ||
111 | typedef int (*vfs_mount_t)(bhv_desc_t *, | 112 | typedef int (*vfs_mount_t)(bhv_desc_t *, |
112 | struct xfs_mount_args *, struct cred *); | 113 | struct xfs_mount_args *, struct cred *); |
diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index a832d165f24f..250cad54e892 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c | |||
@@ -411,13 +411,13 @@ vn_remove( | |||
411 | /* 0 */ (void *)(__psint_t)(vk), \ | 411 | /* 0 */ (void *)(__psint_t)(vk), \ |
412 | /* 1 */ (void *)(s), \ | 412 | /* 1 */ (void *)(s), \ |
413 | /* 2 */ (void *)(__psint_t) line, \ | 413 | /* 2 */ (void *)(__psint_t) line, \ |
414 | /* 3 */ (void *)(vn_count(vp)), \ | 414 | /* 3 */ (void *)(__psint_t)(vn_count(vp)), \ |
415 | /* 4 */ (void *)(ra), \ | 415 | /* 4 */ (void *)(ra), \ |
416 | /* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \ | 416 | /* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \ |
417 | /* 6 */ (void *)(__psint_t)current_cpu(), \ | 417 | /* 6 */ (void *)(__psint_t)current_cpu(), \ |
418 | /* 7 */ (void *)(__psint_t)current_pid(), \ | 418 | /* 7 */ (void *)(__psint_t)current_pid(), \ |
419 | /* 8 */ (void *)__return_address, \ | 419 | /* 8 */ (void *)__return_address, \ |
420 | /* 9 */ 0, 0, 0, 0, 0, 0, 0) | 420 | /* 9 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL) |
421 | 421 | ||
422 | /* | 422 | /* |
423 | * Vnode tracing code. | 423 | * Vnode tracing code. |
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 00466c3194ac..a6e57c647be4 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h | |||
@@ -426,7 +426,7 @@ typedef struct vattr { | |||
426 | u_long va_extsize; /* file extent size */ | 426 | u_long va_extsize; /* file extent size */ |
427 | u_long va_nextents; /* number of extents in file */ | 427 | u_long va_nextents; /* number of extents in file */ |
428 | u_long va_anextents; /* number of attr extents in file */ | 428 | u_long va_anextents; /* number of attr extents in file */ |
429 | int va_projid; /* project id */ | 429 | prid_t va_projid; /* project id */ |
430 | } vattr_t; | 430 | } vattr_t; |
431 | 431 | ||
432 | /* | 432 | /* |
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index 740d20d33187..46ce1e3ce1d6 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c | |||
@@ -101,7 +101,7 @@ int xfs_dqerror_mod = 33; | |||
101 | * is the d_id field. The idea is to fill in the entire q_core | 101 | * is the d_id field. The idea is to fill in the entire q_core |
102 | * when we read in the on disk dquot. | 102 | * when we read in the on disk dquot. |
103 | */ | 103 | */ |
104 | xfs_dquot_t * | 104 | STATIC xfs_dquot_t * |
105 | xfs_qm_dqinit( | 105 | xfs_qm_dqinit( |
106 | xfs_mount_t *mp, | 106 | xfs_mount_t *mp, |
107 | xfs_dqid_t id, | 107 | xfs_dqid_t id, |
@@ -286,7 +286,9 @@ xfs_qm_adjust_dqlimits( | |||
286 | * We also return 0 as the values of the timers in Q_GETQUOTA calls, when | 286 | * We also return 0 as the values of the timers in Q_GETQUOTA calls, when |
287 | * enforcement's off. | 287 | * enforcement's off. |
288 | * In contrast, warnings are a little different in that they don't | 288 | * In contrast, warnings are a little different in that they don't |
289 | * 'automatically' get started when limits get exceeded. | 289 | * 'automatically' get started when limits get exceeded. They do |
290 | * get reset to zero, however, when we find the count to be under | ||
291 | * the soft limit (they are only ever set non-zero via userspace). | ||
290 | */ | 292 | */ |
291 | void | 293 | void |
292 | xfs_qm_adjust_dqtimers( | 294 | xfs_qm_adjust_dqtimers( |
@@ -315,6 +317,8 @@ xfs_qm_adjust_dqtimers( | |||
315 | INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { | 317 | INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { |
316 | INT_SET(d->d_btimer, ARCH_CONVERT, | 318 | INT_SET(d->d_btimer, ARCH_CONVERT, |
317 | get_seconds() + XFS_QI_BTIMELIMIT(mp)); | 319 | get_seconds() + XFS_QI_BTIMELIMIT(mp)); |
320 | } else { | ||
321 | d->d_bwarns = 0; | ||
318 | } | 322 | } |
319 | } else { | 323 | } else { |
320 | if ((!d->d_blk_softlimit || | 324 | if ((!d->d_blk_softlimit || |
@@ -336,6 +340,8 @@ xfs_qm_adjust_dqtimers( | |||
336 | INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { | 340 | INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { |
337 | INT_SET(d->d_itimer, ARCH_CONVERT, | 341 | INT_SET(d->d_itimer, ARCH_CONVERT, |
338 | get_seconds() + XFS_QI_ITIMELIMIT(mp)); | 342 | get_seconds() + XFS_QI_ITIMELIMIT(mp)); |
343 | } else { | ||
344 | d->d_iwarns = 0; | ||
339 | } | 345 | } |
340 | } else { | 346 | } else { |
341 | if ((!d->d_ino_softlimit || | 347 | if ((!d->d_ino_softlimit || |
@@ -357,6 +363,8 @@ xfs_qm_adjust_dqtimers( | |||
357 | INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) { | 363 | INT_GET(d->d_rtb_hardlimit, ARCH_CONVERT)))) { |
358 | INT_SET(d->d_rtbtimer, ARCH_CONVERT, | 364 | INT_SET(d->d_rtbtimer, ARCH_CONVERT, |
359 | get_seconds() + XFS_QI_RTBTIMELIMIT(mp)); | 365 | get_seconds() + XFS_QI_RTBTIMELIMIT(mp)); |
366 | } else { | ||
367 | d->d_rtbwarns = 0; | ||
360 | } | 368 | } |
361 | } else { | 369 | } else { |
362 | if ((!d->d_rtb_softlimit || | 370 | if ((!d->d_rtb_softlimit || |
@@ -371,68 +379,6 @@ xfs_qm_adjust_dqtimers( | |||
371 | } | 379 | } |
372 | 380 | ||
373 | /* | 381 | /* |
374 | * Increment or reset warnings of a given dquot. | ||
375 | */ | ||
376 | int | ||
377 | xfs_qm_dqwarn( | ||
378 | xfs_disk_dquot_t *d, | ||
379 | uint flags) | ||
380 | { | ||
381 | int warned; | ||
382 | |||
383 | /* | ||
384 | * root's limits are not real limits. | ||
385 | */ | ||
386 | if (!d->d_id) | ||
387 | return (0); | ||
388 | |||
389 | warned = 0; | ||
390 | if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) && | ||
391 | (INT_GET(d->d_bcount, ARCH_CONVERT) >= | ||
392 | INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) { | ||
393 | if (flags & XFS_QMOPT_DOWARN) { | ||
394 | INT_MOD(d->d_bwarns, ARCH_CONVERT, +1); | ||
395 | warned++; | ||
396 | } | ||
397 | } else { | ||
398 | if (!d->d_blk_softlimit || | ||
399 | (INT_GET(d->d_bcount, ARCH_CONVERT) < | ||
400 | INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) { | ||
401 | d->d_bwarns = 0; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 && | ||
406 | (INT_GET(d->d_icount, ARCH_CONVERT) >= | ||
407 | INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) { | ||
408 | if (flags & XFS_QMOPT_DOWARN) { | ||
409 | INT_MOD(d->d_iwarns, ARCH_CONVERT, +1); | ||
410 | warned++; | ||
411 | } | ||
412 | } else { | ||
413 | if (!d->d_ino_softlimit || | ||
414 | (INT_GET(d->d_icount, ARCH_CONVERT) < | ||
415 | INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) { | ||
416 | d->d_iwarns = 0; | ||
417 | } | ||
418 | } | ||
419 | #ifdef QUOTADEBUG | ||
420 | if (INT_GET(d->d_iwarns, ARCH_CONVERT)) | ||
421 | cmn_err(CE_DEBUG, | ||
422 | "--------@@Inode warnings running : %Lu >= %Lu", | ||
423 | INT_GET(d->d_icount, ARCH_CONVERT), | ||
424 | INT_GET(d->d_ino_softlimit, ARCH_CONVERT)); | ||
425 | if (INT_GET(d->d_bwarns, ARCH_CONVERT)) | ||
426 | cmn_err(CE_DEBUG, | ||
427 | "--------@@Blks warnings running : %Lu >= %Lu", | ||
428 | INT_GET(d->d_bcount, ARCH_CONVERT), | ||
429 | INT_GET(d->d_blk_softlimit, ARCH_CONVERT)); | ||
430 | #endif | ||
431 | return (warned); | ||
432 | } | ||
433 | |||
434 | |||
435 | /* | ||
436 | * initialize a buffer full of dquots and log the whole thing | 382 | * initialize a buffer full of dquots and log the whole thing |
437 | */ | 383 | */ |
438 | STATIC void | 384 | STATIC void |
@@ -461,9 +407,9 @@ xfs_qm_init_dquot_blk( | |||
461 | for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++) | 407 | for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++) |
462 | xfs_qm_dqinit_core(curid, type, d); | 408 | xfs_qm_dqinit_core(curid, type, d); |
463 | xfs_trans_dquot_buf(tp, bp, | 409 | xfs_trans_dquot_buf(tp, bp, |
464 | type & XFS_DQ_USER ? | 410 | (type & XFS_DQ_USER ? XFS_BLI_UDQUOT_BUF : |
465 | XFS_BLI_UDQUOT_BUF : | 411 | ((type & XFS_DQ_PROJ) ? XFS_BLI_PDQUOT_BUF : |
466 | XFS_BLI_GDQUOT_BUF); | 412 | XFS_BLI_GDQUOT_BUF))); |
467 | xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1); | 413 | xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1); |
468 | } | 414 | } |
469 | 415 | ||
@@ -544,8 +490,7 @@ xfs_qm_dqalloc( | |||
544 | * the entire thing. | 490 | * the entire thing. |
545 | */ | 491 | */ |
546 | xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT), | 492 | xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT), |
547 | dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP), | 493 | dqp->dq_flags & XFS_DQ_ALLTYPES, bp); |
548 | bp); | ||
549 | 494 | ||
550 | if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) { | 495 | if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) { |
551 | goto error1; | 496 | goto error1; |
@@ -675,8 +620,7 @@ xfs_qm_dqtobp( | |||
675 | /* | 620 | /* |
676 | * A simple sanity check in case we got a corrupted dquot... | 621 | * A simple sanity check in case we got a corrupted dquot... |
677 | */ | 622 | */ |
678 | if (xfs_qm_dqcheck(ddq, id, | 623 | if (xfs_qm_dqcheck(ddq, id, dqp->dq_flags & XFS_DQ_ALLTYPES, |
679 | dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP), | ||
680 | flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN), | 624 | flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN), |
681 | "dqtobp")) { | 625 | "dqtobp")) { |
682 | if (!(flags & XFS_QMOPT_DQREPAIR)) { | 626 | if (!(flags & XFS_QMOPT_DQREPAIR)) { |
@@ -953,8 +897,8 @@ int | |||
953 | xfs_qm_dqget( | 897 | xfs_qm_dqget( |
954 | xfs_mount_t *mp, | 898 | xfs_mount_t *mp, |
955 | xfs_inode_t *ip, /* locked inode (optional) */ | 899 | xfs_inode_t *ip, /* locked inode (optional) */ |
956 | xfs_dqid_t id, /* gid or uid, depending on type */ | 900 | xfs_dqid_t id, /* uid/projid/gid depending on type */ |
957 | uint type, /* UDQUOT or GDQUOT */ | 901 | uint type, /* XFS_DQ_USER/XFS_DQ_PROJ/XFS_DQ_GROUP */ |
958 | uint flags, /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */ | 902 | uint flags, /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */ |
959 | xfs_dquot_t **O_dqpp) /* OUT : locked incore dquot */ | 903 | xfs_dquot_t **O_dqpp) /* OUT : locked incore dquot */ |
960 | { | 904 | { |
@@ -965,6 +909,7 @@ xfs_qm_dqget( | |||
965 | 909 | ||
966 | ASSERT(XFS_IS_QUOTA_RUNNING(mp)); | 910 | ASSERT(XFS_IS_QUOTA_RUNNING(mp)); |
967 | if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) || | 911 | if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) || |
912 | (! XFS_IS_PQUOTA_ON(mp) && type == XFS_DQ_PROJ) || | ||
968 | (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) { | 913 | (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) { |
969 | return (ESRCH); | 914 | return (ESRCH); |
970 | } | 915 | } |
@@ -983,7 +928,9 @@ xfs_qm_dqget( | |||
983 | again: | 928 | again: |
984 | 929 | ||
985 | #ifdef DEBUG | 930 | #ifdef DEBUG |
986 | ASSERT(type == XFS_DQ_USER || type == XFS_DQ_GROUP); | 931 | ASSERT(type == XFS_DQ_USER || |
932 | type == XFS_DQ_PROJ || | ||
933 | type == XFS_DQ_GROUP); | ||
987 | if (ip) { | 934 | if (ip) { |
988 | ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); | 935 | ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); |
989 | if (type == XFS_DQ_USER) | 936 | if (type == XFS_DQ_USER) |
@@ -1306,8 +1253,8 @@ xfs_qm_dqflush( | |||
1306 | return (error); | 1253 | return (error); |
1307 | } | 1254 | } |
1308 | 1255 | ||
1309 | if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), 0, XFS_QMOPT_DOWARN, | 1256 | if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), |
1310 | "dqflush (incore copy)")) { | 1257 | 0, XFS_QMOPT_DOWARN, "dqflush (incore copy)")) { |
1311 | xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE); | 1258 | xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE); |
1312 | return XFS_ERROR(EIO); | 1259 | return XFS_ERROR(EIO); |
1313 | } | 1260 | } |
@@ -1459,7 +1406,8 @@ xfs_dqlock2( | |||
1459 | { | 1406 | { |
1460 | if (d1 && d2) { | 1407 | if (d1 && d2) { |
1461 | ASSERT(d1 != d2); | 1408 | ASSERT(d1 != d2); |
1462 | if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > INT_GET(d2->q_core.d_id, ARCH_CONVERT)) { | 1409 | if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > |
1410 | INT_GET(d2->q_core.d_id, ARCH_CONVERT)) { | ||
1463 | xfs_dqlock(d2); | 1411 | xfs_dqlock(d2); |
1464 | xfs_dqlock(d1); | 1412 | xfs_dqlock(d1); |
1465 | } else { | 1413 | } else { |
@@ -1582,8 +1530,7 @@ xfs_qm_dqprint(xfs_dquot_t *dqp) | |||
1582 | cmn_err(CE_DEBUG, "-----------KERNEL DQUOT----------------"); | 1530 | cmn_err(CE_DEBUG, "-----------KERNEL DQUOT----------------"); |
1583 | cmn_err(CE_DEBUG, "---- dquotID = %d", | 1531 | cmn_err(CE_DEBUG, "---- dquotID = %d", |
1584 | (int)INT_GET(dqp->q_core.d_id, ARCH_CONVERT)); | 1532 | (int)INT_GET(dqp->q_core.d_id, ARCH_CONVERT)); |
1585 | cmn_err(CE_DEBUG, "---- type = %s", | 1533 | cmn_err(CE_DEBUG, "---- type = %s", DQFLAGTO_TYPESTR(dqp)); |
1586 | XFS_QM_ISUDQ(dqp) ? "USR" : "GRP"); | ||
1587 | cmn_err(CE_DEBUG, "---- fs = 0x%p", dqp->q_mount); | 1534 | cmn_err(CE_DEBUG, "---- fs = 0x%p", dqp->q_mount); |
1588 | cmn_err(CE_DEBUG, "---- blkno = 0x%x", (int) dqp->q_blkno); | 1535 | cmn_err(CE_DEBUG, "---- blkno = 0x%x", (int) dqp->q_blkno); |
1589 | cmn_err(CE_DEBUG, "---- boffset = 0x%x", (int) dqp->q_bufoffset); | 1536 | cmn_err(CE_DEBUG, "---- boffset = 0x%x", (int) dqp->q_bufoffset); |
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h index 0c3fe3175baa..39175103c8e0 100644 --- a/fs/xfs/quota/xfs_dquot.h +++ b/fs/xfs/quota/xfs_dquot.h | |||
@@ -114,25 +114,18 @@ typedef struct xfs_dquot { | |||
114 | #define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++) | 114 | #define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++) |
115 | 115 | ||
116 | /* | 116 | /* |
117 | * Quota Accounting flags | 117 | * Quota Accounting/Enforcement flags |
118 | */ | 118 | */ |
119 | #define XFS_ALL_QUOTA_ACCT (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT) | 119 | #define XFS_ALL_QUOTA_ACCT \ |
120 | #define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD) | 120 | (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT) |
121 | #define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD) | 121 | #define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD) |
122 | #define XFS_ALL_QUOTA_ACTV (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE) | 122 | #define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD) |
123 | #define XFS_ALL_QUOTA_ACCT_ENFD (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ | ||
124 | XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD) | ||
125 | 123 | ||
126 | #define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT) | 124 | #define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT) |
127 | #define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT) | ||
128 | #define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT) | ||
129 | |||
130 | /* | ||
131 | * Quota Limit Enforcement flags | ||
132 | */ | ||
133 | #define XFS_IS_QUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD) | 125 | #define XFS_IS_QUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD) |
134 | #define XFS_IS_UQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_UQUOTA_ENFD) | 126 | #define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT) |
135 | #define XFS_IS_GQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_GQUOTA_ENFD) | 127 | #define XFS_IS_PQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_PQUOTA_ACCT) |
128 | #define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT) | ||
136 | 129 | ||
137 | #ifdef DEBUG | 130 | #ifdef DEBUG |
138 | static inline int | 131 | static inline int |
@@ -167,6 +160,8 @@ XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp) | |||
167 | #define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp)) | 160 | #define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp)) |
168 | #define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) | 161 | #define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) |
169 | #define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER) | 162 | #define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER) |
163 | #define XFS_QM_ISPDQ(dqp) ((dqp)->dq_flags & XFS_DQ_PROJ) | ||
164 | #define XFS_QM_ISGDQ(dqp) ((dqp)->dq_flags & XFS_DQ_GROUP) | ||
170 | #define XFS_DQ_TO_QINF(dqp) ((dqp)->q_mount->m_quotainfo) | 165 | #define XFS_DQ_TO_QINF(dqp) ((dqp)->q_mount->m_quotainfo) |
171 | #define XFS_DQ_TO_QIP(dqp) (XFS_QM_ISUDQ(dqp) ? \ | 166 | #define XFS_DQ_TO_QIP(dqp) (XFS_QM_ISUDQ(dqp) ? \ |
172 | XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \ | 167 | XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \ |
@@ -174,7 +169,7 @@ XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp) | |||
174 | 169 | ||
175 | #define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \ | 170 | #define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \ |
176 | (XFS_IS_UQUOTA_ON((d)->q_mount)) : \ | 171 | (XFS_IS_UQUOTA_ON((d)->q_mount)) : \ |
177 | (XFS_IS_GQUOTA_ON((d)->q_mount)))) | 172 | (XFS_IS_OQUOTA_ON((d)->q_mount)))) |
178 | 173 | ||
179 | #ifdef XFS_DQUOT_TRACE | 174 | #ifdef XFS_DQUOT_TRACE |
180 | /* | 175 | /* |
@@ -211,7 +206,6 @@ extern void xfs_qm_adjust_dqtimers(xfs_mount_t *, | |||
211 | xfs_disk_dquot_t *); | 206 | xfs_disk_dquot_t *); |
212 | extern void xfs_qm_adjust_dqlimits(xfs_mount_t *, | 207 | extern void xfs_qm_adjust_dqlimits(xfs_mount_t *, |
213 | xfs_disk_dquot_t *); | 208 | xfs_disk_dquot_t *); |
214 | extern int xfs_qm_dqwarn(xfs_disk_dquot_t *, uint); | ||
215 | extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *, | 209 | extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *, |
216 | xfs_dqid_t, uint, uint, xfs_dquot_t **); | 210 | xfs_dqid_t, uint, uint, xfs_dquot_t **); |
217 | extern void xfs_qm_dqput(xfs_dquot_t *); | 211 | extern void xfs_qm_dqput(xfs_dquot_t *); |
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index a5425ee6e7bd..f5271b7b1e84 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c | |||
@@ -428,7 +428,7 @@ xfs_qm_dquot_logitem_committing( | |||
428 | /* | 428 | /* |
429 | * This is the ops vector for dquots | 429 | * This is the ops vector for dquots |
430 | */ | 430 | */ |
431 | struct xfs_item_ops xfs_dquot_item_ops = { | 431 | STATIC struct xfs_item_ops xfs_dquot_item_ops = { |
432 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size, | 432 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size, |
433 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) | 433 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) |
434 | xfs_qm_dquot_logitem_format, | 434 | xfs_qm_dquot_logitem_format, |
@@ -646,7 +646,7 @@ xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn) | |||
646 | return; | 646 | return; |
647 | } | 647 | } |
648 | 648 | ||
649 | struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { | 649 | STATIC struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { |
650 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, | 650 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, |
651 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) | 651 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) |
652 | xfs_qm_qoff_logitem_format, | 652 | xfs_qm_qoff_logitem_format, |
@@ -669,7 +669,7 @@ struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { | |||
669 | /* | 669 | /* |
670 | * This is the ops vector shared by all quotaoff-start log items. | 670 | * This is the ops vector shared by all quotaoff-start log items. |
671 | */ | 671 | */ |
672 | struct xfs_item_ops xfs_qm_qoff_logitem_ops = { | 672 | STATIC struct xfs_item_ops xfs_qm_qoff_logitem_ops = { |
673 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, | 673 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, |
674 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) | 674 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) |
675 | xfs_qm_qoff_logitem_format, | 675 | xfs_qm_qoff_logitem_format, |
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 89f2cd656ebf..f665ca8f9e96 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c | |||
@@ -81,12 +81,18 @@ struct xfs_qm *xfs_Gqm; | |||
81 | 81 | ||
82 | kmem_zone_t *qm_dqzone; | 82 | kmem_zone_t *qm_dqzone; |
83 | kmem_zone_t *qm_dqtrxzone; | 83 | kmem_zone_t *qm_dqtrxzone; |
84 | kmem_shaker_t xfs_qm_shaker; | 84 | STATIC kmem_shaker_t xfs_qm_shaker; |
85 | 85 | ||
86 | STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int); | 86 | STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int); |
87 | STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); | 87 | STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); |
88 | 88 | ||
89 | STATIC void xfs_qm_freelist_init(xfs_frlist_t *); | ||
90 | STATIC void xfs_qm_freelist_destroy(xfs_frlist_t *); | ||
91 | STATIC int xfs_qm_mplist_nowait(xfs_mount_t *); | ||
92 | STATIC int xfs_qm_dqhashlock_nowait(xfs_dquot_t *); | ||
93 | |||
89 | STATIC int xfs_qm_init_quotainos(xfs_mount_t *); | 94 | STATIC int xfs_qm_init_quotainos(xfs_mount_t *); |
95 | STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); | ||
90 | STATIC int xfs_qm_shake(int, unsigned int); | 96 | STATIC int xfs_qm_shake(int, unsigned int); |
91 | 97 | ||
92 | #ifdef DEBUG | 98 | #ifdef DEBUG |
@@ -184,7 +190,7 @@ xfs_Gqm_init(void) | |||
184 | /* | 190 | /* |
185 | * Destroy the global quota manager when its reference count goes to zero. | 191 | * Destroy the global quota manager when its reference count goes to zero. |
186 | */ | 192 | */ |
187 | void | 193 | STATIC void |
188 | xfs_qm_destroy( | 194 | xfs_qm_destroy( |
189 | struct xfs_qm *xqm) | 195 | struct xfs_qm *xqm) |
190 | { | 196 | { |
@@ -304,9 +310,9 @@ xfs_qm_mount_quotainit( | |||
304 | uint flags) | 310 | uint flags) |
305 | { | 311 | { |
306 | /* | 312 | /* |
307 | * User or group quotas has to be on. | 313 | * User, projects or group quotas has to be on. |
308 | */ | 314 | */ |
309 | ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA)); | 315 | ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_PQUOTA | XFSMNT_GQUOTA)); |
310 | 316 | ||
311 | /* | 317 | /* |
312 | * Initialize the flags in the mount structure. From this point | 318 | * Initialize the flags in the mount structure. From this point |
@@ -324,7 +330,11 @@ xfs_qm_mount_quotainit( | |||
324 | if (flags & XFSMNT_GQUOTA) { | 330 | if (flags & XFSMNT_GQUOTA) { |
325 | mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); | 331 | mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); |
326 | if (flags & XFSMNT_GQUOTAENF) | 332 | if (flags & XFSMNT_GQUOTAENF) |
327 | mp->m_qflags |= XFS_GQUOTA_ENFD; | 333 | mp->m_qflags |= XFS_OQUOTA_ENFD; |
334 | } else if (flags & XFSMNT_PQUOTA) { | ||
335 | mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); | ||
336 | if (flags & XFSMNT_PQUOTAENF) | ||
337 | mp->m_qflags |= XFS_OQUOTA_ENFD; | ||
328 | } | 338 | } |
329 | } | 339 | } |
330 | 340 | ||
@@ -357,11 +367,11 @@ xfs_qm_mount_quotas( | |||
357 | 367 | ||
358 | /* | 368 | /* |
359 | * If a file system had quotas running earlier, but decided to | 369 | * If a file system had quotas running earlier, but decided to |
360 | * mount without -o quota/uquota/gquota options, revoke the | 370 | * mount without -o uquota/pquota/gquota options, revoke the |
361 | * quotachecked license, and bail out. | 371 | * quotachecked license, and bail out. |
362 | */ | 372 | */ |
363 | if (! XFS_IS_QUOTA_ON(mp) && | 373 | if (! XFS_IS_QUOTA_ON(mp) && |
364 | (mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) { | 374 | (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT)) { |
365 | mp->m_qflags = 0; | 375 | mp->m_qflags = 0; |
366 | goto write_changes; | 376 | goto write_changes; |
367 | } | 377 | } |
@@ -509,7 +519,7 @@ out: | |||
509 | * Flush all dquots of the given file system to disk. The dquots are | 519 | * Flush all dquots of the given file system to disk. The dquots are |
510 | * _not_ purged from memory here, just their data written to disk. | 520 | * _not_ purged from memory here, just their data written to disk. |
511 | */ | 521 | */ |
512 | int | 522 | STATIC int |
513 | xfs_qm_dqflush_all( | 523 | xfs_qm_dqflush_all( |
514 | xfs_mount_t *mp, | 524 | xfs_mount_t *mp, |
515 | int flags) | 525 | int flags) |
@@ -613,7 +623,7 @@ xfs_qm_detach_gdquots( | |||
613 | STATIC int | 623 | STATIC int |
614 | xfs_qm_dqpurge_int( | 624 | xfs_qm_dqpurge_int( |
615 | xfs_mount_t *mp, | 625 | xfs_mount_t *mp, |
616 | uint flags) /* QUOTAOFF/UMOUNTING/UQUOTA/GQUOTA */ | 626 | uint flags) /* QUOTAOFF/UMOUNTING/UQUOTA/PQUOTA/GQUOTA */ |
617 | { | 627 | { |
618 | xfs_dquot_t *dqp; | 628 | xfs_dquot_t *dqp; |
619 | uint dqtype; | 629 | uint dqtype; |
@@ -625,6 +635,7 @@ xfs_qm_dqpurge_int( | |||
625 | return (0); | 635 | return (0); |
626 | 636 | ||
627 | dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0; | 637 | dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0; |
638 | dqtype |= (flags & XFS_QMOPT_PQUOTA) ? XFS_DQ_PROJ : 0; | ||
628 | dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0; | 639 | dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0; |
629 | 640 | ||
630 | xfs_qm_mplist_lock(mp); | 641 | xfs_qm_mplist_lock(mp); |
@@ -734,11 +745,11 @@ xfs_qm_dqattach_one( | |||
734 | 745 | ||
735 | /* | 746 | /* |
736 | * udqhint is the i_udquot field in inode, and is non-NULL only | 747 | * udqhint is the i_udquot field in inode, and is non-NULL only |
737 | * when the type arg is XFS_DQ_GROUP. Its purpose is to save a | 748 | * when the type arg is group/project. Its purpose is to save a |
738 | * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside | 749 | * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside |
739 | * the user dquot. | 750 | * the user dquot. |
740 | */ | 751 | */ |
741 | ASSERT(!udqhint || type == XFS_DQ_GROUP); | 752 | ASSERT(!udqhint || type == XFS_DQ_GROUP || type == XFS_DQ_PROJ); |
742 | if (udqhint && !dolock) | 753 | if (udqhint && !dolock) |
743 | xfs_dqlock(udqhint); | 754 | xfs_dqlock(udqhint); |
744 | 755 | ||
@@ -897,8 +908,8 @@ xfs_qm_dqattach_grouphint( | |||
897 | 908 | ||
898 | 909 | ||
899 | /* | 910 | /* |
900 | * Given a locked inode, attach dquot(s) to it, taking UQUOTAON / GQUOTAON | 911 | * Given a locked inode, attach dquot(s) to it, taking U/G/P-QUOTAON |
901 | * in to account. | 912 | * into account. |
902 | * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed. | 913 | * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed. |
903 | * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty | 914 | * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty |
904 | * much made this code a complete mess, but it has been pretty useful. | 915 | * much made this code a complete mess, but it has been pretty useful. |
@@ -937,8 +948,13 @@ xfs_qm_dqattach( | |||
937 | nquotas++; | 948 | nquotas++; |
938 | } | 949 | } |
939 | ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); | 950 | ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); |
940 | if (XFS_IS_GQUOTA_ON(mp)) { | 951 | if (XFS_IS_OQUOTA_ON(mp)) { |
941 | error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP, | 952 | error = XFS_IS_GQUOTA_ON(mp) ? |
953 | xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP, | ||
954 | flags & XFS_QMOPT_DQALLOC, | ||
955 | flags & XFS_QMOPT_DQLOCK, | ||
956 | ip->i_udquot, &ip->i_gdquot) : | ||
957 | xfs_qm_dqattach_one(ip, ip->i_d.di_projid, XFS_DQ_PROJ, | ||
942 | flags & XFS_QMOPT_DQALLOC, | 958 | flags & XFS_QMOPT_DQALLOC, |
943 | flags & XFS_QMOPT_DQLOCK, | 959 | flags & XFS_QMOPT_DQLOCK, |
944 | ip->i_udquot, &ip->i_gdquot); | 960 | ip->i_udquot, &ip->i_gdquot); |
@@ -989,7 +1005,7 @@ xfs_qm_dqattach( | |||
989 | } | 1005 | } |
990 | if (XFS_IS_UQUOTA_ON(mp)) | 1006 | if (XFS_IS_UQUOTA_ON(mp)) |
991 | ASSERT(ip->i_udquot); | 1007 | ASSERT(ip->i_udquot); |
992 | if (XFS_IS_GQUOTA_ON(mp)) | 1008 | if (XFS_IS_OQUOTA_ON(mp)) |
993 | ASSERT(ip->i_gdquot); | 1009 | ASSERT(ip->i_gdquot); |
994 | } | 1010 | } |
995 | #endif | 1011 | #endif |
@@ -1018,13 +1034,13 @@ xfs_qm_dqdetach( | |||
1018 | 1034 | ||
1019 | ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino); | 1035 | ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino); |
1020 | ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino); | 1036 | ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino); |
1021 | if (ip->i_udquot) | ||
1022 | xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip); | ||
1023 | if (ip->i_udquot) { | 1037 | if (ip->i_udquot) { |
1038 | xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip); | ||
1024 | xfs_qm_dqrele(ip->i_udquot); | 1039 | xfs_qm_dqrele(ip->i_udquot); |
1025 | ip->i_udquot = NULL; | 1040 | ip->i_udquot = NULL; |
1026 | } | 1041 | } |
1027 | if (ip->i_gdquot) { | 1042 | if (ip->i_gdquot) { |
1043 | xfs_dqtrace_entry_ino(ip->i_gdquot, "DQDETTACH", ip); | ||
1028 | xfs_qm_dqrele(ip->i_gdquot); | 1044 | xfs_qm_dqrele(ip->i_gdquot); |
1029 | ip->i_gdquot = NULL; | 1045 | ip->i_gdquot = NULL; |
1030 | } | 1046 | } |
@@ -1149,7 +1165,7 @@ xfs_qm_sync( | |||
1149 | * This initializes all the quota information that's kept in the | 1165 | * This initializes all the quota information that's kept in the |
1150 | * mount structure | 1166 | * mount structure |
1151 | */ | 1167 | */ |
1152 | int | 1168 | STATIC int |
1153 | xfs_qm_init_quotainfo( | 1169 | xfs_qm_init_quotainfo( |
1154 | xfs_mount_t *mp) | 1170 | xfs_mount_t *mp) |
1155 | { | 1171 | { |
@@ -1202,8 +1218,9 @@ xfs_qm_init_quotainfo( | |||
1202 | * and group quotas, at least not at this point. | 1218 | * and group quotas, at least not at this point. |
1203 | */ | 1219 | */ |
1204 | error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0, | 1220 | error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0, |
1205 | (XFS_IS_UQUOTA_RUNNING(mp)) ? | 1221 | XFS_IS_UQUOTA_RUNNING(mp) ? XFS_DQ_USER : |
1206 | XFS_DQ_USER : XFS_DQ_GROUP, | 1222 | (XFS_IS_GQUOTA_RUNNING(mp) ? XFS_DQ_GROUP : |
1223 | XFS_DQ_PROJ), | ||
1207 | XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN, | 1224 | XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN, |
1208 | &dqp); | 1225 | &dqp); |
1209 | if (! error) { | 1226 | if (! error) { |
@@ -1234,6 +1251,10 @@ xfs_qm_init_quotainfo( | |||
1234 | INT_GET(ddqp->d_iwarns, ARCH_CONVERT) ? | 1251 | INT_GET(ddqp->d_iwarns, ARCH_CONVERT) ? |
1235 | INT_GET(ddqp->d_iwarns, ARCH_CONVERT) : | 1252 | INT_GET(ddqp->d_iwarns, ARCH_CONVERT) : |
1236 | XFS_QM_IWARNLIMIT; | 1253 | XFS_QM_IWARNLIMIT; |
1254 | qinf->qi_rtbwarnlimit = | ||
1255 | INT_GET(ddqp->d_rtbwarns, ARCH_CONVERT) ? | ||
1256 | INT_GET(ddqp->d_rtbwarns, ARCH_CONVERT) : | ||
1257 | XFS_QM_RTBWARNLIMIT; | ||
1237 | qinf->qi_bhardlimit = | 1258 | qinf->qi_bhardlimit = |
1238 | INT_GET(ddqp->d_blk_hardlimit, ARCH_CONVERT); | 1259 | INT_GET(ddqp->d_blk_hardlimit, ARCH_CONVERT); |
1239 | qinf->qi_bsoftlimit = | 1260 | qinf->qi_bsoftlimit = |
@@ -1259,6 +1280,7 @@ xfs_qm_init_quotainfo( | |||
1259 | qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT; | 1280 | qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT; |
1260 | qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT; | 1281 | qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT; |
1261 | qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT; | 1282 | qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT; |
1283 | qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT; | ||
1262 | } | 1284 | } |
1263 | 1285 | ||
1264 | return (0); | 1286 | return (0); |
@@ -1366,13 +1388,20 @@ xfs_qm_dqget_noattach( | |||
1366 | ASSERT(udqp); | 1388 | ASSERT(udqp); |
1367 | } | 1389 | } |
1368 | 1390 | ||
1369 | if (XFS_IS_GQUOTA_ON(mp)) { | 1391 | if (XFS_IS_OQUOTA_ON(mp)) { |
1370 | ASSERT(ip->i_gdquot == NULL); | 1392 | ASSERT(ip->i_gdquot == NULL); |
1371 | if (udqp) | 1393 | if (udqp) |
1372 | xfs_dqunlock(udqp); | 1394 | xfs_dqunlock(udqp); |
1373 | if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_gid, XFS_DQ_GROUP, | 1395 | error = XFS_IS_GQUOTA_ON(mp) ? |
1374 | XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN, | 1396 | xfs_qm_dqget(mp, ip, |
1375 | &gdqp))) { | 1397 | ip->i_d.di_gid, XFS_DQ_GROUP, |
1398 | XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN, | ||
1399 | &gdqp) : | ||
1400 | xfs_qm_dqget(mp, ip, | ||
1401 | ip->i_d.di_projid, XFS_DQ_PROJ, | ||
1402 | XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN, | ||
1403 | &gdqp); | ||
1404 | if (error) { | ||
1376 | if (udqp) | 1405 | if (udqp) |
1377 | xfs_qm_dqrele(udqp); | 1406 | xfs_qm_dqrele(udqp); |
1378 | ASSERT(error != ESRCH); | 1407 | ASSERT(error != ESRCH); |
@@ -1521,8 +1550,10 @@ xfs_qm_reset_dqcounts( | |||
1521 | INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL); | 1550 | INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL); |
1522 | INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0); | 1551 | INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0); |
1523 | INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0); | 1552 | INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0); |
1553 | INT_SET(ddq->d_rtbtimer, ARCH_CONVERT, (time_t)0); | ||
1524 | INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL); | 1554 | INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL); |
1525 | INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL); | 1555 | INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL); |
1556 | INT_SET(ddq->d_rtbwarns, ARCH_CONVERT, 0UL); | ||
1526 | ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1); | 1557 | ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1); |
1527 | } | 1558 | } |
1528 | 1559 | ||
@@ -1541,11 +1572,14 @@ xfs_qm_dqiter_bufs( | |||
1541 | int error; | 1572 | int error; |
1542 | int notcommitted; | 1573 | int notcommitted; |
1543 | int incr; | 1574 | int incr; |
1575 | int type; | ||
1544 | 1576 | ||
1545 | ASSERT(blkcnt > 0); | 1577 | ASSERT(blkcnt > 0); |
1546 | notcommitted = 0; | 1578 | notcommitted = 0; |
1547 | incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ? | 1579 | incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ? |
1548 | XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt; | 1580 | XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt; |
1581 | type = flags & XFS_QMOPT_UQUOTA ? XFS_DQ_USER : | ||
1582 | (flags & XFS_QMOPT_PQUOTA ? XFS_DQ_PROJ : XFS_DQ_GROUP); | ||
1549 | error = 0; | 1583 | error = 0; |
1550 | 1584 | ||
1551 | /* | 1585 | /* |
@@ -1564,9 +1598,7 @@ xfs_qm_dqiter_bufs( | |||
1564 | if (error) | 1598 | if (error) |
1565 | break; | 1599 | break; |
1566 | 1600 | ||
1567 | (void) xfs_qm_reset_dqcounts(mp, bp, firstid, | 1601 | (void) xfs_qm_reset_dqcounts(mp, bp, firstid, type); |
1568 | flags & XFS_QMOPT_UQUOTA ? | ||
1569 | XFS_DQ_USER : XFS_DQ_GROUP); | ||
1570 | xfs_bdwrite(mp, bp); | 1602 | xfs_bdwrite(mp, bp); |
1571 | /* | 1603 | /* |
1572 | * goto the next block. | 1604 | * goto the next block. |
@@ -1578,7 +1610,7 @@ xfs_qm_dqiter_bufs( | |||
1578 | } | 1610 | } |
1579 | 1611 | ||
1580 | /* | 1612 | /* |
1581 | * Iterate over all allocated USR/GRP dquots in the system, calling a | 1613 | * Iterate over all allocated USR/GRP/PRJ dquots in the system, calling a |
1582 | * caller supplied function for every chunk of dquots that we find. | 1614 | * caller supplied function for every chunk of dquots that we find. |
1583 | */ | 1615 | */ |
1584 | STATIC int | 1616 | STATIC int |
@@ -1849,7 +1881,7 @@ xfs_qm_dqusage_adjust( | |||
1849 | xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks); | 1881 | xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks); |
1850 | xfs_qm_dqput(udqp); | 1882 | xfs_qm_dqput(udqp); |
1851 | } | 1883 | } |
1852 | if (XFS_IS_GQUOTA_ON(mp)) { | 1884 | if (XFS_IS_OQUOTA_ON(mp)) { |
1853 | ASSERT(gdqp); | 1885 | ASSERT(gdqp); |
1854 | xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks); | 1886 | xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks); |
1855 | xfs_qm_dqput(gdqp); | 1887 | xfs_qm_dqput(gdqp); |
@@ -1898,7 +1930,7 @@ xfs_qm_quotacheck( | |||
1898 | cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname); | 1930 | cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname); |
1899 | 1931 | ||
1900 | /* | 1932 | /* |
1901 | * First we go thru all the dquots on disk, USR and GRP, and reset | 1933 | * First we go thru all the dquots on disk, USR and GRP/PRJ, and reset |
1902 | * their counters to zero. We need a clean slate. | 1934 | * their counters to zero. We need a clean slate. |
1903 | * We don't log our changes till later. | 1935 | * We don't log our changes till later. |
1904 | */ | 1936 | */ |
@@ -1909,9 +1941,10 @@ xfs_qm_quotacheck( | |||
1909 | } | 1941 | } |
1910 | 1942 | ||
1911 | if ((gip = XFS_QI_GQIP(mp))) { | 1943 | if ((gip = XFS_QI_GQIP(mp))) { |
1912 | if ((error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA))) | 1944 | if ((error = xfs_qm_dqiterate(mp, gip, XFS_IS_GQUOTA_ON(mp) ? |
1945 | XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA))) | ||
1913 | goto error_return; | 1946 | goto error_return; |
1914 | flags |= XFS_GQUOTA_CHKD; | 1947 | flags |= XFS_OQUOTA_CHKD; |
1915 | } | 1948 | } |
1916 | 1949 | ||
1917 | do { | 1950 | do { |
@@ -1938,7 +1971,7 @@ xfs_qm_quotacheck( | |||
1938 | if (error) { | 1971 | if (error) { |
1939 | xfs_qm_dqpurge_all(mp, | 1972 | xfs_qm_dqpurge_all(mp, |
1940 | XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA| | 1973 | XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA| |
1941 | XFS_QMOPT_QUOTAOFF); | 1974 | XFS_QMOPT_PQUOTA|XFS_QMOPT_QUOTAOFF); |
1942 | goto error_return; | 1975 | goto error_return; |
1943 | } | 1976 | } |
1944 | /* | 1977 | /* |
@@ -1961,7 +1994,7 @@ xfs_qm_quotacheck( | |||
1961 | * quotachecked status, since we won't be doing accounting for | 1994 | * quotachecked status, since we won't be doing accounting for |
1962 | * that type anymore. | 1995 | * that type anymore. |
1963 | */ | 1996 | */ |
1964 | mp->m_qflags &= ~(XFS_GQUOTA_CHKD | XFS_UQUOTA_CHKD); | 1997 | mp->m_qflags &= ~(XFS_OQUOTA_CHKD | XFS_UQUOTA_CHKD); |
1965 | mp->m_qflags |= flags; | 1998 | mp->m_qflags |= flags; |
1966 | 1999 | ||
1967 | XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++"); | 2000 | XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++"); |
@@ -2013,7 +2046,7 @@ xfs_qm_init_quotainos( | |||
2013 | 0, 0, &uip, 0))) | 2046 | 0, 0, &uip, 0))) |
2014 | return XFS_ERROR(error); | 2047 | return XFS_ERROR(error); |
2015 | } | 2048 | } |
2016 | if (XFS_IS_GQUOTA_ON(mp) && | 2049 | if (XFS_IS_OQUOTA_ON(mp) && |
2017 | mp->m_sb.sb_gquotino != NULLFSINO) { | 2050 | mp->m_sb.sb_gquotino != NULLFSINO) { |
2018 | ASSERT(mp->m_sb.sb_gquotino > 0); | 2051 | ASSERT(mp->m_sb.sb_gquotino > 0); |
2019 | if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, | 2052 | if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, |
@@ -2043,10 +2076,12 @@ xfs_qm_init_quotainos( | |||
2043 | 2076 | ||
2044 | flags &= ~XFS_QMOPT_SBVERSION; | 2077 | flags &= ~XFS_QMOPT_SBVERSION; |
2045 | } | 2078 | } |
2046 | if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) { | 2079 | if (XFS_IS_OQUOTA_ON(mp) && gip == NULL) { |
2047 | if ((error = xfs_qm_qino_alloc(mp, &gip, | 2080 | flags |= (XFS_IS_GQUOTA_ON(mp) ? |
2048 | sbflags | XFS_SB_GQUOTINO, | 2081 | XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA); |
2049 | flags | XFS_QMOPT_GQUOTA))) { | 2082 | error = xfs_qm_qino_alloc(mp, &gip, |
2083 | sbflags | XFS_SB_GQUOTINO, flags); | ||
2084 | if (error) { | ||
2050 | if (uip) | 2085 | if (uip) |
2051 | VN_RELE(XFS_ITOV(uip)); | 2086 | VN_RELE(XFS_ITOV(uip)); |
2052 | 2087 | ||
@@ -2452,6 +2487,7 @@ xfs_qm_vop_dqalloc( | |||
2452 | xfs_inode_t *ip, | 2487 | xfs_inode_t *ip, |
2453 | uid_t uid, | 2488 | uid_t uid, |
2454 | gid_t gid, | 2489 | gid_t gid, |
2490 | prid_t prid, | ||
2455 | uint flags, | 2491 | uint flags, |
2456 | xfs_dquot_t **O_udqpp, | 2492 | xfs_dquot_t **O_udqpp, |
2457 | xfs_dquot_t **O_gdqpp) | 2493 | xfs_dquot_t **O_gdqpp) |
@@ -2483,8 +2519,7 @@ xfs_qm_vop_dqalloc( | |||
2483 | } | 2519 | } |
2484 | 2520 | ||
2485 | uq = gq = NULL; | 2521 | uq = gq = NULL; |
2486 | if ((flags & XFS_QMOPT_UQUOTA) && | 2522 | if ((flags & XFS_QMOPT_UQUOTA) && XFS_IS_UQUOTA_ON(mp)) { |
2487 | XFS_IS_UQUOTA_ON(mp)) { | ||
2488 | if (ip->i_d.di_uid != uid) { | 2523 | if (ip->i_d.di_uid != uid) { |
2489 | /* | 2524 | /* |
2490 | * What we need is the dquot that has this uid, and | 2525 | * What we need is the dquot that has this uid, and |
@@ -2522,8 +2557,7 @@ xfs_qm_vop_dqalloc( | |||
2522 | xfs_dqunlock(uq); | 2557 | xfs_dqunlock(uq); |
2523 | } | 2558 | } |
2524 | } | 2559 | } |
2525 | if ((flags & XFS_QMOPT_GQUOTA) && | 2560 | if ((flags & XFS_QMOPT_GQUOTA) && XFS_IS_GQUOTA_ON(mp)) { |
2526 | XFS_IS_GQUOTA_ON(mp)) { | ||
2527 | if (ip->i_d.di_gid != gid) { | 2561 | if (ip->i_d.di_gid != gid) { |
2528 | xfs_iunlock(ip, lockflags); | 2562 | xfs_iunlock(ip, lockflags); |
2529 | if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid, | 2563 | if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid, |
@@ -2546,6 +2580,29 @@ xfs_qm_vop_dqalloc( | |||
2546 | XFS_DQHOLD(gq); | 2580 | XFS_DQHOLD(gq); |
2547 | xfs_dqunlock(gq); | 2581 | xfs_dqunlock(gq); |
2548 | } | 2582 | } |
2583 | } else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) { | ||
2584 | if (ip->i_d.di_projid != prid) { | ||
2585 | xfs_iunlock(ip, lockflags); | ||
2586 | if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid, | ||
2587 | XFS_DQ_PROJ, | ||
2588 | XFS_QMOPT_DQALLOC | | ||
2589 | XFS_QMOPT_DOWARN, | ||
2590 | &gq))) { | ||
2591 | if (uq) | ||
2592 | xfs_qm_dqrele(uq); | ||
2593 | ASSERT(error != ENOENT); | ||
2594 | return (error); | ||
2595 | } | ||
2596 | xfs_dqunlock(gq); | ||
2597 | lockflags = XFS_ILOCK_SHARED; | ||
2598 | xfs_ilock(ip, lockflags); | ||
2599 | } else { | ||
2600 | ASSERT(ip->i_gdquot); | ||
2601 | gq = ip->i_gdquot; | ||
2602 | xfs_dqlock(gq); | ||
2603 | XFS_DQHOLD(gq); | ||
2604 | xfs_dqunlock(gq); | ||
2605 | } | ||
2549 | } | 2606 | } |
2550 | if (uq) | 2607 | if (uq) |
2551 | xfs_dqtrace_entry_ino(uq, "DQALLOC", ip); | 2608 | xfs_dqtrace_entry_ino(uq, "DQALLOC", ip); |
@@ -2574,6 +2631,9 @@ xfs_qm_vop_chown( | |||
2574 | xfs_dquot_t *newdq) | 2631 | xfs_dquot_t *newdq) |
2575 | { | 2632 | { |
2576 | xfs_dquot_t *prevdq; | 2633 | xfs_dquot_t *prevdq; |
2634 | uint bfield = XFS_IS_REALTIME_INODE(ip) ? | ||
2635 | XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT; | ||
2636 | |||
2577 | ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); | 2637 | ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); |
2578 | ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount)); | 2638 | ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount)); |
2579 | 2639 | ||
@@ -2582,20 +2642,12 @@ xfs_qm_vop_chown( | |||
2582 | ASSERT(prevdq); | 2642 | ASSERT(prevdq); |
2583 | ASSERT(prevdq != newdq); | 2643 | ASSERT(prevdq != newdq); |
2584 | 2644 | ||
2585 | xfs_trans_mod_dquot(tp, prevdq, | 2645 | xfs_trans_mod_dquot(tp, prevdq, bfield, -(ip->i_d.di_nblocks)); |
2586 | XFS_TRANS_DQ_BCOUNT, | 2646 | xfs_trans_mod_dquot(tp, prevdq, XFS_TRANS_DQ_ICOUNT, -1); |
2587 | -(ip->i_d.di_nblocks)); | ||
2588 | xfs_trans_mod_dquot(tp, prevdq, | ||
2589 | XFS_TRANS_DQ_ICOUNT, | ||
2590 | -1); | ||
2591 | 2647 | ||
2592 | /* the sparkling new dquot */ | 2648 | /* the sparkling new dquot */ |
2593 | xfs_trans_mod_dquot(tp, newdq, | 2649 | xfs_trans_mod_dquot(tp, newdq, bfield, ip->i_d.di_nblocks); |
2594 | XFS_TRANS_DQ_BCOUNT, | 2650 | xfs_trans_mod_dquot(tp, newdq, XFS_TRANS_DQ_ICOUNT, 1); |
2595 | ip->i_d.di_nblocks); | ||
2596 | xfs_trans_mod_dquot(tp, newdq, | ||
2597 | XFS_TRANS_DQ_ICOUNT, | ||
2598 | 1); | ||
2599 | 2651 | ||
2600 | /* | 2652 | /* |
2601 | * Take an extra reference, because the inode | 2653 | * Take an extra reference, because the inode |
@@ -2611,7 +2663,7 @@ xfs_qm_vop_chown( | |||
2611 | } | 2663 | } |
2612 | 2664 | ||
2613 | /* | 2665 | /* |
2614 | * Quota reservations for setattr(AT_UID|AT_GID). | 2666 | * Quota reservations for setattr(AT_UID|AT_GID|AT_PROJID). |
2615 | */ | 2667 | */ |
2616 | int | 2668 | int |
2617 | xfs_qm_vop_chown_reserve( | 2669 | xfs_qm_vop_chown_reserve( |
@@ -2623,7 +2675,7 @@ xfs_qm_vop_chown_reserve( | |||
2623 | { | 2675 | { |
2624 | int error; | 2676 | int error; |
2625 | xfs_mount_t *mp; | 2677 | xfs_mount_t *mp; |
2626 | uint delblks; | 2678 | uint delblks, blkflags; |
2627 | xfs_dquot_t *unresudq, *unresgdq, *delblksudq, *delblksgdq; | 2679 | xfs_dquot_t *unresudq, *unresgdq, *delblksudq, *delblksgdq; |
2628 | 2680 | ||
2629 | ASSERT(XFS_ISLOCKED_INODE(ip)); | 2681 | ASSERT(XFS_ISLOCKED_INODE(ip)); |
@@ -2632,6 +2684,8 @@ xfs_qm_vop_chown_reserve( | |||
2632 | 2684 | ||
2633 | delblks = ip->i_delayed_blks; | 2685 | delblks = ip->i_delayed_blks; |
2634 | delblksudq = delblksgdq = unresudq = unresgdq = NULL; | 2686 | delblksudq = delblksgdq = unresudq = unresgdq = NULL; |
2687 | blkflags = XFS_IS_REALTIME_INODE(ip) ? | ||
2688 | XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS; | ||
2635 | 2689 | ||
2636 | if (XFS_IS_UQUOTA_ON(mp) && udqp && | 2690 | if (XFS_IS_UQUOTA_ON(mp) && udqp && |
2637 | ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) { | 2691 | ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) { |
@@ -2646,18 +2700,22 @@ xfs_qm_vop_chown_reserve( | |||
2646 | unresudq = ip->i_udquot; | 2700 | unresudq = ip->i_udquot; |
2647 | } | 2701 | } |
2648 | } | 2702 | } |
2649 | if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp && | 2703 | if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) { |
2650 | ip->i_d.di_gid != INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) { | 2704 | if ((XFS_IS_GQUOTA_ON(ip->i_mount) && ip->i_d.di_gid != |
2651 | delblksgdq = gdqp; | 2705 | INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) || |
2652 | if (delblks) { | 2706 | (XFS_IS_PQUOTA_ON(ip->i_mount) && ip->i_d.di_projid != |
2653 | ASSERT(ip->i_gdquot); | 2707 | INT_GET(gdqp->q_core.d_id, ARCH_CONVERT))) { |
2654 | unresgdq = ip->i_gdquot; | 2708 | delblksgdq = gdqp; |
2709 | if (delblks) { | ||
2710 | ASSERT(ip->i_gdquot); | ||
2711 | unresgdq = ip->i_gdquot; | ||
2712 | } | ||
2655 | } | 2713 | } |
2656 | } | 2714 | } |
2657 | 2715 | ||
2658 | if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount, | 2716 | if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount, |
2659 | delblksudq, delblksgdq, ip->i_d.di_nblocks, 1, | 2717 | delblksudq, delblksgdq, ip->i_d.di_nblocks, 1, |
2660 | flags | XFS_QMOPT_RES_REGBLKS))) | 2718 | flags | blkflags))) |
2661 | return (error); | 2719 | return (error); |
2662 | 2720 | ||
2663 | /* | 2721 | /* |
@@ -2674,11 +2732,11 @@ xfs_qm_vop_chown_reserve( | |||
2674 | ASSERT(unresudq || unresgdq); | 2732 | ASSERT(unresudq || unresgdq); |
2675 | if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount, | 2733 | if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount, |
2676 | delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0, | 2734 | delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0, |
2677 | flags | XFS_QMOPT_RES_REGBLKS))) | 2735 | flags | blkflags))) |
2678 | return (error); | 2736 | return (error); |
2679 | xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount, | 2737 | xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount, |
2680 | unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0, | 2738 | unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0, |
2681 | XFS_QMOPT_RES_REGBLKS); | 2739 | blkflags); |
2682 | } | 2740 | } |
2683 | 2741 | ||
2684 | return (0); | 2742 | return (0); |
@@ -2751,7 +2809,7 @@ xfs_qm_vop_dqattach_and_dqmod_newinode( | |||
2751 | } | 2809 | } |
2752 | 2810 | ||
2753 | /* ------------- list stuff -----------------*/ | 2811 | /* ------------- list stuff -----------------*/ |
2754 | void | 2812 | STATIC void |
2755 | xfs_qm_freelist_init(xfs_frlist_t *ql) | 2813 | xfs_qm_freelist_init(xfs_frlist_t *ql) |
2756 | { | 2814 | { |
2757 | ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql; | 2815 | ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql; |
@@ -2760,7 +2818,7 @@ xfs_qm_freelist_init(xfs_frlist_t *ql) | |||
2760 | ql->qh_nelems = 0; | 2818 | ql->qh_nelems = 0; |
2761 | } | 2819 | } |
2762 | 2820 | ||
2763 | void | 2821 | STATIC void |
2764 | xfs_qm_freelist_destroy(xfs_frlist_t *ql) | 2822 | xfs_qm_freelist_destroy(xfs_frlist_t *ql) |
2765 | { | 2823 | { |
2766 | xfs_dquot_t *dqp, *nextdqp; | 2824 | xfs_dquot_t *dqp, *nextdqp; |
@@ -2786,7 +2844,7 @@ xfs_qm_freelist_destroy(xfs_frlist_t *ql) | |||
2786 | ASSERT(ql->qh_nelems == 0); | 2844 | ASSERT(ql->qh_nelems == 0); |
2787 | } | 2845 | } |
2788 | 2846 | ||
2789 | void | 2847 | STATIC void |
2790 | xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq) | 2848 | xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq) |
2791 | { | 2849 | { |
2792 | dq->dq_flnext = ql->qh_next; | 2850 | dq->dq_flnext = ql->qh_next; |
@@ -2816,7 +2874,7 @@ xfs_qm_freelist_append(xfs_frlist_t *ql, xfs_dquot_t *dq) | |||
2816 | xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq); | 2874 | xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq); |
2817 | } | 2875 | } |
2818 | 2876 | ||
2819 | int | 2877 | STATIC int |
2820 | xfs_qm_dqhashlock_nowait( | 2878 | xfs_qm_dqhashlock_nowait( |
2821 | xfs_dquot_t *dqp) | 2879 | xfs_dquot_t *dqp) |
2822 | { | 2880 | { |
@@ -2836,7 +2894,7 @@ xfs_qm_freelist_lock_nowait( | |||
2836 | return (locked); | 2894 | return (locked); |
2837 | } | 2895 | } |
2838 | 2896 | ||
2839 | int | 2897 | STATIC int |
2840 | xfs_qm_mplist_nowait( | 2898 | xfs_qm_mplist_nowait( |
2841 | xfs_mount_t *mp) | 2899 | xfs_mount_t *mp) |
2842 | { | 2900 | { |
diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h index dcf1a7a831d8..b03eecf3b6cb 100644 --- a/fs/xfs/quota/xfs_qm.h +++ b/fs/xfs/quota/xfs_qm.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. | 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of version 2 of the GNU General Public License as | 5 | * under the terms of version 2 of the GNU General Public License as |
@@ -133,8 +133,9 @@ typedef struct xfs_quotainfo { | |||
133 | time_t qi_btimelimit; /* limit for blks timer */ | 133 | time_t qi_btimelimit; /* limit for blks timer */ |
134 | time_t qi_itimelimit; /* limit for inodes timer */ | 134 | time_t qi_itimelimit; /* limit for inodes timer */ |
135 | time_t qi_rtbtimelimit;/* limit for rt blks timer */ | 135 | time_t qi_rtbtimelimit;/* limit for rt blks timer */ |
136 | xfs_qwarncnt_t qi_bwarnlimit; /* limit for num warnings */ | 136 | xfs_qwarncnt_t qi_bwarnlimit; /* limit for blks warnings */ |
137 | xfs_qwarncnt_t qi_iwarnlimit; /* limit for num warnings */ | 137 | xfs_qwarncnt_t qi_iwarnlimit; /* limit for inodes warnings */ |
138 | xfs_qwarncnt_t qi_rtbwarnlimit;/* limit for rt blks warnings */ | ||
138 | mutex_t qi_quotaofflock;/* to serialize quotaoff */ | 139 | mutex_t qi_quotaofflock;/* to serialize quotaoff */ |
139 | xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */ | 140 | xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */ |
140 | uint qi_dqperchunk; /* # ondisk dqs in above chunk */ | 141 | uint qi_dqperchunk; /* # ondisk dqs in above chunk */ |
@@ -176,6 +177,7 @@ typedef struct xfs_dquot_acct { | |||
176 | 177 | ||
177 | #define XFS_QM_BWARNLIMIT 5 | 178 | #define XFS_QM_BWARNLIMIT 5 |
178 | #define XFS_QM_IWARNLIMIT 5 | 179 | #define XFS_QM_IWARNLIMIT 5 |
180 | #define XFS_QM_RTBWARNLIMIT 5 | ||
179 | 181 | ||
180 | #define XFS_QM_LOCK(xqm) (mutex_lock(&xqm##_lock, PINOD)) | 182 | #define XFS_QM_LOCK(xqm) (mutex_lock(&xqm##_lock, PINOD)) |
181 | #define XFS_QM_UNLOCK(xqm) (mutex_unlock(&xqm##_lock)) | 183 | #define XFS_QM_UNLOCK(xqm) (mutex_unlock(&xqm##_lock)) |
@@ -184,7 +186,6 @@ typedef struct xfs_dquot_acct { | |||
184 | 186 | ||
185 | extern void xfs_mount_reset_sbqflags(xfs_mount_t *); | 187 | extern void xfs_mount_reset_sbqflags(xfs_mount_t *); |
186 | 188 | ||
187 | extern int xfs_qm_init_quotainfo(xfs_mount_t *); | ||
188 | extern void xfs_qm_destroy_quotainfo(xfs_mount_t *); | 189 | extern void xfs_qm_destroy_quotainfo(xfs_mount_t *); |
189 | extern int xfs_qm_mount_quotas(xfs_mount_t *, int); | 190 | extern int xfs_qm_mount_quotas(xfs_mount_t *, int); |
190 | extern void xfs_qm_mount_quotainit(xfs_mount_t *, uint); | 191 | extern void xfs_qm_mount_quotainit(xfs_mount_t *, uint); |
@@ -203,7 +204,7 @@ extern void xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint); | |||
203 | 204 | ||
204 | /* vop stuff */ | 205 | /* vop stuff */ |
205 | extern int xfs_qm_vop_dqalloc(xfs_mount_t *, xfs_inode_t *, | 206 | extern int xfs_qm_vop_dqalloc(xfs_mount_t *, xfs_inode_t *, |
206 | uid_t, gid_t, uint, | 207 | uid_t, gid_t, prid_t, uint, |
207 | xfs_dquot_t **, xfs_dquot_t **); | 208 | xfs_dquot_t **, xfs_dquot_t **); |
208 | extern void xfs_qm_vop_dqattach_and_dqmod_newinode( | 209 | extern void xfs_qm_vop_dqattach_and_dqmod_newinode( |
209 | xfs_trans_t *, xfs_inode_t *, | 210 | xfs_trans_t *, xfs_inode_t *, |
@@ -215,14 +216,9 @@ extern int xfs_qm_vop_chown_reserve(xfs_trans_t *, xfs_inode_t *, | |||
215 | xfs_dquot_t *, xfs_dquot_t *, uint); | 216 | xfs_dquot_t *, xfs_dquot_t *, uint); |
216 | 217 | ||
217 | /* list stuff */ | 218 | /* list stuff */ |
218 | extern void xfs_qm_freelist_init(xfs_frlist_t *); | ||
219 | extern void xfs_qm_freelist_destroy(xfs_frlist_t *); | ||
220 | extern void xfs_qm_freelist_insert(xfs_frlist_t *, xfs_dquot_t *); | ||
221 | extern void xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *); | 219 | extern void xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *); |
222 | extern void xfs_qm_freelist_unlink(xfs_dquot_t *); | 220 | extern void xfs_qm_freelist_unlink(xfs_dquot_t *); |
223 | extern int xfs_qm_freelist_lock_nowait(xfs_qm_t *); | 221 | extern int xfs_qm_freelist_lock_nowait(xfs_qm_t *); |
224 | extern int xfs_qm_mplist_nowait(xfs_mount_t *); | ||
225 | extern int xfs_qm_dqhashlock_nowait(xfs_dquot_t *); | ||
226 | 222 | ||
227 | /* system call interface */ | 223 | /* system call interface */ |
228 | extern int xfs_qm_quotactl(bhv_desc_t *, int, int, xfs_caddr_t); | 224 | extern int xfs_qm_quotactl(bhv_desc_t *, int, int, xfs_caddr_t); |
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c index be67d9c265f8..dc3c37a1e158 100644 --- a/fs/xfs/quota/xfs_qm_bhv.c +++ b/fs/xfs/quota/xfs_qm_bhv.c | |||
@@ -71,10 +71,13 @@ | |||
71 | #define MNTOPT_NOQUOTA "noquota" /* no quotas */ | 71 | #define MNTOPT_NOQUOTA "noquota" /* no quotas */ |
72 | #define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */ | 72 | #define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */ |
73 | #define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */ | 73 | #define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */ |
74 | #define MNTOPT_PRJQUOTA "prjquota" /* project quota enabled */ | ||
74 | #define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */ | 75 | #define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */ |
75 | #define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */ | 76 | #define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */ |
77 | #define MNTOPT_PQUOTA "pquota" /* project quota (IRIX variant) */ | ||
76 | #define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ | 78 | #define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ |
77 | #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ | 79 | #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ |
80 | #define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */ | ||
78 | #define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ | 81 | #define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ |
79 | 82 | ||
80 | STATIC int | 83 | STATIC int |
@@ -109,6 +112,14 @@ xfs_qm_parseargs( | |||
109 | args->flags |= XFSMNT_UQUOTA; | 112 | args->flags |= XFSMNT_UQUOTA; |
110 | args->flags &= ~XFSMNT_UQUOTAENF; | 113 | args->flags &= ~XFSMNT_UQUOTAENF; |
111 | referenced = 1; | 114 | referenced = 1; |
115 | } else if (!strcmp(this_char, MNTOPT_PQUOTA) || | ||
116 | !strcmp(this_char, MNTOPT_PRJQUOTA)) { | ||
117 | args->flags |= XFSMNT_PQUOTA | XFSMNT_PQUOTAENF; | ||
118 | referenced = 1; | ||
119 | } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) { | ||
120 | args->flags |= XFSMNT_PQUOTA; | ||
121 | args->flags &= ~XFSMNT_PQUOTAENF; | ||
122 | referenced = 1; | ||
112 | } else if (!strcmp(this_char, MNTOPT_GQUOTA) || | 123 | } else if (!strcmp(this_char, MNTOPT_GQUOTA) || |
113 | !strcmp(this_char, MNTOPT_GRPQUOTA)) { | 124 | !strcmp(this_char, MNTOPT_GRPQUOTA)) { |
114 | args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF; | 125 | args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF; |
@@ -127,6 +138,12 @@ xfs_qm_parseargs( | |||
127 | *this_char++ = ','; | 138 | *this_char++ = ','; |
128 | } | 139 | } |
129 | 140 | ||
141 | if ((args->flags & XFSMNT_GQUOTA) && (args->flags & XFSMNT_PQUOTA)) { | ||
142 | cmn_err(CE_WARN, | ||
143 | "XFS: cannot mount with both project and group quota"); | ||
144 | return XFS_ERROR(EINVAL); | ||
145 | } | ||
146 | |||
130 | PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error); | 147 | PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error); |
131 | if (!error && !referenced) | 148 | if (!error && !referenced) |
132 | bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM); | 149 | bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM); |
@@ -148,13 +165,19 @@ xfs_qm_showargs( | |||
148 | seq_puts(m, "," MNTOPT_UQUOTANOENF); | 165 | seq_puts(m, "," MNTOPT_UQUOTANOENF); |
149 | } | 166 | } |
150 | 167 | ||
168 | if (mp->m_qflags & XFS_PQUOTA_ACCT) { | ||
169 | (mp->m_qflags & XFS_OQUOTA_ENFD) ? | ||
170 | seq_puts(m, "," MNTOPT_PRJQUOTA) : | ||
171 | seq_puts(m, "," MNTOPT_PQUOTANOENF); | ||
172 | } | ||
173 | |||
151 | if (mp->m_qflags & XFS_GQUOTA_ACCT) { | 174 | if (mp->m_qflags & XFS_GQUOTA_ACCT) { |
152 | (mp->m_qflags & XFS_GQUOTA_ENFD) ? | 175 | (mp->m_qflags & XFS_OQUOTA_ENFD) ? |
153 | seq_puts(m, "," MNTOPT_GRPQUOTA) : | 176 | seq_puts(m, "," MNTOPT_GRPQUOTA) : |
154 | seq_puts(m, "," MNTOPT_GQUOTANOENF); | 177 | seq_puts(m, "," MNTOPT_GQUOTANOENF); |
155 | } | 178 | } |
156 | 179 | ||
157 | if (!(mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) | 180 | if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) |
158 | seq_puts(m, "," MNTOPT_NOQUOTA); | 181 | seq_puts(m, "," MNTOPT_NOQUOTA); |
159 | 182 | ||
160 | PVFS_SHOWARGS(BHV_NEXT(bhv), m, error); | 183 | PVFS_SHOWARGS(BHV_NEXT(bhv), m, error); |
@@ -171,7 +194,7 @@ xfs_qm_mount( | |||
171 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); | 194 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); |
172 | int error; | 195 | int error; |
173 | 196 | ||
174 | if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA)) | 197 | if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | XFSMNT_PQUOTA)) |
175 | xfs_qm_mount_quotainit(mp, args->flags); | 198 | xfs_qm_mount_quotainit(mp, args->flags); |
176 | PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error); | 199 | PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error); |
177 | return error; | 200 | return error; |
@@ -255,16 +278,17 @@ xfs_qm_newmount( | |||
255 | uint *quotaflags) | 278 | uint *quotaflags) |
256 | { | 279 | { |
257 | uint quotaondisk; | 280 | uint quotaondisk; |
258 | uint uquotaondisk = 0, gquotaondisk = 0; | 281 | uint uquotaondisk = 0, gquotaondisk = 0, pquotaondisk = 0; |
259 | 282 | ||
260 | *quotaflags = 0; | 283 | *quotaflags = 0; |
261 | *needquotamount = B_FALSE; | 284 | *needquotamount = B_FALSE; |
262 | 285 | ||
263 | quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && | 286 | quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && |
264 | mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT); | 287 | (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT); |
265 | 288 | ||
266 | if (quotaondisk) { | 289 | if (quotaondisk) { |
267 | uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT; | 290 | uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT; |
291 | pquotaondisk = mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT; | ||
268 | gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT; | 292 | gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT; |
269 | } | 293 | } |
270 | 294 | ||
@@ -277,13 +301,16 @@ xfs_qm_newmount( | |||
277 | 301 | ||
278 | if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) || | 302 | if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) || |
279 | (!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) || | 303 | (!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) || |
304 | (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) || | ||
305 | (!pquotaondisk && XFS_IS_PQUOTA_ON(mp)) || | ||
280 | (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) || | 306 | (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) || |
281 | (!gquotaondisk && XFS_IS_GQUOTA_ON(mp))) && | 307 | (!gquotaondisk && XFS_IS_OQUOTA_ON(mp))) && |
282 | xfs_dev_is_read_only(mp, "changing quota state")) { | 308 | xfs_dev_is_read_only(mp, "changing quota state")) { |
283 | cmn_err(CE_WARN, | 309 | cmn_err(CE_WARN, |
284 | "XFS: please mount with%s%s%s.", | 310 | "XFS: please mount with%s%s%s%s.", |
285 | (!quotaondisk ? "out quota" : ""), | 311 | (!quotaondisk ? "out quota" : ""), |
286 | (uquotaondisk ? " usrquota" : ""), | 312 | (uquotaondisk ? " usrquota" : ""), |
313 | (pquotaondisk ? " prjquota" : ""), | ||
287 | (gquotaondisk ? " grpquota" : "")); | 314 | (gquotaondisk ? " grpquota" : "")); |
288 | return XFS_ERROR(EPERM); | 315 | return XFS_ERROR(EPERM); |
289 | } | 316 | } |
@@ -359,7 +386,7 @@ xfs_qm_dqrele_null( | |||
359 | } | 386 | } |
360 | 387 | ||
361 | 388 | ||
362 | struct xfs_qmops xfs_qmcore_xfs = { | 389 | STATIC struct xfs_qmops xfs_qmcore_xfs = { |
363 | .xfs_qminit = xfs_qm_newmount, | 390 | .xfs_qminit = xfs_qm_newmount, |
364 | .xfs_qmdone = xfs_qm_unmount_quotadestroy, | 391 | .xfs_qmdone = xfs_qm_unmount_quotadestroy, |
365 | .xfs_qmmount = xfs_qm_endmount, | 392 | .xfs_qmmount = xfs_qm_endmount, |
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index 229f5b5a2d25..68e98962dbef 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c | |||
@@ -118,40 +118,41 @@ xfs_qm_quotactl( | |||
118 | * The following commands are valid even when quotaoff. | 118 | * The following commands are valid even when quotaoff. |
119 | */ | 119 | */ |
120 | switch (cmd) { | 120 | switch (cmd) { |
121 | case Q_XQUOTARM: | ||
121 | /* | 122 | /* |
122 | * truncate quota files. quota must be off. | 123 | * Truncate quota files. quota must be off. |
123 | */ | 124 | */ |
124 | case Q_XQUOTARM: | ||
125 | if (XFS_IS_QUOTA_ON(mp) || addr == NULL) | 125 | if (XFS_IS_QUOTA_ON(mp) || addr == NULL) |
126 | return XFS_ERROR(EINVAL); | 126 | return XFS_ERROR(EINVAL); |
127 | if (vfsp->vfs_flag & VFS_RDONLY) | 127 | if (vfsp->vfs_flag & VFS_RDONLY) |
128 | return XFS_ERROR(EROFS); | 128 | return XFS_ERROR(EROFS); |
129 | return (xfs_qm_scall_trunc_qfiles(mp, | 129 | return (xfs_qm_scall_trunc_qfiles(mp, |
130 | xfs_qm_import_qtype_flags(*(uint *)addr))); | 130 | xfs_qm_import_qtype_flags(*(uint *)addr))); |
131 | |||
132 | case Q_XGETQSTAT: | ||
131 | /* | 133 | /* |
132 | * Get quota status information. | 134 | * Get quota status information. |
133 | */ | 135 | */ |
134 | case Q_XGETQSTAT: | ||
135 | return (xfs_qm_scall_getqstat(mp, (fs_quota_stat_t *)addr)); | 136 | return (xfs_qm_scall_getqstat(mp, (fs_quota_stat_t *)addr)); |
136 | 137 | ||
138 | case Q_XQUOTAON: | ||
137 | /* | 139 | /* |
138 | * QUOTAON for root f/s and quota enforcement on others.. | 140 | * QUOTAON - enabling quota enforcement. |
139 | * Quota accounting for non-root f/s's must be turned on | 141 | * Quota accounting must be turned on at mount time. |
140 | * at mount time. | ||
141 | */ | 142 | */ |
142 | case Q_XQUOTAON: | ||
143 | if (addr == NULL) | 143 | if (addr == NULL) |
144 | return XFS_ERROR(EINVAL); | 144 | return XFS_ERROR(EINVAL); |
145 | if (vfsp->vfs_flag & VFS_RDONLY) | 145 | if (vfsp->vfs_flag & VFS_RDONLY) |
146 | return XFS_ERROR(EROFS); | 146 | return XFS_ERROR(EROFS); |
147 | return (xfs_qm_scall_quotaon(mp, | 147 | return (xfs_qm_scall_quotaon(mp, |
148 | xfs_qm_import_flags(*(uint *)addr))); | 148 | xfs_qm_import_flags(*(uint *)addr))); |
149 | case Q_XQUOTAOFF: | 149 | |
150 | case Q_XQUOTAOFF: | ||
150 | if (vfsp->vfs_flag & VFS_RDONLY) | 151 | if (vfsp->vfs_flag & VFS_RDONLY) |
151 | return XFS_ERROR(EROFS); | 152 | return XFS_ERROR(EROFS); |
152 | break; | 153 | break; |
153 | 154 | ||
154 | default: | 155 | default: |
155 | break; | 156 | break; |
156 | } | 157 | } |
157 | 158 | ||
@@ -159,7 +160,7 @@ xfs_qm_quotactl( | |||
159 | return XFS_ERROR(ESRCH); | 160 | return XFS_ERROR(ESRCH); |
160 | 161 | ||
161 | switch (cmd) { | 162 | switch (cmd) { |
162 | case Q_XQUOTAOFF: | 163 | case Q_XQUOTAOFF: |
163 | if (vfsp->vfs_flag & VFS_RDONLY) | 164 | if (vfsp->vfs_flag & VFS_RDONLY) |
164 | return XFS_ERROR(EROFS); | 165 | return XFS_ERROR(EROFS); |
165 | error = xfs_qm_scall_quotaoff(mp, | 166 | error = xfs_qm_scall_quotaoff(mp, |
@@ -167,42 +168,39 @@ xfs_qm_quotactl( | |||
167 | B_FALSE); | 168 | B_FALSE); |
168 | break; | 169 | break; |
169 | 170 | ||
170 | /* | 171 | case Q_XGETQUOTA: |
171 | * Defaults to XFS_GETUQUOTA. | ||
172 | */ | ||
173 | case Q_XGETQUOTA: | ||
174 | error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_USER, | 172 | error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_USER, |
175 | (fs_disk_quota_t *)addr); | 173 | (fs_disk_quota_t *)addr); |
176 | break; | 174 | break; |
177 | /* | 175 | case Q_XGETGQUOTA: |
178 | * Set limits, both hard and soft. Defaults to Q_SETUQLIM. | 176 | error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, |
179 | */ | 177 | (fs_disk_quota_t *)addr); |
180 | case Q_XSETQLIM: | 178 | break; |
179 | case Q_XGETPQUOTA: | ||
180 | error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_PROJ, | ||
181 | (fs_disk_quota_t *)addr); | ||
182 | break; | ||
183 | |||
184 | case Q_XSETQLIM: | ||
181 | if (vfsp->vfs_flag & VFS_RDONLY) | 185 | if (vfsp->vfs_flag & VFS_RDONLY) |
182 | return XFS_ERROR(EROFS); | 186 | return XFS_ERROR(EROFS); |
183 | error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_USER, | 187 | error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_USER, |
184 | (fs_disk_quota_t *)addr); | 188 | (fs_disk_quota_t *)addr); |
185 | break; | 189 | break; |
186 | 190 | case Q_XSETGQLIM: | |
187 | case Q_XSETGQLIM: | ||
188 | if (vfsp->vfs_flag & VFS_RDONLY) | 191 | if (vfsp->vfs_flag & VFS_RDONLY) |
189 | return XFS_ERROR(EROFS); | 192 | return XFS_ERROR(EROFS); |
190 | error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, | 193 | error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, |
191 | (fs_disk_quota_t *)addr); | 194 | (fs_disk_quota_t *)addr); |
192 | break; | 195 | break; |
193 | 196 | case Q_XSETPQLIM: | |
194 | 197 | if (vfsp->vfs_flag & VFS_RDONLY) | |
195 | case Q_XGETGQUOTA: | 198 | return XFS_ERROR(EROFS); |
196 | error = xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, XFS_DQ_GROUP, | 199 | error = xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, XFS_DQ_PROJ, |
197 | (fs_disk_quota_t *)addr); | 200 | (fs_disk_quota_t *)addr); |
198 | break; | 201 | break; |
199 | 202 | ||
200 | /* | 203 | default: |
201 | * Quotas are entirely undefined after quotaoff in XFS quotas. | ||
202 | * For instance, there's no way to set limits when quotaoff. | ||
203 | */ | ||
204 | |||
205 | default: | ||
206 | error = XFS_ERROR(EINVAL); | 204 | error = XFS_ERROR(EINVAL); |
207 | break; | 205 | break; |
208 | } | 206 | } |
@@ -286,8 +284,12 @@ xfs_qm_scall_quotaoff( | |||
286 | } | 284 | } |
287 | if (flags & XFS_GQUOTA_ACCT) { | 285 | if (flags & XFS_GQUOTA_ACCT) { |
288 | dqtype |= XFS_QMOPT_GQUOTA; | 286 | dqtype |= XFS_QMOPT_GQUOTA; |
289 | flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD); | 287 | flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD); |
290 | inactivate_flags |= XFS_GQUOTA_ACTIVE; | 288 | inactivate_flags |= XFS_GQUOTA_ACTIVE; |
289 | } else if (flags & XFS_PQUOTA_ACCT) { | ||
290 | dqtype |= XFS_QMOPT_PQUOTA; | ||
291 | flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD); | ||
292 | inactivate_flags |= XFS_PQUOTA_ACTIVE; | ||
291 | } | 293 | } |
292 | 294 | ||
293 | /* | 295 | /* |
@@ -364,7 +366,8 @@ xfs_qm_scall_quotaoff( | |||
364 | /* | 366 | /* |
365 | * If quotas is completely disabled, close shop. | 367 | * If quotas is completely disabled, close shop. |
366 | */ | 368 | */ |
367 | if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) { | 369 | if (((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET1) || |
370 | ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET2)) { | ||
368 | mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); | 371 | mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); |
369 | xfs_qm_destroy_quotainfo(mp); | 372 | xfs_qm_destroy_quotainfo(mp); |
370 | return (0); | 373 | return (0); |
@@ -378,7 +381,7 @@ xfs_qm_scall_quotaoff( | |||
378 | XFS_PURGE_INODE(XFS_QI_UQIP(mp)); | 381 | XFS_PURGE_INODE(XFS_QI_UQIP(mp)); |
379 | XFS_QI_UQIP(mp) = NULL; | 382 | XFS_QI_UQIP(mp) = NULL; |
380 | } | 383 | } |
381 | if ((dqtype & XFS_QMOPT_GQUOTA) && XFS_QI_GQIP(mp)) { | 384 | if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && XFS_QI_GQIP(mp)) { |
382 | XFS_PURGE_INODE(XFS_QI_GQIP(mp)); | 385 | XFS_PURGE_INODE(XFS_QI_GQIP(mp)); |
383 | XFS_QI_GQIP(mp) = NULL; | 386 | XFS_QI_GQIP(mp) = NULL; |
384 | } | 387 | } |
@@ -411,7 +414,8 @@ xfs_qm_scall_trunc_qfiles( | |||
411 | } | 414 | } |
412 | } | 415 | } |
413 | 416 | ||
414 | if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) { | 417 | if ((flags & (XFS_DQ_GROUP|XFS_DQ_PROJ)) && |
418 | mp->m_sb.sb_gquotino != NULLFSINO) { | ||
415 | error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip, 0); | 419 | error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip, 0); |
416 | if (! error) { | 420 | if (! error) { |
417 | (void) xfs_truncate_file(mp, qip); | 421 | (void) xfs_truncate_file(mp, qip); |
@@ -434,7 +438,7 @@ xfs_qm_scall_quotaon( | |||
434 | uint flags) | 438 | uint flags) |
435 | { | 439 | { |
436 | int error; | 440 | int error; |
437 | unsigned long s; | 441 | unsigned long s; |
438 | uint qf; | 442 | uint qf; |
439 | uint accflags; | 443 | uint accflags; |
440 | __int64_t sbflags; | 444 | __int64_t sbflags; |
@@ -468,9 +472,13 @@ xfs_qm_scall_quotaon( | |||
468 | (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 && | 472 | (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 && |
469 | (flags & XFS_UQUOTA_ENFD)) | 473 | (flags & XFS_UQUOTA_ENFD)) |
470 | || | 474 | || |
475 | ((flags & XFS_PQUOTA_ACCT) == 0 && | ||
476 | (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 && | ||
477 | (flags & XFS_OQUOTA_ENFD)) | ||
478 | || | ||
471 | ((flags & XFS_GQUOTA_ACCT) == 0 && | 479 | ((flags & XFS_GQUOTA_ACCT) == 0 && |
472 | (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 && | 480 | (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 && |
473 | (flags & XFS_GQUOTA_ENFD))) { | 481 | (flags & XFS_OQUOTA_ENFD))) { |
474 | qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n", | 482 | qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n", |
475 | flags, mp->m_sb.sb_qflags); | 483 | flags, mp->m_sb.sb_qflags); |
476 | return XFS_ERROR(EINVAL); | 484 | return XFS_ERROR(EINVAL); |
@@ -504,6 +512,10 @@ xfs_qm_scall_quotaon( | |||
504 | */ | 512 | */ |
505 | if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) != | 513 | if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) != |
506 | (mp->m_qflags & XFS_UQUOTA_ACCT)) || | 514 | (mp->m_qflags & XFS_UQUOTA_ACCT)) || |
515 | ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) != | ||
516 | (mp->m_qflags & XFS_PQUOTA_ACCT)) || | ||
517 | ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) != | ||
518 | (mp->m_qflags & XFS_GQUOTA_ACCT)) || | ||
507 | (flags & XFS_ALL_QUOTA_ENFD) == 0) | 519 | (flags & XFS_ALL_QUOTA_ENFD) == 0) |
508 | return (0); | 520 | return (0); |
509 | 521 | ||
@@ -521,7 +533,6 @@ xfs_qm_scall_quotaon( | |||
521 | } | 533 | } |
522 | 534 | ||
523 | 535 | ||
524 | |||
525 | /* | 536 | /* |
526 | * Return quota status information, such as uquota-off, enforcements, etc. | 537 | * Return quota status information, such as uquota-off, enforcements, etc. |
527 | */ | 538 | */ |
@@ -606,7 +617,8 @@ xfs_qm_scall_setqlim( | |||
606 | if (!capable(CAP_SYS_ADMIN)) | 617 | if (!capable(CAP_SYS_ADMIN)) |
607 | return XFS_ERROR(EPERM); | 618 | return XFS_ERROR(EPERM); |
608 | 619 | ||
609 | if ((newlim->d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK)) == 0) | 620 | if ((newlim->d_fieldmask & |
621 | (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK|FS_DQ_WARNS_MASK)) == 0) | ||
610 | return (0); | 622 | return (0); |
611 | 623 | ||
612 | tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM); | 624 | tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM); |
@@ -691,12 +703,23 @@ xfs_qm_scall_setqlim( | |||
691 | qdprintk("ihard %Ld < isoft %Ld\n", hard, soft); | 703 | qdprintk("ihard %Ld < isoft %Ld\n", hard, soft); |
692 | } | 704 | } |
693 | 705 | ||
706 | /* | ||
707 | * Update warnings counter(s) if requested | ||
708 | */ | ||
709 | if (newlim->d_fieldmask & FS_DQ_BWARNS) | ||
710 | INT_SET(ddq->d_bwarns, ARCH_CONVERT, newlim->d_bwarns); | ||
711 | if (newlim->d_fieldmask & FS_DQ_IWARNS) | ||
712 | INT_SET(ddq->d_iwarns, ARCH_CONVERT, newlim->d_iwarns); | ||
713 | if (newlim->d_fieldmask & FS_DQ_RTBWARNS) | ||
714 | INT_SET(ddq->d_rtbwarns, ARCH_CONVERT, newlim->d_rtbwarns); | ||
715 | |||
694 | if (id == 0) { | 716 | if (id == 0) { |
695 | /* | 717 | /* |
696 | * Timelimits for the super user set the relative time | 718 | * Timelimits for the super user set the relative time |
697 | * the other users can be over quota for this file system. | 719 | * the other users can be over quota for this file system. |
698 | * If it is zero a default is used. Ditto for the default | 720 | * If it is zero a default is used. Ditto for the default |
699 | * soft and hard limit values (already done, above). | 721 | * soft and hard limit values (already done, above), and |
722 | * for warnings. | ||
700 | */ | 723 | */ |
701 | if (newlim->d_fieldmask & FS_DQ_BTIMER) { | 724 | if (newlim->d_fieldmask & FS_DQ_BTIMER) { |
702 | mp->m_quotainfo->qi_btimelimit = newlim->d_btimer; | 725 | mp->m_quotainfo->qi_btimelimit = newlim->d_btimer; |
@@ -710,7 +733,13 @@ xfs_qm_scall_setqlim( | |||
710 | mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer; | 733 | mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer; |
711 | INT_SET(ddq->d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer); | 734 | INT_SET(ddq->d_rtbtimer, ARCH_CONVERT, newlim->d_rtbtimer); |
712 | } | 735 | } |
713 | } else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ { | 736 | if (newlim->d_fieldmask & FS_DQ_BWARNS) |
737 | mp->m_quotainfo->qi_bwarnlimit = newlim->d_bwarns; | ||
738 | if (newlim->d_fieldmask & FS_DQ_IWARNS) | ||
739 | mp->m_quotainfo->qi_iwarnlimit = newlim->d_iwarns; | ||
740 | if (newlim->d_fieldmask & FS_DQ_RTBWARNS) | ||
741 | mp->m_quotainfo->qi_rtbwarnlimit = newlim->d_rtbwarns; | ||
742 | } else { | ||
714 | /* | 743 | /* |
715 | * If the user is now over quota, start the timelimit. | 744 | * If the user is now over quota, start the timelimit. |
716 | * The user will not be 'warned'. | 745 | * The user will not be 'warned'. |
@@ -776,9 +805,9 @@ xfs_qm_log_quotaoff_end( | |||
776 | xfs_qoff_logitem_t *startqoff, | 805 | xfs_qoff_logitem_t *startqoff, |
777 | uint flags) | 806 | uint flags) |
778 | { | 807 | { |
779 | xfs_trans_t *tp; | 808 | xfs_trans_t *tp; |
780 | int error; | 809 | int error; |
781 | xfs_qoff_logitem_t *qoffi; | 810 | xfs_qoff_logitem_t *qoffi; |
782 | 811 | ||
783 | tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END); | 812 | tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END); |
784 | 813 | ||
@@ -928,18 +957,26 @@ xfs_qm_export_dquot( | |||
928 | 957 | ||
929 | STATIC uint | 958 | STATIC uint |
930 | xfs_qm_import_qtype_flags( | 959 | xfs_qm_import_qtype_flags( |
931 | uint uflags) | 960 | uint uflags) |
932 | { | 961 | { |
962 | uint oflags = 0; | ||
963 | |||
933 | /* | 964 | /* |
934 | * Can't be both at the same time. | 965 | * Can't be more than one, or none. |
935 | */ | 966 | */ |
936 | if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == | 967 | if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == |
937 | (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) || | 968 | (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) || |
938 | ((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == 0)) | 969 | ((uflags & (XFS_GROUP_QUOTA | XFS_PROJ_QUOTA)) == |
970 | (XFS_GROUP_QUOTA | XFS_PROJ_QUOTA)) || | ||
971 | ((uflags & (XFS_USER_QUOTA | XFS_PROJ_QUOTA)) == | ||
972 | (XFS_USER_QUOTA | XFS_PROJ_QUOTA)) || | ||
973 | ((uflags & (XFS_GROUP_QUOTA|XFS_USER_QUOTA|XFS_PROJ_QUOTA)) == 0)) | ||
939 | return (0); | 974 | return (0); |
940 | 975 | ||
941 | return (uflags & XFS_USER_QUOTA) ? | 976 | oflags |= (uflags & XFS_USER_QUOTA) ? XFS_DQ_USER : 0; |
942 | XFS_DQ_USER : XFS_DQ_GROUP; | 977 | oflags |= (uflags & XFS_PROJ_QUOTA) ? XFS_DQ_PROJ : 0; |
978 | oflags |= (uflags & XFS_GROUP_QUOTA) ? XFS_DQ_GROUP: 0; | ||
979 | return oflags; | ||
943 | } | 980 | } |
944 | 981 | ||
945 | STATIC uint | 982 | STATIC uint |
@@ -947,14 +984,19 @@ xfs_qm_export_qtype_flags( | |||
947 | uint flags) | 984 | uint flags) |
948 | { | 985 | { |
949 | /* | 986 | /* |
950 | * Can't be both at the same time. | 987 | * Can't be more than one, or none. |
951 | */ | 988 | */ |
952 | ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != | 989 | ASSERT((flags & (XFS_PROJ_QUOTA | XFS_USER_QUOTA)) != |
953 | (XFS_GROUP_QUOTA | XFS_USER_QUOTA)); | 990 | (XFS_PROJ_QUOTA | XFS_USER_QUOTA)); |
954 | ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != 0); | 991 | ASSERT((flags & (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)) != |
992 | (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)); | ||
993 | ASSERT((flags & (XFS_USER_QUOTA | XFS_GROUP_QUOTA)) != | ||
994 | (XFS_USER_QUOTA | XFS_GROUP_QUOTA)); | ||
995 | ASSERT((flags & (XFS_PROJ_QUOTA|XFS_USER_QUOTA|XFS_GROUP_QUOTA)) != 0); | ||
955 | 996 | ||
956 | return (flags & XFS_DQ_USER) ? | 997 | return (flags & XFS_DQ_USER) ? |
957 | XFS_USER_QUOTA : XFS_GROUP_QUOTA; | 998 | XFS_USER_QUOTA : (flags & XFS_DQ_PROJ) ? |
999 | XFS_PROJ_QUOTA : XFS_GROUP_QUOTA; | ||
958 | } | 1000 | } |
959 | 1001 | ||
960 | STATIC uint | 1002 | STATIC uint |
@@ -965,12 +1007,14 @@ xfs_qm_import_flags( | |||
965 | 1007 | ||
966 | if (uflags & XFS_QUOTA_UDQ_ACCT) | 1008 | if (uflags & XFS_QUOTA_UDQ_ACCT) |
967 | flags |= XFS_UQUOTA_ACCT; | 1009 | flags |= XFS_UQUOTA_ACCT; |
1010 | if (uflags & XFS_QUOTA_PDQ_ACCT) | ||
1011 | flags |= XFS_PQUOTA_ACCT; | ||
968 | if (uflags & XFS_QUOTA_GDQ_ACCT) | 1012 | if (uflags & XFS_QUOTA_GDQ_ACCT) |
969 | flags |= XFS_GQUOTA_ACCT; | 1013 | flags |= XFS_GQUOTA_ACCT; |
970 | if (uflags & XFS_QUOTA_UDQ_ENFD) | 1014 | if (uflags & XFS_QUOTA_UDQ_ENFD) |
971 | flags |= XFS_UQUOTA_ENFD; | 1015 | flags |= XFS_UQUOTA_ENFD; |
972 | if (uflags & XFS_QUOTA_GDQ_ENFD) | 1016 | if (uflags & (XFS_QUOTA_PDQ_ENFD|XFS_QUOTA_GDQ_ENFD)) |
973 | flags |= XFS_GQUOTA_ENFD; | 1017 | flags |= XFS_OQUOTA_ENFD; |
974 | return (flags); | 1018 | return (flags); |
975 | } | 1019 | } |
976 | 1020 | ||
@@ -984,12 +1028,16 @@ xfs_qm_export_flags( | |||
984 | uflags = 0; | 1028 | uflags = 0; |
985 | if (flags & XFS_UQUOTA_ACCT) | 1029 | if (flags & XFS_UQUOTA_ACCT) |
986 | uflags |= XFS_QUOTA_UDQ_ACCT; | 1030 | uflags |= XFS_QUOTA_UDQ_ACCT; |
1031 | if (flags & XFS_PQUOTA_ACCT) | ||
1032 | uflags |= XFS_QUOTA_PDQ_ACCT; | ||
987 | if (flags & XFS_GQUOTA_ACCT) | 1033 | if (flags & XFS_GQUOTA_ACCT) |
988 | uflags |= XFS_QUOTA_GDQ_ACCT; | 1034 | uflags |= XFS_QUOTA_GDQ_ACCT; |
989 | if (flags & XFS_UQUOTA_ENFD) | 1035 | if (flags & XFS_UQUOTA_ENFD) |
990 | uflags |= XFS_QUOTA_UDQ_ENFD; | 1036 | uflags |= XFS_QUOTA_UDQ_ENFD; |
991 | if (flags & XFS_GQUOTA_ENFD) | 1037 | if (flags & (XFS_OQUOTA_ENFD)) { |
992 | uflags |= XFS_QUOTA_GDQ_ENFD; | 1038 | uflags |= (flags & XFS_GQUOTA_ACCT) ? |
1039 | XFS_QUOTA_GDQ_ENFD : XFS_QUOTA_PDQ_ENFD; | ||
1040 | } | ||
993 | return (uflags); | 1041 | return (uflags); |
994 | } | 1042 | } |
995 | 1043 | ||
@@ -1070,7 +1118,7 @@ again: | |||
1070 | xfs_qm_dqrele(ip->i_udquot); | 1118 | xfs_qm_dqrele(ip->i_udquot); |
1071 | ip->i_udquot = NULL; | 1119 | ip->i_udquot = NULL; |
1072 | } | 1120 | } |
1073 | if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) { | 1121 | if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) { |
1074 | xfs_qm_dqrele(ip->i_gdquot); | 1122 | xfs_qm_dqrele(ip->i_gdquot); |
1075 | ip->i_gdquot = NULL; | 1123 | ip->i_gdquot = NULL; |
1076 | } | 1124 | } |
@@ -1160,7 +1208,6 @@ xfs_qm_dqtest_print( | |||
1160 | { | 1208 | { |
1161 | cmn_err(CE_DEBUG, "-----------DQTEST DQUOT----------------"); | 1209 | cmn_err(CE_DEBUG, "-----------DQTEST DQUOT----------------"); |
1162 | cmn_err(CE_DEBUG, "---- dquot ID = %d", d->d_id); | 1210 | cmn_err(CE_DEBUG, "---- dquot ID = %d", d->d_id); |
1163 | cmn_err(CE_DEBUG, "---- type = %s", XFS_QM_ISUDQ(d)? "USR" : "GRP"); | ||
1164 | cmn_err(CE_DEBUG, "---- fs = 0x%p", d->q_mount); | 1211 | cmn_err(CE_DEBUG, "---- fs = 0x%p", d->q_mount); |
1165 | cmn_err(CE_DEBUG, "---- bcount = %Lu (0x%x)", | 1212 | cmn_err(CE_DEBUG, "---- bcount = %Lu (0x%x)", |
1166 | d->d_bcount, (int)d->d_bcount); | 1213 | d->d_bcount, (int)d->d_bcount); |
@@ -1231,7 +1278,7 @@ xfs_dqtest_cmp2( | |||
1231 | #ifdef QUOTADEBUG | 1278 | #ifdef QUOTADEBUG |
1232 | if (!err) { | 1279 | if (!err) { |
1233 | cmn_err(CE_DEBUG, "%d [%s] [0x%p] qchecked", | 1280 | cmn_err(CE_DEBUG, "%d [%s] [0x%p] qchecked", |
1234 | d->d_id, XFS_QM_ISUDQ(d) ? "USR" : "GRP", d->q_mount); | 1281 | d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount); |
1235 | } | 1282 | } |
1236 | #endif | 1283 | #endif |
1237 | return (err); | 1284 | return (err); |
@@ -1287,6 +1334,7 @@ STATIC void | |||
1287 | xfs_qm_internalqcheck_get_dquots( | 1334 | xfs_qm_internalqcheck_get_dquots( |
1288 | xfs_mount_t *mp, | 1335 | xfs_mount_t *mp, |
1289 | xfs_dqid_t uid, | 1336 | xfs_dqid_t uid, |
1337 | xfs_dqid_t projid, | ||
1290 | xfs_dqid_t gid, | 1338 | xfs_dqid_t gid, |
1291 | xfs_dqtest_t **ud, | 1339 | xfs_dqtest_t **ud, |
1292 | xfs_dqtest_t **gd) | 1340 | xfs_dqtest_t **gd) |
@@ -1295,6 +1343,8 @@ xfs_qm_internalqcheck_get_dquots( | |||
1295 | xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud); | 1343 | xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud); |
1296 | if (XFS_IS_GQUOTA_ON(mp)) | 1344 | if (XFS_IS_GQUOTA_ON(mp)) |
1297 | xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd); | 1345 | xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd); |
1346 | else if (XFS_IS_PQUOTA_ON(mp)) | ||
1347 | xfs_qm_internalqcheck_dqget(mp, projid, XFS_DQ_PROJ, gd); | ||
1298 | } | 1348 | } |
1299 | 1349 | ||
1300 | 1350 | ||
@@ -1362,13 +1412,14 @@ xfs_qm_internalqcheck_adjust( | |||
1362 | } | 1412 | } |
1363 | xfs_qm_internalqcheck_get_dquots(mp, | 1413 | xfs_qm_internalqcheck_get_dquots(mp, |
1364 | (xfs_dqid_t) ip->i_d.di_uid, | 1414 | (xfs_dqid_t) ip->i_d.di_uid, |
1415 | (xfs_dqid_t) ip->i_d.di_projid, | ||
1365 | (xfs_dqid_t) ip->i_d.di_gid, | 1416 | (xfs_dqid_t) ip->i_d.di_gid, |
1366 | &ud, &gd); | 1417 | &ud, &gd); |
1367 | if (XFS_IS_UQUOTA_ON(mp)) { | 1418 | if (XFS_IS_UQUOTA_ON(mp)) { |
1368 | ASSERT(ud); | 1419 | ASSERT(ud); |
1369 | xfs_qm_internalqcheck_dqadjust(ip, ud); | 1420 | xfs_qm_internalqcheck_dqadjust(ip, ud); |
1370 | } | 1421 | } |
1371 | if (XFS_IS_GQUOTA_ON(mp)) { | 1422 | if (XFS_IS_OQUOTA_ON(mp)) { |
1372 | ASSERT(gd); | 1423 | ASSERT(gd); |
1373 | xfs_qm_internalqcheck_dqadjust(ip, gd); | 1424 | xfs_qm_internalqcheck_dqadjust(ip, gd); |
1374 | } | 1425 | } |
diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h index 414b6004af21..bf413e70ec07 100644 --- a/fs/xfs/quota/xfs_quota_priv.h +++ b/fs/xfs/quota/xfs_quota_priv.h | |||
@@ -56,6 +56,7 @@ | |||
56 | #define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit) | 56 | #define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit) |
57 | #define XFS_QI_ITIMELIMIT(mp) ((mp)->m_quotainfo->qi_itimelimit) | 57 | #define XFS_QI_ITIMELIMIT(mp) ((mp)->m_quotainfo->qi_itimelimit) |
58 | #define XFS_QI_BWARNLIMIT(mp) ((mp)->m_quotainfo->qi_bwarnlimit) | 58 | #define XFS_QI_BWARNLIMIT(mp) ((mp)->m_quotainfo->qi_bwarnlimit) |
59 | #define XFS_QI_RTBWARNLIMIT(mp) ((mp)->m_quotainfo->qi_rtbwarnlimit) | ||
59 | #define XFS_QI_IWARNLIMIT(mp) ((mp)->m_quotainfo->qi_iwarnlimit) | 60 | #define XFS_QI_IWARNLIMIT(mp) ((mp)->m_quotainfo->qi_iwarnlimit) |
60 | #define XFS_QI_QOFFLOCK(mp) ((mp)->m_quotainfo->qi_quotaofflock) | 61 | #define XFS_QI_QOFFLOCK(mp) ((mp)->m_quotainfo->qi_quotaofflock) |
61 | 62 | ||
@@ -102,7 +103,8 @@ static inline int XQMISLCKD(struct xfs_dqhash *h) | |||
102 | (xfs_Gqm->qm_grp_dqhtable + \ | 103 | (xfs_Gqm->qm_grp_dqhtable + \ |
103 | XFS_DQ_HASHVAL(mp, id))) | 104 | XFS_DQ_HASHVAL(mp, id))) |
104 | #define XFS_IS_DQTYPE_ON(mp, type) (type == XFS_DQ_USER ? \ | 105 | #define XFS_IS_DQTYPE_ON(mp, type) (type == XFS_DQ_USER ? \ |
105 | XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp)) | 106 | XFS_IS_UQUOTA_ON(mp) : \ |
107 | XFS_IS_OQUOTA_ON(mp)) | ||
106 | #define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \ | 108 | #define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \ |
107 | !dqp->q_core.d_blk_hardlimit && \ | 109 | !dqp->q_core.d_blk_hardlimit && \ |
108 | !dqp->q_core.d_blk_softlimit && \ | 110 | !dqp->q_core.d_blk_softlimit && \ |
@@ -177,16 +179,11 @@ for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \ | |||
177 | (!((dqp)->q_core.d_id)) | 179 | (!((dqp)->q_core.d_id)) |
178 | 180 | ||
179 | #define XFS_PURGE_INODE(ip) \ | 181 | #define XFS_PURGE_INODE(ip) \ |
180 | { \ | 182 | IRELE(ip); |
181 | vmap_t dqvmap; \ | ||
182 | vnode_t *dqvp; \ | ||
183 | dqvp = XFS_ITOV(ip); \ | ||
184 | VMAP(dqvp, dqvmap); \ | ||
185 | VN_RELE(dqvp); \ | ||
186 | } | ||
187 | 183 | ||
188 | #define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \ | 184 | #define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \ |
189 | (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???")) | 185 | (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : \ |
186 | (((d)->dq_flags & XFS_DQ_PROJ) ? "PRJ":"???"))) | ||
190 | #define DQFLAGTO_DIRTYSTR(d) (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY") | 187 | #define DQFLAGTO_DIRTYSTR(d) (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY") |
191 | 188 | ||
192 | #endif /* __XFS_QUOTA_PRIV_H__ */ | 189 | #endif /* __XFS_QUOTA_PRIV_H__ */ |
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c index 149b2a1fd949..3b99daf8a640 100644 --- a/fs/xfs/quota/xfs_trans_dquot.c +++ b/fs/xfs/quota/xfs_trans_dquot.c | |||
@@ -187,7 +187,7 @@ xfs_trans_dup_dqinfo( | |||
187 | /* | 187 | /* |
188 | * Wrap around mod_dquot to account for both user and group quotas. | 188 | * Wrap around mod_dquot to account for both user and group quotas. |
189 | */ | 189 | */ |
190 | void | 190 | STATIC void |
191 | xfs_trans_mod_dquot_byino( | 191 | xfs_trans_mod_dquot_byino( |
192 | xfs_trans_t *tp, | 192 | xfs_trans_t *tp, |
193 | xfs_inode_t *ip, | 193 | xfs_inode_t *ip, |
@@ -207,12 +207,10 @@ xfs_trans_mod_dquot_byino( | |||
207 | if (tp->t_dqinfo == NULL) | 207 | if (tp->t_dqinfo == NULL) |
208 | xfs_trans_alloc_dqinfo(tp); | 208 | xfs_trans_alloc_dqinfo(tp); |
209 | 209 | ||
210 | if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) { | 210 | if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot) |
211 | (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta); | 211 | (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta); |
212 | } | 212 | if (XFS_IS_OQUOTA_ON(mp) && ip->i_gdquot) |
213 | if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot) { | ||
214 | (void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta); | 213 | (void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta); |
215 | } | ||
216 | } | 214 | } |
217 | 215 | ||
218 | STATIC xfs_dqtrx_t * | 216 | STATIC xfs_dqtrx_t * |
@@ -368,7 +366,7 @@ xfs_trans_dqlockedjoin( | |||
368 | * Unreserve just the reservations done by this transaction. | 366 | * Unreserve just the reservations done by this transaction. |
369 | * dquot is still left locked at exit. | 367 | * dquot is still left locked at exit. |
370 | */ | 368 | */ |
371 | void | 369 | STATIC void |
372 | xfs_trans_apply_dquot_deltas( | 370 | xfs_trans_apply_dquot_deltas( |
373 | xfs_trans_t *tp) | 371 | xfs_trans_t *tp) |
374 | { | 372 | { |
@@ -499,7 +497,7 @@ xfs_trans_apply_dquot_deltas( | |||
499 | * Adjust the RT reservation. | 497 | * Adjust the RT reservation. |
500 | */ | 498 | */ |
501 | if (qtrx->qt_rtblk_res != 0) { | 499 | if (qtrx->qt_rtblk_res != 0) { |
502 | if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) { | 500 | if (qtrx->qt_rtblk_res != qtrx->qt_rtblk_res_used) { |
503 | if (qtrx->qt_rtblk_res > | 501 | if (qtrx->qt_rtblk_res > |
504 | qtrx->qt_rtblk_res_used) | 502 | qtrx->qt_rtblk_res_used) |
505 | dqp->q_res_rtbcount -= (xfs_qcnt_t) | 503 | dqp->q_res_rtbcount -= (xfs_qcnt_t) |
@@ -532,12 +530,6 @@ xfs_trans_apply_dquot_deltas( | |||
532 | (xfs_qcnt_t)qtrx->qt_icount_delta; | 530 | (xfs_qcnt_t)qtrx->qt_icount_delta; |
533 | } | 531 | } |
534 | 532 | ||
535 | |||
536 | #ifdef QUOTADEBUG | ||
537 | if (qtrx->qt_rtblk_res != 0) | ||
538 | cmn_err(CE_DEBUG, "RT res %d for 0x%p\n", | ||
539 | (int) qtrx->qt_rtblk_res, dqp); | ||
540 | #endif | ||
541 | ASSERT(dqp->q_res_bcount >= | 533 | ASSERT(dqp->q_res_bcount >= |
542 | INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); | 534 | INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); |
543 | ASSERT(dqp->q_res_icount >= | 535 | ASSERT(dqp->q_res_icount >= |
@@ -638,7 +630,10 @@ xfs_trans_dqresv( | |||
638 | int error; | 630 | int error; |
639 | xfs_qcnt_t hardlimit; | 631 | xfs_qcnt_t hardlimit; |
640 | xfs_qcnt_t softlimit; | 632 | xfs_qcnt_t softlimit; |
641 | time_t btimer; | 633 | time_t timer; |
634 | xfs_qwarncnt_t warns; | ||
635 | xfs_qwarncnt_t warnlimit; | ||
636 | xfs_qcnt_t count; | ||
642 | xfs_qcnt_t *resbcountp; | 637 | xfs_qcnt_t *resbcountp; |
643 | xfs_quotainfo_t *q = mp->m_quotainfo; | 638 | xfs_quotainfo_t *q = mp->m_quotainfo; |
644 | 639 | ||
@@ -653,7 +648,9 @@ xfs_trans_dqresv( | |||
653 | softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT); | 648 | softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT); |
654 | if (!softlimit) | 649 | if (!softlimit) |
655 | softlimit = q->qi_bsoftlimit; | 650 | softlimit = q->qi_bsoftlimit; |
656 | btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT); | 651 | timer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT); |
652 | warns = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT); | ||
653 | warnlimit = XFS_QI_BWARNLIMIT(dqp->q_mount); | ||
657 | resbcountp = &dqp->q_res_bcount; | 654 | resbcountp = &dqp->q_res_bcount; |
658 | } else { | 655 | } else { |
659 | ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS); | 656 | ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS); |
@@ -663,7 +660,9 @@ xfs_trans_dqresv( | |||
663 | softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT); | 660 | softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT); |
664 | if (!softlimit) | 661 | if (!softlimit) |
665 | softlimit = q->qi_rtbsoftlimit; | 662 | softlimit = q->qi_rtbsoftlimit; |
666 | btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT); | 663 | timer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT); |
664 | warns = INT_GET(dqp->q_core.d_rtbwarns, ARCH_CONVERT); | ||
665 | warnlimit = XFS_QI_RTBWARNLIMIT(dqp->q_mount); | ||
667 | resbcountp = &dqp->q_res_rtbcount; | 666 | resbcountp = &dqp->q_res_rtbcount; |
668 | } | 667 | } |
669 | error = 0; | 668 | error = 0; |
@@ -693,37 +692,36 @@ xfs_trans_dqresv( | |||
693 | * If timer or warnings has expired, | 692 | * If timer or warnings has expired, |
694 | * return EDQUOT | 693 | * return EDQUOT |
695 | */ | 694 | */ |
696 | if ((btimer != 0 && get_seconds() > btimer) || | 695 | if ((timer != 0 && get_seconds() > timer) || |
697 | (dqp->q_core.d_bwarns && | 696 | (warns != 0 && warns >= warnlimit)) { |
698 | INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >= | ||
699 | XFS_QI_BWARNLIMIT(dqp->q_mount))) { | ||
700 | error = EDQUOT; | 697 | error = EDQUOT; |
701 | goto error_return; | 698 | goto error_return; |
702 | } | 699 | } |
703 | } | 700 | } |
704 | } | 701 | } |
705 | if (ninos > 0) { | 702 | if (ninos > 0) { |
706 | hardlimit = INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT); | 703 | count = INT_GET(dqp->q_core.d_icount, ARCH_CONVERT); |
704 | timer = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT); | ||
705 | warns = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT); | ||
706 | warnlimit = XFS_QI_IWARNLIMIT(dqp->q_mount); | ||
707 | hardlimit = INT_GET(dqp->q_core.d_ino_hardlimit, | ||
708 | ARCH_CONVERT); | ||
707 | if (!hardlimit) | 709 | if (!hardlimit) |
708 | hardlimit = q->qi_ihardlimit; | 710 | hardlimit = q->qi_ihardlimit; |
709 | softlimit = INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT); | 711 | softlimit = INT_GET(dqp->q_core.d_ino_softlimit, |
712 | ARCH_CONVERT); | ||
710 | if (!softlimit) | 713 | if (!softlimit) |
711 | softlimit = q->qi_isoftlimit; | 714 | softlimit = q->qi_isoftlimit; |
712 | if (hardlimit > 0ULL && | 715 | if (hardlimit > 0ULL && count >= hardlimit) { |
713 | INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= hardlimit) { | ||
714 | error = EDQUOT; | 716 | error = EDQUOT; |
715 | goto error_return; | 717 | goto error_return; |
716 | } else if (softlimit > 0ULL && | 718 | } else if (softlimit > 0ULL && count >= softlimit) { |
717 | INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= softlimit) { | ||
718 | /* | 719 | /* |
719 | * If timer or warnings has expired, | 720 | * If timer or warnings has expired, |
720 | * return EDQUOT | 721 | * return EDQUOT |
721 | */ | 722 | */ |
722 | if ((dqp->q_core.d_itimer && | 723 | if ((timer != 0 && get_seconds() > timer) || |
723 | get_seconds() > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) || | 724 | (warns != 0 && warns >= warnlimit)) { |
724 | (dqp->q_core.d_iwarns && | ||
725 | INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >= | ||
726 | XFS_QI_IWARNLIMIT(dqp->q_mount))) { | ||
727 | error = EDQUOT; | 725 | error = EDQUOT; |
728 | goto error_return; | 726 | goto error_return; |
729 | } | 727 | } |
diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c index 7d6e1f37df10..4ed7b6928cd7 100644 --- a/fs/xfs/support/debug.c +++ b/fs/xfs/support/debug.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <linux/kernel.h> | 37 | #include <linux/kernel.h> |
38 | 38 | ||
39 | int doass = 1; | ||
40 | static char message[256]; /* keep it off the stack */ | 39 | static char message[256]; /* keep it off the stack */ |
41 | static DEFINE_SPINLOCK(xfs_err_lock); | 40 | static DEFINE_SPINLOCK(xfs_err_lock); |
42 | 41 | ||
diff --git a/fs/xfs/support/debug.h b/fs/xfs/support/debug.h index 40b0f4c54d9e..c5b9365a7e2a 100644 --- a/fs/xfs/support/debug.h +++ b/fs/xfs/support/debug.h | |||
@@ -50,16 +50,11 @@ extern void cmn_err(int, char *, ...); | |||
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | #ifdef DEBUG | 52 | #ifdef DEBUG |
53 | # ifdef lint | 53 | # define ASSERT(EX) ((EX) ? ((void)0) : assfail(#EX, __FILE__, __LINE__)) |
54 | # define ASSERT(EX) ((void)0) /* avoid "constant in conditional" babble */ | ||
55 | # else | ||
56 | # define ASSERT(EX) ((!doass||(EX))?((void)0):assfail(#EX, __FILE__, __LINE__)) | ||
57 | # endif /* lint */ | ||
58 | #else | 54 | #else |
59 | # define ASSERT(x) ((void)0) | 55 | # define ASSERT(x) ((void)0) |
60 | #endif | 56 | #endif |
61 | 57 | ||
62 | extern int doass; /* dynamically turn off asserts */ | ||
63 | extern void assfail(char *, char *, int); | 58 | extern void assfail(char *, char *, int); |
64 | #ifdef DEBUG | 59 | #ifdef DEBUG |
65 | extern unsigned long random(void); | 60 | extern unsigned long random(void); |
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 36603db10fe9..dcfe19703620 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
@@ -59,7 +59,7 @@ | |||
59 | #define XFSA_FIXUP_BNO_OK 1 | 59 | #define XFSA_FIXUP_BNO_OK 1 |
60 | #define XFSA_FIXUP_CNT_OK 2 | 60 | #define XFSA_FIXUP_CNT_OK 2 |
61 | 61 | ||
62 | int | 62 | STATIC int |
63 | xfs_alloc_search_busy(xfs_trans_t *tp, | 63 | xfs_alloc_search_busy(xfs_trans_t *tp, |
64 | xfs_agnumber_t agno, | 64 | xfs_agnumber_t agno, |
65 | xfs_agblock_t bno, | 65 | xfs_agblock_t bno, |
@@ -2562,7 +2562,7 @@ xfs_alloc_clear_busy(xfs_trans_t *tp, | |||
2562 | /* | 2562 | /* |
2563 | * returns non-zero if any of (agno,bno):len is in a busy list | 2563 | * returns non-zero if any of (agno,bno):len is in a busy list |
2564 | */ | 2564 | */ |
2565 | int | 2565 | STATIC int |
2566 | xfs_alloc_search_busy(xfs_trans_t *tp, | 2566 | xfs_alloc_search_busy(xfs_trans_t *tp, |
2567 | xfs_agnumber_t agno, | 2567 | xfs_agnumber_t agno, |
2568 | xfs_agblock_t bno, | 2568 | xfs_agblock_t bno, |
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index ee8b5904ec7c..a41ad3a5e554 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c | |||
@@ -71,6 +71,11 @@ | |||
71 | * Provide the external interfaces to manage attribute lists. | 71 | * Provide the external interfaces to manage attribute lists. |
72 | */ | 72 | */ |
73 | 73 | ||
74 | #define ATTR_SYSCOUNT 2 | ||
75 | STATIC struct attrnames posix_acl_access; | ||
76 | STATIC struct attrnames posix_acl_default; | ||
77 | STATIC struct attrnames *attr_system_names[ATTR_SYSCOUNT]; | ||
78 | |||
74 | /*======================================================================== | 79 | /*======================================================================== |
75 | * Function prototypes for the kernel. | 80 | * Function prototypes for the kernel. |
76 | *========================================================================*/ | 81 | *========================================================================*/ |
@@ -83,6 +88,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); | |||
83 | /* | 88 | /* |
84 | * Internal routines when attribute list is one block. | 89 | * Internal routines when attribute list is one block. |
85 | */ | 90 | */ |
91 | STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); | ||
86 | STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); | 92 | STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); |
87 | STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); | 93 | STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); |
88 | STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); | 94 | STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); |
@@ -90,6 +96,7 @@ STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); | |||
90 | /* | 96 | /* |
91 | * Internal routines when attribute list is more than one block. | 97 | * Internal routines when attribute list is more than one block. |
92 | */ | 98 | */ |
99 | STATIC int xfs_attr_node_get(xfs_da_args_t *args); | ||
93 | STATIC int xfs_attr_node_addname(xfs_da_args_t *args); | 100 | STATIC int xfs_attr_node_addname(xfs_da_args_t *args); |
94 | STATIC int xfs_attr_node_removename(xfs_da_args_t *args); | 101 | STATIC int xfs_attr_node_removename(xfs_da_args_t *args); |
95 | STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context); | 102 | STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context); |
@@ -1102,7 +1109,7 @@ xfs_attr_leaf_removename(xfs_da_args_t *args) | |||
1102 | * This leaf block cannot have a "remote" value, we only call this routine | 1109 | * This leaf block cannot have a "remote" value, we only call this routine |
1103 | * if bmap_one_block() says there is only one block (ie: no remote blks). | 1110 | * if bmap_one_block() says there is only one block (ie: no remote blks). |
1104 | */ | 1111 | */ |
1105 | int | 1112 | STATIC int |
1106 | xfs_attr_leaf_get(xfs_da_args_t *args) | 1113 | xfs_attr_leaf_get(xfs_da_args_t *args) |
1107 | { | 1114 | { |
1108 | xfs_dabuf_t *bp; | 1115 | xfs_dabuf_t *bp; |
@@ -1707,7 +1714,7 @@ xfs_attr_refillstate(xfs_da_state_t *state) | |||
1707 | * block, ie: both true Btree attr lists and for single-leaf-blocks with | 1714 | * block, ie: both true Btree attr lists and for single-leaf-blocks with |
1708 | * "remote" values taking up more blocks. | 1715 | * "remote" values taking up more blocks. |
1709 | */ | 1716 | */ |
1710 | int | 1717 | STATIC int |
1711 | xfs_attr_node_get(xfs_da_args_t *args) | 1718 | xfs_attr_node_get(xfs_da_args_t *args) |
1712 | { | 1719 | { |
1713 | xfs_da_state_t *state; | 1720 | xfs_da_state_t *state; |
@@ -2398,7 +2405,7 @@ posix_acl_default_exists( | |||
2398 | return xfs_acl_vhasacl_default(vp); | 2405 | return xfs_acl_vhasacl_default(vp); |
2399 | } | 2406 | } |
2400 | 2407 | ||
2401 | struct attrnames posix_acl_access = { | 2408 | STATIC struct attrnames posix_acl_access = { |
2402 | .attr_name = "posix_acl_access", | 2409 | .attr_name = "posix_acl_access", |
2403 | .attr_namelen = sizeof("posix_acl_access") - 1, | 2410 | .attr_namelen = sizeof("posix_acl_access") - 1, |
2404 | .attr_get = posix_acl_access_get, | 2411 | .attr_get = posix_acl_access_get, |
@@ -2407,7 +2414,7 @@ struct attrnames posix_acl_access = { | |||
2407 | .attr_exists = posix_acl_access_exists, | 2414 | .attr_exists = posix_acl_access_exists, |
2408 | }; | 2415 | }; |
2409 | 2416 | ||
2410 | struct attrnames posix_acl_default = { | 2417 | STATIC struct attrnames posix_acl_default = { |
2411 | .attr_name = "posix_acl_default", | 2418 | .attr_name = "posix_acl_default", |
2412 | .attr_namelen = sizeof("posix_acl_default") - 1, | 2419 | .attr_namelen = sizeof("posix_acl_default") - 1, |
2413 | .attr_get = posix_acl_default_get, | 2420 | .attr_get = posix_acl_default_get, |
@@ -2416,7 +2423,7 @@ struct attrnames posix_acl_default = { | |||
2416 | .attr_exists = posix_acl_default_exists, | 2423 | .attr_exists = posix_acl_default_exists, |
2417 | }; | 2424 | }; |
2418 | 2425 | ||
2419 | struct attrnames *attr_system_names[] = | 2426 | STATIC struct attrnames *attr_system_names[] = |
2420 | { &posix_acl_access, &posix_acl_default }; | 2427 | { &posix_acl_access, &posix_acl_default }; |
2421 | 2428 | ||
2422 | 2429 | ||
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h index 67cd0f5ac1a7..45ab1c542baf 100644 --- a/fs/xfs/xfs_attr.h +++ b/fs/xfs/xfs_attr.h | |||
@@ -76,11 +76,6 @@ extern struct attrnames attr_system; | |||
76 | extern struct attrnames attr_trusted; | 76 | extern struct attrnames attr_trusted; |
77 | extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT]; | 77 | extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT]; |
78 | 78 | ||
79 | #define ATTR_SYSCOUNT 2 | ||
80 | extern struct attrnames posix_acl_access; | ||
81 | extern struct attrnames posix_acl_default; | ||
82 | extern struct attrnames *attr_system_names[ATTR_SYSCOUNT]; | ||
83 | |||
84 | extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int); | 79 | extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int); |
85 | extern int attr_generic_list(struct vnode *, void *, size_t, int, ssize_t *); | 80 | extern int attr_generic_list(struct vnode *, void *, size_t, int, ssize_t *); |
86 | 81 | ||
@@ -184,8 +179,6 @@ int xfs_attr_list(bhv_desc_t *, char *, int, int, | |||
184 | struct attrlist_cursor_kern *, struct cred *); | 179 | struct attrlist_cursor_kern *, struct cred *); |
185 | int xfs_attr_inactive(struct xfs_inode *dp); | 180 | int xfs_attr_inactive(struct xfs_inode *dp); |
186 | 181 | ||
187 | int xfs_attr_node_get(struct xfs_da_args *); | ||
188 | int xfs_attr_leaf_get(struct xfs_da_args *); | ||
189 | int xfs_attr_shortform_getvalue(struct xfs_da_args *); | 182 | int xfs_attr_shortform_getvalue(struct xfs_da_args *); |
190 | int xfs_attr_fetch(struct xfs_inode *, char *, int, | 183 | int xfs_attr_fetch(struct xfs_inode *, char *, int, |
191 | char *, int *, int, struct cred *); | 184 | char *, int *, int, struct cred *); |
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index b11256e58bf4..1cdd574c63a9 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c | |||
@@ -79,6 +79,8 @@ | |||
79 | /* | 79 | /* |
80 | * Routines used for growing the Btree. | 80 | * Routines used for growing the Btree. |
81 | */ | 81 | */ |
82 | STATIC int xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t which_block, | ||
83 | xfs_dabuf_t **bpp); | ||
82 | STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args, | 84 | STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args, |
83 | int freemap_index); | 85 | int freemap_index); |
84 | STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer); | 86 | STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer); |
@@ -92,6 +94,16 @@ STATIC int xfs_attr_leaf_figure_balance(xfs_da_state_t *state, | |||
92 | int *number_usedbytes_in_blk1); | 94 | int *number_usedbytes_in_blk1); |
93 | 95 | ||
94 | /* | 96 | /* |
97 | * Routines used for shrinking the Btree. | ||
98 | */ | ||
99 | STATIC int xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, | ||
100 | xfs_dabuf_t *bp, int level); | ||
101 | STATIC int xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, | ||
102 | xfs_dabuf_t *bp); | ||
103 | STATIC int xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, | ||
104 | xfs_dablk_t blkno, int blkcnt); | ||
105 | |||
106 | /* | ||
95 | * Utility routines. | 107 | * Utility routines. |
96 | */ | 108 | */ |
97 | STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf, | 109 | STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf, |
@@ -99,6 +111,10 @@ STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf, | |||
99 | xfs_attr_leafblock_t *dst_leaf, | 111 | xfs_attr_leafblock_t *dst_leaf, |
100 | int dst_start, int move_count, | 112 | int dst_start, int move_count, |
101 | xfs_mount_t *mp); | 113 | xfs_mount_t *mp); |
114 | STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); | ||
115 | STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context, | ||
116 | attrnames_t *, char *name, int namelen, | ||
117 | int valuelen); | ||
102 | 118 | ||
103 | 119 | ||
104 | /*======================================================================== | 120 | /*======================================================================== |
@@ -774,7 +790,7 @@ out: | |||
774 | * Create the initial contents of a leaf attribute list | 790 | * Create the initial contents of a leaf attribute list |
775 | * or a leaf in a node attribute list. | 791 | * or a leaf in a node attribute list. |
776 | */ | 792 | */ |
777 | int | 793 | STATIC int |
778 | xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) | 794 | xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) |
779 | { | 795 | { |
780 | xfs_attr_leafblock_t *leaf; | 796 | xfs_attr_leafblock_t *leaf; |
@@ -2209,7 +2225,7 @@ xfs_attr_leaf_lasthash(xfs_dabuf_t *bp, int *count) | |||
2209 | * Calculate the number of bytes used to store the indicated attribute | 2225 | * Calculate the number of bytes used to store the indicated attribute |
2210 | * (whether local or remote only calculate bytes in this block). | 2226 | * (whether local or remote only calculate bytes in this block). |
2211 | */ | 2227 | */ |
2212 | int | 2228 | STATIC int |
2213 | xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index) | 2229 | xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index) |
2214 | { | 2230 | { |
2215 | xfs_attr_leaf_name_local_t *name_loc; | 2231 | xfs_attr_leaf_name_local_t *name_loc; |
@@ -2380,7 +2396,7 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) | |||
2380 | * we may be reading them directly out of a user buffer. | 2396 | * we may be reading them directly out of a user buffer. |
2381 | */ | 2397 | */ |
2382 | /*ARGSUSED*/ | 2398 | /*ARGSUSED*/ |
2383 | int | 2399 | STATIC int |
2384 | xfs_attr_put_listent(xfs_attr_list_context_t *context, | 2400 | xfs_attr_put_listent(xfs_attr_list_context_t *context, |
2385 | attrnames_t *namesp, char *name, int namelen, int valuelen) | 2401 | attrnames_t *namesp, char *name, int namelen, int valuelen) |
2386 | { | 2402 | { |
@@ -2740,7 +2756,7 @@ xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp) | |||
2740 | * Recurse (gasp!) through the attribute nodes until we find leaves. | 2756 | * Recurse (gasp!) through the attribute nodes until we find leaves. |
2741 | * We're doing a depth-first traversal in order to invalidate everything. | 2757 | * We're doing a depth-first traversal in order to invalidate everything. |
2742 | */ | 2758 | */ |
2743 | int | 2759 | STATIC int |
2744 | xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp, | 2760 | xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp, |
2745 | int level) | 2761 | int level) |
2746 | { | 2762 | { |
@@ -2849,7 +2865,7 @@ xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp, | |||
2849 | * Note that we must release the lock on the buffer so that we are not | 2865 | * Note that we must release the lock on the buffer so that we are not |
2850 | * caught holding something that the logging code wants to flush to disk. | 2866 | * caught holding something that the logging code wants to flush to disk. |
2851 | */ | 2867 | */ |
2852 | int | 2868 | STATIC int |
2853 | xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp) | 2869 | xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp) |
2854 | { | 2870 | { |
2855 | xfs_attr_leafblock_t *leaf; | 2871 | xfs_attr_leafblock_t *leaf; |
@@ -2934,7 +2950,7 @@ xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp) | |||
2934 | * Look at all the extents for this logical region, | 2950 | * Look at all the extents for this logical region, |
2935 | * invalidate any buffers that are incore/in transactions. | 2951 | * invalidate any buffers that are incore/in transactions. |
2936 | */ | 2952 | */ |
2937 | int | 2953 | STATIC int |
2938 | xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, | 2954 | xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, |
2939 | xfs_dablk_t blkno, int blkcnt) | 2955 | xfs_dablk_t blkno, int blkcnt) |
2940 | { | 2956 | { |
diff --git a/fs/xfs/xfs_attr_leaf.h b/fs/xfs/xfs_attr_leaf.h index b1480e0b3349..0a4cfad6df91 100644 --- a/fs/xfs/xfs_attr_leaf.h +++ b/fs/xfs/xfs_attr_leaf.h | |||
@@ -261,8 +261,6 @@ int xfs_attr_leaf_flipflags(xfs_da_args_t *args); | |||
261 | /* | 261 | /* |
262 | * Routines used for growing the Btree. | 262 | * Routines used for growing the Btree. |
263 | */ | 263 | */ |
264 | int xfs_attr_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, | ||
265 | struct xfs_dabuf **bpp); | ||
266 | int xfs_attr_leaf_split(struct xfs_da_state *state, | 264 | int xfs_attr_leaf_split(struct xfs_da_state *state, |
267 | struct xfs_da_state_blk *oldblk, | 265 | struct xfs_da_state_blk *oldblk, |
268 | struct xfs_da_state_blk *newblk); | 266 | struct xfs_da_state_blk *newblk); |
@@ -284,12 +282,6 @@ void xfs_attr_leaf_unbalance(struct xfs_da_state *state, | |||
284 | struct xfs_da_state_blk *drop_blk, | 282 | struct xfs_da_state_blk *drop_blk, |
285 | struct xfs_da_state_blk *save_blk); | 283 | struct xfs_da_state_blk *save_blk); |
286 | int xfs_attr_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp); | 284 | int xfs_attr_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp); |
287 | int xfs_attr_node_inactive(struct xfs_trans **trans, struct xfs_inode *dp, | ||
288 | struct xfs_dabuf *bp, int level); | ||
289 | int xfs_attr_leaf_inactive(struct xfs_trans **trans, struct xfs_inode *dp, | ||
290 | struct xfs_dabuf *bp); | ||
291 | int xfs_attr_leaf_freextent(struct xfs_trans **trans, struct xfs_inode *dp, | ||
292 | xfs_dablk_t blkno, int blkcnt); | ||
293 | 285 | ||
294 | /* | 286 | /* |
295 | * Utility routines. | 287 | * Utility routines. |
@@ -299,10 +291,6 @@ int xfs_attr_leaf_order(struct xfs_dabuf *leaf1_bp, | |||
299 | struct xfs_dabuf *leaf2_bp); | 291 | struct xfs_dabuf *leaf2_bp); |
300 | int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int blocksize, | 292 | int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int blocksize, |
301 | int *local); | 293 | int *local); |
302 | int xfs_attr_leaf_entsize(struct xfs_attr_leafblock *leaf, int index); | ||
303 | int xfs_attr_put_listent(struct xfs_attr_list_context *context, | ||
304 | struct attrnames *, char *name, int namelen, | ||
305 | int valuelen); | ||
306 | int xfs_attr_rolltrans(struct xfs_trans **transp, struct xfs_inode *dp); | 294 | int xfs_attr_rolltrans(struct xfs_trans **transp, struct xfs_inode *dp); |
307 | 295 | ||
308 | #endif /* __XFS_ATTR_LEAF_H__ */ | 296 | #endif /* __XFS_ATTR_LEAF_H__ */ |
diff --git a/fs/xfs/xfs_bit.c b/fs/xfs/xfs_bit.c index a20a6c3dc13e..76c9ad3875ef 100644 --- a/fs/xfs/xfs_bit.c +++ b/fs/xfs/xfs_bit.c | |||
@@ -45,7 +45,7 @@ | |||
45 | /* | 45 | /* |
46 | * Index of high bit number in byte, -1 for none set, 0..7 otherwise. | 46 | * Index of high bit number in byte, -1 for none set, 0..7 otherwise. |
47 | */ | 47 | */ |
48 | const char xfs_highbit[256] = { | 48 | STATIC const char xfs_highbit[256] = { |
49 | -1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */ | 49 | -1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */ |
50 | 3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */ | 50 | 3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */ |
51 | 4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */ | 51 | 4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */ |
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index de3162418663..6f5d283888aa 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -301,6 +301,19 @@ xfs_bmap_search_extents( | |||
301 | xfs_bmbt_irec_t *gotp, /* out: extent entry found */ | 301 | xfs_bmbt_irec_t *gotp, /* out: extent entry found */ |
302 | xfs_bmbt_irec_t *prevp); /* out: previous extent entry found */ | 302 | xfs_bmbt_irec_t *prevp); /* out: previous extent entry found */ |
303 | 303 | ||
304 | /* | ||
305 | * Check the last inode extent to determine whether this allocation will result | ||
306 | * in blocks being allocated at the end of the file. When we allocate new data | ||
307 | * blocks at the end of the file which do not start at the previous data block, | ||
308 | * we will try to align the new blocks at stripe unit boundaries. | ||
309 | */ | ||
310 | STATIC int /* error */ | ||
311 | xfs_bmap_isaeof( | ||
312 | xfs_inode_t *ip, /* incore inode pointer */ | ||
313 | xfs_fileoff_t off, /* file offset in fsblocks */ | ||
314 | int whichfork, /* data or attribute fork */ | ||
315 | char *aeof); /* return value */ | ||
316 | |||
304 | #ifdef XFS_BMAP_TRACE | 317 | #ifdef XFS_BMAP_TRACE |
305 | /* | 318 | /* |
306 | * Add a bmap trace buffer entry. Base routine for the others. | 319 | * Add a bmap trace buffer entry. Base routine for the others. |
@@ -4532,18 +4545,17 @@ xfs_bmapi( | |||
4532 | xfs_extlen_t alen; /* allocated extent length */ | 4545 | xfs_extlen_t alen; /* allocated extent length */ |
4533 | xfs_fileoff_t aoff; /* allocated file offset */ | 4546 | xfs_fileoff_t aoff; /* allocated file offset */ |
4534 | xfs_bmalloca_t bma; /* args for xfs_bmap_alloc */ | 4547 | xfs_bmalloca_t bma; /* args for xfs_bmap_alloc */ |
4535 | char contig; /* allocation must be one extent */ | ||
4536 | xfs_btree_cur_t *cur; /* bmap btree cursor */ | 4548 | xfs_btree_cur_t *cur; /* bmap btree cursor */ |
4537 | char delay; /* this request is for delayed alloc */ | ||
4538 | xfs_fileoff_t end; /* end of mapped file region */ | 4549 | xfs_fileoff_t end; /* end of mapped file region */ |
4539 | int eof; /* we've hit the end of extent list */ | 4550 | int eof; /* we've hit the end of extent list */ |
4551 | char contig; /* allocation must be one extent */ | ||
4552 | char delay; /* this request is for delayed alloc */ | ||
4553 | char exact; /* don't do all of wasdelayed extent */ | ||
4540 | xfs_bmbt_rec_t *ep; /* extent list entry pointer */ | 4554 | xfs_bmbt_rec_t *ep; /* extent list entry pointer */ |
4541 | int error; /* error return */ | 4555 | int error; /* error return */ |
4542 | char exact; /* don't do all of wasdelayed extent */ | ||
4543 | xfs_bmbt_irec_t got; /* current extent list record */ | 4556 | xfs_bmbt_irec_t got; /* current extent list record */ |
4544 | xfs_ifork_t *ifp; /* inode fork pointer */ | 4557 | xfs_ifork_t *ifp; /* inode fork pointer */ |
4545 | xfs_extlen_t indlen; /* indirect blocks length */ | 4558 | xfs_extlen_t indlen; /* indirect blocks length */ |
4546 | char inhole; /* current location is hole in file */ | ||
4547 | xfs_extnum_t lastx; /* last useful extent number */ | 4559 | xfs_extnum_t lastx; /* last useful extent number */ |
4548 | int logflags; /* flags for transaction logging */ | 4560 | int logflags; /* flags for transaction logging */ |
4549 | xfs_extlen_t minleft; /* min blocks left after allocation */ | 4561 | xfs_extlen_t minleft; /* min blocks left after allocation */ |
@@ -4554,13 +4566,15 @@ xfs_bmapi( | |||
4554 | xfs_extnum_t nextents; /* number of extents in file */ | 4566 | xfs_extnum_t nextents; /* number of extents in file */ |
4555 | xfs_fileoff_t obno; /* old block number (offset) */ | 4567 | xfs_fileoff_t obno; /* old block number (offset) */ |
4556 | xfs_bmbt_irec_t prev; /* previous extent list record */ | 4568 | xfs_bmbt_irec_t prev; /* previous extent list record */ |
4557 | char stateless; /* ignore state flag set */ | ||
4558 | int tmp_logflags; /* temp flags holder */ | 4569 | int tmp_logflags; /* temp flags holder */ |
4570 | int whichfork; /* data or attr fork */ | ||
4571 | char inhole; /* current location is hole in file */ | ||
4572 | char stateless; /* ignore state flag set */ | ||
4559 | char trim; /* output trimmed to match range */ | 4573 | char trim; /* output trimmed to match range */ |
4560 | char userdata; /* allocating non-metadata */ | 4574 | char userdata; /* allocating non-metadata */ |
4561 | char wasdelay; /* old extent was delayed */ | 4575 | char wasdelay; /* old extent was delayed */ |
4562 | int whichfork; /* data or attr fork */ | ||
4563 | char wr; /* this is a write request */ | 4576 | char wr; /* this is a write request */ |
4577 | char rt; /* this is a realtime file */ | ||
4564 | char rsvd; /* OK to allocate reserved blocks */ | 4578 | char rsvd; /* OK to allocate reserved blocks */ |
4565 | #ifdef DEBUG | 4579 | #ifdef DEBUG |
4566 | xfs_fileoff_t orig_bno; /* original block number value */ | 4580 | xfs_fileoff_t orig_bno; /* original block number value */ |
@@ -4590,6 +4604,7 @@ xfs_bmapi( | |||
4590 | } | 4604 | } |
4591 | if (XFS_FORCED_SHUTDOWN(mp)) | 4605 | if (XFS_FORCED_SHUTDOWN(mp)) |
4592 | return XFS_ERROR(EIO); | 4606 | return XFS_ERROR(EIO); |
4607 | rt = XFS_IS_REALTIME_INODE(ip); | ||
4593 | ifp = XFS_IFORK_PTR(ip, whichfork); | 4608 | ifp = XFS_IFORK_PTR(ip, whichfork); |
4594 | ASSERT(ifp->if_ext_max == | 4609 | ASSERT(ifp->if_ext_max == |
4595 | XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); | 4610 | XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); |
@@ -4694,9 +4709,16 @@ xfs_bmapi( | |||
4694 | } | 4709 | } |
4695 | minlen = contig ? alen : 1; | 4710 | minlen = contig ? alen : 1; |
4696 | if (delay) { | 4711 | if (delay) { |
4697 | indlen = (xfs_extlen_t) | 4712 | xfs_extlen_t extsz = 0; |
4698 | xfs_bmap_worst_indlen(ip, alen); | 4713 | |
4699 | ASSERT(indlen > 0); | 4714 | /* Figure out the extent size, adjust alen */ |
4715 | if (rt) { | ||
4716 | if (!(extsz = ip->i_d.di_extsize)) | ||
4717 | extsz = mp->m_sb.sb_rextsize; | ||
4718 | alen = roundup(alen, extsz); | ||
4719 | extsz = alen / mp->m_sb.sb_rextsize; | ||
4720 | } | ||
4721 | |||
4700 | /* | 4722 | /* |
4701 | * Make a transaction-less quota reservation for | 4723 | * Make a transaction-less quota reservation for |
4702 | * delayed allocation blocks. This number gets | 4724 | * delayed allocation blocks. This number gets |
@@ -4704,8 +4726,10 @@ xfs_bmapi( | |||
4704 | * We return EDQUOT if we haven't allocated | 4726 | * We return EDQUOT if we haven't allocated |
4705 | * blks already inside this loop; | 4727 | * blks already inside this loop; |
4706 | */ | 4728 | */ |
4707 | if (XFS_TRANS_RESERVE_BLKQUOTA( | 4729 | if (XFS_TRANS_RESERVE_QUOTA_NBLKS( |
4708 | mp, NULL, ip, (long)alen)) { | 4730 | mp, NULL, ip, (long)alen, 0, |
4731 | rt ? XFS_QMOPT_RES_RTBLKS : | ||
4732 | XFS_QMOPT_RES_REGBLKS)) { | ||
4709 | if (n == 0) { | 4733 | if (n == 0) { |
4710 | *nmap = 0; | 4734 | *nmap = 0; |
4711 | ASSERT(cur == NULL); | 4735 | ASSERT(cur == NULL); |
@@ -4718,40 +4742,34 @@ xfs_bmapi( | |||
4718 | * Split changing sb for alen and indlen since | 4742 | * Split changing sb for alen and indlen since |
4719 | * they could be coming from different places. | 4743 | * they could be coming from different places. |
4720 | */ | 4744 | */ |
4721 | if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { | 4745 | indlen = (xfs_extlen_t) |
4722 | xfs_extlen_t extsz; | 4746 | xfs_bmap_worst_indlen(ip, alen); |
4723 | xfs_extlen_t ralen; | 4747 | ASSERT(indlen > 0); |
4724 | if (!(extsz = ip->i_d.di_extsize)) | ||
4725 | extsz = mp->m_sb.sb_rextsize; | ||
4726 | ralen = roundup(alen, extsz); | ||
4727 | ralen = ralen / mp->m_sb.sb_rextsize; | ||
4728 | if (xfs_mod_incore_sb(mp, | ||
4729 | XFS_SBS_FREXTENTS, | ||
4730 | -(ralen), rsvd)) { | ||
4731 | if (XFS_IS_QUOTA_ON(ip->i_mount)) | ||
4732 | XFS_TRANS_UNRESERVE_BLKQUOTA( | ||
4733 | mp, NULL, ip, | ||
4734 | (long)alen); | ||
4735 | break; | ||
4736 | } | ||
4737 | } else { | ||
4738 | if (xfs_mod_incore_sb(mp, | ||
4739 | XFS_SBS_FDBLOCKS, | ||
4740 | -(alen), rsvd)) { | ||
4741 | if (XFS_IS_QUOTA_ON(ip->i_mount)) | ||
4742 | XFS_TRANS_UNRESERVE_BLKQUOTA( | ||
4743 | mp, NULL, ip, | ||
4744 | (long)alen); | ||
4745 | break; | ||
4746 | } | ||
4747 | } | ||
4748 | 4748 | ||
4749 | if (xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, | 4749 | if (rt) |
4750 | -(indlen), rsvd)) { | 4750 | error = xfs_mod_incore_sb(mp, |
4751 | XFS_TRANS_UNRESERVE_BLKQUOTA( | 4751 | XFS_SBS_FREXTENTS, |
4752 | mp, NULL, ip, (long)alen); | 4752 | -(extsz), rsvd); |
4753 | else | ||
4754 | error = xfs_mod_incore_sb(mp, | ||
4755 | XFS_SBS_FDBLOCKS, | ||
4756 | -(alen), rsvd); | ||
4757 | if (!error) | ||
4758 | error = xfs_mod_incore_sb(mp, | ||
4759 | XFS_SBS_FDBLOCKS, | ||
4760 | -(indlen), rsvd); | ||
4761 | |||
4762 | if (error) { | ||
4763 | if (XFS_IS_QUOTA_ON(ip->i_mount)) | ||
4764 | /* unreserve the blocks now */ | ||
4765 | XFS_TRANS_UNRESERVE_QUOTA_NBLKS( | ||
4766 | mp, NULL, ip, | ||
4767 | (long)alen, 0, rt ? | ||
4768 | XFS_QMOPT_RES_RTBLKS : | ||
4769 | XFS_QMOPT_RES_REGBLKS); | ||
4753 | break; | 4770 | break; |
4754 | } | 4771 | } |
4772 | |||
4755 | ip->i_delayed_blks += alen; | 4773 | ip->i_delayed_blks += alen; |
4756 | abno = NULLSTARTBLOCK(indlen); | 4774 | abno = NULLSTARTBLOCK(indlen); |
4757 | } else { | 4775 | } else { |
@@ -5376,13 +5394,24 @@ xfs_bunmapi( | |||
5376 | } | 5394 | } |
5377 | if (wasdel) { | 5395 | if (wasdel) { |
5378 | ASSERT(STARTBLOCKVAL(del.br_startblock) > 0); | 5396 | ASSERT(STARTBLOCKVAL(del.br_startblock) > 0); |
5379 | xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, | 5397 | /* Update realtim/data freespace, unreserve quota */ |
5380 | (int)del.br_blockcount, rsvd); | 5398 | if (isrt) { |
5381 | /* Unreserve our quota space */ | 5399 | xfs_filblks_t rtexts; |
5382 | XFS_TRANS_RESERVE_QUOTA_NBLKS( | 5400 | |
5383 | mp, NULL, ip, -((long)del.br_blockcount), 0, | 5401 | rtexts = XFS_FSB_TO_B(mp, del.br_blockcount); |
5384 | isrt ? XFS_QMOPT_RES_RTBLKS : | 5402 | do_div(rtexts, mp->m_sb.sb_rextsize); |
5403 | xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, | ||
5404 | (int)rtexts, rsvd); | ||
5405 | XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip, | ||
5406 | -((long)del.br_blockcount), 0, | ||
5407 | XFS_QMOPT_RES_RTBLKS); | ||
5408 | } else { | ||
5409 | xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, | ||
5410 | (int)del.br_blockcount, rsvd); | ||
5411 | XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip, | ||
5412 | -((long)del.br_blockcount), 0, | ||
5385 | XFS_QMOPT_RES_REGBLKS); | 5413 | XFS_QMOPT_RES_REGBLKS); |
5414 | } | ||
5386 | ip->i_delayed_blks -= del.br_blockcount; | 5415 | ip->i_delayed_blks -= del.br_blockcount; |
5387 | if (cur) | 5416 | if (cur) |
5388 | cur->bc_private.b.flags |= | 5417 | cur->bc_private.b.flags |= |
@@ -5714,7 +5743,7 @@ unlock_and_return: | |||
5714 | * blocks at the end of the file which do not start at the previous data block, | 5743 | * blocks at the end of the file which do not start at the previous data block, |
5715 | * we will try to align the new blocks at stripe unit boundaries. | 5744 | * we will try to align the new blocks at stripe unit boundaries. |
5716 | */ | 5745 | */ |
5717 | int /* error */ | 5746 | STATIC int /* error */ |
5718 | xfs_bmap_isaeof( | 5747 | xfs_bmap_isaeof( |
5719 | xfs_inode_t *ip, /* incore inode pointer */ | 5748 | xfs_inode_t *ip, /* incore inode pointer */ |
5720 | xfs_fileoff_t off, /* file offset in fsblocks */ | 5749 | xfs_fileoff_t off, /* file offset in fsblocks */ |
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index f1bc22fb26ae..e6d22ec9b2e4 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h | |||
@@ -332,19 +332,6 @@ xfs_getbmap( | |||
332 | int iflags); /* interface flags */ | 332 | int iflags); /* interface flags */ |
333 | 333 | ||
334 | /* | 334 | /* |
335 | * Check the last inode extent to determine whether this allocation will result | ||
336 | * in blocks being allocated at the end of the file. When we allocate new data | ||
337 | * blocks at the end of the file which do not start at the previous data block, | ||
338 | * we will try to align the new blocks at stripe unit boundaries. | ||
339 | */ | ||
340 | int | ||
341 | xfs_bmap_isaeof( | ||
342 | struct xfs_inode *ip, | ||
343 | xfs_fileoff_t off, | ||
344 | int whichfork, | ||
345 | char *aeof); | ||
346 | |||
347 | /* | ||
348 | * Check if the endoff is outside the last extent. If so the caller will grow | 335 | * Check if the endoff is outside the last extent. If so the caller will grow |
349 | * the allocation to a stripe unit boundary | 336 | * the allocation to a stripe unit boundary |
350 | */ | 337 | */ |
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 163305a79fcc..09c413576ba8 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
@@ -2331,20 +2331,6 @@ xfs_bmbt_lookup_ge( | |||
2331 | return xfs_bmbt_lookup(cur, XFS_LOOKUP_GE, stat); | 2331 | return xfs_bmbt_lookup(cur, XFS_LOOKUP_GE, stat); |
2332 | } | 2332 | } |
2333 | 2333 | ||
2334 | int /* error */ | ||
2335 | xfs_bmbt_lookup_le( | ||
2336 | xfs_btree_cur_t *cur, | ||
2337 | xfs_fileoff_t off, | ||
2338 | xfs_fsblock_t bno, | ||
2339 | xfs_filblks_t len, | ||
2340 | int *stat) /* success/failure */ | ||
2341 | { | ||
2342 | cur->bc_rec.b.br_startoff = off; | ||
2343 | cur->bc_rec.b.br_startblock = bno; | ||
2344 | cur->bc_rec.b.br_blockcount = len; | ||
2345 | return xfs_bmbt_lookup(cur, XFS_LOOKUP_LE, stat); | ||
2346 | } | ||
2347 | |||
2348 | /* | 2334 | /* |
2349 | * Give the bmap btree a new root block. Copy the old broot contents | 2335 | * Give the bmap btree a new root block. Copy the old broot contents |
2350 | * down into a real block and make the broot point to it. | 2336 | * down into a real block and make the broot point to it. |
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index 843ff12b4bf2..0a40cf126c28 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h | |||
@@ -580,14 +580,6 @@ xfs_bmbt_lookup_ge( | |||
580 | xfs_filblks_t, | 580 | xfs_filblks_t, |
581 | int *); | 581 | int *); |
582 | 582 | ||
583 | int | ||
584 | xfs_bmbt_lookup_le( | ||
585 | struct xfs_btree_cur *, | ||
586 | xfs_fileoff_t, | ||
587 | xfs_fsblock_t, | ||
588 | xfs_filblks_t, | ||
589 | int *); | ||
590 | |||
591 | /* | 583 | /* |
592 | * Give the bmap btree a new root block. Copy the old broot contents | 584 | * Give the bmap btree a new root block. Copy the old broot contents |
593 | * down into a real block and make the broot point to it. | 585 | * down into a real block and make the broot point to it. |
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 9dd22dd95487..0cc63d657a14 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
@@ -90,6 +90,16 @@ xfs_btree_maxrecs( | |||
90 | */ | 90 | */ |
91 | 91 | ||
92 | /* | 92 | /* |
93 | * Retrieve the block pointer from the cursor at the given level. | ||
94 | * This may be a bmap btree root or from a buffer. | ||
95 | */ | ||
96 | STATIC xfs_btree_block_t * /* generic btree block pointer */ | ||
97 | xfs_btree_get_block( | ||
98 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
99 | int level, /* level in btree */ | ||
100 | struct xfs_buf **bpp); /* buffer containing the block */ | ||
101 | |||
102 | /* | ||
93 | * Checking routine: return maxrecs for the block. | 103 | * Checking routine: return maxrecs for the block. |
94 | */ | 104 | */ |
95 | STATIC int /* number of records fitting in block */ | 105 | STATIC int /* number of records fitting in block */ |
@@ -497,7 +507,7 @@ xfs_btree_firstrec( | |||
497 | * Retrieve the block pointer from the cursor at the given level. | 507 | * Retrieve the block pointer from the cursor at the given level. |
498 | * This may be a bmap btree root or from a buffer. | 508 | * This may be a bmap btree root or from a buffer. |
499 | */ | 509 | */ |
500 | xfs_btree_block_t * /* generic btree block pointer */ | 510 | STATIC xfs_btree_block_t * /* generic btree block pointer */ |
501 | xfs_btree_get_block( | 511 | xfs_btree_get_block( |
502 | xfs_btree_cur_t *cur, /* btree cursor */ | 512 | xfs_btree_cur_t *cur, /* btree cursor */ |
503 | int level, /* level in btree */ | 513 | int level, /* level in btree */ |
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index 93872bba41f5..09b4e1532a35 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h | |||
@@ -325,16 +325,6 @@ xfs_btree_firstrec( | |||
325 | int level); /* level to change */ | 325 | int level); /* level to change */ |
326 | 326 | ||
327 | /* | 327 | /* |
328 | * Retrieve the block pointer from the cursor at the given level. | ||
329 | * This may be a bmap btree root or from a buffer. | ||
330 | */ | ||
331 | xfs_btree_block_t * /* generic btree block pointer */ | ||
332 | xfs_btree_get_block( | ||
333 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
334 | int level, /* level in btree */ | ||
335 | struct xfs_buf **bpp); /* buffer containing the block */ | ||
336 | |||
337 | /* | ||
338 | * Get a buffer for the block, return it with no data read. | 328 | * Get a buffer for the block, return it with no data read. |
339 | * Long-form addressing. | 329 | * Long-form addressing. |
340 | */ | 330 | */ |
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 9ab0039f07df..30b8285ad476 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c | |||
@@ -172,7 +172,7 @@ STATIC void xfs_buf_do_callbacks(xfs_buf_t *bp, xfs_log_item_t *lip); | |||
172 | * | 172 | * |
173 | * If the XFS_BLI_STALE flag has been set, then log nothing. | 173 | * If the XFS_BLI_STALE flag has been set, then log nothing. |
174 | */ | 174 | */ |
175 | uint | 175 | STATIC uint |
176 | xfs_buf_item_size( | 176 | xfs_buf_item_size( |
177 | xfs_buf_log_item_t *bip) | 177 | xfs_buf_log_item_t *bip) |
178 | { | 178 | { |
@@ -240,7 +240,7 @@ xfs_buf_item_size( | |||
240 | * format structure, and the rest point to contiguous chunks | 240 | * format structure, and the rest point to contiguous chunks |
241 | * within the buffer. | 241 | * within the buffer. |
242 | */ | 242 | */ |
243 | void | 243 | STATIC void |
244 | xfs_buf_item_format( | 244 | xfs_buf_item_format( |
245 | xfs_buf_log_item_t *bip, | 245 | xfs_buf_log_item_t *bip, |
246 | xfs_log_iovec_t *log_vector) | 246 | xfs_log_iovec_t *log_vector) |
@@ -365,7 +365,7 @@ xfs_buf_item_format( | |||
365 | * item in memory so it cannot be written out. Simply call bpin() | 365 | * item in memory so it cannot be written out. Simply call bpin() |
366 | * on the buffer to do this. | 366 | * on the buffer to do this. |
367 | */ | 367 | */ |
368 | void | 368 | STATIC void |
369 | xfs_buf_item_pin( | 369 | xfs_buf_item_pin( |
370 | xfs_buf_log_item_t *bip) | 370 | xfs_buf_log_item_t *bip) |
371 | { | 371 | { |
@@ -391,7 +391,7 @@ xfs_buf_item_pin( | |||
391 | * If the XFS_BLI_STALE flag is set and we are the last reference, | 391 | * If the XFS_BLI_STALE flag is set and we are the last reference, |
392 | * then free up the buf log item and unlock the buffer. | 392 | * then free up the buf log item and unlock the buffer. |
393 | */ | 393 | */ |
394 | void | 394 | STATIC void |
395 | xfs_buf_item_unpin( | 395 | xfs_buf_item_unpin( |
396 | xfs_buf_log_item_t *bip, | 396 | xfs_buf_log_item_t *bip, |
397 | int stale) | 397 | int stale) |
@@ -446,7 +446,7 @@ xfs_buf_item_unpin( | |||
446 | * so we need to free the item's descriptor (that points to the item) | 446 | * so we need to free the item's descriptor (that points to the item) |
447 | * in the transaction. | 447 | * in the transaction. |
448 | */ | 448 | */ |
449 | void | 449 | STATIC void |
450 | xfs_buf_item_unpin_remove( | 450 | xfs_buf_item_unpin_remove( |
451 | xfs_buf_log_item_t *bip, | 451 | xfs_buf_log_item_t *bip, |
452 | xfs_trans_t *tp) | 452 | xfs_trans_t *tp) |
@@ -493,7 +493,7 @@ xfs_buf_item_unpin_remove( | |||
493 | * the lock right away, return 0. If we can get the lock, pull the | 493 | * the lock right away, return 0. If we can get the lock, pull the |
494 | * buffer from the free list, mark it busy, and return 1. | 494 | * buffer from the free list, mark it busy, and return 1. |
495 | */ | 495 | */ |
496 | uint | 496 | STATIC uint |
497 | xfs_buf_item_trylock( | 497 | xfs_buf_item_trylock( |
498 | xfs_buf_log_item_t *bip) | 498 | xfs_buf_log_item_t *bip) |
499 | { | 499 | { |
@@ -537,7 +537,7 @@ xfs_buf_item_trylock( | |||
537 | * This is for support of xfs_trans_bhold(). Make sure the | 537 | * This is for support of xfs_trans_bhold(). Make sure the |
538 | * XFS_BLI_HOLD field is cleared if we don't free the item. | 538 | * XFS_BLI_HOLD field is cleared if we don't free the item. |
539 | */ | 539 | */ |
540 | void | 540 | STATIC void |
541 | xfs_buf_item_unlock( | 541 | xfs_buf_item_unlock( |
542 | xfs_buf_log_item_t *bip) | 542 | xfs_buf_log_item_t *bip) |
543 | { | 543 | { |
@@ -635,7 +635,7 @@ xfs_buf_item_unlock( | |||
635 | * by returning the original lsn of that transaction here rather than | 635 | * by returning the original lsn of that transaction here rather than |
636 | * the current one. | 636 | * the current one. |
637 | */ | 637 | */ |
638 | xfs_lsn_t | 638 | STATIC xfs_lsn_t |
639 | xfs_buf_item_committed( | 639 | xfs_buf_item_committed( |
640 | xfs_buf_log_item_t *bip, | 640 | xfs_buf_log_item_t *bip, |
641 | xfs_lsn_t lsn) | 641 | xfs_lsn_t lsn) |
@@ -654,7 +654,7 @@ xfs_buf_item_committed( | |||
654 | * and have aborted this transaction, we'll trap this buffer when it tries to | 654 | * and have aborted this transaction, we'll trap this buffer when it tries to |
655 | * get written out. | 655 | * get written out. |
656 | */ | 656 | */ |
657 | void | 657 | STATIC void |
658 | xfs_buf_item_abort( | 658 | xfs_buf_item_abort( |
659 | xfs_buf_log_item_t *bip) | 659 | xfs_buf_log_item_t *bip) |
660 | { | 660 | { |
@@ -674,7 +674,7 @@ xfs_buf_item_abort( | |||
674 | * B_DELWRI set, then get it going out to disk with a call to bawrite(). | 674 | * B_DELWRI set, then get it going out to disk with a call to bawrite(). |
675 | * If not, then just release the buffer. | 675 | * If not, then just release the buffer. |
676 | */ | 676 | */ |
677 | void | 677 | STATIC void |
678 | xfs_buf_item_push( | 678 | xfs_buf_item_push( |
679 | xfs_buf_log_item_t *bip) | 679 | xfs_buf_log_item_t *bip) |
680 | { | 680 | { |
@@ -693,7 +693,7 @@ xfs_buf_item_push( | |||
693 | } | 693 | } |
694 | 694 | ||
695 | /* ARGSUSED */ | 695 | /* ARGSUSED */ |
696 | void | 696 | STATIC void |
697 | xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn) | 697 | xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn) |
698 | { | 698 | { |
699 | } | 699 | } |
@@ -701,7 +701,7 @@ xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn) | |||
701 | /* | 701 | /* |
702 | * This is the ops vector shared by all buf log items. | 702 | * This is the ops vector shared by all buf log items. |
703 | */ | 703 | */ |
704 | struct xfs_item_ops xfs_buf_item_ops = { | 704 | STATIC struct xfs_item_ops xfs_buf_item_ops = { |
705 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_buf_item_size, | 705 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_buf_item_size, |
706 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) | 706 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) |
707 | xfs_buf_item_format, | 707 | xfs_buf_item_format, |
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index 5f1b0c9308f6..01aed5f2d579 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h | |||
@@ -80,7 +80,7 @@ typedef struct xfs_buf_log_format_t { | |||
80 | * user or group dquots and may require special recovery handling. | 80 | * user or group dquots and may require special recovery handling. |
81 | */ | 81 | */ |
82 | #define XFS_BLI_UDQUOT_BUF 0x4 | 82 | #define XFS_BLI_UDQUOT_BUF 0x4 |
83 | /* #define XFS_BLI_PDQUOT_BUF 0x8 */ | 83 | #define XFS_BLI_PDQUOT_BUF 0x8 |
84 | #define XFS_BLI_GDQUOT_BUF 0x10 | 84 | #define XFS_BLI_GDQUOT_BUF 0x10 |
85 | 85 | ||
86 | #define XFS_BLI_CHUNK 128 | 86 | #define XFS_BLI_CHUNK 128 |
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index d7fe28866764..8b792ddf2164 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c | |||
@@ -113,7 +113,10 @@ STATIC void xfs_da_node_unbalance(xfs_da_state_t *state, | |||
113 | STATIC uint xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count); | 113 | STATIC uint xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count); |
114 | STATIC int xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp); | 114 | STATIC int xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp); |
115 | STATIC xfs_dabuf_t *xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra); | 115 | STATIC xfs_dabuf_t *xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra); |
116 | 116 | STATIC int xfs_da_blk_unlink(xfs_da_state_t *state, | |
117 | xfs_da_state_blk_t *drop_blk, | ||
118 | xfs_da_state_blk_t *save_blk); | ||
119 | STATIC void xfs_da_state_kill_altpath(xfs_da_state_t *state); | ||
117 | 120 | ||
118 | /*======================================================================== | 121 | /*======================================================================== |
119 | * Routines used for growing the Btree. | 122 | * Routines used for growing the Btree. |
@@ -1424,7 +1427,7 @@ xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count) | |||
1424 | /* | 1427 | /* |
1425 | * Unlink a block from a doubly linked list of blocks. | 1428 | * Unlink a block from a doubly linked list of blocks. |
1426 | */ | 1429 | */ |
1427 | int /* error */ | 1430 | STATIC int /* error */ |
1428 | xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, | 1431 | xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, |
1429 | xfs_da_state_blk_t *save_blk) | 1432 | xfs_da_state_blk_t *save_blk) |
1430 | { | 1433 | { |
@@ -2381,7 +2384,7 @@ xfs_da_state_alloc(void) | |||
2381 | /* | 2384 | /* |
2382 | * Kill the altpath contents of a da-state structure. | 2385 | * Kill the altpath contents of a da-state structure. |
2383 | */ | 2386 | */ |
2384 | void | 2387 | STATIC void |
2385 | xfs_da_state_kill_altpath(xfs_da_state_t *state) | 2388 | xfs_da_state_kill_altpath(xfs_da_state_t *state) |
2386 | { | 2389 | { |
2387 | int i; | 2390 | int i; |
diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index 9fc699d96995..3a9b9e809c60 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h | |||
@@ -296,8 +296,6 @@ int xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, | |||
296 | /* | 296 | /* |
297 | * Utility routines. | 297 | * Utility routines. |
298 | */ | 298 | */ |
299 | int xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, | ||
300 | xfs_da_state_blk_t *save_blk); | ||
301 | int xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, | 299 | int xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, |
302 | xfs_da_state_blk_t *new_blk); | 300 | xfs_da_state_blk_t *new_blk); |
303 | 301 | ||
@@ -320,7 +318,6 @@ uint xfs_da_hashname(uchar_t *name_string, int name_length); | |||
320 | uint xfs_da_log2_roundup(uint i); | 318 | uint xfs_da_log2_roundup(uint i); |
321 | xfs_da_state_t *xfs_da_state_alloc(void); | 319 | xfs_da_state_t *xfs_da_state_alloc(void); |
322 | void xfs_da_state_free(xfs_da_state_t *state); | 320 | void xfs_da_state_free(xfs_da_state_t *state); |
323 | void xfs_da_state_kill_altpath(xfs_da_state_t *state); | ||
324 | 321 | ||
325 | void xfs_da_buf_done(xfs_dabuf_t *dabuf); | 322 | void xfs_da_buf_done(xfs_dabuf_t *dabuf); |
326 | void xfs_da_log_buf(struct xfs_trans *tp, xfs_dabuf_t *dabuf, uint first, | 323 | void xfs_da_log_buf(struct xfs_trans *tp, xfs_dabuf_t *dabuf, uint first, |
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 63abdc2ac7f4..681be5c93af5 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c | |||
@@ -180,9 +180,10 @@ xfs_swapext( | |||
180 | goto error0; | 180 | goto error0; |
181 | } | 181 | } |
182 | 182 | ||
183 | if (VN_CACHED(tvp) != 0) | 183 | if (VN_CACHED(tvp) != 0) { |
184 | xfs_inval_cached_pages(XFS_ITOV(tip), &(tip->i_iocore), | 184 | xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1); |
185 | (xfs_off_t)0, 0, 0); | 185 | VOP_FLUSHINVAL_PAGES(tvp, 0, -1, FI_REMAPF_LOCKED); |
186 | } | ||
186 | 187 | ||
187 | /* Verify O_DIRECT for ftmp */ | 188 | /* Verify O_DIRECT for ftmp */ |
188 | if (VN_CACHED(tvp) != 0) { | 189 | if (VN_CACHED(tvp) != 0) { |
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c index db9887a107de..a0aa0e44ff9d 100644 --- a/fs/xfs/xfs_dir2_data.c +++ b/fs/xfs/xfs_dir2_data.c | |||
@@ -304,7 +304,7 @@ xfs_dir2_data_freeinsert( | |||
304 | /* | 304 | /* |
305 | * Remove a bestfree entry from the table. | 305 | * Remove a bestfree entry from the table. |
306 | */ | 306 | */ |
307 | void | 307 | STATIC void |
308 | xfs_dir2_data_freeremove( | 308 | xfs_dir2_data_freeremove( |
309 | xfs_dir2_data_t *d, /* data block pointer */ | 309 | xfs_dir2_data_t *d, /* data block pointer */ |
310 | xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */ | 310 | xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */ |
diff --git a/fs/xfs/xfs_dir2_data.h b/fs/xfs/xfs_dir2_data.h index 3f02294ccff0..476cac920bf5 100644 --- a/fs/xfs/xfs_dir2_data.h +++ b/fs/xfs/xfs_dir2_data.h | |||
@@ -193,10 +193,6 @@ extern xfs_dir2_data_free_t * | |||
193 | xfs_dir2_data_unused_t *dup, int *loghead); | 193 | xfs_dir2_data_unused_t *dup, int *loghead); |
194 | 194 | ||
195 | extern void | 195 | extern void |
196 | xfs_dir2_data_freeremove(xfs_dir2_data_t *d, | ||
197 | xfs_dir2_data_free_t *dfp, int *loghead); | ||
198 | |||
199 | extern void | ||
200 | xfs_dir2_data_freescan(struct xfs_mount *mp, xfs_dir2_data_t *d, | 196 | xfs_dir2_data_freescan(struct xfs_mount *mp, xfs_dir2_data_t *d, |
201 | int *loghead, char *aendp); | 197 | int *loghead, char *aendp); |
202 | 198 | ||
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 262d1e86df30..056f5283904b 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c | |||
@@ -77,6 +77,10 @@ static void xfs_dir2_leaf_check(xfs_inode_t *dp, xfs_dabuf_t *bp); | |||
77 | #endif | 77 | #endif |
78 | static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **lbpp, | 78 | static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **lbpp, |
79 | int *indexp, xfs_dabuf_t **dbpp); | 79 | int *indexp, xfs_dabuf_t **dbpp); |
80 | static void xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, | ||
81 | int first, int last); | ||
82 | static void xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp); | ||
83 | |||
80 | 84 | ||
81 | /* | 85 | /* |
82 | * Convert a block form directory to a leaf form directory. | 86 | * Convert a block form directory to a leaf form directory. |
@@ -1214,7 +1218,7 @@ xfs_dir2_leaf_init( | |||
1214 | /* | 1218 | /* |
1215 | * Log the bests entries indicated from a leaf1 block. | 1219 | * Log the bests entries indicated from a leaf1 block. |
1216 | */ | 1220 | */ |
1217 | void | 1221 | static void |
1218 | xfs_dir2_leaf_log_bests( | 1222 | xfs_dir2_leaf_log_bests( |
1219 | xfs_trans_t *tp, /* transaction pointer */ | 1223 | xfs_trans_t *tp, /* transaction pointer */ |
1220 | xfs_dabuf_t *bp, /* leaf buffer */ | 1224 | xfs_dabuf_t *bp, /* leaf buffer */ |
@@ -1278,7 +1282,7 @@ xfs_dir2_leaf_log_header( | |||
1278 | /* | 1282 | /* |
1279 | * Log the tail of the leaf1 block. | 1283 | * Log the tail of the leaf1 block. |
1280 | */ | 1284 | */ |
1281 | void | 1285 | STATIC void |
1282 | xfs_dir2_leaf_log_tail( | 1286 | xfs_dir2_leaf_log_tail( |
1283 | xfs_trans_t *tp, /* transaction pointer */ | 1287 | xfs_trans_t *tp, /* transaction pointer */ |
1284 | xfs_dabuf_t *bp) /* leaf buffer */ | 1288 | xfs_dabuf_t *bp) /* leaf buffer */ |
diff --git a/fs/xfs/xfs_dir2_leaf.h b/fs/xfs/xfs_dir2_leaf.h index 7f20eee56a52..3303cd6f4c00 100644 --- a/fs/xfs/xfs_dir2_leaf.h +++ b/fs/xfs/xfs_dir2_leaf.h | |||
@@ -330,15 +330,8 @@ extern void | |||
330 | int first, int last); | 330 | int first, int last); |
331 | 331 | ||
332 | extern void | 332 | extern void |
333 | xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, | ||
334 | int first, int last); | ||
335 | |||
336 | extern void | ||
337 | xfs_dir2_leaf_log_header(struct xfs_trans *tp, struct xfs_dabuf *bp); | 333 | xfs_dir2_leaf_log_header(struct xfs_trans *tp, struct xfs_dabuf *bp); |
338 | 334 | ||
339 | extern void | ||
340 | xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp); | ||
341 | |||
342 | extern int | 335 | extern int |
343 | xfs_dir2_leaf_lookup(struct xfs_da_args *args); | 336 | xfs_dir2_leaf_lookup(struct xfs_da_args *args); |
344 | 337 | ||
diff --git a/fs/xfs/xfs_dir_leaf.c b/fs/xfs/xfs_dir_leaf.c index 617018d6bbdc..c2ea6171fb0e 100644 --- a/fs/xfs/xfs_dir_leaf.c +++ b/fs/xfs/xfs_dir_leaf.c | |||
@@ -91,6 +91,10 @@ STATIC int xfs_dir_leaf_figure_balance(xfs_da_state_t *state, | |||
91 | int *number_entries_in_blk1, | 91 | int *number_entries_in_blk1, |
92 | int *number_namebytes_in_blk1); | 92 | int *number_namebytes_in_blk1); |
93 | 93 | ||
94 | STATIC int xfs_dir_leaf_create(struct xfs_da_args *args, | ||
95 | xfs_dablk_t which_block, | ||
96 | struct xfs_dabuf **bpp); | ||
97 | |||
94 | /* | 98 | /* |
95 | * Utility routines. | 99 | * Utility routines. |
96 | */ | 100 | */ |
@@ -781,7 +785,7 @@ xfs_dir_leaf_to_node(xfs_da_args_t *args) | |||
781 | * Create the initial contents of a leaf directory | 785 | * Create the initial contents of a leaf directory |
782 | * or a leaf in a node directory. | 786 | * or a leaf in a node directory. |
783 | */ | 787 | */ |
784 | int | 788 | STATIC int |
785 | xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) | 789 | xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) |
786 | { | 790 | { |
787 | xfs_dir_leafblock_t *leaf; | 791 | xfs_dir_leafblock_t *leaf; |
diff --git a/fs/xfs/xfs_dir_leaf.h b/fs/xfs/xfs_dir_leaf.h index 00d68d33cc7a..dd423ce1bc8d 100644 --- a/fs/xfs/xfs_dir_leaf.h +++ b/fs/xfs/xfs_dir_leaf.h | |||
@@ -202,8 +202,6 @@ int xfs_dir_leaf_to_shortform(struct xfs_da_args *args); | |||
202 | /* | 202 | /* |
203 | * Routines used for growing the Btree. | 203 | * Routines used for growing the Btree. |
204 | */ | 204 | */ |
205 | int xfs_dir_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, | ||
206 | struct xfs_dabuf **bpp); | ||
207 | int xfs_dir_leaf_split(struct xfs_da_state *state, | 205 | int xfs_dir_leaf_split(struct xfs_da_state *state, |
208 | struct xfs_da_state_blk *oldblk, | 206 | struct xfs_da_state_blk *oldblk, |
209 | struct xfs_da_state_blk *newblk); | 207 | struct xfs_da_state_blk *newblk); |
diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h index 55ae3e67d245..55c17adaaa37 100644 --- a/fs/xfs/xfs_dmapi.h +++ b/fs/xfs/xfs_dmapi.h | |||
@@ -166,27 +166,32 @@ typedef enum { | |||
166 | #define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */ | 166 | #define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */ |
167 | #define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */ | 167 | #define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */ |
168 | #define DM_FLAGS_ISEM 0x004 /* thread holds i_sem */ | 168 | #define DM_FLAGS_ISEM 0x004 /* thread holds i_sem */ |
169 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) | ||
170 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21) | ||
171 | /* i_alloc_sem was added in 2.4.22-pre1 */ | ||
172 | #define DM_FLAGS_IALLOCSEM_RD 0x010 /* thread holds i_alloc_sem rd */ | 169 | #define DM_FLAGS_IALLOCSEM_RD 0x010 /* thread holds i_alloc_sem rd */ |
173 | #define DM_FLAGS_IALLOCSEM_WR 0x020 /* thread holds i_alloc_sem wr */ | 170 | #define DM_FLAGS_IALLOCSEM_WR 0x020 /* thread holds i_alloc_sem wr */ |
174 | #endif | ||
175 | #endif | ||
176 | 171 | ||
177 | /* | 172 | /* |
178 | * Based on IO_ISDIRECT, decide which i_ flag is set. | 173 | * Based on IO_ISDIRECT, decide which i_ flag is set. |
179 | */ | 174 | */ |
180 | #ifdef DM_FLAGS_IALLOCSEM_RD | 175 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) |
176 | #define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \ | ||
177 | DM_FLAGS_ISEM : 0) | ||
178 | #define DM_SEM_FLAG_WR (DM_FLAGS_IALLOCSEM_WR | DM_FLAGS_ISEM) | ||
179 | #endif | ||
180 | |||
181 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) && \ | ||
182 | (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22)) | ||
181 | #define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \ | 183 | #define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \ |
182 | DM_FLAGS_IALLOCSEM_RD : DM_FLAGS_ISEM) | 184 | DM_FLAGS_IALLOCSEM_RD : DM_FLAGS_ISEM) |
183 | #define DM_SEM_FLAG_WR (DM_FLAGS_IALLOCSEM_WR | DM_FLAGS_ISEM) | 185 | #define DM_SEM_FLAG_WR (DM_FLAGS_IALLOCSEM_WR | DM_FLAGS_ISEM) |
184 | #else | 186 | #endif |
187 | |||
188 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,21) | ||
185 | #define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \ | 189 | #define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \ |
186 | 0 : DM_FLAGS_ISEM) | 190 | 0 : DM_FLAGS_ISEM) |
187 | #define DM_SEM_FLAG_WR (DM_FLAGS_ISEM) | 191 | #define DM_SEM_FLAG_WR (DM_FLAGS_ISEM) |
188 | #endif | 192 | #endif |
189 | 193 | ||
194 | |||
190 | /* | 195 | /* |
191 | * Macros to turn caller specified delay/block flags into | 196 | * Macros to turn caller specified delay/block flags into |
192 | * dm_send_xxxx_event flag DM_FLAGS_NDELAY. | 197 | * dm_send_xxxx_event flag DM_FLAGS_NDELAY. |
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c index bbe1dea11c08..dcd3fdd5c1f7 100644 --- a/fs/xfs/xfs_error.c +++ b/fs/xfs/xfs_error.c | |||
@@ -280,7 +280,7 @@ xfs_error_report( | |||
280 | } | 280 | } |
281 | } | 281 | } |
282 | 282 | ||
283 | void | 283 | STATIC void |
284 | xfs_hex_dump(void *p, int length) | 284 | xfs_hex_dump(void *p, int length) |
285 | { | 285 | { |
286 | __uint8_t *uip = (__uint8_t*)p; | 286 | __uint8_t *uip = (__uint8_t*)p; |
diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h index 6bc0535c0a65..52ee2b90b5ed 100644 --- a/fs/xfs/xfs_error.h +++ b/fs/xfs/xfs_error.h | |||
@@ -73,9 +73,6 @@ xfs_corruption_error( | |||
73 | int linenum, | 73 | int linenum, |
74 | inst_t *ra); | 74 | inst_t *ra); |
75 | 75 | ||
76 | extern void | ||
77 | xfs_hex_dump(void *p, int length); | ||
78 | |||
79 | #define XFS_ERROR_REPORT(e, lvl, mp) \ | 76 | #define XFS_ERROR_REPORT(e, lvl, mp) \ |
80 | xfs_error_report(e, lvl, mp, __FILE__, __LINE__, __return_address) | 77 | xfs_error_report(e, lvl, mp, __FILE__, __LINE__, __return_address) |
81 | #define XFS_CORRUPTION_ERROR(e, lvl, mp, mem) \ | 78 | #define XFS_CORRUPTION_ERROR(e, lvl, mp, mem) \ |
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 5eafd5b63211..db7cbd1bc857 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c | |||
@@ -59,6 +59,18 @@ STATIC void xfs_efi_item_abort(xfs_efi_log_item_t *); | |||
59 | STATIC void xfs_efd_item_abort(xfs_efd_log_item_t *); | 59 | STATIC void xfs_efd_item_abort(xfs_efd_log_item_t *); |
60 | 60 | ||
61 | 61 | ||
62 | void | ||
63 | xfs_efi_item_free(xfs_efi_log_item_t *efip) | ||
64 | { | ||
65 | int nexts = efip->efi_format.efi_nextents; | ||
66 | |||
67 | if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { | ||
68 | kmem_free(efip, sizeof(xfs_efi_log_item_t) + | ||
69 | (nexts - 1) * sizeof(xfs_extent_t)); | ||
70 | } else { | ||
71 | kmem_zone_free(xfs_efi_zone, efip); | ||
72 | } | ||
73 | } | ||
62 | 74 | ||
63 | /* | 75 | /* |
64 | * This returns the number of iovecs needed to log the given efi item. | 76 | * This returns the number of iovecs needed to log the given efi item. |
@@ -120,8 +132,6 @@ xfs_efi_item_pin(xfs_efi_log_item_t *efip) | |||
120 | STATIC void | 132 | STATIC void |
121 | xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale) | 133 | xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale) |
122 | { | 134 | { |
123 | int nexts; | ||
124 | int size; | ||
125 | xfs_mount_t *mp; | 135 | xfs_mount_t *mp; |
126 | SPLDECL(s); | 136 | SPLDECL(s); |
127 | 137 | ||
@@ -132,21 +142,11 @@ xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale) | |||
132 | * xfs_trans_delete_ail() drops the AIL lock. | 142 | * xfs_trans_delete_ail() drops the AIL lock. |
133 | */ | 143 | */ |
134 | xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); | 144 | xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); |
135 | 145 | xfs_efi_item_free(efip); | |
136 | nexts = efip->efi_format.efi_nextents; | ||
137 | if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { | ||
138 | size = sizeof(xfs_efi_log_item_t); | ||
139 | size += (nexts - 1) * sizeof(xfs_extent_t); | ||
140 | kmem_free(efip, size); | ||
141 | } else { | ||
142 | kmem_zone_free(xfs_efi_zone, efip); | ||
143 | } | ||
144 | } else { | 146 | } else { |
145 | efip->efi_flags |= XFS_EFI_COMMITTED; | 147 | efip->efi_flags |= XFS_EFI_COMMITTED; |
146 | AIL_UNLOCK(mp, s); | 148 | AIL_UNLOCK(mp, s); |
147 | } | 149 | } |
148 | |||
149 | return; | ||
150 | } | 150 | } |
151 | 151 | ||
152 | /* | 152 | /* |
@@ -159,8 +159,6 @@ xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale) | |||
159 | STATIC void | 159 | STATIC void |
160 | xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) | 160 | xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) |
161 | { | 161 | { |
162 | int nexts; | ||
163 | int size; | ||
164 | xfs_mount_t *mp; | 162 | xfs_mount_t *mp; |
165 | xfs_log_item_desc_t *lidp; | 163 | xfs_log_item_desc_t *lidp; |
166 | SPLDECL(s); | 164 | SPLDECL(s); |
@@ -178,23 +176,11 @@ xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) | |||
178 | * xfs_trans_delete_ail() drops the AIL lock. | 176 | * xfs_trans_delete_ail() drops the AIL lock. |
179 | */ | 177 | */ |
180 | xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); | 178 | xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); |
181 | /* | 179 | xfs_efi_item_free(efip); |
182 | * now free the item itself | ||
183 | */ | ||
184 | nexts = efip->efi_format.efi_nextents; | ||
185 | if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { | ||
186 | size = sizeof(xfs_efi_log_item_t); | ||
187 | size += (nexts - 1) * sizeof(xfs_extent_t); | ||
188 | kmem_free(efip, size); | ||
189 | } else { | ||
190 | kmem_zone_free(xfs_efi_zone, efip); | ||
191 | } | ||
192 | } else { | 180 | } else { |
193 | efip->efi_flags |= XFS_EFI_COMMITTED; | 181 | efip->efi_flags |= XFS_EFI_COMMITTED; |
194 | AIL_UNLOCK(mp, s); | 182 | AIL_UNLOCK(mp, s); |
195 | } | 183 | } |
196 | |||
197 | return; | ||
198 | } | 184 | } |
199 | 185 | ||
200 | /* | 186 | /* |
@@ -245,18 +231,7 @@ xfs_efi_item_committed(xfs_efi_log_item_t *efip, xfs_lsn_t lsn) | |||
245 | STATIC void | 231 | STATIC void |
246 | xfs_efi_item_abort(xfs_efi_log_item_t *efip) | 232 | xfs_efi_item_abort(xfs_efi_log_item_t *efip) |
247 | { | 233 | { |
248 | int nexts; | 234 | xfs_efi_item_free(efip); |
249 | int size; | ||
250 | |||
251 | nexts = efip->efi_format.efi_nextents; | ||
252 | if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { | ||
253 | size = sizeof(xfs_efi_log_item_t); | ||
254 | size += (nexts - 1) * sizeof(xfs_extent_t); | ||
255 | kmem_free(efip, size); | ||
256 | } else { | ||
257 | kmem_zone_free(xfs_efi_zone, efip); | ||
258 | } | ||
259 | return; | ||
260 | } | 235 | } |
261 | 236 | ||
262 | /* | 237 | /* |
@@ -288,7 +263,7 @@ xfs_efi_item_committing(xfs_efi_log_item_t *efip, xfs_lsn_t lsn) | |||
288 | /* | 263 | /* |
289 | * This is the ops vector shared by all efi log items. | 264 | * This is the ops vector shared by all efi log items. |
290 | */ | 265 | */ |
291 | struct xfs_item_ops xfs_efi_item_ops = { | 266 | STATIC struct xfs_item_ops xfs_efi_item_ops = { |
292 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_efi_item_size, | 267 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_efi_item_size, |
293 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) | 268 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) |
294 | xfs_efi_item_format, | 269 | xfs_efi_item_format, |
@@ -355,8 +330,6 @@ xfs_efi_release(xfs_efi_log_item_t *efip, | |||
355 | { | 330 | { |
356 | xfs_mount_t *mp; | 331 | xfs_mount_t *mp; |
357 | int extents_left; | 332 | int extents_left; |
358 | uint size; | ||
359 | int nexts; | ||
360 | SPLDECL(s); | 333 | SPLDECL(s); |
361 | 334 | ||
362 | mp = efip->efi_item.li_mountp; | 335 | mp = efip->efi_item.li_mountp; |
@@ -372,20 +345,10 @@ xfs_efi_release(xfs_efi_log_item_t *efip, | |||
372 | * xfs_trans_delete_ail() drops the AIL lock. | 345 | * xfs_trans_delete_ail() drops the AIL lock. |
373 | */ | 346 | */ |
374 | xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); | 347 | xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); |
348 | xfs_efi_item_free(efip); | ||
375 | } else { | 349 | } else { |
376 | AIL_UNLOCK(mp, s); | 350 | AIL_UNLOCK(mp, s); |
377 | } | 351 | } |
378 | |||
379 | if (extents_left == 0) { | ||
380 | nexts = efip->efi_format.efi_nextents; | ||
381 | if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { | ||
382 | size = sizeof(xfs_efi_log_item_t); | ||
383 | size += (nexts - 1) * sizeof(xfs_extent_t); | ||
384 | kmem_free(efip, size); | ||
385 | } else { | ||
386 | kmem_zone_free(xfs_efi_zone, efip); | ||
387 | } | ||
388 | } | ||
389 | } | 352 | } |
390 | 353 | ||
391 | /* | 354 | /* |
@@ -398,8 +361,6 @@ STATIC void | |||
398 | xfs_efi_cancel( | 361 | xfs_efi_cancel( |
399 | xfs_efi_log_item_t *efip) | 362 | xfs_efi_log_item_t *efip) |
400 | { | 363 | { |
401 | int nexts; | ||
402 | int size; | ||
403 | xfs_mount_t *mp; | 364 | xfs_mount_t *mp; |
404 | SPLDECL(s); | 365 | SPLDECL(s); |
405 | 366 | ||
@@ -410,26 +371,25 @@ xfs_efi_cancel( | |||
410 | * xfs_trans_delete_ail() drops the AIL lock. | 371 | * xfs_trans_delete_ail() drops the AIL lock. |
411 | */ | 372 | */ |
412 | xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); | 373 | xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); |
413 | 374 | xfs_efi_item_free(efip); | |
414 | nexts = efip->efi_format.efi_nextents; | ||
415 | if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { | ||
416 | size = sizeof(xfs_efi_log_item_t); | ||
417 | size += (nexts - 1) * sizeof(xfs_extent_t); | ||
418 | kmem_free(efip, size); | ||
419 | } else { | ||
420 | kmem_zone_free(xfs_efi_zone, efip); | ||
421 | } | ||
422 | } else { | 375 | } else { |
423 | efip->efi_flags |= XFS_EFI_CANCELED; | 376 | efip->efi_flags |= XFS_EFI_CANCELED; |
424 | AIL_UNLOCK(mp, s); | 377 | AIL_UNLOCK(mp, s); |
425 | } | 378 | } |
426 | |||
427 | return; | ||
428 | } | 379 | } |
429 | 380 | ||
381 | STATIC void | ||
382 | xfs_efd_item_free(xfs_efd_log_item_t *efdp) | ||
383 | { | ||
384 | int nexts = efdp->efd_format.efd_nextents; | ||
430 | 385 | ||
431 | 386 | if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { | |
432 | 387 | kmem_free(efdp, sizeof(xfs_efd_log_item_t) + | |
388 | (nexts - 1) * sizeof(xfs_extent_t)); | ||
389 | } else { | ||
390 | kmem_zone_free(xfs_efd_zone, efdp); | ||
391 | } | ||
392 | } | ||
433 | 393 | ||
434 | /* | 394 | /* |
435 | * This returns the number of iovecs needed to log the given efd item. | 395 | * This returns the number of iovecs needed to log the given efd item. |
@@ -533,9 +493,6 @@ xfs_efd_item_unlock(xfs_efd_log_item_t *efdp) | |||
533 | STATIC xfs_lsn_t | 493 | STATIC xfs_lsn_t |
534 | xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn) | 494 | xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn) |
535 | { | 495 | { |
536 | uint size; | ||
537 | int nexts; | ||
538 | |||
539 | /* | 496 | /* |
540 | * If we got a log I/O error, it's always the case that the LR with the | 497 | * If we got a log I/O error, it's always the case that the LR with the |
541 | * EFI got unpinned and freed before the EFD got aborted. | 498 | * EFI got unpinned and freed before the EFD got aborted. |
@@ -543,15 +500,7 @@ xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn) | |||
543 | if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0) | 500 | if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0) |
544 | xfs_efi_release(efdp->efd_efip, efdp->efd_format.efd_nextents); | 501 | xfs_efi_release(efdp->efd_efip, efdp->efd_format.efd_nextents); |
545 | 502 | ||
546 | nexts = efdp->efd_format.efd_nextents; | 503 | xfs_efd_item_free(efdp); |
547 | if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { | ||
548 | size = sizeof(xfs_efd_log_item_t); | ||
549 | size += (nexts - 1) * sizeof(xfs_extent_t); | ||
550 | kmem_free(efdp, size); | ||
551 | } else { | ||
552 | kmem_zone_free(xfs_efd_zone, efdp); | ||
553 | } | ||
554 | |||
555 | return (xfs_lsn_t)-1; | 504 | return (xfs_lsn_t)-1; |
556 | } | 505 | } |
557 | 506 | ||
@@ -565,9 +514,6 @@ xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn) | |||
565 | STATIC void | 514 | STATIC void |
566 | xfs_efd_item_abort(xfs_efd_log_item_t *efdp) | 515 | xfs_efd_item_abort(xfs_efd_log_item_t *efdp) |
567 | { | 516 | { |
568 | int nexts; | ||
569 | int size; | ||
570 | |||
571 | /* | 517 | /* |
572 | * If we got a log I/O error, it's always the case that the LR with the | 518 | * If we got a log I/O error, it's always the case that the LR with the |
573 | * EFI got unpinned and freed before the EFD got aborted. So don't | 519 | * EFI got unpinned and freed before the EFD got aborted. So don't |
@@ -576,15 +522,7 @@ xfs_efd_item_abort(xfs_efd_log_item_t *efdp) | |||
576 | if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0) | 522 | if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0) |
577 | xfs_efi_cancel(efdp->efd_efip); | 523 | xfs_efi_cancel(efdp->efd_efip); |
578 | 524 | ||
579 | nexts = efdp->efd_format.efd_nextents; | 525 | xfs_efd_item_free(efdp); |
580 | if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { | ||
581 | size = sizeof(xfs_efd_log_item_t); | ||
582 | size += (nexts - 1) * sizeof(xfs_extent_t); | ||
583 | kmem_free(efdp, size); | ||
584 | } else { | ||
585 | kmem_zone_free(xfs_efd_zone, efdp); | ||
586 | } | ||
587 | return; | ||
588 | } | 526 | } |
589 | 527 | ||
590 | /* | 528 | /* |
@@ -615,7 +553,7 @@ xfs_efd_item_committing(xfs_efd_log_item_t *efip, xfs_lsn_t lsn) | |||
615 | /* | 553 | /* |
616 | * This is the ops vector shared by all efd log items. | 554 | * This is the ops vector shared by all efd log items. |
617 | */ | 555 | */ |
618 | struct xfs_item_ops xfs_efd_item_ops = { | 556 | STATIC struct xfs_item_ops xfs_efd_item_ops = { |
619 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_efd_item_size, | 557 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_efd_item_size, |
620 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) | 558 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) |
621 | xfs_efd_item_format, | 559 | xfs_efd_item_format, |
diff --git a/fs/xfs/xfs_extfree_item.h b/fs/xfs/xfs_extfree_item.h index 7122d6101d15..d433bac9f59d 100644 --- a/fs/xfs/xfs_extfree_item.h +++ b/fs/xfs/xfs_extfree_item.h | |||
@@ -118,6 +118,8 @@ xfs_efi_log_item_t *xfs_efi_init(struct xfs_mount *, uint); | |||
118 | xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *, | 118 | xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *, |
119 | uint); | 119 | uint); |
120 | 120 | ||
121 | void xfs_efi_item_free(xfs_efi_log_item_t *); | ||
122 | |||
121 | #endif /* __KERNEL__ */ | 123 | #endif /* __KERNEL__ */ |
122 | 124 | ||
123 | #endif /* __XFS_EXTFREE_ITEM_H__ */ | 125 | #endif /* __XFS_EXTFREE_ITEM_H__ */ |
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index 6ee8443bf9d3..095af0a5cff3 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h | |||
@@ -60,7 +60,8 @@ struct fsxattr { | |||
60 | __u32 fsx_xflags; /* xflags field value (get/set) */ | 60 | __u32 fsx_xflags; /* xflags field value (get/set) */ |
61 | __u32 fsx_extsize; /* extsize field value (get/set)*/ | 61 | __u32 fsx_extsize; /* extsize field value (get/set)*/ |
62 | __u32 fsx_nextents; /* nextents field value (get) */ | 62 | __u32 fsx_nextents; /* nextents field value (get) */ |
63 | unsigned char fsx_pad[16]; | 63 | __u32 fsx_projid; /* project identifier (get/set) */ |
64 | unsigned char fsx_pad[12]; | ||
64 | }; | 65 | }; |
65 | #endif | 66 | #endif |
66 | 67 | ||
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 21213057c27f..ca535d613190 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
@@ -559,32 +559,6 @@ xfs_reserve_blocks( | |||
559 | return(0); | 559 | return(0); |
560 | } | 560 | } |
561 | 561 | ||
562 | void | ||
563 | xfs_fs_log_dummy(xfs_mount_t *mp) | ||
564 | { | ||
565 | xfs_trans_t *tp; | ||
566 | xfs_inode_t *ip; | ||
567 | |||
568 | |||
569 | tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); | ||
570 | atomic_inc(&mp->m_active_trans); | ||
571 | if (xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0)) { | ||
572 | xfs_trans_cancel(tp, 0); | ||
573 | return; | ||
574 | } | ||
575 | |||
576 | ip = mp->m_rootip; | ||
577 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
578 | |||
579 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | ||
580 | xfs_trans_ihold(tp, ip); | ||
581 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
582 | xfs_trans_set_sync(tp); | ||
583 | xfs_trans_commit(tp, 0, NULL); | ||
584 | |||
585 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
586 | } | ||
587 | |||
588 | int | 562 | int |
589 | xfs_fs_goingdown( | 563 | xfs_fs_goingdown( |
590 | xfs_mount_t *mp, | 564 | xfs_mount_t *mp, |
diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h index 803c4d17a057..44be188674a6 100644 --- a/fs/xfs/xfs_ialloc_btree.h +++ b/fs/xfs/xfs_ialloc_btree.h | |||
@@ -100,9 +100,13 @@ xfs_inofree_t xfs_inobt_mask(int i); | |||
100 | #endif | 100 | #endif |
101 | #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_FREE) | 101 | #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_FREE) |
102 | int xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i); | 102 | int xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i); |
103 | #define XFS_INOBT_IS_FREE(rp,i) xfs_inobt_is_free(rp,i) | 103 | #define XFS_INOBT_IS_FREE(rp,i) xfs_inobt_is_free(rp,i) |
104 | #define XFS_INOBT_IS_FREE_DISK(rp,i) xfs_inobt_is_free_disk(rp,i) | ||
104 | #else | 105 | #else |
105 | #define XFS_INOBT_IS_FREE(rp,i) (((rp)->ir_free & XFS_INOBT_MASK(i)) != 0) | 106 | #define XFS_INOBT_IS_FREE(rp,i) \ |
107 | (((rp)->ir_free & XFS_INOBT_MASK(i)) != 0) | ||
108 | #define XFS_INOBT_IS_FREE_DISK(rp,i) \ | ||
109 | ((INT_GET((rp)->ir_free, ARCH_CONVERT) & XFS_INOBT_MASK(i)) != 0) | ||
106 | #endif | 110 | #endif |
107 | #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_SET_FREE) | 111 | #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_SET_FREE) |
108 | void xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i); | 112 | void xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i); |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index bc8c8c7f9039..34bdf5909687 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -146,51 +146,6 @@ xfs_inobp_check( | |||
146 | #endif | 146 | #endif |
147 | 147 | ||
148 | /* | 148 | /* |
149 | * called from bwrite on xfs inode buffers | ||
150 | */ | ||
151 | void | ||
152 | xfs_inobp_bwcheck(xfs_buf_t *bp) | ||
153 | { | ||
154 | xfs_mount_t *mp; | ||
155 | int i; | ||
156 | int j; | ||
157 | xfs_dinode_t *dip; | ||
158 | |||
159 | ASSERT(XFS_BUF_FSPRIVATE3(bp, void *) != NULL); | ||
160 | |||
161 | mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *); | ||
162 | |||
163 | |||
164 | j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; | ||
165 | |||
166 | for (i = 0; i < j; i++) { | ||
167 | dip = (xfs_dinode_t *) xfs_buf_offset(bp, | ||
168 | i * mp->m_sb.sb_inodesize); | ||
169 | if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { | ||
170 | cmn_err(CE_WARN, | ||
171 | "Bad magic # 0x%x in XFS inode buffer 0x%Lx, starting blockno %Ld, offset 0x%x", | ||
172 | INT_GET(dip->di_core.di_magic, ARCH_CONVERT), | ||
173 | (__uint64_t)(__psunsigned_t) bp, | ||
174 | (__int64_t) XFS_BUF_ADDR(bp), | ||
175 | xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); | ||
176 | xfs_fs_cmn_err(CE_WARN, mp, | ||
177 | "corrupt, unmount and run xfs_repair"); | ||
178 | } | ||
179 | if (!dip->di_next_unlinked) { | ||
180 | cmn_err(CE_WARN, | ||
181 | "Bad next_unlinked field (0) in XFS inode buffer 0x%p, starting blockno %Ld, offset 0x%x", | ||
182 | (__uint64_t)(__psunsigned_t) bp, | ||
183 | (__int64_t) XFS_BUF_ADDR(bp), | ||
184 | xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); | ||
185 | xfs_fs_cmn_err(CE_WARN, mp, | ||
186 | "corrupt, unmount and run xfs_repair"); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | return; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * This routine is called to map an inode number within a file | 149 | * This routine is called to map an inode number within a file |
195 | * system to the buffer containing the on-disk version of the | 150 | * system to the buffer containing the on-disk version of the |
196 | * inode. It returns a pointer to the buffer containing the | 151 | * inode. It returns a pointer to the buffer containing the |
@@ -203,7 +158,7 @@ xfs_inobp_bwcheck(xfs_buf_t *bp) | |||
203 | * Use xfs_imap() to determine the size and location of the | 158 | * Use xfs_imap() to determine the size and location of the |
204 | * buffer to read from disk. | 159 | * buffer to read from disk. |
205 | */ | 160 | */ |
206 | int | 161 | STATIC int |
207 | xfs_inotobp( | 162 | xfs_inotobp( |
208 | xfs_mount_t *mp, | 163 | xfs_mount_t *mp, |
209 | xfs_trans_t *tp, | 164 | xfs_trans_t *tp, |
@@ -1247,26 +1202,32 @@ xfs_ialloc( | |||
1247 | case S_IFREG: | 1202 | case S_IFREG: |
1248 | case S_IFDIR: | 1203 | case S_IFDIR: |
1249 | if (unlikely(pip->i_d.di_flags & XFS_DIFLAG_ANY)) { | 1204 | if (unlikely(pip->i_d.di_flags & XFS_DIFLAG_ANY)) { |
1250 | if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) { | 1205 | uint di_flags = 0; |
1251 | if ((mode & S_IFMT) == S_IFDIR) { | 1206 | |
1252 | ip->i_d.di_flags |= XFS_DIFLAG_RTINHERIT; | 1207 | if ((mode & S_IFMT) == S_IFDIR) { |
1253 | } else { | 1208 | if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) |
1254 | ip->i_d.di_flags |= XFS_DIFLAG_REALTIME; | 1209 | di_flags |= XFS_DIFLAG_RTINHERIT; |
1210 | } else { | ||
1211 | if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) { | ||
1212 | di_flags |= XFS_DIFLAG_REALTIME; | ||
1255 | ip->i_iocore.io_flags |= XFS_IOCORE_RT; | 1213 | ip->i_iocore.io_flags |= XFS_IOCORE_RT; |
1256 | } | 1214 | } |
1257 | } | 1215 | } |
1258 | if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) && | 1216 | if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) && |
1259 | xfs_inherit_noatime) | 1217 | xfs_inherit_noatime) |
1260 | ip->i_d.di_flags |= XFS_DIFLAG_NOATIME; | 1218 | di_flags |= XFS_DIFLAG_NOATIME; |
1261 | if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) && | 1219 | if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) && |
1262 | xfs_inherit_nodump) | 1220 | xfs_inherit_nodump) |
1263 | ip->i_d.di_flags |= XFS_DIFLAG_NODUMP; | 1221 | di_flags |= XFS_DIFLAG_NODUMP; |
1264 | if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) && | 1222 | if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) && |
1265 | xfs_inherit_sync) | 1223 | xfs_inherit_sync) |
1266 | ip->i_d.di_flags |= XFS_DIFLAG_SYNC; | 1224 | di_flags |= XFS_DIFLAG_SYNC; |
1267 | if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) && | 1225 | if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) && |
1268 | xfs_inherit_nosymlinks) | 1226 | xfs_inherit_nosymlinks) |
1269 | ip->i_d.di_flags |= XFS_DIFLAG_NOSYMLINKS; | 1227 | di_flags |= XFS_DIFLAG_NOSYMLINKS; |
1228 | if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) | ||
1229 | di_flags |= XFS_DIFLAG_PROJINHERIT; | ||
1230 | ip->i_d.di_flags |= di_flags; | ||
1270 | } | 1231 | } |
1271 | /* FALLTHROUGH */ | 1232 | /* FALLTHROUGH */ |
1272 | case S_IFLNK: | 1233 | case S_IFLNK: |
@@ -2156,7 +2117,7 @@ static __inline__ int xfs_inode_clean(xfs_inode_t *ip) | |||
2156 | (ip->i_update_core == 0)); | 2117 | (ip->i_update_core == 0)); |
2157 | } | 2118 | } |
2158 | 2119 | ||
2159 | void | 2120 | STATIC void |
2160 | xfs_ifree_cluster( | 2121 | xfs_ifree_cluster( |
2161 | xfs_inode_t *free_ip, | 2122 | xfs_inode_t *free_ip, |
2162 | xfs_trans_t *tp, | 2123 | xfs_trans_t *tp, |
@@ -2875,7 +2836,7 @@ xfs_iunpin( | |||
2875 | * be subsequently pinned once someone is waiting for it to be | 2836 | * be subsequently pinned once someone is waiting for it to be |
2876 | * unpinned. | 2837 | * unpinned. |
2877 | */ | 2838 | */ |
2878 | void | 2839 | STATIC void |
2879 | xfs_iunpin_wait( | 2840 | xfs_iunpin_wait( |
2880 | xfs_inode_t *ip) | 2841 | xfs_inode_t *ip) |
2881 | { | 2842 | { |
@@ -3601,107 +3562,43 @@ corrupt_out: | |||
3601 | 3562 | ||
3602 | 3563 | ||
3603 | /* | 3564 | /* |
3604 | * Flush all inactive inodes in mp. Return true if no user references | 3565 | * Flush all inactive inodes in mp. |
3605 | * were found, false otherwise. | ||
3606 | */ | 3566 | */ |
3607 | int | 3567 | void |
3608 | xfs_iflush_all( | 3568 | xfs_iflush_all( |
3609 | xfs_mount_t *mp, | 3569 | xfs_mount_t *mp) |
3610 | int flag) | ||
3611 | { | 3570 | { |
3612 | int busy; | ||
3613 | int done; | ||
3614 | int purged; | ||
3615 | xfs_inode_t *ip; | 3571 | xfs_inode_t *ip; |
3616 | vmap_t vmap; | ||
3617 | vnode_t *vp; | 3572 | vnode_t *vp; |
3618 | 3573 | ||
3619 | busy = done = 0; | 3574 | again: |
3620 | while (!done) { | 3575 | XFS_MOUNT_ILOCK(mp); |
3621 | purged = 0; | 3576 | ip = mp->m_inodes; |
3622 | XFS_MOUNT_ILOCK(mp); | 3577 | if (ip == NULL) |
3623 | ip = mp->m_inodes; | 3578 | goto out; |
3624 | if (ip == NULL) { | ||
3625 | break; | ||
3626 | } | ||
3627 | do { | ||
3628 | /* Make sure we skip markers inserted by sync */ | ||
3629 | if (ip->i_mount == NULL) { | ||
3630 | ip = ip->i_mnext; | ||
3631 | continue; | ||
3632 | } | ||
3633 | |||
3634 | /* | ||
3635 | * It's up to our caller to purge the root | ||
3636 | * and quota vnodes later. | ||
3637 | */ | ||
3638 | vp = XFS_ITOV_NULL(ip); | ||
3639 | |||
3640 | if (!vp) { | ||
3641 | XFS_MOUNT_IUNLOCK(mp); | ||
3642 | xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC); | ||
3643 | purged = 1; | ||
3644 | break; | ||
3645 | } | ||
3646 | 3579 | ||
3647 | if (vn_count(vp) != 0) { | 3580 | do { |
3648 | if (vn_count(vp) == 1 && | 3581 | /* Make sure we skip markers inserted by sync */ |
3649 | (ip == mp->m_rootip || | 3582 | if (ip->i_mount == NULL) { |
3650 | (mp->m_quotainfo && | 3583 | ip = ip->i_mnext; |
3651 | (ip->i_ino == mp->m_sb.sb_uquotino || | 3584 | continue; |
3652 | ip->i_ino == mp->m_sb.sb_gquotino)))) { | 3585 | } |
3653 | 3586 | ||
3654 | ip = ip->i_mnext; | 3587 | vp = XFS_ITOV_NULL(ip); |
3655 | continue; | 3588 | if (!vp) { |
3656 | } | ||
3657 | if (!(flag & XFS_FLUSH_ALL)) { | ||
3658 | busy = 1; | ||
3659 | done = 1; | ||
3660 | break; | ||
3661 | } | ||
3662 | /* | ||
3663 | * Ignore busy inodes but continue flushing | ||
3664 | * others. | ||
3665 | */ | ||
3666 | ip = ip->i_mnext; | ||
3667 | continue; | ||
3668 | } | ||
3669 | /* | ||
3670 | * Sample vp mapping while holding mp locked on MP | ||
3671 | * systems, so we don't purge a reclaimed or | ||
3672 | * nonexistent vnode. We break from the loop | ||
3673 | * since we know that we modify | ||
3674 | * it by pulling ourselves from it in xfs_reclaim() | ||
3675 | * called via vn_purge() below. Set ip to the next | ||
3676 | * entry in the list anyway so we'll know below | ||
3677 | * whether we reached the end or not. | ||
3678 | */ | ||
3679 | VMAP(vp, vmap); | ||
3680 | XFS_MOUNT_IUNLOCK(mp); | 3589 | XFS_MOUNT_IUNLOCK(mp); |
3590 | xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC); | ||
3591 | goto again; | ||
3592 | } | ||
3681 | 3593 | ||
3682 | vn_purge(vp, &vmap); | 3594 | ASSERT(vn_count(vp) == 0); |
3683 | 3595 | ||
3684 | purged = 1; | 3596 | ip = ip->i_mnext; |
3685 | break; | 3597 | } while (ip != mp->m_inodes); |
3686 | } while (ip != mp->m_inodes); | 3598 | out: |
3687 | /* | ||
3688 | * We need to distinguish between when we exit the loop | ||
3689 | * after a purge and when we simply hit the end of the | ||
3690 | * list. We can't use the (ip == mp->m_inodes) test, | ||
3691 | * because when we purge an inode at the start of the list | ||
3692 | * the next inode on the list becomes mp->m_inodes. That | ||
3693 | * would cause such a test to bail out early. The purged | ||
3694 | * variable tells us how we got out of the loop. | ||
3695 | */ | ||
3696 | if (!purged) { | ||
3697 | done = 1; | ||
3698 | } | ||
3699 | } | ||
3700 | XFS_MOUNT_IUNLOCK(mp); | 3599 | XFS_MOUNT_IUNLOCK(mp); |
3701 | return !busy; | ||
3702 | } | 3600 | } |
3703 | 3601 | ||
3704 | |||
3705 | /* | 3602 | /* |
3706 | * xfs_iaccess: check accessibility of inode for mode. | 3603 | * xfs_iaccess: check accessibility of inode for mode. |
3707 | */ | 3604 | */ |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 37e1c316f3b6..54d9e54c7c95 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -412,11 +412,6 @@ void xfs_ifork_next_set(xfs_inode_t *ip, int w, int n); | |||
412 | #define XFS_IFLUSH_DELWRI 5 | 412 | #define XFS_IFLUSH_DELWRI 5 |
413 | 413 | ||
414 | /* | 414 | /* |
415 | * Flags for xfs_iflush_all. | ||
416 | */ | ||
417 | #define XFS_FLUSH_ALL 0x1 | ||
418 | |||
419 | /* | ||
420 | * Flags for xfs_itruncate_start(). | 415 | * Flags for xfs_itruncate_start(). |
421 | */ | 416 | */ |
422 | #define XFS_ITRUNC_DEFINITE 0x1 | 417 | #define XFS_ITRUNC_DEFINITE 0x1 |
@@ -487,8 +482,6 @@ int xfs_finish_reclaim_all(struct xfs_mount *, int); | |||
487 | /* | 482 | /* |
488 | * xfs_inode.c prototypes. | 483 | * xfs_inode.c prototypes. |
489 | */ | 484 | */ |
490 | int xfs_inotobp(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, | ||
491 | xfs_dinode_t **, struct xfs_buf **, int *); | ||
492 | int xfs_itobp(struct xfs_mount *, struct xfs_trans *, | 485 | int xfs_itobp(struct xfs_mount *, struct xfs_trans *, |
493 | xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **, | 486 | xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **, |
494 | xfs_daddr_t); | 487 | xfs_daddr_t); |
@@ -522,7 +515,7 @@ void xfs_ipin(xfs_inode_t *); | |||
522 | void xfs_iunpin(xfs_inode_t *); | 515 | void xfs_iunpin(xfs_inode_t *); |
523 | int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_t *, int); | 516 | int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_t *, int); |
524 | int xfs_iflush(xfs_inode_t *, uint); | 517 | int xfs_iflush(xfs_inode_t *, uint); |
525 | int xfs_iflush_all(struct xfs_mount *, int); | 518 | void xfs_iflush_all(struct xfs_mount *); |
526 | int xfs_iaccess(xfs_inode_t *, mode_t, cred_t *); | 519 | int xfs_iaccess(xfs_inode_t *, mode_t, cred_t *); |
527 | uint xfs_iroundup(uint); | 520 | uint xfs_iroundup(uint); |
528 | void xfs_ichgtime(xfs_inode_t *, int); | 521 | void xfs_ichgtime(xfs_inode_t *, int); |
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 768cb1816b8e..0eed30f5cb19 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c | |||
@@ -910,7 +910,7 @@ xfs_inode_item_committing( | |||
910 | /* | 910 | /* |
911 | * This is the ops vector shared by all buf log items. | 911 | * This is the ops vector shared by all buf log items. |
912 | */ | 912 | */ |
913 | struct xfs_item_ops xfs_inode_item_ops = { | 913 | STATIC struct xfs_item_ops xfs_inode_item_ops = { |
914 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_inode_item_size, | 914 | .iop_size = (uint(*)(xfs_log_item_t*))xfs_inode_item_size, |
915 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) | 915 | .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) |
916 | xfs_inode_item_format, | 916 | xfs_inode_item_format, |
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 991f8a61f7c4..2edd6769e5d3 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
@@ -278,7 +278,9 @@ phase2: | |||
278 | switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE|BMAPI_UNWRITTEN)) { | 278 | switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE|BMAPI_UNWRITTEN)) { |
279 | case BMAPI_WRITE: | 279 | case BMAPI_WRITE: |
280 | /* If we found an extent, return it */ | 280 | /* If we found an extent, return it */ |
281 | if (nimaps && (imap.br_startblock != HOLESTARTBLOCK)) { | 281 | if (nimaps && |
282 | (imap.br_startblock != HOLESTARTBLOCK) && | ||
283 | (imap.br_startblock != DELAYSTARTBLOCK)) { | ||
282 | xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io, | 284 | xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io, |
283 | offset, count, iomapp, &imap, flags); | 285 | offset, count, iomapp, &imap, flags); |
284 | break; | 286 | break; |
@@ -383,15 +385,15 @@ xfs_iomap_write_direct( | |||
383 | int nimaps, maps; | 385 | int nimaps, maps; |
384 | int error; | 386 | int error; |
385 | int bmapi_flag; | 387 | int bmapi_flag; |
388 | int quota_flag; | ||
386 | int rt; | 389 | int rt; |
387 | xfs_trans_t *tp; | 390 | xfs_trans_t *tp; |
388 | xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp; | 391 | xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp; |
389 | xfs_bmap_free_t free_list; | 392 | xfs_bmap_free_t free_list; |
390 | int aeof; | 393 | int aeof; |
391 | xfs_filblks_t datablocks; | 394 | xfs_filblks_t datablocks, qblocks, resblks; |
392 | int committed; | 395 | int committed; |
393 | int numrtextents; | 396 | int numrtextents; |
394 | uint resblks; | ||
395 | 397 | ||
396 | /* | 398 | /* |
397 | * Make sure that the dquots are there. This doesn't hold | 399 | * Make sure that the dquots are there. This doesn't hold |
@@ -417,7 +419,6 @@ xfs_iomap_write_direct( | |||
417 | xfs_fileoff_t map_last_fsb; | 419 | xfs_fileoff_t map_last_fsb; |
418 | 420 | ||
419 | map_last_fsb = ret_imap->br_blockcount + ret_imap->br_startoff; | 421 | map_last_fsb = ret_imap->br_blockcount + ret_imap->br_startoff; |
420 | |||
421 | if (map_last_fsb < last_fsb) { | 422 | if (map_last_fsb < last_fsb) { |
422 | last_fsb = map_last_fsb; | 423 | last_fsb = map_last_fsb; |
423 | count_fsb = last_fsb - offset_fsb; | 424 | count_fsb = last_fsb - offset_fsb; |
@@ -426,56 +427,47 @@ xfs_iomap_write_direct( | |||
426 | } | 427 | } |
427 | 428 | ||
428 | /* | 429 | /* |
429 | * determine if reserving space on | 430 | * Determine if reserving space on the data or realtime partition. |
430 | * the data or realtime partition. | ||
431 | */ | 431 | */ |
432 | if ((rt = XFS_IS_REALTIME_INODE(ip))) { | 432 | if ((rt = XFS_IS_REALTIME_INODE(ip))) { |
433 | int sbrtextsize, iprtextsize; | 433 | xfs_extlen_t extsz; |
434 | 434 | ||
435 | sbrtextsize = mp->m_sb.sb_rextsize; | 435 | if (!(extsz = ip->i_d.di_extsize)) |
436 | iprtextsize = | 436 | extsz = mp->m_sb.sb_rextsize; |
437 | ip->i_d.di_extsize ? ip->i_d.di_extsize : sbrtextsize; | 437 | numrtextents = qblocks = (count_fsb + extsz - 1); |
438 | numrtextents = (count_fsb + iprtextsize - 1); | 438 | do_div(numrtextents, mp->m_sb.sb_rextsize); |
439 | do_div(numrtextents, sbrtextsize); | 439 | quota_flag = XFS_QMOPT_RES_RTBLKS; |
440 | datablocks = 0; | 440 | datablocks = 0; |
441 | } else { | 441 | } else { |
442 | datablocks = count_fsb; | 442 | datablocks = qblocks = count_fsb; |
443 | quota_flag = XFS_QMOPT_RES_REGBLKS; | ||
443 | numrtextents = 0; | 444 | numrtextents = 0; |
444 | } | 445 | } |
445 | 446 | ||
446 | /* | 447 | /* |
447 | * allocate and setup the transaction | 448 | * Allocate and setup the transaction |
448 | */ | 449 | */ |
449 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 450 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
450 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); | 451 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); |
451 | |||
452 | resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks); | 452 | resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks); |
453 | |||
454 | error = xfs_trans_reserve(tp, resblks, | 453 | error = xfs_trans_reserve(tp, resblks, |
455 | XFS_WRITE_LOG_RES(mp), numrtextents, | 454 | XFS_WRITE_LOG_RES(mp), numrtextents, |
456 | XFS_TRANS_PERM_LOG_RES, | 455 | XFS_TRANS_PERM_LOG_RES, |
457 | XFS_WRITE_LOG_COUNT); | 456 | XFS_WRITE_LOG_COUNT); |
458 | 457 | ||
459 | /* | 458 | /* |
460 | * check for running out of space | 459 | * Check for running out of space, note: need lock to return |
461 | */ | 460 | */ |
462 | if (error) | 461 | if (error) |
463 | /* | ||
464 | * Free the transaction structure. | ||
465 | */ | ||
466 | xfs_trans_cancel(tp, 0); | 462 | xfs_trans_cancel(tp, 0); |
467 | |||
468 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 463 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
469 | |||
470 | if (error) | 464 | if (error) |
471 | goto error_out; /* Don't return in above if .. trans .., | 465 | goto error_out; |
472 | need lock to return */ | ||
473 | 466 | ||
474 | if (XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, resblks)) { | 467 | if (XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag)) { |
475 | error = (EDQUOT); | 468 | error = (EDQUOT); |
476 | goto error1; | 469 | goto error1; |
477 | } | 470 | } |
478 | nimaps = 1; | ||
479 | 471 | ||
480 | bmapi_flag = XFS_BMAPI_WRITE; | 472 | bmapi_flag = XFS_BMAPI_WRITE; |
481 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 473 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
@@ -485,31 +477,29 @@ xfs_iomap_write_direct( | |||
485 | bmapi_flag |= XFS_BMAPI_PREALLOC; | 477 | bmapi_flag |= XFS_BMAPI_PREALLOC; |
486 | 478 | ||
487 | /* | 479 | /* |
488 | * issue the bmapi() call to allocate the blocks | 480 | * Issue the bmapi() call to allocate the blocks |
489 | */ | 481 | */ |
490 | XFS_BMAP_INIT(&free_list, &firstfsb); | 482 | XFS_BMAP_INIT(&free_list, &firstfsb); |
483 | nimaps = 1; | ||
491 | imapp = &imap[0]; | 484 | imapp = &imap[0]; |
492 | error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, | 485 | error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, |
493 | bmapi_flag, &firstfsb, 0, imapp, &nimaps, &free_list); | 486 | bmapi_flag, &firstfsb, 0, imapp, &nimaps, &free_list); |
494 | if (error) { | 487 | if (error) |
495 | goto error0; | 488 | goto error0; |
496 | } | ||
497 | 489 | ||
498 | /* | 490 | /* |
499 | * complete the transaction | 491 | * Complete the transaction |
500 | */ | 492 | */ |
501 | |||
502 | error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); | 493 | error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); |
503 | if (error) { | 494 | if (error) |
504 | goto error0; | 495 | goto error0; |
505 | } | ||
506 | |||
507 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); | 496 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); |
508 | if (error) { | 497 | if (error) |
509 | goto error_out; | 498 | goto error_out; |
510 | } | ||
511 | 499 | ||
512 | /* copy any maps to caller's array and return any error. */ | 500 | /* |
501 | * Copy any maps to caller's array and return any error. | ||
502 | */ | ||
513 | if (nimaps == 0) { | 503 | if (nimaps == 0) { |
514 | error = (ENOSPC); | 504 | error = (ENOSPC); |
515 | goto error_out; | 505 | goto error_out; |
@@ -528,10 +518,11 @@ xfs_iomap_write_direct( | |||
528 | } | 518 | } |
529 | return 0; | 519 | return 0; |
530 | 520 | ||
531 | error0: /* Cancel bmap, unlock inode, and cancel trans */ | 521 | error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */ |
532 | xfs_bmap_cancel(&free_list); | 522 | xfs_bmap_cancel(&free_list); |
523 | XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag); | ||
533 | 524 | ||
534 | error1: /* Just cancel transaction */ | 525 | error1: /* Just cancel transaction */ |
535 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | 526 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); |
536 | *nmaps = 0; /* nothing set-up here */ | 527 | *nmaps = 0; /* nothing set-up here */ |
537 | 528 | ||
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 092d5fb096b1..1cd2ac163877 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
@@ -134,7 +134,7 @@ STATIC void xlog_verify_tail_lsn(xlog_t *log, xlog_in_core_t *iclog, | |||
134 | #define xlog_verify_tail_lsn(a,b,c) | 134 | #define xlog_verify_tail_lsn(a,b,c) |
135 | #endif | 135 | #endif |
136 | 136 | ||
137 | int xlog_iclogs_empty(xlog_t *log); | 137 | STATIC int xlog_iclogs_empty(xlog_t *log); |
138 | 138 | ||
139 | #ifdef DEBUG | 139 | #ifdef DEBUG |
140 | int xlog_do_error = 0; | 140 | int xlog_do_error = 0; |
@@ -1857,7 +1857,7 @@ xlog_write(xfs_mount_t * mp, | |||
1857 | * | 1857 | * |
1858 | * State Change: DIRTY -> ACTIVE | 1858 | * State Change: DIRTY -> ACTIVE |
1859 | */ | 1859 | */ |
1860 | void | 1860 | STATIC void |
1861 | xlog_state_clean_log(xlog_t *log) | 1861 | xlog_state_clean_log(xlog_t *log) |
1862 | { | 1862 | { |
1863 | xlog_in_core_t *iclog; | 1863 | xlog_in_core_t *iclog; |
@@ -3542,7 +3542,7 @@ xfs_log_force_umount( | |||
3542 | return (retval); | 3542 | return (retval); |
3543 | } | 3543 | } |
3544 | 3544 | ||
3545 | int | 3545 | STATIC int |
3546 | xlog_iclogs_empty(xlog_t *log) | 3546 | xlog_iclogs_empty(xlog_t *log) |
3547 | { | 3547 | { |
3548 | xlog_in_core_t *iclog; | 3548 | xlog_in_core_t *iclog; |
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index c31e3ce3be66..1a1d452f15f9 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h | |||
@@ -535,7 +535,6 @@ typedef struct log { | |||
535 | 535 | ||
536 | /* common routines */ | 536 | /* common routines */ |
537 | extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp); | 537 | extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp); |
538 | extern int xlog_find_head(xlog_t *log, xfs_daddr_t *head_blk); | ||
539 | extern int xlog_find_tail(xlog_t *log, | 538 | extern int xlog_find_tail(xlog_t *log, |
540 | xfs_daddr_t *head_blk, | 539 | xfs_daddr_t *head_blk, |
541 | xfs_daddr_t *tail_blk, | 540 | xfs_daddr_t *tail_blk, |
@@ -548,7 +547,6 @@ extern void xlog_recover_process_iunlinks(xlog_t *log); | |||
548 | extern struct xfs_buf *xlog_get_bp(xlog_t *, int); | 547 | extern struct xfs_buf *xlog_get_bp(xlog_t *, int); |
549 | extern void xlog_put_bp(struct xfs_buf *); | 548 | extern void xlog_put_bp(struct xfs_buf *); |
550 | extern int xlog_bread(xlog_t *, xfs_daddr_t, int, struct xfs_buf *); | 549 | extern int xlog_bread(xlog_t *, xfs_daddr_t, int, struct xfs_buf *); |
551 | extern xfs_caddr_t xlog_align(xlog_t *, xfs_daddr_t, int, struct xfs_buf *); | ||
552 | 550 | ||
553 | /* iclog tracing */ | 551 | /* iclog tracing */ |
554 | #define XLOG_TRACE_GRAB_FLUSH 1 | 552 | #define XLOG_TRACE_GRAB_FLUSH 1 |
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 9824b5bf0ec0..0aac28ddb81c 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -148,7 +148,7 @@ xlog_bread( | |||
148 | * The buffer is kept locked across the write and is returned locked. | 148 | * The buffer is kept locked across the write and is returned locked. |
149 | * This can only be used for synchronous log writes. | 149 | * This can only be used for synchronous log writes. |
150 | */ | 150 | */ |
151 | int | 151 | STATIC int |
152 | xlog_bwrite( | 152 | xlog_bwrite( |
153 | xlog_t *log, | 153 | xlog_t *log, |
154 | xfs_daddr_t blk_no, | 154 | xfs_daddr_t blk_no, |
@@ -179,7 +179,7 @@ xlog_bwrite( | |||
179 | return error; | 179 | return error; |
180 | } | 180 | } |
181 | 181 | ||
182 | xfs_caddr_t | 182 | STATIC xfs_caddr_t |
183 | xlog_align( | 183 | xlog_align( |
184 | xlog_t *log, | 184 | xlog_t *log, |
185 | xfs_daddr_t blk_no, | 185 | xfs_daddr_t blk_no, |
@@ -528,7 +528,7 @@ out: | |||
528 | * | 528 | * |
529 | * Return: zero if normal, non-zero if error. | 529 | * Return: zero if normal, non-zero if error. |
530 | */ | 530 | */ |
531 | int | 531 | STATIC int |
532 | xlog_find_head( | 532 | xlog_find_head( |
533 | xlog_t *log, | 533 | xlog_t *log, |
534 | xfs_daddr_t *return_head_blk) | 534 | xfs_daddr_t *return_head_blk) |
@@ -1964,7 +1964,8 @@ xlog_recover_do_reg_buffer( | |||
1964 | * probably a good thing to do for other buf types also. | 1964 | * probably a good thing to do for other buf types also. |
1965 | */ | 1965 | */ |
1966 | error = 0; | 1966 | error = 0; |
1967 | if (buf_f->blf_flags & (XFS_BLI_UDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) { | 1967 | if (buf_f->blf_flags & |
1968 | (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) { | ||
1968 | error = xfs_qm_dqcheck((xfs_disk_dquot_t *) | 1969 | error = xfs_qm_dqcheck((xfs_disk_dquot_t *) |
1969 | item->ri_buf[i].i_addr, | 1970 | item->ri_buf[i].i_addr, |
1970 | -1, 0, XFS_QMOPT_DOWARN, | 1971 | -1, 0, XFS_QMOPT_DOWARN, |
@@ -2030,6 +2031,7 @@ xfs_qm_dqcheck( | |||
2030 | } | 2031 | } |
2031 | 2032 | ||
2032 | if (INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_USER && | 2033 | if (INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_USER && |
2034 | INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_PROJ && | ||
2033 | INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_GROUP) { | 2035 | INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_GROUP) { |
2034 | if (flags & XFS_QMOPT_DOWARN) | 2036 | if (flags & XFS_QMOPT_DOWARN) |
2035 | cmn_err(CE_ALERT, | 2037 | cmn_err(CE_ALERT, |
@@ -2135,6 +2137,8 @@ xlog_recover_do_dquot_buffer( | |||
2135 | type = 0; | 2137 | type = 0; |
2136 | if (buf_f->blf_flags & XFS_BLI_UDQUOT_BUF) | 2138 | if (buf_f->blf_flags & XFS_BLI_UDQUOT_BUF) |
2137 | type |= XFS_DQ_USER; | 2139 | type |= XFS_DQ_USER; |
2140 | if (buf_f->blf_flags & XFS_BLI_PDQUOT_BUF) | ||
2141 | type |= XFS_DQ_PROJ; | ||
2138 | if (buf_f->blf_flags & XFS_BLI_GDQUOT_BUF) | 2142 | if (buf_f->blf_flags & XFS_BLI_GDQUOT_BUF) |
2139 | type |= XFS_DQ_GROUP; | 2143 | type |= XFS_DQ_GROUP; |
2140 | /* | 2144 | /* |
@@ -2247,7 +2251,8 @@ xlog_recover_do_buffer_trans( | |||
2247 | error = 0; | 2251 | error = 0; |
2248 | if (flags & XFS_BLI_INODE_BUF) { | 2252 | if (flags & XFS_BLI_INODE_BUF) { |
2249 | error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f); | 2253 | error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f); |
2250 | } else if (flags & (XFS_BLI_UDQUOT_BUF | XFS_BLI_GDQUOT_BUF)) { | 2254 | } else if (flags & |
2255 | (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) { | ||
2251 | xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f); | 2256 | xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f); |
2252 | } else { | 2257 | } else { |
2253 | xlog_recover_do_reg_buffer(mp, item, bp, buf_f); | 2258 | xlog_recover_do_reg_buffer(mp, item, bp, buf_f); |
@@ -2619,7 +2624,7 @@ xlog_recover_do_dquot_trans( | |||
2619 | * This type of quotas was turned off, so ignore this record. | 2624 | * This type of quotas was turned off, so ignore this record. |
2620 | */ | 2625 | */ |
2621 | type = INT_GET(recddq->d_flags, ARCH_CONVERT) & | 2626 | type = INT_GET(recddq->d_flags, ARCH_CONVERT) & |
2622 | (XFS_DQ_USER | XFS_DQ_GROUP); | 2627 | (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP); |
2623 | ASSERT(type); | 2628 | ASSERT(type); |
2624 | if (log->l_quotaoffs_flag & type) | 2629 | if (log->l_quotaoffs_flag & type) |
2625 | return (0); | 2630 | return (0); |
@@ -2742,7 +2747,6 @@ xlog_recover_do_efd_trans( | |||
2742 | xfs_efi_log_item_t *efip = NULL; | 2747 | xfs_efi_log_item_t *efip = NULL; |
2743 | xfs_log_item_t *lip; | 2748 | xfs_log_item_t *lip; |
2744 | int gen; | 2749 | int gen; |
2745 | int nexts; | ||
2746 | __uint64_t efi_id; | 2750 | __uint64_t efi_id; |
2747 | SPLDECL(s); | 2751 | SPLDECL(s); |
2748 | 2752 | ||
@@ -2777,22 +2781,15 @@ xlog_recover_do_efd_trans( | |||
2777 | } | 2781 | } |
2778 | lip = xfs_trans_next_ail(mp, lip, &gen, NULL); | 2782 | lip = xfs_trans_next_ail(mp, lip, &gen, NULL); |
2779 | } | 2783 | } |
2780 | if (lip == NULL) { | ||
2781 | AIL_UNLOCK(mp, s); | ||
2782 | } | ||
2783 | 2784 | ||
2784 | /* | 2785 | /* |
2785 | * If we found it, then free it up. If it wasn't there, it | 2786 | * If we found it, then free it up. If it wasn't there, it |
2786 | * must have been overwritten in the log. Oh well. | 2787 | * must have been overwritten in the log. Oh well. |
2787 | */ | 2788 | */ |
2788 | if (lip != NULL) { | 2789 | if (lip != NULL) { |
2789 | nexts = efip->efi_format.efi_nextents; | 2790 | xfs_efi_item_free(efip); |
2790 | if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { | 2791 | } else { |
2791 | kmem_free(lip, sizeof(xfs_efi_log_item_t) + | 2792 | AIL_UNLOCK(mp, s); |
2792 | ((nexts - 1) * sizeof(xfs_extent_t))); | ||
2793 | } else { | ||
2794 | kmem_zone_free(xfs_efi_zone, efip); | ||
2795 | } | ||
2796 | } | 2793 | } |
2797 | } | 2794 | } |
2798 | 2795 | ||
diff --git a/fs/xfs/xfs_macros.c b/fs/xfs/xfs_macros.c index ce4f46c6b3ab..698c2cd62858 100644 --- a/fs/xfs/xfs_macros.c +++ b/fs/xfs/xfs_macros.c | |||
@@ -1658,6 +1658,11 @@ xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i) | |||
1658 | { | 1658 | { |
1659 | return XFS_INOBT_IS_FREE(rp, i); | 1659 | return XFS_INOBT_IS_FREE(rp, i); |
1660 | } | 1660 | } |
1661 | int | ||
1662 | xfs_inobt_is_free_disk(xfs_inobt_rec_t *rp, int i) | ||
1663 | { | ||
1664 | return XFS_INOBT_IS_FREE_DISK(rp, i); | ||
1665 | } | ||
1661 | #endif | 1666 | #endif |
1662 | 1667 | ||
1663 | #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_IS_LAST_REC) | 1668 | #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_IS_LAST_REC) |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 2ec967d93e5a..82e1646e6243 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -64,6 +64,7 @@ | |||
64 | STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t); | 64 | STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t); |
65 | STATIC int xfs_uuid_mount(xfs_mount_t *); | 65 | STATIC int xfs_uuid_mount(xfs_mount_t *); |
66 | STATIC void xfs_uuid_unmount(xfs_mount_t *mp); | 66 | STATIC void xfs_uuid_unmount(xfs_mount_t *mp); |
67 | STATIC void xfs_unmountfs_wait(xfs_mount_t *); | ||
67 | 68 | ||
68 | static struct { | 69 | static struct { |
69 | short offset; | 70 | short offset; |
@@ -555,7 +556,7 @@ xfs_readsb(xfs_mount_t *mp) | |||
555 | * fields from the superblock associated with the given | 556 | * fields from the superblock associated with the given |
556 | * mount structure | 557 | * mount structure |
557 | */ | 558 | */ |
558 | void | 559 | STATIC void |
559 | xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) | 560 | xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) |
560 | { | 561 | { |
561 | int i; | 562 | int i; |
@@ -1081,7 +1082,7 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) | |||
1081 | int64_t fsid; | 1082 | int64_t fsid; |
1082 | #endif | 1083 | #endif |
1083 | 1084 | ||
1084 | xfs_iflush_all(mp, XFS_FLUSH_ALL); | 1085 | xfs_iflush_all(mp); |
1085 | 1086 | ||
1086 | XFS_QM_DQPURGEALL(mp, | 1087 | XFS_QM_DQPURGEALL(mp, |
1087 | XFS_QMOPT_UQUOTA | XFS_QMOPT_GQUOTA | XFS_QMOPT_UMOUNTING); | 1088 | XFS_QMOPT_UQUOTA | XFS_QMOPT_GQUOTA | XFS_QMOPT_UMOUNTING); |
@@ -1111,15 +1112,6 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) | |||
1111 | */ | 1112 | */ |
1112 | ASSERT(mp->m_inodes == NULL); | 1113 | ASSERT(mp->m_inodes == NULL); |
1113 | 1114 | ||
1114 | /* | ||
1115 | * We may have bufs that are in the process of getting written still. | ||
1116 | * We must wait for the I/O completion of those. The sync flag here | ||
1117 | * does a two pass iteration thru the bufcache. | ||
1118 | */ | ||
1119 | if (XFS_FORCED_SHUTDOWN(mp)) { | ||
1120 | xfs_incore_relse(mp->m_ddev_targp, 0, 1); /* synchronous */ | ||
1121 | } | ||
1122 | |||
1123 | xfs_unmountfs_close(mp, cr); | 1115 | xfs_unmountfs_close(mp, cr); |
1124 | if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) | 1116 | if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) |
1125 | xfs_uuid_unmount(mp); | 1117 | xfs_uuid_unmount(mp); |
@@ -1146,7 +1138,7 @@ xfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr) | |||
1146 | xfs_free_buftarg(mp->m_ddev_targp, 0); | 1138 | xfs_free_buftarg(mp->m_ddev_targp, 0); |
1147 | } | 1139 | } |
1148 | 1140 | ||
1149 | void | 1141 | STATIC void |
1150 | xfs_unmountfs_wait(xfs_mount_t *mp) | 1142 | xfs_unmountfs_wait(xfs_mount_t *mp) |
1151 | { | 1143 | { |
1152 | if (mp->m_logdev_targp != mp->m_ddev_targp) | 1144 | if (mp->m_logdev_targp != mp->m_ddev_targp) |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 30dd08fb9f57..5affba38a577 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -141,7 +141,7 @@ typedef int (*xfs_dqattach_t)(struct xfs_inode *, uint); | |||
141 | typedef void (*xfs_dqdetach_t)(struct xfs_inode *); | 141 | typedef void (*xfs_dqdetach_t)(struct xfs_inode *); |
142 | typedef int (*xfs_dqpurgeall_t)(struct xfs_mount *, uint); | 142 | typedef int (*xfs_dqpurgeall_t)(struct xfs_mount *, uint); |
143 | typedef int (*xfs_dqvopalloc_t)(struct xfs_mount *, | 143 | typedef int (*xfs_dqvopalloc_t)(struct xfs_mount *, |
144 | struct xfs_inode *, uid_t, gid_t, uint, | 144 | struct xfs_inode *, uid_t, gid_t, prid_t, uint, |
145 | struct xfs_dquot **, struct xfs_dquot **); | 145 | struct xfs_dquot **, struct xfs_dquot **); |
146 | typedef void (*xfs_dqvopcreate_t)(struct xfs_trans *, struct xfs_inode *, | 146 | typedef void (*xfs_dqvopcreate_t)(struct xfs_trans *, struct xfs_inode *, |
147 | struct xfs_dquot *, struct xfs_dquot *); | 147 | struct xfs_dquot *, struct xfs_dquot *); |
@@ -185,8 +185,8 @@ typedef struct xfs_qmops { | |||
185 | (*(mp)->m_qm_ops.xfs_dqdetach)(ip) | 185 | (*(mp)->m_qm_ops.xfs_dqdetach)(ip) |
186 | #define XFS_QM_DQPURGEALL(mp, fl) \ | 186 | #define XFS_QM_DQPURGEALL(mp, fl) \ |
187 | (*(mp)->m_qm_ops.xfs_dqpurgeall)(mp, fl) | 187 | (*(mp)->m_qm_ops.xfs_dqpurgeall)(mp, fl) |
188 | #define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, fl, dq1, dq2) \ | 188 | #define XFS_QM_DQVOPALLOC(mp, ip, uid, gid, prid, fl, dq1, dq2) \ |
189 | (*(mp)->m_qm_ops.xfs_dqvopalloc)(mp, ip, uid, gid, fl, dq1, dq2) | 189 | (*(mp)->m_qm_ops.xfs_dqvopalloc)(mp, ip, uid, gid, prid, fl, dq1, dq2) |
190 | #define XFS_QM_DQVOPCREATE(mp, tp, ip, dq1, dq2) \ | 190 | #define XFS_QM_DQVOPCREATE(mp, tp, ip, dq1, dq2) \ |
191 | (*(mp)->m_qm_ops.xfs_dqvopcreate)(tp, ip, dq1, dq2) | 191 | (*(mp)->m_qm_ops.xfs_dqvopcreate)(tp, ip, dq1, dq2) |
192 | #define XFS_QM_DQVOPRENAME(mp, ip) \ | 192 | #define XFS_QM_DQVOPRENAME(mp, ip) \ |
@@ -544,7 +544,6 @@ extern void xfs_mount_free(xfs_mount_t *mp, int remove_bhv); | |||
544 | extern int xfs_mountfs(struct vfs *, xfs_mount_t *mp, int); | 544 | extern int xfs_mountfs(struct vfs *, xfs_mount_t *mp, int); |
545 | 545 | ||
546 | extern int xfs_unmountfs(xfs_mount_t *, struct cred *); | 546 | extern int xfs_unmountfs(xfs_mount_t *, struct cred *); |
547 | extern void xfs_unmountfs_wait(xfs_mount_t *); | ||
548 | extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *); | 547 | extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *); |
549 | extern int xfs_unmountfs_writesb(xfs_mount_t *); | 548 | extern int xfs_unmountfs_writesb(xfs_mount_t *); |
550 | extern int xfs_unmount_flush(xfs_mount_t *, int); | 549 | extern int xfs_unmount_flush(xfs_mount_t *, int); |
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index 703ec4efcb41..7134576ae7fa 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h | |||
@@ -96,7 +96,7 @@ typedef struct xfs_dqblk { | |||
96 | * flags for q_flags field in the dquot. | 96 | * flags for q_flags field in the dquot. |
97 | */ | 97 | */ |
98 | #define XFS_DQ_USER 0x0001 /* a user quota */ | 98 | #define XFS_DQ_USER 0x0001 /* a user quota */ |
99 | /* #define XFS_DQ_PROJ 0x0002 -- project quota (IRIX) */ | 99 | #define XFS_DQ_PROJ 0x0002 /* project quota */ |
100 | #define XFS_DQ_GROUP 0x0004 /* a group quota */ | 100 | #define XFS_DQ_GROUP 0x0004 /* a group quota */ |
101 | #define XFS_DQ_FLOCKED 0x0008 /* flush lock taken */ | 101 | #define XFS_DQ_FLOCKED 0x0008 /* flush lock taken */ |
102 | #define XFS_DQ_DIRTY 0x0010 /* dquot is dirty */ | 102 | #define XFS_DQ_DIRTY 0x0010 /* dquot is dirty */ |
@@ -104,6 +104,8 @@ typedef struct xfs_dqblk { | |||
104 | #define XFS_DQ_INACTIVE 0x0040 /* dq off mplist & hashlist */ | 104 | #define XFS_DQ_INACTIVE 0x0040 /* dq off mplist & hashlist */ |
105 | #define XFS_DQ_MARKER 0x0080 /* sentinel */ | 105 | #define XFS_DQ_MARKER 0x0080 /* sentinel */ |
106 | 106 | ||
107 | #define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP) | ||
108 | |||
107 | /* | 109 | /* |
108 | * In the worst case, when both user and group quotas are on, | 110 | * In the worst case, when both user and group quotas are on, |
109 | * we can have a max of three dquots changing in a single transaction. | 111 | * we can have a max of three dquots changing in a single transaction. |
@@ -124,7 +126,7 @@ typedef struct xfs_dqblk { | |||
124 | typedef struct xfs_dq_logformat { | 126 | typedef struct xfs_dq_logformat { |
125 | __uint16_t qlf_type; /* dquot log item type */ | 127 | __uint16_t qlf_type; /* dquot log item type */ |
126 | __uint16_t qlf_size; /* size of this item */ | 128 | __uint16_t qlf_size; /* size of this item */ |
127 | xfs_dqid_t qlf_id; /* usr/grp id number : 32 bits */ | 129 | xfs_dqid_t qlf_id; /* usr/grp/proj id : 32 bits */ |
128 | __int64_t qlf_blkno; /* blkno of dquot buffer */ | 130 | __int64_t qlf_blkno; /* blkno of dquot buffer */ |
129 | __int32_t qlf_len; /* len of dquot buffer */ | 131 | __int32_t qlf_len; /* len of dquot buffer */ |
130 | __uint32_t qlf_boffset; /* off of dquot in buffer */ | 132 | __uint32_t qlf_boffset; /* off of dquot in buffer */ |
@@ -152,9 +154,9 @@ typedef struct xfs_qoff_logformat { | |||
152 | #define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */ | 154 | #define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */ |
153 | #define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */ | 155 | #define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */ |
154 | #define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */ | 156 | #define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */ |
155 | #define XFS_PQUOTA_ACCT 0x0008 /* (IRIX) project quota accounting ON */ | 157 | #define XFS_PQUOTA_ACCT 0x0008 /* project quota accounting ON */ |
156 | #define XFS_GQUOTA_ENFD 0x0010 /* group quota limits enforced */ | 158 | #define XFS_OQUOTA_ENFD 0x0010 /* other (grp/prj) quota limits enforced */ |
157 | #define XFS_GQUOTA_CHKD 0x0020 /* quotacheck run on grp quotas */ | 159 | #define XFS_OQUOTA_CHKD 0x0020 /* quotacheck run on other (grp/prj) quotas */ |
158 | #define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */ | 160 | #define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */ |
159 | 161 | ||
160 | /* | 162 | /* |
@@ -162,17 +164,22 @@ typedef struct xfs_qoff_logformat { | |||
162 | * are in the process of getting turned off. These flags are in m_qflags but | 164 | * are in the process of getting turned off. These flags are in m_qflags but |
163 | * never in sb_qflags. | 165 | * never in sb_qflags. |
164 | */ | 166 | */ |
165 | #define XFS_UQUOTA_ACTIVE 0x0080 /* uquotas are being turned off */ | 167 | #define XFS_UQUOTA_ACTIVE 0x0100 /* uquotas are being turned off */ |
166 | #define XFS_GQUOTA_ACTIVE 0x0100 /* gquotas are being turned off */ | 168 | #define XFS_PQUOTA_ACTIVE 0x0200 /* pquotas are being turned off */ |
169 | #define XFS_GQUOTA_ACTIVE 0x0400 /* gquotas are being turned off */ | ||
167 | 170 | ||
168 | /* | 171 | /* |
169 | * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees | 172 | * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees |
170 | * quota will be not be switched off as long as that inode lock is held. | 173 | * quota will be not be switched off as long as that inode lock is held. |
171 | */ | 174 | */ |
172 | #define XFS_IS_QUOTA_ON(mp) ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \ | 175 | #define XFS_IS_QUOTA_ON(mp) ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \ |
173 | XFS_GQUOTA_ACTIVE)) | 176 | XFS_GQUOTA_ACTIVE | \ |
177 | XFS_PQUOTA_ACTIVE)) | ||
178 | #define XFS_IS_OQUOTA_ON(mp) ((mp)->m_qflags & (XFS_GQUOTA_ACTIVE | \ | ||
179 | XFS_PQUOTA_ACTIVE)) | ||
174 | #define XFS_IS_UQUOTA_ON(mp) ((mp)->m_qflags & XFS_UQUOTA_ACTIVE) | 180 | #define XFS_IS_UQUOTA_ON(mp) ((mp)->m_qflags & XFS_UQUOTA_ACTIVE) |
175 | #define XFS_IS_GQUOTA_ON(mp) ((mp)->m_qflags & XFS_GQUOTA_ACTIVE) | 181 | #define XFS_IS_GQUOTA_ON(mp) ((mp)->m_qflags & XFS_GQUOTA_ACTIVE) |
182 | #define XFS_IS_PQUOTA_ON(mp) ((mp)->m_qflags & XFS_PQUOTA_ACTIVE) | ||
176 | 183 | ||
177 | /* | 184 | /* |
178 | * Flags to tell various functions what to do. Not all of these are meaningful | 185 | * Flags to tell various functions what to do. Not all of these are meaningful |
@@ -182,7 +189,7 @@ typedef struct xfs_qoff_logformat { | |||
182 | #define XFS_QMOPT_DQLOCK 0x0000001 /* dqlock */ | 189 | #define XFS_QMOPT_DQLOCK 0x0000001 /* dqlock */ |
183 | #define XFS_QMOPT_DQALLOC 0x0000002 /* alloc dquot ondisk if needed */ | 190 | #define XFS_QMOPT_DQALLOC 0x0000002 /* alloc dquot ondisk if needed */ |
184 | #define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */ | 191 | #define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */ |
185 | #define XFS_QMOPT_GQUOTA 0x0000008 /* group dquot requested */ | 192 | #define XFS_QMOPT_PQUOTA 0x0000008 /* project dquot requested */ |
186 | #define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */ | 193 | #define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */ |
187 | #define XFS_QMOPT_DQSUSER 0x0000020 /* don't cache super users dquot */ | 194 | #define XFS_QMOPT_DQSUSER 0x0000020 /* don't cache super users dquot */ |
188 | #define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */ | 195 | #define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */ |
@@ -192,6 +199,7 @@ typedef struct xfs_qoff_logformat { | |||
192 | #define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if necessary */ | 199 | #define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if necessary */ |
193 | #define XFS_QMOPT_ILOCKED 0x0000800 /* inode is already locked (excl) */ | 200 | #define XFS_QMOPT_ILOCKED 0x0000800 /* inode is already locked (excl) */ |
194 | #define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot, if damaged. */ | 201 | #define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot, if damaged. */ |
202 | #define XFS_QMOPT_GQUOTA 0x0002000 /* group dquot requested */ | ||
195 | 203 | ||
196 | /* | 204 | /* |
197 | * flags to xfs_trans_mod_dquot to indicate which field needs to be | 205 | * flags to xfs_trans_mod_dquot to indicate which field needs to be |
@@ -231,7 +239,8 @@ typedef struct xfs_qoff_logformat { | |||
231 | #define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT | 239 | #define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT |
232 | 240 | ||
233 | 241 | ||
234 | #define XFS_QMOPT_QUOTALL (XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA) | 242 | #define XFS_QMOPT_QUOTALL \ |
243 | (XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA) | ||
235 | #define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) | 244 | #define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) |
236 | 245 | ||
237 | #ifdef __KERNEL__ | 246 | #ifdef __KERNEL__ |
@@ -246,21 +255,33 @@ typedef struct xfs_qoff_logformat { | |||
246 | */ | 255 | */ |
247 | #define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\ | 256 | #define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\ |
248 | (ip)->i_udquot == NULL) || \ | 257 | (ip)->i_udquot == NULL) || \ |
249 | (XFS_IS_GQUOTA_ON(mp) && \ | 258 | (XFS_IS_OQUOTA_ON(mp) && \ |
250 | (ip)->i_gdquot == NULL)) | 259 | (ip)->i_gdquot == NULL)) |
251 | 260 | ||
252 | #define XFS_QM_NEED_QUOTACHECK(mp) ((XFS_IS_UQUOTA_ON(mp) && \ | 261 | #define XFS_QM_NEED_QUOTACHECK(mp) \ |
253 | (mp->m_sb.sb_qflags & \ | 262 | ((XFS_IS_UQUOTA_ON(mp) && \ |
254 | XFS_UQUOTA_CHKD) == 0) || \ | 263 | (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD) == 0) || \ |
255 | (XFS_IS_GQUOTA_ON(mp) && \ | 264 | (XFS_IS_GQUOTA_ON(mp) && \ |
256 | (mp->m_sb.sb_qflags & \ | 265 | ((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \ |
257 | XFS_GQUOTA_CHKD) == 0)) | 266 | (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT))) || \ |
267 | (XFS_IS_PQUOTA_ON(mp) && \ | ||
268 | ((mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD) == 0 || \ | ||
269 | (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT)))) | ||
270 | |||
271 | #define XFS_MOUNT_QUOTA_SET1 (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ | ||
272 | XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\ | ||
273 | XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD) | ||
274 | |||
275 | #define XFS_MOUNT_QUOTA_SET2 (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ | ||
276 | XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\ | ||
277 | XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD) | ||
258 | 278 | ||
259 | #define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ | 279 | #define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ |
260 | XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\ | 280 | XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\ |
261 | XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD) | 281 | XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD|\ |
282 | XFS_GQUOTA_ACCT) | ||
262 | #define XFS_MOUNT_QUOTA_MASK (XFS_MOUNT_QUOTA_ALL | XFS_UQUOTA_ACTIVE | \ | 283 | #define XFS_MOUNT_QUOTA_MASK (XFS_MOUNT_QUOTA_ALL | XFS_UQUOTA_ACTIVE | \ |
263 | XFS_GQUOTA_ACTIVE) | 284 | XFS_GQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE) |
264 | 285 | ||
265 | 286 | ||
266 | /* | 287 | /* |
@@ -331,15 +352,8 @@ typedef struct xfs_dqtrxops { | |||
331 | #define XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp) \ | 352 | #define XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp) \ |
332 | XFS_DQTRXOP_VOID(mp, tp, qo_unreserve_and_mod_dquots) | 353 | XFS_DQTRXOP_VOID(mp, tp, qo_unreserve_and_mod_dquots) |
333 | 354 | ||
334 | #define XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, nblks) \ | 355 | #define XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, ninos, flags) \ |
335 | XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \ | 356 | XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, -(nblks), -(ninos), flags) |
336 | XFS_QMOPT_RES_REGBLKS) | ||
337 | #define XFS_TRANS_RESERVE_BLKQUOTA_FORCE(mp, tp, ip, nblks) \ | ||
338 | XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, nblks, 0, \ | ||
339 | XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES) | ||
340 | #define XFS_TRANS_UNRESERVE_BLKQUOTA(mp, tp, ip, nblks) \ | ||
341 | XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, -(nblks), 0, \ | ||
342 | XFS_QMOPT_RES_REGBLKS) | ||
343 | #define XFS_TRANS_RESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \ | 357 | #define XFS_TRANS_RESERVE_QUOTA(mp, tp, ud, gd, nb, ni, f) \ |
344 | XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, \ | 358 | XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, ud, gd, nb, ni, \ |
345 | f | XFS_QMOPT_RES_REGBLKS) | 359 | f | XFS_QMOPT_RES_REGBLKS) |
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index cb13f9a1d45b..23b48ac1cb7e 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c | |||
@@ -234,9 +234,6 @@ xfs_lock_for_rename( | |||
234 | return 0; | 234 | return 0; |
235 | } | 235 | } |
236 | 236 | ||
237 | |||
238 | int rename_which_error_return = 0; | ||
239 | |||
240 | /* | 237 | /* |
241 | * xfs_rename | 238 | * xfs_rename |
242 | */ | 239 | */ |
@@ -316,7 +313,6 @@ xfs_rename( | |||
316 | &num_inodes); | 313 | &num_inodes); |
317 | 314 | ||
318 | if (error) { | 315 | if (error) { |
319 | rename_which_error_return = __LINE__; | ||
320 | /* | 316 | /* |
321 | * We have nothing locked, no inode references, and | 317 | * We have nothing locked, no inode references, and |
322 | * no transaction, so just get out. | 318 | * no transaction, so just get out. |
@@ -332,7 +328,6 @@ xfs_rename( | |||
332 | */ | 328 | */ |
333 | if (target_ip == NULL && (src_dp != target_dp) && | 329 | if (target_ip == NULL && (src_dp != target_dp) && |
334 | target_dp->i_d.di_nlink >= XFS_MAXLINK) { | 330 | target_dp->i_d.di_nlink >= XFS_MAXLINK) { |
335 | rename_which_error_return = __LINE__; | ||
336 | error = XFS_ERROR(EMLINK); | 331 | error = XFS_ERROR(EMLINK); |
337 | xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); | 332 | xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); |
338 | goto rele_return; | 333 | goto rele_return; |
@@ -359,7 +354,6 @@ xfs_rename( | |||
359 | XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); | 354 | XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); |
360 | } | 355 | } |
361 | if (error) { | 356 | if (error) { |
362 | rename_which_error_return = __LINE__; | ||
363 | xfs_trans_cancel(tp, 0); | 357 | xfs_trans_cancel(tp, 0); |
364 | goto rele_return; | 358 | goto rele_return; |
365 | } | 359 | } |
@@ -369,7 +363,6 @@ xfs_rename( | |||
369 | */ | 363 | */ |
370 | if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) { | 364 | if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) { |
371 | xfs_trans_cancel(tp, cancel_flags); | 365 | xfs_trans_cancel(tp, cancel_flags); |
372 | rename_which_error_return = __LINE__; | ||
373 | goto rele_return; | 366 | goto rele_return; |
374 | } | 367 | } |
375 | 368 | ||
@@ -413,7 +406,6 @@ xfs_rename( | |||
413 | if (spaceres == 0 && | 406 | if (spaceres == 0 && |
414 | (error = XFS_DIR_CANENTER(mp, tp, target_dp, target_name, | 407 | (error = XFS_DIR_CANENTER(mp, tp, target_dp, target_name, |
415 | target_namelen))) { | 408 | target_namelen))) { |
416 | rename_which_error_return = __LINE__; | ||
417 | goto error_return; | 409 | goto error_return; |
418 | } | 410 | } |
419 | /* | 411 | /* |
@@ -425,11 +417,9 @@ xfs_rename( | |||
425 | target_namelen, src_ip->i_ino, | 417 | target_namelen, src_ip->i_ino, |
426 | &first_block, &free_list, spaceres); | 418 | &first_block, &free_list, spaceres); |
427 | if (error == ENOSPC) { | 419 | if (error == ENOSPC) { |
428 | rename_which_error_return = __LINE__; | ||
429 | goto error_return; | 420 | goto error_return; |
430 | } | 421 | } |
431 | if (error) { | 422 | if (error) { |
432 | rename_which_error_return = __LINE__; | ||
433 | goto abort_return; | 423 | goto abort_return; |
434 | } | 424 | } |
435 | xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 425 | xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
@@ -437,7 +427,6 @@ xfs_rename( | |||
437 | if (new_parent && src_is_directory) { | 427 | if (new_parent && src_is_directory) { |
438 | error = xfs_bumplink(tp, target_dp); | 428 | error = xfs_bumplink(tp, target_dp); |
439 | if (error) { | 429 | if (error) { |
440 | rename_which_error_return = __LINE__; | ||
441 | goto abort_return; | 430 | goto abort_return; |
442 | } | 431 | } |
443 | } | 432 | } |
@@ -455,7 +444,6 @@ xfs_rename( | |||
455 | if (!(XFS_DIR_ISEMPTY(target_ip->i_mount, target_ip)) || | 444 | if (!(XFS_DIR_ISEMPTY(target_ip->i_mount, target_ip)) || |
456 | (target_ip->i_d.di_nlink > 2)) { | 445 | (target_ip->i_d.di_nlink > 2)) { |
457 | error = XFS_ERROR(EEXIST); | 446 | error = XFS_ERROR(EEXIST); |
458 | rename_which_error_return = __LINE__; | ||
459 | goto error_return; | 447 | goto error_return; |
460 | } | 448 | } |
461 | } | 449 | } |
@@ -473,7 +461,6 @@ xfs_rename( | |||
473 | target_namelen, src_ip->i_ino, &first_block, | 461 | target_namelen, src_ip->i_ino, &first_block, |
474 | &free_list, spaceres); | 462 | &free_list, spaceres); |
475 | if (error) { | 463 | if (error) { |
476 | rename_which_error_return = __LINE__; | ||
477 | goto abort_return; | 464 | goto abort_return; |
478 | } | 465 | } |
479 | xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 466 | xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
@@ -484,7 +471,6 @@ xfs_rename( | |||
484 | */ | 471 | */ |
485 | error = xfs_droplink(tp, target_ip); | 472 | error = xfs_droplink(tp, target_ip); |
486 | if (error) { | 473 | if (error) { |
487 | rename_which_error_return = __LINE__; | ||
488 | goto abort_return; | 474 | goto abort_return; |
489 | } | 475 | } |
490 | target_ip_dropped = 1; | 476 | target_ip_dropped = 1; |
@@ -495,7 +481,6 @@ xfs_rename( | |||
495 | */ | 481 | */ |
496 | error = xfs_droplink(tp, target_ip); | 482 | error = xfs_droplink(tp, target_ip); |
497 | if (error) { | 483 | if (error) { |
498 | rename_which_error_return = __LINE__; | ||
499 | goto abort_return; | 484 | goto abort_return; |
500 | } | 485 | } |
501 | } | 486 | } |
@@ -519,7 +504,6 @@ xfs_rename( | |||
519 | &free_list, spaceres); | 504 | &free_list, spaceres); |
520 | ASSERT(error != EEXIST); | 505 | ASSERT(error != EEXIST); |
521 | if (error) { | 506 | if (error) { |
522 | rename_which_error_return = __LINE__; | ||
523 | goto abort_return; | 507 | goto abort_return; |
524 | } | 508 | } |
525 | xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 509 | xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
@@ -550,7 +534,6 @@ xfs_rename( | |||
550 | */ | 534 | */ |
551 | error = xfs_droplink(tp, src_dp); | 535 | error = xfs_droplink(tp, src_dp); |
552 | if (error) { | 536 | if (error) { |
553 | rename_which_error_return = __LINE__; | ||
554 | goto abort_return; | 537 | goto abort_return; |
555 | } | 538 | } |
556 | } | 539 | } |
@@ -558,7 +541,6 @@ xfs_rename( | |||
558 | error = XFS_DIR_REMOVENAME(mp, tp, src_dp, src_name, src_namelen, | 541 | error = XFS_DIR_REMOVENAME(mp, tp, src_dp, src_name, src_namelen, |
559 | src_ip->i_ino, &first_block, &free_list, spaceres); | 542 | src_ip->i_ino, &first_block, &free_list, spaceres); |
560 | if (error) { | 543 | if (error) { |
561 | rename_which_error_return = __LINE__; | ||
562 | goto abort_return; | 544 | goto abort_return; |
563 | } | 545 | } |
564 | xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 546 | xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 3db0e2200775..06dfca531f79 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c | |||
@@ -332,25 +332,6 @@ undo_blocks: | |||
332 | 332 | ||
333 | 333 | ||
334 | /* | 334 | /* |
335 | * This is called to set the a callback to be called when the given | ||
336 | * transaction is committed to disk. The transaction pointer and the | ||
337 | * argument pointer will be passed to the callback routine. | ||
338 | * | ||
339 | * Only one callback can be associated with any single transaction. | ||
340 | */ | ||
341 | void | ||
342 | xfs_trans_callback( | ||
343 | xfs_trans_t *tp, | ||
344 | xfs_trans_callback_t callback, | ||
345 | void *arg) | ||
346 | { | ||
347 | ASSERT(tp->t_callback == NULL); | ||
348 | tp->t_callback = callback; | ||
349 | tp->t_callarg = arg; | ||
350 | } | ||
351 | |||
352 | |||
353 | /* | ||
354 | * Record the indicated change to the given field for application | 335 | * Record the indicated change to the given field for application |
355 | * to the file system's superblock when the transaction commits. | 336 | * to the file system's superblock when the transaction commits. |
356 | * For now, just store the change in the transaction structure. | 337 | * For now, just store the change in the transaction structure. |
@@ -551,7 +532,7 @@ xfs_trans_apply_sb_deltas( | |||
551 | * | 532 | * |
552 | * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). | 533 | * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). |
553 | */ | 534 | */ |
554 | void | 535 | STATIC void |
555 | xfs_trans_unreserve_and_mod_sb( | 536 | xfs_trans_unreserve_and_mod_sb( |
556 | xfs_trans_t *tp) | 537 | xfs_trans_t *tp) |
557 | { | 538 | { |
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index bd37ccb85e76..ec541d66fa2a 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h | |||
@@ -987,8 +987,6 @@ xfs_trans_t *_xfs_trans_alloc(struct xfs_mount *, uint); | |||
987 | xfs_trans_t *xfs_trans_dup(xfs_trans_t *); | 987 | xfs_trans_t *xfs_trans_dup(xfs_trans_t *); |
988 | int xfs_trans_reserve(xfs_trans_t *, uint, uint, uint, | 988 | int xfs_trans_reserve(xfs_trans_t *, uint, uint, uint, |
989 | uint, uint); | 989 | uint, uint); |
990 | void xfs_trans_callback(xfs_trans_t *, | ||
991 | void (*)(xfs_trans_t *, void *), void *); | ||
992 | void xfs_trans_mod_sb(xfs_trans_t *, uint, long); | 990 | void xfs_trans_mod_sb(xfs_trans_t *, uint, long); |
993 | struct xfs_buf *xfs_trans_get_buf(xfs_trans_t *, struct xfs_buftarg *, xfs_daddr_t, | 991 | struct xfs_buf *xfs_trans_get_buf(xfs_trans_t *, struct xfs_buftarg *, xfs_daddr_t, |
994 | int, uint); | 992 | int, uint); |
@@ -1010,7 +1008,6 @@ int xfs_trans_iget(struct xfs_mount *, xfs_trans_t *, | |||
1010 | xfs_ino_t , uint, uint, struct xfs_inode **); | 1008 | xfs_ino_t , uint, uint, struct xfs_inode **); |
1011 | void xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint); | 1009 | void xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint); |
1012 | void xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *); | 1010 | void xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *); |
1013 | void xfs_trans_ihold_release(xfs_trans_t *, struct xfs_inode *); | ||
1014 | void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); | 1011 | void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); |
1015 | void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); | 1012 | void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); |
1016 | struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint); | 1013 | struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint); |
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index a9682b9510c1..144da7a85466 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c | |||
@@ -976,6 +976,7 @@ xfs_trans_dquot_buf( | |||
976 | ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); | 976 | ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); |
977 | ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); | 977 | ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); |
978 | ASSERT(type == XFS_BLI_UDQUOT_BUF || | 978 | ASSERT(type == XFS_BLI_UDQUOT_BUF || |
979 | type == XFS_BLI_PDQUOT_BUF || | ||
979 | type == XFS_BLI_GDQUOT_BUF); | 980 | type == XFS_BLI_GDQUOT_BUF); |
980 | 981 | ||
981 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); | 982 | bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); |
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c index e2c3706f453d..7e7631ca4979 100644 --- a/fs/xfs/xfs_trans_inode.c +++ b/fs/xfs/xfs_trans_inode.c | |||
@@ -253,24 +253,6 @@ xfs_trans_ihold( | |||
253 | ip->i_itemp->ili_flags |= XFS_ILI_HOLD; | 253 | ip->i_itemp->ili_flags |= XFS_ILI_HOLD; |
254 | } | 254 | } |
255 | 255 | ||
256 | /* | ||
257 | * Cancel the previous inode hold request made on this inode | ||
258 | * for this transaction. | ||
259 | */ | ||
260 | /*ARGSUSED*/ | ||
261 | void | ||
262 | xfs_trans_ihold_release( | ||
263 | xfs_trans_t *tp, | ||
264 | xfs_inode_t *ip) | ||
265 | { | ||
266 | ASSERT(ip->i_transp == tp); | ||
267 | ASSERT(ip->i_itemp != NULL); | ||
268 | ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); | ||
269 | ASSERT(ip->i_itemp->ili_flags & XFS_ILI_HOLD); | ||
270 | |||
271 | ip->i_itemp->ili_flags &= ~XFS_ILI_HOLD; | ||
272 | } | ||
273 | |||
274 | 256 | ||
275 | /* | 257 | /* |
276 | * This is called to mark the fields indicated in fieldmask as needing | 258 | * This is called to mark the fields indicated in fieldmask as needing |
diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h index e4bf711e48ff..16f5371ce102 100644 --- a/fs/xfs/xfs_types.h +++ b/fs/xfs/xfs_types.h | |||
@@ -55,7 +55,7 @@ typedef signed long long int __int64_t; | |||
55 | typedef unsigned long long int __uint64_t; | 55 | typedef unsigned long long int __uint64_t; |
56 | 56 | ||
57 | typedef enum { B_FALSE,B_TRUE } boolean_t; | 57 | typedef enum { B_FALSE,B_TRUE } boolean_t; |
58 | typedef __int64_t prid_t; /* project ID */ | 58 | typedef __uint32_t prid_t; /* project ID */ |
59 | typedef __uint32_t inst_t; /* an instruction */ | 59 | typedef __uint32_t inst_t; /* an instruction */ |
60 | 60 | ||
61 | typedef __s64 xfs_off_t; /* <file offset> type */ | 61 | typedef __s64 xfs_off_t; /* <file offset> type */ |
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c index d1f8146a06ea..11351f08d438 100644 --- a/fs/xfs/xfs_utils.c +++ b/fs/xfs/xfs_utils.c | |||
@@ -428,7 +428,7 @@ xfs_truncate_file( | |||
428 | if (ip->i_ino != mp->m_sb.sb_uquotino) | 428 | if (ip->i_ino != mp->m_sb.sb_uquotino) |
429 | ASSERT(ip->i_udquot); | 429 | ASSERT(ip->i_udquot); |
430 | } | 430 | } |
431 | if (XFS_IS_GQUOTA_ON(mp)) { | 431 | if (XFS_IS_OQUOTA_ON(mp)) { |
432 | if (ip->i_ino != mp->m_sb.sb_gquotino) | 432 | if (ip->i_ino != mp->m_sb.sb_gquotino) |
433 | ASSERT(ip->i_gdquot); | 433 | ASSERT(ip->i_gdquot); |
434 | } | 434 | } |
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index b53736650100..42bcc0215203 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c | |||
@@ -368,16 +368,6 @@ xfs_finish_flags( | |||
368 | } | 368 | } |
369 | 369 | ||
370 | /* | 370 | /* |
371 | * disallow mount attempts with (IRIX) project quota enabled | ||
372 | */ | ||
373 | if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && | ||
374 | (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT)) { | ||
375 | cmn_err(CE_WARN, | ||
376 | "XFS: cannot mount a filesystem with IRIX project quota enabled"); | ||
377 | return XFS_ERROR(ENOSYS); | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * check for shared mount. | 371 | * check for shared mount. |
382 | */ | 372 | */ |
383 | if (ap->flags & XFSMNT_SHARED) { | 373 | if (ap->flags & XFSMNT_SHARED) { |
@@ -622,7 +612,34 @@ out: | |||
622 | return XFS_ERROR(error); | 612 | return XFS_ERROR(error); |
623 | } | 613 | } |
624 | 614 | ||
625 | #define REMOUNT_READONLY_FLAGS (SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT) | 615 | STATIC int |
616 | xfs_quiesce_fs( | ||
617 | xfs_mount_t *mp) | ||
618 | { | ||
619 | int count = 0, pincount; | ||
620 | |||
621 | xfs_refcache_purge_mp(mp); | ||
622 | xfs_flush_buftarg(mp->m_ddev_targp, 0); | ||
623 | xfs_finish_reclaim_all(mp, 0); | ||
624 | |||
625 | /* This loop must run at least twice. | ||
626 | * The first instance of the loop will flush | ||
627 | * most meta data but that will generate more | ||
628 | * meta data (typically directory updates). | ||
629 | * Which then must be flushed and logged before | ||
630 | * we can write the unmount record. | ||
631 | */ | ||
632 | do { | ||
633 | xfs_syncsub(mp, SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT, 0, NULL); | ||
634 | pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); | ||
635 | if (!pincount) { | ||
636 | delay(50); | ||
637 | count++; | ||
638 | } | ||
639 | } while (count < 2); | ||
640 | |||
641 | return 0; | ||
642 | } | ||
626 | 643 | ||
627 | STATIC int | 644 | STATIC int |
628 | xfs_mntupdate( | 645 | xfs_mntupdate( |
@@ -632,8 +649,7 @@ xfs_mntupdate( | |||
632 | { | 649 | { |
633 | struct vfs *vfsp = bhvtovfs(bdp); | 650 | struct vfs *vfsp = bhvtovfs(bdp); |
634 | xfs_mount_t *mp = XFS_BHVTOM(bdp); | 651 | xfs_mount_t *mp = XFS_BHVTOM(bdp); |
635 | int pincount, error; | 652 | int error; |
636 | int count = 0; | ||
637 | 653 | ||
638 | if (args->flags & XFSMNT_NOATIME) | 654 | if (args->flags & XFSMNT_NOATIME) |
639 | mp->m_flags |= XFS_MOUNT_NOATIME; | 655 | mp->m_flags |= XFS_MOUNT_NOATIME; |
@@ -645,25 +661,7 @@ xfs_mntupdate( | |||
645 | } | 661 | } |
646 | 662 | ||
647 | if (*flags & MS_RDONLY) { | 663 | if (*flags & MS_RDONLY) { |
648 | xfs_refcache_purge_mp(mp); | 664 | xfs_quiesce_fs(mp); |
649 | xfs_flush_buftarg(mp->m_ddev_targp, 0); | ||
650 | xfs_finish_reclaim_all(mp, 0); | ||
651 | |||
652 | /* This loop must run at least twice. | ||
653 | * The first instance of the loop will flush | ||
654 | * most meta data but that will generate more | ||
655 | * meta data (typically directory updates). | ||
656 | * Which then must be flushed and logged before | ||
657 | * we can write the unmount record. | ||
658 | */ | ||
659 | do { | ||
660 | VFS_SYNC(vfsp, REMOUNT_READONLY_FLAGS, NULL, error); | ||
661 | pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); | ||
662 | if (!pincount) { | ||
663 | delay(50); | ||
664 | count++; | ||
665 | } | ||
666 | } while (count < 2); | ||
667 | 665 | ||
668 | /* Ok now write out an unmount record */ | 666 | /* Ok now write out an unmount record */ |
669 | xfs_log_unmount_write(mp); | 667 | xfs_log_unmount_write(mp); |
@@ -879,10 +877,12 @@ xfs_sync( | |||
879 | int flags, | 877 | int flags, |
880 | cred_t *credp) | 878 | cred_t *credp) |
881 | { | 879 | { |
882 | xfs_mount_t *mp; | 880 | xfs_mount_t *mp = XFS_BHVTOM(bdp); |
883 | 881 | ||
884 | mp = XFS_BHVTOM(bdp); | 882 | if (unlikely(flags == SYNC_QUIESCE)) |
885 | return (xfs_syncsub(mp, flags, 0, NULL)); | 883 | return xfs_quiesce_fs(mp); |
884 | else | ||
885 | return xfs_syncsub(mp, flags, 0, NULL); | ||
886 | } | 886 | } |
887 | 887 | ||
888 | /* | 888 | /* |
@@ -1681,7 +1681,7 @@ suffix_strtoul(const char *cp, char **endp, unsigned int base) | |||
1681 | return simple_strtoul(cp, endp, base) << shift_left_factor; | 1681 | return simple_strtoul(cp, endp, base) << shift_left_factor; |
1682 | } | 1682 | } |
1683 | 1683 | ||
1684 | int | 1684 | STATIC int |
1685 | xfs_parseargs( | 1685 | xfs_parseargs( |
1686 | struct bhv_desc *bhv, | 1686 | struct bhv_desc *bhv, |
1687 | char *options, | 1687 | char *options, |
@@ -1867,7 +1867,7 @@ printk("XFS: irixsgid is now a sysctl(2) variable, option is deprecated.\n"); | |||
1867 | return 0; | 1867 | return 0; |
1868 | } | 1868 | } |
1869 | 1869 | ||
1870 | int | 1870 | STATIC int |
1871 | xfs_showargs( | 1871 | xfs_showargs( |
1872 | struct bhv_desc *bhv, | 1872 | struct bhv_desc *bhv, |
1873 | struct seq_file *m) | 1873 | struct seq_file *m) |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 25a526629b12..1377c868f3f4 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. | 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of version 2 of the GNU General Public License as | 5 | * under the terms of version 2 of the GNU General Public License as |
@@ -351,21 +351,28 @@ xfs_setattr( | |||
351 | * If the IDs do change before we take the ilock, we're covered | 351 | * If the IDs do change before we take the ilock, we're covered |
352 | * because the i_*dquot fields will get updated anyway. | 352 | * because the i_*dquot fields will get updated anyway. |
353 | */ | 353 | */ |
354 | if (XFS_IS_QUOTA_ON(mp) && (mask & (XFS_AT_UID|XFS_AT_GID))) { | 354 | if (XFS_IS_QUOTA_ON(mp) && |
355 | (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) { | ||
355 | uint qflags = 0; | 356 | uint qflags = 0; |
356 | 357 | ||
357 | if (mask & XFS_AT_UID) { | 358 | if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) { |
358 | uid = vap->va_uid; | 359 | uid = vap->va_uid; |
359 | qflags |= XFS_QMOPT_UQUOTA; | 360 | qflags |= XFS_QMOPT_UQUOTA; |
360 | } else { | 361 | } else { |
361 | uid = ip->i_d.di_uid; | 362 | uid = ip->i_d.di_uid; |
362 | } | 363 | } |
363 | if (mask & XFS_AT_GID) { | 364 | if ((mask & XFS_AT_GID) && XFS_IS_GQUOTA_ON(mp)) { |
364 | gid = vap->va_gid; | 365 | gid = vap->va_gid; |
365 | qflags |= XFS_QMOPT_GQUOTA; | 366 | qflags |= XFS_QMOPT_GQUOTA; |
366 | } else { | 367 | } else { |
367 | gid = ip->i_d.di_gid; | 368 | gid = ip->i_d.di_gid; |
368 | } | 369 | } |
370 | if ((mask & XFS_AT_PROJID) && XFS_IS_PQUOTA_ON(mp)) { | ||
371 | projid = vap->va_projid; | ||
372 | qflags |= XFS_QMOPT_PQUOTA; | ||
373 | } else { | ||
374 | projid = ip->i_d.di_projid; | ||
375 | } | ||
369 | /* | 376 | /* |
370 | * We take a reference when we initialize udqp and gdqp, | 377 | * We take a reference when we initialize udqp and gdqp, |
371 | * so it is important that we never blindly double trip on | 378 | * so it is important that we never blindly double trip on |
@@ -373,7 +380,8 @@ xfs_setattr( | |||
373 | */ | 380 | */ |
374 | ASSERT(udqp == NULL); | 381 | ASSERT(udqp == NULL); |
375 | ASSERT(gdqp == NULL); | 382 | ASSERT(gdqp == NULL); |
376 | code = XFS_QM_DQVOPALLOC(mp, ip, uid,gid, qflags, &udqp, &gdqp); | 383 | code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags, |
384 | &udqp, &gdqp); | ||
377 | if (code) | 385 | if (code) |
378 | return (code); | 386 | return (code); |
379 | } | 387 | } |
@@ -499,8 +507,6 @@ xfs_setattr( | |||
499 | * that the group ID supplied to the chown() function | 507 | * that the group ID supplied to the chown() function |
500 | * shall be equal to either the group ID or one of the | 508 | * shall be equal to either the group ID or one of the |
501 | * supplementary group IDs of the calling process. | 509 | * supplementary group IDs of the calling process. |
502 | * | ||
503 | * XXX: How does restricted_chown affect projid? | ||
504 | */ | 510 | */ |
505 | if (restricted_chown && | 511 | if (restricted_chown && |
506 | (iuid != uid || (igid != gid && | 512 | (iuid != uid || (igid != gid && |
@@ -510,10 +516,11 @@ xfs_setattr( | |||
510 | goto error_return; | 516 | goto error_return; |
511 | } | 517 | } |
512 | /* | 518 | /* |
513 | * Do a quota reservation only if uid or gid is actually | 519 | * Do a quota reservation only if uid/projid/gid is actually |
514 | * going to change. | 520 | * going to change. |
515 | */ | 521 | */ |
516 | if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || | 522 | if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || |
523 | (XFS_IS_PQUOTA_ON(mp) && iprojid != projid) || | ||
517 | (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { | 524 | (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { |
518 | ASSERT(tp); | 525 | ASSERT(tp); |
519 | code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, | 526 | code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, |
@@ -774,6 +781,7 @@ xfs_setattr( | |||
774 | } | 781 | } |
775 | if (igid != gid) { | 782 | if (igid != gid) { |
776 | if (XFS_IS_GQUOTA_ON(mp)) { | 783 | if (XFS_IS_GQUOTA_ON(mp)) { |
784 | ASSERT(!XFS_IS_PQUOTA_ON(mp)); | ||
777 | ASSERT(mask & XFS_AT_GID); | 785 | ASSERT(mask & XFS_AT_GID); |
778 | ASSERT(gdqp); | 786 | ASSERT(gdqp); |
779 | olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, | 787 | olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, |
@@ -782,6 +790,13 @@ xfs_setattr( | |||
782 | ip->i_d.di_gid = gid; | 790 | ip->i_d.di_gid = gid; |
783 | } | 791 | } |
784 | if (iprojid != projid) { | 792 | if (iprojid != projid) { |
793 | if (XFS_IS_PQUOTA_ON(mp)) { | ||
794 | ASSERT(!XFS_IS_GQUOTA_ON(mp)); | ||
795 | ASSERT(mask & XFS_AT_PROJID); | ||
796 | ASSERT(gdqp); | ||
797 | olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, | ||
798 | &ip->i_gdquot, gdqp); | ||
799 | } | ||
785 | ip->i_d.di_projid = projid; | 800 | ip->i_d.di_projid = projid; |
786 | /* | 801 | /* |
787 | * We may have to rev the inode as well as | 802 | * We may have to rev the inode as well as |
@@ -843,6 +858,8 @@ xfs_setattr( | |||
843 | di_flags |= XFS_DIFLAG_NOATIME; | 858 | di_flags |= XFS_DIFLAG_NOATIME; |
844 | if (vap->va_xflags & XFS_XFLAG_NODUMP) | 859 | if (vap->va_xflags & XFS_XFLAG_NODUMP) |
845 | di_flags |= XFS_DIFLAG_NODUMP; | 860 | di_flags |= XFS_DIFLAG_NODUMP; |
861 | if (vap->va_xflags & XFS_XFLAG_PROJINHERIT) | ||
862 | di_flags |= XFS_DIFLAG_PROJINHERIT; | ||
846 | if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { | 863 | if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { |
847 | if (vap->va_xflags & XFS_XFLAG_RTINHERIT) | 864 | if (vap->va_xflags & XFS_XFLAG_RTINHERIT) |
848 | di_flags |= XFS_DIFLAG_RTINHERIT; | 865 | di_flags |= XFS_DIFLAG_RTINHERIT; |
@@ -1898,7 +1915,9 @@ xfs_create( | |||
1898 | /* Return through std_return after this point. */ | 1915 | /* Return through std_return after this point. */ |
1899 | 1916 | ||
1900 | udqp = gdqp = NULL; | 1917 | udqp = gdqp = NULL; |
1901 | if (vap->va_mask & XFS_AT_PROJID) | 1918 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) |
1919 | prid = dp->i_d.di_projid; | ||
1920 | else if (vap->va_mask & XFS_AT_PROJID) | ||
1902 | prid = (xfs_prid_t)vap->va_projid; | 1921 | prid = (xfs_prid_t)vap->va_projid; |
1903 | else | 1922 | else |
1904 | prid = (xfs_prid_t)dfltprid; | 1923 | prid = (xfs_prid_t)dfltprid; |
@@ -1907,7 +1926,7 @@ xfs_create( | |||
1907 | * Make sure that we have allocated dquot(s) on disk. | 1926 | * Make sure that we have allocated dquot(s) on disk. |
1908 | */ | 1927 | */ |
1909 | error = XFS_QM_DQVOPALLOC(mp, dp, | 1928 | error = XFS_QM_DQVOPALLOC(mp, dp, |
1910 | current_fsuid(credp), current_fsgid(credp), | 1929 | current_fsuid(credp), current_fsgid(credp), prid, |
1911 | XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp); | 1930 | XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp); |
1912 | if (error) | 1931 | if (error) |
1913 | goto std_return; | 1932 | goto std_return; |
@@ -2604,17 +2623,7 @@ xfs_link( | |||
2604 | if (src_vp->v_type == VDIR) | 2623 | if (src_vp->v_type == VDIR) |
2605 | return XFS_ERROR(EPERM); | 2624 | return XFS_ERROR(EPERM); |
2606 | 2625 | ||
2607 | /* | ||
2608 | * For now, manually find the XFS behavior descriptor for | ||
2609 | * the source vnode. If it doesn't exist then something | ||
2610 | * is wrong and we should just return an error. | ||
2611 | * Eventually we need to figure out how link is going to | ||
2612 | * work in the face of stacked vnodes. | ||
2613 | */ | ||
2614 | src_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(src_vp), &xfs_vnodeops); | 2626 | src_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(src_vp), &xfs_vnodeops); |
2615 | if (src_bdp == NULL) { | ||
2616 | return XFS_ERROR(EXDEV); | ||
2617 | } | ||
2618 | sip = XFS_BHVTOI(src_bdp); | 2627 | sip = XFS_BHVTOI(src_bdp); |
2619 | tdp = XFS_BHVTOI(target_dir_bdp); | 2628 | tdp = XFS_BHVTOI(target_dir_bdp); |
2620 | mp = tdp->i_mount; | 2629 | mp = tdp->i_mount; |
@@ -2681,6 +2690,17 @@ xfs_link( | |||
2681 | goto error_return; | 2690 | goto error_return; |
2682 | } | 2691 | } |
2683 | 2692 | ||
2693 | /* | ||
2694 | * If we are using project inheritance, we only allow hard link | ||
2695 | * creation in our tree when the project IDs are the same; else | ||
2696 | * the tree quota mechanism could be circumvented. | ||
2697 | */ | ||
2698 | if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && | ||
2699 | (tdp->i_d.di_projid != sip->i_d.di_projid))) { | ||
2700 | error = XFS_ERROR(EPERM); | ||
2701 | goto error_return; | ||
2702 | } | ||
2703 | |||
2684 | if (resblks == 0 && | 2704 | if (resblks == 0 && |
2685 | (error = XFS_DIR_CANENTER(mp, tp, tdp, target_name, | 2705 | (error = XFS_DIR_CANENTER(mp, tp, tdp, target_name, |
2686 | target_namelen))) | 2706 | target_namelen))) |
@@ -2803,7 +2823,9 @@ xfs_mkdir( | |||
2803 | 2823 | ||
2804 | mp = dp->i_mount; | 2824 | mp = dp->i_mount; |
2805 | udqp = gdqp = NULL; | 2825 | udqp = gdqp = NULL; |
2806 | if (vap->va_mask & XFS_AT_PROJID) | 2826 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) |
2827 | prid = dp->i_d.di_projid; | ||
2828 | else if (vap->va_mask & XFS_AT_PROJID) | ||
2807 | prid = (xfs_prid_t)vap->va_projid; | 2829 | prid = (xfs_prid_t)vap->va_projid; |
2808 | else | 2830 | else |
2809 | prid = (xfs_prid_t)dfltprid; | 2831 | prid = (xfs_prid_t)dfltprid; |
@@ -2812,7 +2834,7 @@ xfs_mkdir( | |||
2812 | * Make sure that we have allocated dquot(s) on disk. | 2834 | * Make sure that we have allocated dquot(s) on disk. |
2813 | */ | 2835 | */ |
2814 | error = XFS_QM_DQVOPALLOC(mp, dp, | 2836 | error = XFS_QM_DQVOPALLOC(mp, dp, |
2815 | current_fsuid(credp), current_fsgid(credp), | 2837 | current_fsuid(credp), current_fsgid(credp), prid, |
2816 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); | 2838 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); |
2817 | if (error) | 2839 | if (error) |
2818 | goto std_return; | 2840 | goto std_return; |
@@ -3357,7 +3379,9 @@ xfs_symlink( | |||
3357 | /* Return through std_return after this point. */ | 3379 | /* Return through std_return after this point. */ |
3358 | 3380 | ||
3359 | udqp = gdqp = NULL; | 3381 | udqp = gdqp = NULL; |
3360 | if (vap->va_mask & XFS_AT_PROJID) | 3382 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) |
3383 | prid = dp->i_d.di_projid; | ||
3384 | else if (vap->va_mask & XFS_AT_PROJID) | ||
3361 | prid = (xfs_prid_t)vap->va_projid; | 3385 | prid = (xfs_prid_t)vap->va_projid; |
3362 | else | 3386 | else |
3363 | prid = (xfs_prid_t)dfltprid; | 3387 | prid = (xfs_prid_t)dfltprid; |
@@ -3366,7 +3390,7 @@ xfs_symlink( | |||
3366 | * Make sure that we have allocated dquot(s) on disk. | 3390 | * Make sure that we have allocated dquot(s) on disk. |
3367 | */ | 3391 | */ |
3368 | error = XFS_QM_DQVOPALLOC(mp, dp, | 3392 | error = XFS_QM_DQVOPALLOC(mp, dp, |
3369 | current_fsuid(credp), current_fsgid(credp), | 3393 | current_fsuid(credp), current_fsgid(credp), prid, |
3370 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); | 3394 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); |
3371 | if (error) | 3395 | if (error) |
3372 | goto std_return; | 3396 | goto std_return; |
@@ -4028,7 +4052,7 @@ xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock) | |||
4028 | * errno on error | 4052 | * errno on error |
4029 | * | 4053 | * |
4030 | */ | 4054 | */ |
4031 | int | 4055 | STATIC int |
4032 | xfs_alloc_file_space( | 4056 | xfs_alloc_file_space( |
4033 | xfs_inode_t *ip, | 4057 | xfs_inode_t *ip, |
4034 | xfs_off_t offset, | 4058 | xfs_off_t offset, |
@@ -4151,9 +4175,8 @@ retry: | |||
4151 | break; | 4175 | break; |
4152 | } | 4176 | } |
4153 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 4177 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
4154 | error = XFS_TRANS_RESERVE_QUOTA_BYDQUOTS(mp, tp, | 4178 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, |
4155 | ip->i_udquot, ip->i_gdquot, resblks, 0, rt ? | 4179 | ip->i_udquot, ip->i_gdquot, resblks, 0, 0); |
4156 | XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS); | ||
4157 | if (error) | 4180 | if (error) |
4158 | goto error1; | 4181 | goto error1; |
4159 | 4182 | ||
@@ -4305,6 +4328,7 @@ xfs_free_file_space( | |||
4305 | xfs_off_t len, | 4328 | xfs_off_t len, |
4306 | int attr_flags) | 4329 | int attr_flags) |
4307 | { | 4330 | { |
4331 | vnode_t *vp; | ||
4308 | int committed; | 4332 | int committed; |
4309 | int done; | 4333 | int done; |
4310 | xfs_off_t end_dmi_offset; | 4334 | xfs_off_t end_dmi_offset; |
@@ -4325,9 +4349,11 @@ xfs_free_file_space( | |||
4325 | xfs_trans_t *tp; | 4349 | xfs_trans_t *tp; |
4326 | int need_iolock = 1; | 4350 | int need_iolock = 1; |
4327 | 4351 | ||
4328 | vn_trace_entry(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address); | 4352 | vp = XFS_ITOV(ip); |
4329 | mp = ip->i_mount; | 4353 | mp = ip->i_mount; |
4330 | 4354 | ||
4355 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); | ||
4356 | |||
4331 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) | 4357 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) |
4332 | return error; | 4358 | return error; |
4333 | 4359 | ||
@@ -4344,7 +4370,7 @@ xfs_free_file_space( | |||
4344 | DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) { | 4370 | DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) { |
4345 | if (end_dmi_offset > ip->i_d.di_size) | 4371 | if (end_dmi_offset > ip->i_d.di_size) |
4346 | end_dmi_offset = ip->i_d.di_size; | 4372 | end_dmi_offset = ip->i_d.di_size; |
4347 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOV(ip), | 4373 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, vp, |
4348 | offset, end_dmi_offset - offset, | 4374 | offset, end_dmi_offset - offset, |
4349 | AT_DELAY_FLAG(attr_flags), NULL); | 4375 | AT_DELAY_FLAG(attr_flags), NULL); |
4350 | if (error) | 4376 | if (error) |
@@ -4363,7 +4389,14 @@ xfs_free_file_space( | |||
4363 | ioffset = offset & ~(rounding - 1); | 4389 | ioffset = offset & ~(rounding - 1); |
4364 | if (ilen & (rounding - 1)) | 4390 | if (ilen & (rounding - 1)) |
4365 | ilen = (ilen + rounding) & ~(rounding - 1); | 4391 | ilen = (ilen + rounding) & ~(rounding - 1); |
4366 | xfs_inval_cached_pages(XFS_ITOV(ip), &(ip->i_iocore), ioffset, 0, 0); | 4392 | |
4393 | if (VN_CACHED(vp) != 0) { | ||
4394 | xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1, | ||
4395 | ctooff(offtoct(ioffset)), -1); | ||
4396 | VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(ioffset)), | ||
4397 | -1, FI_REMAPF_LOCKED); | ||
4398 | } | ||
4399 | |||
4367 | /* | 4400 | /* |
4368 | * Need to zero the stuff we're not freeing, on disk. | 4401 | * Need to zero the stuff we're not freeing, on disk. |
4369 | * If its a realtime file & can't use unwritten extents then we | 4402 | * If its a realtime file & can't use unwritten extents then we |