Commit 742ae1e35b038ed65ddd86182723441ea74db765
Committed by
Ben Myers
1 parent
cab09a81fb
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
xfs: introduce CONFIG_XFS_WARN
Running a CONFIG_XFS_DEBUG kernel in production environments is not the best idea as it introduces significant overhead, can change the behaviour of algorithms (such as allocation) to improve test coverage, and (most importantly) panic the machine on non-fatal errors. There are many cases where all we want to do is run a kernel with more bounds checking enabled, such as is provided by the ASSERT() statements throughout the code, but without all the potential overhead and drawbacks. This patch converts all the ASSERT statements to evaluate as WARN_ON(1) statements and hence if they fail dump a warning and a stack trace to the log. This has minimal overhead and does not change any algorithms, and will allow us to find strange "out of bounds" problems more easily on production machines. There are a few places where assert statements contain debug only code. These are converted to be debug-or-warn only code so that we still get all the assert checks in the code. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Showing 13 changed files with 63 additions and 24 deletions Inline Diff
fs/xfs/Kconfig
1 | config XFS_FS | 1 | config XFS_FS |
2 | tristate "XFS filesystem support" | 2 | tristate "XFS filesystem support" |
3 | depends on BLOCK | 3 | depends on BLOCK |
4 | select EXPORTFS | 4 | select EXPORTFS |
5 | select LIBCRC32C | 5 | select LIBCRC32C |
6 | help | 6 | help |
7 | XFS is a high performance journaling filesystem which originated | 7 | XFS is a high performance journaling filesystem which originated |
8 | on the SGI IRIX platform. It is completely multi-threaded, can | 8 | on the SGI IRIX platform. It is completely multi-threaded, can |
9 | support large files and large filesystems, extended attributes, | 9 | support large files and large filesystems, extended attributes, |
10 | variable block sizes, is extent based, and makes extensive use of | 10 | variable block sizes, is extent based, and makes extensive use of |
11 | Btrees (directories, extents, free space) to aid both performance | 11 | Btrees (directories, extents, free space) to aid both performance |
12 | and scalability. | 12 | and scalability. |
13 | 13 | ||
14 | Refer to the documentation at <http://oss.sgi.com/projects/xfs/> | 14 | Refer to the documentation at <http://oss.sgi.com/projects/xfs/> |
15 | for complete details. This implementation is on-disk compatible | 15 | for complete details. This implementation is on-disk compatible |
16 | with the IRIX version of XFS. | 16 | with the IRIX version of XFS. |
17 | 17 | ||
18 | To compile this file system support as a module, choose M here: the | 18 | To compile this file system support as a module, choose M here: the |
19 | module will be called xfs. Be aware, however, that if the file | 19 | module will be called xfs. Be aware, however, that if the file |
20 | system of your root partition is compiled as a module, you'll need | 20 | system of your root partition is compiled as a module, you'll need |
21 | to use an initial ramdisk (initrd) to boot. | 21 | to use an initial ramdisk (initrd) to boot. |
22 | 22 | ||
23 | config XFS_QUOTA | 23 | config XFS_QUOTA |
24 | bool "XFS Quota support" | 24 | bool "XFS Quota support" |
25 | depends on XFS_FS | 25 | depends on XFS_FS |
26 | select QUOTACTL | 26 | select QUOTACTL |
27 | help | 27 | help |
28 | If you say Y here, you will be able to set limits for disk usage on | 28 | If you say Y here, you will be able to set limits for disk usage on |
29 | a per user and/or a per group basis under XFS. XFS considers quota | 29 | a per user and/or a per group basis under XFS. XFS considers quota |
30 | information as filesystem metadata and uses journaling to provide a | 30 | information as filesystem metadata and uses journaling to provide a |
31 | higher level guarantee of consistency. The on-disk data format for | 31 | higher level guarantee of consistency. The on-disk data format for |
32 | quota is also compatible with the IRIX version of XFS, allowing a | 32 | quota is also compatible with the IRIX version of XFS, allowing a |
33 | filesystem to be migrated between Linux and IRIX without any need | 33 | filesystem to be migrated between Linux and IRIX without any need |
34 | for conversion. | 34 | for conversion. |
35 | 35 | ||
36 | If unsure, say N. More comprehensive documentation can be found in | 36 | If unsure, say N. More comprehensive documentation can be found in |
37 | README.quota in the xfsprogs package. XFS quota can be used either | 37 | README.quota in the xfsprogs package. XFS quota can be used either |
38 | with or without the generic quota support enabled (CONFIG_QUOTA) - | 38 | with or without the generic quota support enabled (CONFIG_QUOTA) - |
39 | they are completely independent subsystems. | 39 | they are completely independent subsystems. |
40 | 40 | ||
41 | config XFS_POSIX_ACL | 41 | config XFS_POSIX_ACL |
42 | bool "XFS POSIX ACL support" | 42 | bool "XFS POSIX ACL support" |
43 | depends on XFS_FS | 43 | depends on XFS_FS |
44 | select FS_POSIX_ACL | 44 | select FS_POSIX_ACL |
45 | help | 45 | help |
46 | POSIX Access Control Lists (ACLs) support permissions for users and | 46 | POSIX Access Control Lists (ACLs) support permissions for users and |
47 | groups beyond the owner/group/world scheme. | 47 | groups beyond the owner/group/world scheme. |
48 | 48 | ||
49 | To learn more about Access Control Lists, visit the POSIX ACLs for | 49 | To learn more about Access Control Lists, visit the POSIX ACLs for |
50 | Linux website <http://acl.bestbits.at/>. | 50 | Linux website <http://acl.bestbits.at/>. |
51 | 51 | ||
52 | If you don't know what Access Control Lists are, say N. | 52 | If you don't know what Access Control Lists are, say N. |
53 | 53 | ||
54 | config XFS_RT | 54 | config XFS_RT |
55 | bool "XFS Realtime subvolume support" | 55 | bool "XFS Realtime subvolume support" |
56 | depends on XFS_FS | 56 | depends on XFS_FS |
57 | help | 57 | help |
58 | If you say Y here you will be able to mount and use XFS filesystems | 58 | If you say Y here you will be able to mount and use XFS filesystems |
59 | which contain a realtime subvolume. The realtime subvolume is a | 59 | which contain a realtime subvolume. The realtime subvolume is a |
60 | separate area of disk space where only file data is stored. It was | 60 | separate area of disk space where only file data is stored. It was |
61 | originally designed to provide deterministic data rates suitable | 61 | originally designed to provide deterministic data rates suitable |
62 | for media streaming applications, but is also useful as a generic | 62 | for media streaming applications, but is also useful as a generic |
63 | mechanism for ensuring data and metadata/log I/Os are completely | 63 | mechanism for ensuring data and metadata/log I/Os are completely |
64 | separated. Regular file I/Os are isolated to a separate device | 64 | separated. Regular file I/Os are isolated to a separate device |
65 | from all other requests, and this can be done quite transparently | 65 | from all other requests, and this can be done quite transparently |
66 | to applications via the inherit-realtime directory inode flag. | 66 | to applications via the inherit-realtime directory inode flag. |
67 | 67 | ||
68 | See the xfs man page in section 5 for additional information. | 68 | See the xfs man page in section 5 for additional information. |
69 | 69 | ||
70 | If unsure, say N. | 70 | If unsure, say N. |
71 | 71 | ||
72 | config XFS_WARN | ||
73 | bool "XFS Verbose Warnings" | ||
74 | depends on XFS_FS && !XFS_DEBUG | ||
75 | help | ||
76 | Say Y here to get an XFS build with many additional warnings. | ||
77 | It converts ASSERT checks to WARN, so will log any out-of-bounds | ||
78 | conditions that occur that would otherwise be missed. It is much | ||
79 | lighter weight than XFS_DEBUG and does not modify algorithms and will | ||
80 | not cause the kernel to panic on non-fatal errors. | ||
81 | |||
82 | However, similar to XFS_DEBUG, it is only advisable to use this if you | ||
83 | are debugging a particular problem. | ||
84 | |||
72 | config XFS_DEBUG | 85 | config XFS_DEBUG |
73 | bool "XFS Debugging support" | 86 | bool "XFS Debugging support" |
74 | depends on XFS_FS | 87 | depends on XFS_FS |
75 | help | 88 | help |
76 | Say Y here to get an XFS build with many debugging features, | 89 | Say Y here to get an XFS build with many debugging features, |
77 | including ASSERT checks, function wrappers around macros, | 90 | including ASSERT checks, function wrappers around macros, |
78 | and extra sanity-checking functions in various code paths. | 91 | and extra sanity-checking functions in various code paths. |
79 | 92 | ||
80 | Note that the resulting code will be HUGE and SLOW, and probably | 93 | Note that the resulting code will be HUGE and SLOW, and probably |
81 | not useful unless you are debugging a particular problem. | 94 | not useful unless you are debugging a particular problem. |
82 | 95 | ||
83 | Say N unless you are an XFS developer, or you play one on TV. | 96 | Say N unless you are an XFS developer, or you play one on TV. |
84 | 97 |
fs/xfs/mrlock.h
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | 6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | * | 8 | * |
9 | * This program is distributed in the hope that it would be useful, | 9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | #ifndef __XFS_SUPPORT_MRLOCK_H__ | 18 | #ifndef __XFS_SUPPORT_MRLOCK_H__ |
19 | #define __XFS_SUPPORT_MRLOCK_H__ | 19 | #define __XFS_SUPPORT_MRLOCK_H__ |
20 | 20 | ||
21 | #include <linux/rwsem.h> | 21 | #include <linux/rwsem.h> |
22 | 22 | ||
23 | typedef struct { | 23 | typedef struct { |
24 | struct rw_semaphore mr_lock; | 24 | struct rw_semaphore mr_lock; |
25 | #ifdef DEBUG | 25 | #if defined(DEBUG) || defined(XFS_WARN) |
26 | int mr_writer; | 26 | int mr_writer; |
27 | #endif | 27 | #endif |
28 | } mrlock_t; | 28 | } mrlock_t; |
29 | 29 | ||
30 | #ifdef DEBUG | 30 | #if defined(DEBUG) || defined(XFS_WARN) |
31 | #define mrinit(mrp, name) \ | 31 | #define mrinit(mrp, name) \ |
32 | do { (mrp)->mr_writer = 0; init_rwsem(&(mrp)->mr_lock); } while (0) | 32 | do { (mrp)->mr_writer = 0; init_rwsem(&(mrp)->mr_lock); } while (0) |
33 | #else | 33 | #else |
34 | #define mrinit(mrp, name) \ | 34 | #define mrinit(mrp, name) \ |
35 | do { init_rwsem(&(mrp)->mr_lock); } while (0) | 35 | do { init_rwsem(&(mrp)->mr_lock); } while (0) |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | #define mrlock_init(mrp, t,n,s) mrinit(mrp, n) | 38 | #define mrlock_init(mrp, t,n,s) mrinit(mrp, n) |
39 | #define mrfree(mrp) do { } while (0) | 39 | #define mrfree(mrp) do { } while (0) |
40 | 40 | ||
41 | static inline void mraccess_nested(mrlock_t *mrp, int subclass) | 41 | static inline void mraccess_nested(mrlock_t *mrp, int subclass) |
42 | { | 42 | { |
43 | down_read_nested(&mrp->mr_lock, subclass); | 43 | down_read_nested(&mrp->mr_lock, subclass); |
44 | } | 44 | } |
45 | 45 | ||
46 | static inline void mrupdate_nested(mrlock_t *mrp, int subclass) | 46 | static inline void mrupdate_nested(mrlock_t *mrp, int subclass) |
47 | { | 47 | { |
48 | down_write_nested(&mrp->mr_lock, subclass); | 48 | down_write_nested(&mrp->mr_lock, subclass); |
49 | #ifdef DEBUG | 49 | #if defined(DEBUG) || defined(XFS_WARN) |
50 | mrp->mr_writer = 1; | 50 | mrp->mr_writer = 1; |
51 | #endif | 51 | #endif |
52 | } | 52 | } |
53 | 53 | ||
54 | static inline int mrtryaccess(mrlock_t *mrp) | 54 | static inline int mrtryaccess(mrlock_t *mrp) |
55 | { | 55 | { |
56 | return down_read_trylock(&mrp->mr_lock); | 56 | return down_read_trylock(&mrp->mr_lock); |
57 | } | 57 | } |
58 | 58 | ||
59 | static inline int mrtryupdate(mrlock_t *mrp) | 59 | static inline int mrtryupdate(mrlock_t *mrp) |
60 | { | 60 | { |
61 | if (!down_write_trylock(&mrp->mr_lock)) | 61 | if (!down_write_trylock(&mrp->mr_lock)) |
62 | return 0; | 62 | return 0; |
63 | #ifdef DEBUG | 63 | #if defined(DEBUG) || defined(XFS_WARN) |
64 | mrp->mr_writer = 1; | 64 | mrp->mr_writer = 1; |
65 | #endif | 65 | #endif |
66 | return 1; | 66 | return 1; |
67 | } | 67 | } |
68 | 68 | ||
69 | static inline void mrunlock_excl(mrlock_t *mrp) | 69 | static inline void mrunlock_excl(mrlock_t *mrp) |
70 | { | 70 | { |
71 | #ifdef DEBUG | 71 | #if defined(DEBUG) || defined(XFS_WARN) |
72 | mrp->mr_writer = 0; | 72 | mrp->mr_writer = 0; |
73 | #endif | 73 | #endif |
74 | up_write(&mrp->mr_lock); | 74 | up_write(&mrp->mr_lock); |
75 | } | 75 | } |
76 | 76 | ||
77 | static inline void mrunlock_shared(mrlock_t *mrp) | 77 | static inline void mrunlock_shared(mrlock_t *mrp) |
78 | { | 78 | { |
79 | up_read(&mrp->mr_lock); | 79 | up_read(&mrp->mr_lock); |
80 | } | 80 | } |
81 | 81 | ||
82 | static inline void mrdemote(mrlock_t *mrp) | 82 | static inline void mrdemote(mrlock_t *mrp) |
83 | { | 83 | { |
84 | #ifdef DEBUG | 84 | #if defined(DEBUG) || defined(XFS_WARN) |
85 | mrp->mr_writer = 0; | 85 | mrp->mr_writer = 0; |
86 | #endif | 86 | #endif |
87 | downgrade_write(&mrp->mr_lock); | 87 | downgrade_write(&mrp->mr_lock); |
88 | } | 88 | } |
89 | 89 | ||
90 | #endif /* __XFS_SUPPORT_MRLOCK_H__ */ | 90 | #endif /* __XFS_SUPPORT_MRLOCK_H__ */ |
91 | 91 |
fs/xfs/xfs.h
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | 6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | * | 8 | * |
9 | * This program is distributed in the hope that it would be useful, | 9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | #ifndef __XFS_H__ | 18 | #ifndef __XFS_H__ |
19 | #define __XFS_H__ | 19 | #define __XFS_H__ |
20 | 20 | ||
21 | #ifdef CONFIG_XFS_DEBUG | 21 | #ifdef CONFIG_XFS_DEBUG |
22 | #define STATIC | 22 | #define STATIC |
23 | #define DEBUG 1 | 23 | #define DEBUG 1 |
24 | #define XFS_BUF_LOCK_TRACKING 1 | 24 | #define XFS_BUF_LOCK_TRACKING 1 |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | #ifdef CONFIG_XFS_WARN | ||
28 | #define XFS_WARN 1 | ||
29 | #endif | ||
30 | |||
31 | |||
27 | #include "xfs_linux.h" | 32 | #include "xfs_linux.h" |
28 | 33 | ||
29 | #endif /* __XFS_H__ */ | 34 | #endif /* __XFS_H__ */ |
30 | 35 |
fs/xfs/xfs_alloc_btree.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | 6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | * | 8 | * |
9 | * This program is distributed in the hope that it would be useful, | 9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | #include "xfs.h" | 18 | #include "xfs.h" |
19 | #include "xfs_fs.h" | 19 | #include "xfs_fs.h" |
20 | #include "xfs_types.h" | 20 | #include "xfs_types.h" |
21 | #include "xfs_log.h" | 21 | #include "xfs_log.h" |
22 | #include "xfs_trans.h" | 22 | #include "xfs_trans.h" |
23 | #include "xfs_sb.h" | 23 | #include "xfs_sb.h" |
24 | #include "xfs_ag.h" | 24 | #include "xfs_ag.h" |
25 | #include "xfs_mount.h" | 25 | #include "xfs_mount.h" |
26 | #include "xfs_bmap_btree.h" | 26 | #include "xfs_bmap_btree.h" |
27 | #include "xfs_alloc_btree.h" | 27 | #include "xfs_alloc_btree.h" |
28 | #include "xfs_ialloc_btree.h" | 28 | #include "xfs_ialloc_btree.h" |
29 | #include "xfs_dinode.h" | 29 | #include "xfs_dinode.h" |
30 | #include "xfs_inode.h" | 30 | #include "xfs_inode.h" |
31 | #include "xfs_btree.h" | 31 | #include "xfs_btree.h" |
32 | #include "xfs_alloc.h" | 32 | #include "xfs_alloc.h" |
33 | #include "xfs_extent_busy.h" | 33 | #include "xfs_extent_busy.h" |
34 | #include "xfs_error.h" | 34 | #include "xfs_error.h" |
35 | #include "xfs_trace.h" | 35 | #include "xfs_trace.h" |
36 | #include "xfs_cksum.h" | 36 | #include "xfs_cksum.h" |
37 | 37 | ||
38 | 38 | ||
39 | STATIC struct xfs_btree_cur * | 39 | STATIC struct xfs_btree_cur * |
40 | xfs_allocbt_dup_cursor( | 40 | xfs_allocbt_dup_cursor( |
41 | struct xfs_btree_cur *cur) | 41 | struct xfs_btree_cur *cur) |
42 | { | 42 | { |
43 | return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp, | 43 | return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp, |
44 | cur->bc_private.a.agbp, cur->bc_private.a.agno, | 44 | cur->bc_private.a.agbp, cur->bc_private.a.agno, |
45 | cur->bc_btnum); | 45 | cur->bc_btnum); |
46 | } | 46 | } |
47 | 47 | ||
48 | STATIC void | 48 | STATIC void |
49 | xfs_allocbt_set_root( | 49 | xfs_allocbt_set_root( |
50 | struct xfs_btree_cur *cur, | 50 | struct xfs_btree_cur *cur, |
51 | union xfs_btree_ptr *ptr, | 51 | union xfs_btree_ptr *ptr, |
52 | int inc) | 52 | int inc) |
53 | { | 53 | { |
54 | struct xfs_buf *agbp = cur->bc_private.a.agbp; | 54 | struct xfs_buf *agbp = cur->bc_private.a.agbp; |
55 | struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); | 55 | struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); |
56 | xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); | 56 | xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); |
57 | int btnum = cur->bc_btnum; | 57 | int btnum = cur->bc_btnum; |
58 | struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno); | 58 | struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno); |
59 | 59 | ||
60 | ASSERT(ptr->s != 0); | 60 | ASSERT(ptr->s != 0); |
61 | 61 | ||
62 | agf->agf_roots[btnum] = ptr->s; | 62 | agf->agf_roots[btnum] = ptr->s; |
63 | be32_add_cpu(&agf->agf_levels[btnum], inc); | 63 | be32_add_cpu(&agf->agf_levels[btnum], inc); |
64 | pag->pagf_levels[btnum] += inc; | 64 | pag->pagf_levels[btnum] += inc; |
65 | xfs_perag_put(pag); | 65 | xfs_perag_put(pag); |
66 | 66 | ||
67 | xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); | 67 | xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); |
68 | } | 68 | } |
69 | 69 | ||
70 | STATIC int | 70 | STATIC int |
71 | xfs_allocbt_alloc_block( | 71 | xfs_allocbt_alloc_block( |
72 | struct xfs_btree_cur *cur, | 72 | struct xfs_btree_cur *cur, |
73 | union xfs_btree_ptr *start, | 73 | union xfs_btree_ptr *start, |
74 | union xfs_btree_ptr *new, | 74 | union xfs_btree_ptr *new, |
75 | int length, | 75 | int length, |
76 | int *stat) | 76 | int *stat) |
77 | { | 77 | { |
78 | int error; | 78 | int error; |
79 | xfs_agblock_t bno; | 79 | xfs_agblock_t bno; |
80 | 80 | ||
81 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); | 81 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); |
82 | 82 | ||
83 | /* Allocate the new block from the freelist. If we can't, give up. */ | 83 | /* Allocate the new block from the freelist. If we can't, give up. */ |
84 | error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, | 84 | error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, |
85 | &bno, 1); | 85 | &bno, 1); |
86 | if (error) { | 86 | if (error) { |
87 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | 87 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); |
88 | return error; | 88 | return error; |
89 | } | 89 | } |
90 | 90 | ||
91 | if (bno == NULLAGBLOCK) { | 91 | if (bno == NULLAGBLOCK) { |
92 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | 92 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); |
93 | *stat = 0; | 93 | *stat = 0; |
94 | return 0; | 94 | return 0; |
95 | } | 95 | } |
96 | 96 | ||
97 | xfs_extent_busy_reuse(cur->bc_mp, cur->bc_private.a.agno, bno, 1, false); | 97 | xfs_extent_busy_reuse(cur->bc_mp, cur->bc_private.a.agno, bno, 1, false); |
98 | 98 | ||
99 | xfs_trans_agbtree_delta(cur->bc_tp, 1); | 99 | xfs_trans_agbtree_delta(cur->bc_tp, 1); |
100 | new->s = cpu_to_be32(bno); | 100 | new->s = cpu_to_be32(bno); |
101 | 101 | ||
102 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | 102 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); |
103 | *stat = 1; | 103 | *stat = 1; |
104 | return 0; | 104 | return 0; |
105 | } | 105 | } |
106 | 106 | ||
107 | STATIC int | 107 | STATIC int |
108 | xfs_allocbt_free_block( | 108 | xfs_allocbt_free_block( |
109 | struct xfs_btree_cur *cur, | 109 | struct xfs_btree_cur *cur, |
110 | struct xfs_buf *bp) | 110 | struct xfs_buf *bp) |
111 | { | 111 | { |
112 | struct xfs_buf *agbp = cur->bc_private.a.agbp; | 112 | struct xfs_buf *agbp = cur->bc_private.a.agbp; |
113 | struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); | 113 | struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); |
114 | xfs_agblock_t bno; | 114 | xfs_agblock_t bno; |
115 | int error; | 115 | int error; |
116 | 116 | ||
117 | bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp)); | 117 | bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp)); |
118 | error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1); | 118 | error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1); |
119 | if (error) | 119 | if (error) |
120 | return error; | 120 | return error; |
121 | 121 | ||
122 | xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, | 122 | xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, |
123 | XFS_EXTENT_BUSY_SKIP_DISCARD); | 123 | XFS_EXTENT_BUSY_SKIP_DISCARD); |
124 | xfs_trans_agbtree_delta(cur->bc_tp, -1); | 124 | xfs_trans_agbtree_delta(cur->bc_tp, -1); |
125 | 125 | ||
126 | xfs_trans_binval(cur->bc_tp, bp); | 126 | xfs_trans_binval(cur->bc_tp, bp); |
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | /* | 130 | /* |
131 | * Update the longest extent in the AGF | 131 | * Update the longest extent in the AGF |
132 | */ | 132 | */ |
133 | STATIC void | 133 | STATIC void |
134 | xfs_allocbt_update_lastrec( | 134 | xfs_allocbt_update_lastrec( |
135 | struct xfs_btree_cur *cur, | 135 | struct xfs_btree_cur *cur, |
136 | struct xfs_btree_block *block, | 136 | struct xfs_btree_block *block, |
137 | union xfs_btree_rec *rec, | 137 | union xfs_btree_rec *rec, |
138 | int ptr, | 138 | int ptr, |
139 | int reason) | 139 | int reason) |
140 | { | 140 | { |
141 | struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); | 141 | struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); |
142 | xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); | 142 | xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); |
143 | struct xfs_perag *pag; | 143 | struct xfs_perag *pag; |
144 | __be32 len; | 144 | __be32 len; |
145 | int numrecs; | 145 | int numrecs; |
146 | 146 | ||
147 | ASSERT(cur->bc_btnum == XFS_BTNUM_CNT); | 147 | ASSERT(cur->bc_btnum == XFS_BTNUM_CNT); |
148 | 148 | ||
149 | switch (reason) { | 149 | switch (reason) { |
150 | case LASTREC_UPDATE: | 150 | case LASTREC_UPDATE: |
151 | /* | 151 | /* |
152 | * If this is the last leaf block and it's the last record, | 152 | * If this is the last leaf block and it's the last record, |
153 | * then update the size of the longest extent in the AG. | 153 | * then update the size of the longest extent in the AG. |
154 | */ | 154 | */ |
155 | if (ptr != xfs_btree_get_numrecs(block)) | 155 | if (ptr != xfs_btree_get_numrecs(block)) |
156 | return; | 156 | return; |
157 | len = rec->alloc.ar_blockcount; | 157 | len = rec->alloc.ar_blockcount; |
158 | break; | 158 | break; |
159 | case LASTREC_INSREC: | 159 | case LASTREC_INSREC: |
160 | if (be32_to_cpu(rec->alloc.ar_blockcount) <= | 160 | if (be32_to_cpu(rec->alloc.ar_blockcount) <= |
161 | be32_to_cpu(agf->agf_longest)) | 161 | be32_to_cpu(agf->agf_longest)) |
162 | return; | 162 | return; |
163 | len = rec->alloc.ar_blockcount; | 163 | len = rec->alloc.ar_blockcount; |
164 | break; | 164 | break; |
165 | case LASTREC_DELREC: | 165 | case LASTREC_DELREC: |
166 | numrecs = xfs_btree_get_numrecs(block); | 166 | numrecs = xfs_btree_get_numrecs(block); |
167 | if (ptr <= numrecs) | 167 | if (ptr <= numrecs) |
168 | return; | 168 | return; |
169 | ASSERT(ptr == numrecs + 1); | 169 | ASSERT(ptr == numrecs + 1); |
170 | 170 | ||
171 | if (numrecs) { | 171 | if (numrecs) { |
172 | xfs_alloc_rec_t *rrp; | 172 | xfs_alloc_rec_t *rrp; |
173 | 173 | ||
174 | rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs); | 174 | rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs); |
175 | len = rrp->ar_blockcount; | 175 | len = rrp->ar_blockcount; |
176 | } else { | 176 | } else { |
177 | len = 0; | 177 | len = 0; |
178 | } | 178 | } |
179 | 179 | ||
180 | break; | 180 | break; |
181 | default: | 181 | default: |
182 | ASSERT(0); | 182 | ASSERT(0); |
183 | return; | 183 | return; |
184 | } | 184 | } |
185 | 185 | ||
186 | agf->agf_longest = len; | 186 | agf->agf_longest = len; |
187 | pag = xfs_perag_get(cur->bc_mp, seqno); | 187 | pag = xfs_perag_get(cur->bc_mp, seqno); |
188 | pag->pagf_longest = be32_to_cpu(len); | 188 | pag->pagf_longest = be32_to_cpu(len); |
189 | xfs_perag_put(pag); | 189 | xfs_perag_put(pag); |
190 | xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_LONGEST); | 190 | xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_LONGEST); |
191 | } | 191 | } |
192 | 192 | ||
193 | STATIC int | 193 | STATIC int |
194 | xfs_allocbt_get_minrecs( | 194 | xfs_allocbt_get_minrecs( |
195 | struct xfs_btree_cur *cur, | 195 | struct xfs_btree_cur *cur, |
196 | int level) | 196 | int level) |
197 | { | 197 | { |
198 | return cur->bc_mp->m_alloc_mnr[level != 0]; | 198 | return cur->bc_mp->m_alloc_mnr[level != 0]; |
199 | } | 199 | } |
200 | 200 | ||
201 | STATIC int | 201 | STATIC int |
202 | xfs_allocbt_get_maxrecs( | 202 | xfs_allocbt_get_maxrecs( |
203 | struct xfs_btree_cur *cur, | 203 | struct xfs_btree_cur *cur, |
204 | int level) | 204 | int level) |
205 | { | 205 | { |
206 | return cur->bc_mp->m_alloc_mxr[level != 0]; | 206 | return cur->bc_mp->m_alloc_mxr[level != 0]; |
207 | } | 207 | } |
208 | 208 | ||
209 | STATIC void | 209 | STATIC void |
210 | xfs_allocbt_init_key_from_rec( | 210 | xfs_allocbt_init_key_from_rec( |
211 | union xfs_btree_key *key, | 211 | union xfs_btree_key *key, |
212 | union xfs_btree_rec *rec) | 212 | union xfs_btree_rec *rec) |
213 | { | 213 | { |
214 | ASSERT(rec->alloc.ar_startblock != 0); | 214 | ASSERT(rec->alloc.ar_startblock != 0); |
215 | 215 | ||
216 | key->alloc.ar_startblock = rec->alloc.ar_startblock; | 216 | key->alloc.ar_startblock = rec->alloc.ar_startblock; |
217 | key->alloc.ar_blockcount = rec->alloc.ar_blockcount; | 217 | key->alloc.ar_blockcount = rec->alloc.ar_blockcount; |
218 | } | 218 | } |
219 | 219 | ||
220 | STATIC void | 220 | STATIC void |
221 | xfs_allocbt_init_rec_from_key( | 221 | xfs_allocbt_init_rec_from_key( |
222 | union xfs_btree_key *key, | 222 | union xfs_btree_key *key, |
223 | union xfs_btree_rec *rec) | 223 | union xfs_btree_rec *rec) |
224 | { | 224 | { |
225 | ASSERT(key->alloc.ar_startblock != 0); | 225 | ASSERT(key->alloc.ar_startblock != 0); |
226 | 226 | ||
227 | rec->alloc.ar_startblock = key->alloc.ar_startblock; | 227 | rec->alloc.ar_startblock = key->alloc.ar_startblock; |
228 | rec->alloc.ar_blockcount = key->alloc.ar_blockcount; | 228 | rec->alloc.ar_blockcount = key->alloc.ar_blockcount; |
229 | } | 229 | } |
230 | 230 | ||
231 | STATIC void | 231 | STATIC void |
232 | xfs_allocbt_init_rec_from_cur( | 232 | xfs_allocbt_init_rec_from_cur( |
233 | struct xfs_btree_cur *cur, | 233 | struct xfs_btree_cur *cur, |
234 | union xfs_btree_rec *rec) | 234 | union xfs_btree_rec *rec) |
235 | { | 235 | { |
236 | ASSERT(cur->bc_rec.a.ar_startblock != 0); | 236 | ASSERT(cur->bc_rec.a.ar_startblock != 0); |
237 | 237 | ||
238 | rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock); | 238 | rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock); |
239 | rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount); | 239 | rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount); |
240 | } | 240 | } |
241 | 241 | ||
242 | STATIC void | 242 | STATIC void |
243 | xfs_allocbt_init_ptr_from_cur( | 243 | xfs_allocbt_init_ptr_from_cur( |
244 | struct xfs_btree_cur *cur, | 244 | struct xfs_btree_cur *cur, |
245 | union xfs_btree_ptr *ptr) | 245 | union xfs_btree_ptr *ptr) |
246 | { | 246 | { |
247 | struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); | 247 | struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); |
248 | 248 | ||
249 | ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno)); | 249 | ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno)); |
250 | ASSERT(agf->agf_roots[cur->bc_btnum] != 0); | 250 | ASSERT(agf->agf_roots[cur->bc_btnum] != 0); |
251 | 251 | ||
252 | ptr->s = agf->agf_roots[cur->bc_btnum]; | 252 | ptr->s = agf->agf_roots[cur->bc_btnum]; |
253 | } | 253 | } |
254 | 254 | ||
255 | STATIC __int64_t | 255 | STATIC __int64_t |
256 | xfs_allocbt_key_diff( | 256 | xfs_allocbt_key_diff( |
257 | struct xfs_btree_cur *cur, | 257 | struct xfs_btree_cur *cur, |
258 | union xfs_btree_key *key) | 258 | union xfs_btree_key *key) |
259 | { | 259 | { |
260 | xfs_alloc_rec_incore_t *rec = &cur->bc_rec.a; | 260 | xfs_alloc_rec_incore_t *rec = &cur->bc_rec.a; |
261 | xfs_alloc_key_t *kp = &key->alloc; | 261 | xfs_alloc_key_t *kp = &key->alloc; |
262 | __int64_t diff; | 262 | __int64_t diff; |
263 | 263 | ||
264 | if (cur->bc_btnum == XFS_BTNUM_BNO) { | 264 | if (cur->bc_btnum == XFS_BTNUM_BNO) { |
265 | return (__int64_t)be32_to_cpu(kp->ar_startblock) - | 265 | return (__int64_t)be32_to_cpu(kp->ar_startblock) - |
266 | rec->ar_startblock; | 266 | rec->ar_startblock; |
267 | } | 267 | } |
268 | 268 | ||
269 | diff = (__int64_t)be32_to_cpu(kp->ar_blockcount) - rec->ar_blockcount; | 269 | diff = (__int64_t)be32_to_cpu(kp->ar_blockcount) - rec->ar_blockcount; |
270 | if (diff) | 270 | if (diff) |
271 | return diff; | 271 | return diff; |
272 | 272 | ||
273 | return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; | 273 | return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; |
274 | } | 274 | } |
275 | 275 | ||
276 | static bool | 276 | static bool |
277 | xfs_allocbt_verify( | 277 | xfs_allocbt_verify( |
278 | struct xfs_buf *bp) | 278 | struct xfs_buf *bp) |
279 | { | 279 | { |
280 | struct xfs_mount *mp = bp->b_target->bt_mount; | 280 | struct xfs_mount *mp = bp->b_target->bt_mount; |
281 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); | 281 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); |
282 | struct xfs_perag *pag = bp->b_pag; | 282 | struct xfs_perag *pag = bp->b_pag; |
283 | unsigned int level; | 283 | unsigned int level; |
284 | 284 | ||
285 | /* | 285 | /* |
286 | * magic number and level verification | 286 | * magic number and level verification |
287 | * | 287 | * |
288 | * During growfs operations, we can't verify the exact level or owner as | 288 | * During growfs operations, we can't verify the exact level or owner as |
289 | * the perag is not fully initialised and hence not attached to the | 289 | * the perag is not fully initialised and hence not attached to the |
290 | * buffer. In this case, check against the maximum tree depth. | 290 | * buffer. In this case, check against the maximum tree depth. |
291 | * | 291 | * |
292 | * Similarly, during log recovery we will have a perag structure | 292 | * Similarly, during log recovery we will have a perag structure |
293 | * attached, but the agf information will not yet have been initialised | 293 | * attached, but the agf information will not yet have been initialised |
294 | * from the on disk AGF. Again, we can only check against maximum limits | 294 | * from the on disk AGF. Again, we can only check against maximum limits |
295 | * in this case. | 295 | * in this case. |
296 | */ | 296 | */ |
297 | level = be16_to_cpu(block->bb_level); | 297 | level = be16_to_cpu(block->bb_level); |
298 | switch (block->bb_magic) { | 298 | switch (block->bb_magic) { |
299 | case cpu_to_be32(XFS_ABTB_CRC_MAGIC): | 299 | case cpu_to_be32(XFS_ABTB_CRC_MAGIC): |
300 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | 300 | if (!xfs_sb_version_hascrc(&mp->m_sb)) |
301 | return false; | 301 | return false; |
302 | if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid)) | 302 | if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid)) |
303 | return false; | 303 | return false; |
304 | if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) | 304 | if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) |
305 | return false; | 305 | return false; |
306 | if (pag && | 306 | if (pag && |
307 | be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) | 307 | be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) |
308 | return false; | 308 | return false; |
309 | /* fall through */ | 309 | /* fall through */ |
310 | case cpu_to_be32(XFS_ABTB_MAGIC): | 310 | case cpu_to_be32(XFS_ABTB_MAGIC): |
311 | if (pag && pag->pagf_init) { | 311 | if (pag && pag->pagf_init) { |
312 | if (level >= pag->pagf_levels[XFS_BTNUM_BNOi]) | 312 | if (level >= pag->pagf_levels[XFS_BTNUM_BNOi]) |
313 | return false; | 313 | return false; |
314 | } else if (level >= mp->m_ag_maxlevels) | 314 | } else if (level >= mp->m_ag_maxlevels) |
315 | return false; | 315 | return false; |
316 | break; | 316 | break; |
317 | case cpu_to_be32(XFS_ABTC_CRC_MAGIC): | 317 | case cpu_to_be32(XFS_ABTC_CRC_MAGIC): |
318 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | 318 | if (!xfs_sb_version_hascrc(&mp->m_sb)) |
319 | return false; | 319 | return false; |
320 | if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid)) | 320 | if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid)) |
321 | return false; | 321 | return false; |
322 | if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) | 322 | if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) |
323 | return false; | 323 | return false; |
324 | if (pag && | 324 | if (pag && |
325 | be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) | 325 | be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) |
326 | return false; | 326 | return false; |
327 | /* fall through */ | 327 | /* fall through */ |
328 | case cpu_to_be32(XFS_ABTC_MAGIC): | 328 | case cpu_to_be32(XFS_ABTC_MAGIC): |
329 | if (pag && pag->pagf_init) { | 329 | if (pag && pag->pagf_init) { |
330 | if (level >= pag->pagf_levels[XFS_BTNUM_CNTi]) | 330 | if (level >= pag->pagf_levels[XFS_BTNUM_CNTi]) |
331 | return false; | 331 | return false; |
332 | } else if (level >= mp->m_ag_maxlevels) | 332 | } else if (level >= mp->m_ag_maxlevels) |
333 | return false; | 333 | return false; |
334 | break; | 334 | break; |
335 | default: | 335 | default: |
336 | return false; | 336 | return false; |
337 | } | 337 | } |
338 | 338 | ||
339 | /* numrecs verification */ | 339 | /* numrecs verification */ |
340 | if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[level != 0]) | 340 | if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[level != 0]) |
341 | return false; | 341 | return false; |
342 | 342 | ||
343 | /* sibling pointer verification */ | 343 | /* sibling pointer verification */ |
344 | if (!block->bb_u.s.bb_leftsib || | 344 | if (!block->bb_u.s.bb_leftsib || |
345 | (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks && | 345 | (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks && |
346 | block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK))) | 346 | block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK))) |
347 | return false; | 347 | return false; |
348 | if (!block->bb_u.s.bb_rightsib || | 348 | if (!block->bb_u.s.bb_rightsib || |
349 | (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks && | 349 | (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks && |
350 | block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK))) | 350 | block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK))) |
351 | return false; | 351 | return false; |
352 | 352 | ||
353 | return true; | 353 | return true; |
354 | } | 354 | } |
355 | 355 | ||
356 | static void | 356 | static void |
357 | xfs_allocbt_read_verify( | 357 | xfs_allocbt_read_verify( |
358 | struct xfs_buf *bp) | 358 | struct xfs_buf *bp) |
359 | { | 359 | { |
360 | if (!(xfs_btree_sblock_verify_crc(bp) && | 360 | if (!(xfs_btree_sblock_verify_crc(bp) && |
361 | xfs_allocbt_verify(bp))) { | 361 | xfs_allocbt_verify(bp))) { |
362 | trace_xfs_btree_corrupt(bp, _RET_IP_); | 362 | trace_xfs_btree_corrupt(bp, _RET_IP_); |
363 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, | 363 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, |
364 | bp->b_target->bt_mount, bp->b_addr); | 364 | bp->b_target->bt_mount, bp->b_addr); |
365 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 365 | xfs_buf_ioerror(bp, EFSCORRUPTED); |
366 | } | 366 | } |
367 | } | 367 | } |
368 | 368 | ||
369 | static void | 369 | static void |
370 | xfs_allocbt_write_verify( | 370 | xfs_allocbt_write_verify( |
371 | struct xfs_buf *bp) | 371 | struct xfs_buf *bp) |
372 | { | 372 | { |
373 | if (!xfs_allocbt_verify(bp)) { | 373 | if (!xfs_allocbt_verify(bp)) { |
374 | trace_xfs_btree_corrupt(bp, _RET_IP_); | 374 | trace_xfs_btree_corrupt(bp, _RET_IP_); |
375 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, | 375 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, |
376 | bp->b_target->bt_mount, bp->b_addr); | 376 | bp->b_target->bt_mount, bp->b_addr); |
377 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 377 | xfs_buf_ioerror(bp, EFSCORRUPTED); |
378 | } | 378 | } |
379 | xfs_btree_sblock_calc_crc(bp); | 379 | xfs_btree_sblock_calc_crc(bp); |
380 | 380 | ||
381 | } | 381 | } |
382 | 382 | ||
383 | const struct xfs_buf_ops xfs_allocbt_buf_ops = { | 383 | const struct xfs_buf_ops xfs_allocbt_buf_ops = { |
384 | .verify_read = xfs_allocbt_read_verify, | 384 | .verify_read = xfs_allocbt_read_verify, |
385 | .verify_write = xfs_allocbt_write_verify, | 385 | .verify_write = xfs_allocbt_write_verify, |
386 | }; | 386 | }; |
387 | 387 | ||
388 | 388 | ||
389 | #ifdef DEBUG | 389 | #if defined(DEBUG) || defined(XFS_WARN) |
390 | STATIC int | 390 | STATIC int |
391 | xfs_allocbt_keys_inorder( | 391 | xfs_allocbt_keys_inorder( |
392 | struct xfs_btree_cur *cur, | 392 | struct xfs_btree_cur *cur, |
393 | union xfs_btree_key *k1, | 393 | union xfs_btree_key *k1, |
394 | union xfs_btree_key *k2) | 394 | union xfs_btree_key *k2) |
395 | { | 395 | { |
396 | if (cur->bc_btnum == XFS_BTNUM_BNO) { | 396 | if (cur->bc_btnum == XFS_BTNUM_BNO) { |
397 | return be32_to_cpu(k1->alloc.ar_startblock) < | 397 | return be32_to_cpu(k1->alloc.ar_startblock) < |
398 | be32_to_cpu(k2->alloc.ar_startblock); | 398 | be32_to_cpu(k2->alloc.ar_startblock); |
399 | } else { | 399 | } else { |
400 | return be32_to_cpu(k1->alloc.ar_blockcount) < | 400 | return be32_to_cpu(k1->alloc.ar_blockcount) < |
401 | be32_to_cpu(k2->alloc.ar_blockcount) || | 401 | be32_to_cpu(k2->alloc.ar_blockcount) || |
402 | (k1->alloc.ar_blockcount == k2->alloc.ar_blockcount && | 402 | (k1->alloc.ar_blockcount == k2->alloc.ar_blockcount && |
403 | be32_to_cpu(k1->alloc.ar_startblock) < | 403 | be32_to_cpu(k1->alloc.ar_startblock) < |
404 | be32_to_cpu(k2->alloc.ar_startblock)); | 404 | be32_to_cpu(k2->alloc.ar_startblock)); |
405 | } | 405 | } |
406 | } | 406 | } |
407 | 407 | ||
408 | STATIC int | 408 | STATIC int |
409 | xfs_allocbt_recs_inorder( | 409 | xfs_allocbt_recs_inorder( |
410 | struct xfs_btree_cur *cur, | 410 | struct xfs_btree_cur *cur, |
411 | union xfs_btree_rec *r1, | 411 | union xfs_btree_rec *r1, |
412 | union xfs_btree_rec *r2) | 412 | union xfs_btree_rec *r2) |
413 | { | 413 | { |
414 | if (cur->bc_btnum == XFS_BTNUM_BNO) { | 414 | if (cur->bc_btnum == XFS_BTNUM_BNO) { |
415 | return be32_to_cpu(r1->alloc.ar_startblock) + | 415 | return be32_to_cpu(r1->alloc.ar_startblock) + |
416 | be32_to_cpu(r1->alloc.ar_blockcount) <= | 416 | be32_to_cpu(r1->alloc.ar_blockcount) <= |
417 | be32_to_cpu(r2->alloc.ar_startblock); | 417 | be32_to_cpu(r2->alloc.ar_startblock); |
418 | } else { | 418 | } else { |
419 | return be32_to_cpu(r1->alloc.ar_blockcount) < | 419 | return be32_to_cpu(r1->alloc.ar_blockcount) < |
420 | be32_to_cpu(r2->alloc.ar_blockcount) || | 420 | be32_to_cpu(r2->alloc.ar_blockcount) || |
421 | (r1->alloc.ar_blockcount == r2->alloc.ar_blockcount && | 421 | (r1->alloc.ar_blockcount == r2->alloc.ar_blockcount && |
422 | be32_to_cpu(r1->alloc.ar_startblock) < | 422 | be32_to_cpu(r1->alloc.ar_startblock) < |
423 | be32_to_cpu(r2->alloc.ar_startblock)); | 423 | be32_to_cpu(r2->alloc.ar_startblock)); |
424 | } | 424 | } |
425 | } | 425 | } |
426 | #endif /* DEBUG */ | 426 | #endif /* DEBUG */ |
427 | 427 | ||
428 | static const struct xfs_btree_ops xfs_allocbt_ops = { | 428 | static const struct xfs_btree_ops xfs_allocbt_ops = { |
429 | .rec_len = sizeof(xfs_alloc_rec_t), | 429 | .rec_len = sizeof(xfs_alloc_rec_t), |
430 | .key_len = sizeof(xfs_alloc_key_t), | 430 | .key_len = sizeof(xfs_alloc_key_t), |
431 | 431 | ||
432 | .dup_cursor = xfs_allocbt_dup_cursor, | 432 | .dup_cursor = xfs_allocbt_dup_cursor, |
433 | .set_root = xfs_allocbt_set_root, | 433 | .set_root = xfs_allocbt_set_root, |
434 | .alloc_block = xfs_allocbt_alloc_block, | 434 | .alloc_block = xfs_allocbt_alloc_block, |
435 | .free_block = xfs_allocbt_free_block, | 435 | .free_block = xfs_allocbt_free_block, |
436 | .update_lastrec = xfs_allocbt_update_lastrec, | 436 | .update_lastrec = xfs_allocbt_update_lastrec, |
437 | .get_minrecs = xfs_allocbt_get_minrecs, | 437 | .get_minrecs = xfs_allocbt_get_minrecs, |
438 | .get_maxrecs = xfs_allocbt_get_maxrecs, | 438 | .get_maxrecs = xfs_allocbt_get_maxrecs, |
439 | .init_key_from_rec = xfs_allocbt_init_key_from_rec, | 439 | .init_key_from_rec = xfs_allocbt_init_key_from_rec, |
440 | .init_rec_from_key = xfs_allocbt_init_rec_from_key, | 440 | .init_rec_from_key = xfs_allocbt_init_rec_from_key, |
441 | .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, | 441 | .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, |
442 | .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, | 442 | .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, |
443 | .key_diff = xfs_allocbt_key_diff, | 443 | .key_diff = xfs_allocbt_key_diff, |
444 | .buf_ops = &xfs_allocbt_buf_ops, | 444 | .buf_ops = &xfs_allocbt_buf_ops, |
445 | #ifdef DEBUG | 445 | #if defined(DEBUG) || defined(XFS_WARN) |
446 | .keys_inorder = xfs_allocbt_keys_inorder, | 446 | .keys_inorder = xfs_allocbt_keys_inorder, |
447 | .recs_inorder = xfs_allocbt_recs_inorder, | 447 | .recs_inorder = xfs_allocbt_recs_inorder, |
448 | #endif | 448 | #endif |
449 | }; | 449 | }; |
450 | 450 | ||
451 | /* | 451 | /* |
452 | * Allocate a new allocation btree cursor. | 452 | * Allocate a new allocation btree cursor. |
453 | */ | 453 | */ |
454 | struct xfs_btree_cur * /* new alloc btree cursor */ | 454 | struct xfs_btree_cur * /* new alloc btree cursor */ |
455 | xfs_allocbt_init_cursor( | 455 | xfs_allocbt_init_cursor( |
456 | struct xfs_mount *mp, /* file system mount point */ | 456 | struct xfs_mount *mp, /* file system mount point */ |
457 | struct xfs_trans *tp, /* transaction pointer */ | 457 | struct xfs_trans *tp, /* transaction pointer */ |
458 | struct xfs_buf *agbp, /* buffer for agf structure */ | 458 | struct xfs_buf *agbp, /* buffer for agf structure */ |
459 | xfs_agnumber_t agno, /* allocation group number */ | 459 | xfs_agnumber_t agno, /* allocation group number */ |
460 | xfs_btnum_t btnum) /* btree identifier */ | 460 | xfs_btnum_t btnum) /* btree identifier */ |
461 | { | 461 | { |
462 | struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); | 462 | struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); |
463 | struct xfs_btree_cur *cur; | 463 | struct xfs_btree_cur *cur; |
464 | 464 | ||
465 | ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT); | 465 | ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT); |
466 | 466 | ||
467 | cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); | 467 | cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); |
468 | 468 | ||
469 | cur->bc_tp = tp; | 469 | cur->bc_tp = tp; |
470 | cur->bc_mp = mp; | 470 | cur->bc_mp = mp; |
471 | cur->bc_btnum = btnum; | 471 | cur->bc_btnum = btnum; |
472 | cur->bc_blocklog = mp->m_sb.sb_blocklog; | 472 | cur->bc_blocklog = mp->m_sb.sb_blocklog; |
473 | cur->bc_ops = &xfs_allocbt_ops; | 473 | cur->bc_ops = &xfs_allocbt_ops; |
474 | 474 | ||
475 | if (btnum == XFS_BTNUM_CNT) { | 475 | if (btnum == XFS_BTNUM_CNT) { |
476 | cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]); | 476 | cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]); |
477 | cur->bc_flags = XFS_BTREE_LASTREC_UPDATE; | 477 | cur->bc_flags = XFS_BTREE_LASTREC_UPDATE; |
478 | } else { | 478 | } else { |
479 | cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]); | 479 | cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]); |
480 | } | 480 | } |
481 | 481 | ||
482 | cur->bc_private.a.agbp = agbp; | 482 | cur->bc_private.a.agbp = agbp; |
483 | cur->bc_private.a.agno = agno; | 483 | cur->bc_private.a.agno = agno; |
484 | 484 | ||
485 | if (xfs_sb_version_hascrc(&mp->m_sb)) | 485 | if (xfs_sb_version_hascrc(&mp->m_sb)) |
486 | cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; | 486 | cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; |
487 | 487 | ||
488 | return cur; | 488 | return cur; |
489 | } | 489 | } |
490 | 490 | ||
491 | /* | 491 | /* |
492 | * Calculate number of records in an alloc btree block. | 492 | * Calculate number of records in an alloc btree block. |
493 | */ | 493 | */ |
494 | int | 494 | int |
495 | xfs_allocbt_maxrecs( | 495 | xfs_allocbt_maxrecs( |
496 | struct xfs_mount *mp, | 496 | struct xfs_mount *mp, |
497 | int blocklen, | 497 | int blocklen, |
498 | int leaf) | 498 | int leaf) |
499 | { | 499 | { |
500 | blocklen -= XFS_ALLOC_BLOCK_LEN(mp); | 500 | blocklen -= XFS_ALLOC_BLOCK_LEN(mp); |
501 | 501 | ||
502 | if (leaf) | 502 | if (leaf) |
503 | return blocklen / sizeof(xfs_alloc_rec_t); | 503 | return blocklen / sizeof(xfs_alloc_rec_t); |
504 | return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t)); | 504 | return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t)); |
505 | } | 505 | } |
506 | 506 |
fs/xfs/xfs_bmap_btree.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | 6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | * | 8 | * |
9 | * This program is distributed in the hope that it would be useful, | 9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | #include "xfs.h" | 18 | #include "xfs.h" |
19 | #include "xfs_fs.h" | 19 | #include "xfs_fs.h" |
20 | #include "xfs_types.h" | 20 | #include "xfs_types.h" |
21 | #include "xfs_bit.h" | 21 | #include "xfs_bit.h" |
22 | #include "xfs_log.h" | 22 | #include "xfs_log.h" |
23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
26 | #include "xfs_mount.h" | 26 | #include "xfs_mount.h" |
27 | #include "xfs_bmap_btree.h" | 27 | #include "xfs_bmap_btree.h" |
28 | #include "xfs_alloc_btree.h" | 28 | #include "xfs_alloc_btree.h" |
29 | #include "xfs_ialloc_btree.h" | 29 | #include "xfs_ialloc_btree.h" |
30 | #include "xfs_dinode.h" | 30 | #include "xfs_dinode.h" |
31 | #include "xfs_inode.h" | 31 | #include "xfs_inode.h" |
32 | #include "xfs_inode_item.h" | 32 | #include "xfs_inode_item.h" |
33 | #include "xfs_alloc.h" | 33 | #include "xfs_alloc.h" |
34 | #include "xfs_btree.h" | 34 | #include "xfs_btree.h" |
35 | #include "xfs_itable.h" | 35 | #include "xfs_itable.h" |
36 | #include "xfs_bmap.h" | 36 | #include "xfs_bmap.h" |
37 | #include "xfs_error.h" | 37 | #include "xfs_error.h" |
38 | #include "xfs_quota.h" | 38 | #include "xfs_quota.h" |
39 | #include "xfs_trace.h" | 39 | #include "xfs_trace.h" |
40 | #include "xfs_cksum.h" | 40 | #include "xfs_cksum.h" |
41 | 41 | ||
42 | /* | 42 | /* |
43 | * Determine the extent state. | 43 | * Determine the extent state. |
44 | */ | 44 | */ |
45 | /* ARGSUSED */ | 45 | /* ARGSUSED */ |
46 | STATIC xfs_exntst_t | 46 | STATIC xfs_exntst_t |
47 | xfs_extent_state( | 47 | xfs_extent_state( |
48 | xfs_filblks_t blks, | 48 | xfs_filblks_t blks, |
49 | int extent_flag) | 49 | int extent_flag) |
50 | { | 50 | { |
51 | if (extent_flag) { | 51 | if (extent_flag) { |
52 | ASSERT(blks != 0); /* saved for DMIG */ | 52 | ASSERT(blks != 0); /* saved for DMIG */ |
53 | return XFS_EXT_UNWRITTEN; | 53 | return XFS_EXT_UNWRITTEN; |
54 | } | 54 | } |
55 | return XFS_EXT_NORM; | 55 | return XFS_EXT_NORM; |
56 | } | 56 | } |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Convert on-disk form of btree root to in-memory form. | 59 | * Convert on-disk form of btree root to in-memory form. |
60 | */ | 60 | */ |
61 | void | 61 | void |
62 | xfs_bmdr_to_bmbt( | 62 | xfs_bmdr_to_bmbt( |
63 | struct xfs_inode *ip, | 63 | struct xfs_inode *ip, |
64 | xfs_bmdr_block_t *dblock, | 64 | xfs_bmdr_block_t *dblock, |
65 | int dblocklen, | 65 | int dblocklen, |
66 | struct xfs_btree_block *rblock, | 66 | struct xfs_btree_block *rblock, |
67 | int rblocklen) | 67 | int rblocklen) |
68 | { | 68 | { |
69 | struct xfs_mount *mp = ip->i_mount; | 69 | struct xfs_mount *mp = ip->i_mount; |
70 | int dmxr; | 70 | int dmxr; |
71 | xfs_bmbt_key_t *fkp; | 71 | xfs_bmbt_key_t *fkp; |
72 | __be64 *fpp; | 72 | __be64 *fpp; |
73 | xfs_bmbt_key_t *tkp; | 73 | xfs_bmbt_key_t *tkp; |
74 | __be64 *tpp; | 74 | __be64 *tpp; |
75 | 75 | ||
76 | if (xfs_sb_version_hascrc(&mp->m_sb)) | 76 | if (xfs_sb_version_hascrc(&mp->m_sb)) |
77 | xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, | 77 | xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, |
78 | XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino, | 78 | XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino, |
79 | XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS); | 79 | XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS); |
80 | else | 80 | else |
81 | xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, | 81 | xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, |
82 | XFS_BMAP_MAGIC, 0, 0, ip->i_ino, | 82 | XFS_BMAP_MAGIC, 0, 0, ip->i_ino, |
83 | XFS_BTREE_LONG_PTRS); | 83 | XFS_BTREE_LONG_PTRS); |
84 | 84 | ||
85 | rblock->bb_level = dblock->bb_level; | 85 | rblock->bb_level = dblock->bb_level; |
86 | ASSERT(be16_to_cpu(rblock->bb_level) > 0); | 86 | ASSERT(be16_to_cpu(rblock->bb_level) > 0); |
87 | rblock->bb_numrecs = dblock->bb_numrecs; | 87 | rblock->bb_numrecs = dblock->bb_numrecs; |
88 | dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); | 88 | dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); |
89 | fkp = XFS_BMDR_KEY_ADDR(dblock, 1); | 89 | fkp = XFS_BMDR_KEY_ADDR(dblock, 1); |
90 | tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); | 90 | tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); |
91 | fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); | 91 | fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); |
92 | tpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); | 92 | tpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); |
93 | dmxr = be16_to_cpu(dblock->bb_numrecs); | 93 | dmxr = be16_to_cpu(dblock->bb_numrecs); |
94 | memcpy(tkp, fkp, sizeof(*fkp) * dmxr); | 94 | memcpy(tkp, fkp, sizeof(*fkp) * dmxr); |
95 | memcpy(tpp, fpp, sizeof(*fpp) * dmxr); | 95 | memcpy(tpp, fpp, sizeof(*fpp) * dmxr); |
96 | } | 96 | } |
97 | 97 | ||
98 | /* | 98 | /* |
99 | * Convert a compressed bmap extent record to an uncompressed form. | 99 | * Convert a compressed bmap extent record to an uncompressed form. |
100 | * This code must be in sync with the routines xfs_bmbt_get_startoff, | 100 | * This code must be in sync with the routines xfs_bmbt_get_startoff, |
101 | * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state. | 101 | * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state. |
102 | */ | 102 | */ |
103 | STATIC void | 103 | STATIC void |
104 | __xfs_bmbt_get_all( | 104 | __xfs_bmbt_get_all( |
105 | __uint64_t l0, | 105 | __uint64_t l0, |
106 | __uint64_t l1, | 106 | __uint64_t l1, |
107 | xfs_bmbt_irec_t *s) | 107 | xfs_bmbt_irec_t *s) |
108 | { | 108 | { |
109 | int ext_flag; | 109 | int ext_flag; |
110 | xfs_exntst_t st; | 110 | xfs_exntst_t st; |
111 | 111 | ||
112 | ext_flag = (int)(l0 >> (64 - BMBT_EXNTFLAG_BITLEN)); | 112 | ext_flag = (int)(l0 >> (64 - BMBT_EXNTFLAG_BITLEN)); |
113 | s->br_startoff = ((xfs_fileoff_t)l0 & | 113 | s->br_startoff = ((xfs_fileoff_t)l0 & |
114 | xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; | 114 | xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; |
115 | #if XFS_BIG_BLKNOS | 115 | #if XFS_BIG_BLKNOS |
116 | s->br_startblock = (((xfs_fsblock_t)l0 & xfs_mask64lo(9)) << 43) | | 116 | s->br_startblock = (((xfs_fsblock_t)l0 & xfs_mask64lo(9)) << 43) | |
117 | (((xfs_fsblock_t)l1) >> 21); | 117 | (((xfs_fsblock_t)l1) >> 21); |
118 | #else | 118 | #else |
119 | #ifdef DEBUG | 119 | #ifdef DEBUG |
120 | { | 120 | { |
121 | xfs_dfsbno_t b; | 121 | xfs_dfsbno_t b; |
122 | 122 | ||
123 | b = (((xfs_dfsbno_t)l0 & xfs_mask64lo(9)) << 43) | | 123 | b = (((xfs_dfsbno_t)l0 & xfs_mask64lo(9)) << 43) | |
124 | (((xfs_dfsbno_t)l1) >> 21); | 124 | (((xfs_dfsbno_t)l1) >> 21); |
125 | ASSERT((b >> 32) == 0 || isnulldstartblock(b)); | 125 | ASSERT((b >> 32) == 0 || isnulldstartblock(b)); |
126 | s->br_startblock = (xfs_fsblock_t)b; | 126 | s->br_startblock = (xfs_fsblock_t)b; |
127 | } | 127 | } |
128 | #else /* !DEBUG */ | 128 | #else /* !DEBUG */ |
129 | s->br_startblock = (xfs_fsblock_t)(((xfs_dfsbno_t)l1) >> 21); | 129 | s->br_startblock = (xfs_fsblock_t)(((xfs_dfsbno_t)l1) >> 21); |
130 | #endif /* DEBUG */ | 130 | #endif /* DEBUG */ |
131 | #endif /* XFS_BIG_BLKNOS */ | 131 | #endif /* XFS_BIG_BLKNOS */ |
132 | s->br_blockcount = (xfs_filblks_t)(l1 & xfs_mask64lo(21)); | 132 | s->br_blockcount = (xfs_filblks_t)(l1 & xfs_mask64lo(21)); |
133 | /* This is xfs_extent_state() in-line */ | 133 | /* This is xfs_extent_state() in-line */ |
134 | if (ext_flag) { | 134 | if (ext_flag) { |
135 | ASSERT(s->br_blockcount != 0); /* saved for DMIG */ | 135 | ASSERT(s->br_blockcount != 0); /* saved for DMIG */ |
136 | st = XFS_EXT_UNWRITTEN; | 136 | st = XFS_EXT_UNWRITTEN; |
137 | } else | 137 | } else |
138 | st = XFS_EXT_NORM; | 138 | st = XFS_EXT_NORM; |
139 | s->br_state = st; | 139 | s->br_state = st; |
140 | } | 140 | } |
141 | 141 | ||
142 | void | 142 | void |
143 | xfs_bmbt_get_all( | 143 | xfs_bmbt_get_all( |
144 | xfs_bmbt_rec_host_t *r, | 144 | xfs_bmbt_rec_host_t *r, |
145 | xfs_bmbt_irec_t *s) | 145 | xfs_bmbt_irec_t *s) |
146 | { | 146 | { |
147 | __xfs_bmbt_get_all(r->l0, r->l1, s); | 147 | __xfs_bmbt_get_all(r->l0, r->l1, s); |
148 | } | 148 | } |
149 | 149 | ||
150 | /* | 150 | /* |
151 | * Extract the blockcount field from an in memory bmap extent record. | 151 | * Extract the blockcount field from an in memory bmap extent record. |
152 | */ | 152 | */ |
153 | xfs_filblks_t | 153 | xfs_filblks_t |
154 | xfs_bmbt_get_blockcount( | 154 | xfs_bmbt_get_blockcount( |
155 | xfs_bmbt_rec_host_t *r) | 155 | xfs_bmbt_rec_host_t *r) |
156 | { | 156 | { |
157 | return (xfs_filblks_t)(r->l1 & xfs_mask64lo(21)); | 157 | return (xfs_filblks_t)(r->l1 & xfs_mask64lo(21)); |
158 | } | 158 | } |
159 | 159 | ||
160 | /* | 160 | /* |
161 | * Extract the startblock field from an in memory bmap extent record. | 161 | * Extract the startblock field from an in memory bmap extent record. |
162 | */ | 162 | */ |
163 | xfs_fsblock_t | 163 | xfs_fsblock_t |
164 | xfs_bmbt_get_startblock( | 164 | xfs_bmbt_get_startblock( |
165 | xfs_bmbt_rec_host_t *r) | 165 | xfs_bmbt_rec_host_t *r) |
166 | { | 166 | { |
167 | #if XFS_BIG_BLKNOS | 167 | #if XFS_BIG_BLKNOS |
168 | return (((xfs_fsblock_t)r->l0 & xfs_mask64lo(9)) << 43) | | 168 | return (((xfs_fsblock_t)r->l0 & xfs_mask64lo(9)) << 43) | |
169 | (((xfs_fsblock_t)r->l1) >> 21); | 169 | (((xfs_fsblock_t)r->l1) >> 21); |
170 | #else | 170 | #else |
171 | #ifdef DEBUG | 171 | #ifdef DEBUG |
172 | xfs_dfsbno_t b; | 172 | xfs_dfsbno_t b; |
173 | 173 | ||
174 | b = (((xfs_dfsbno_t)r->l0 & xfs_mask64lo(9)) << 43) | | 174 | b = (((xfs_dfsbno_t)r->l0 & xfs_mask64lo(9)) << 43) | |
175 | (((xfs_dfsbno_t)r->l1) >> 21); | 175 | (((xfs_dfsbno_t)r->l1) >> 21); |
176 | ASSERT((b >> 32) == 0 || isnulldstartblock(b)); | 176 | ASSERT((b >> 32) == 0 || isnulldstartblock(b)); |
177 | return (xfs_fsblock_t)b; | 177 | return (xfs_fsblock_t)b; |
178 | #else /* !DEBUG */ | 178 | #else /* !DEBUG */ |
179 | return (xfs_fsblock_t)(((xfs_dfsbno_t)r->l1) >> 21); | 179 | return (xfs_fsblock_t)(((xfs_dfsbno_t)r->l1) >> 21); |
180 | #endif /* DEBUG */ | 180 | #endif /* DEBUG */ |
181 | #endif /* XFS_BIG_BLKNOS */ | 181 | #endif /* XFS_BIG_BLKNOS */ |
182 | } | 182 | } |
183 | 183 | ||
184 | /* | 184 | /* |
185 | * Extract the startoff field from an in memory bmap extent record. | 185 | * Extract the startoff field from an in memory bmap extent record. |
186 | */ | 186 | */ |
187 | xfs_fileoff_t | 187 | xfs_fileoff_t |
188 | xfs_bmbt_get_startoff( | 188 | xfs_bmbt_get_startoff( |
189 | xfs_bmbt_rec_host_t *r) | 189 | xfs_bmbt_rec_host_t *r) |
190 | { | 190 | { |
191 | return ((xfs_fileoff_t)r->l0 & | 191 | return ((xfs_fileoff_t)r->l0 & |
192 | xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; | 192 | xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; |
193 | } | 193 | } |
194 | 194 | ||
195 | xfs_exntst_t | 195 | xfs_exntst_t |
196 | xfs_bmbt_get_state( | 196 | xfs_bmbt_get_state( |
197 | xfs_bmbt_rec_host_t *r) | 197 | xfs_bmbt_rec_host_t *r) |
198 | { | 198 | { |
199 | int ext_flag; | 199 | int ext_flag; |
200 | 200 | ||
201 | ext_flag = (int)((r->l0) >> (64 - BMBT_EXNTFLAG_BITLEN)); | 201 | ext_flag = (int)((r->l0) >> (64 - BMBT_EXNTFLAG_BITLEN)); |
202 | return xfs_extent_state(xfs_bmbt_get_blockcount(r), | 202 | return xfs_extent_state(xfs_bmbt_get_blockcount(r), |
203 | ext_flag); | 203 | ext_flag); |
204 | } | 204 | } |
205 | 205 | ||
206 | /* | 206 | /* |
207 | * Extract the blockcount field from an on disk bmap extent record. | 207 | * Extract the blockcount field from an on disk bmap extent record. |
208 | */ | 208 | */ |
209 | xfs_filblks_t | 209 | xfs_filblks_t |
210 | xfs_bmbt_disk_get_blockcount( | 210 | xfs_bmbt_disk_get_blockcount( |
211 | xfs_bmbt_rec_t *r) | 211 | xfs_bmbt_rec_t *r) |
212 | { | 212 | { |
213 | return (xfs_filblks_t)(be64_to_cpu(r->l1) & xfs_mask64lo(21)); | 213 | return (xfs_filblks_t)(be64_to_cpu(r->l1) & xfs_mask64lo(21)); |
214 | } | 214 | } |
215 | 215 | ||
216 | /* | 216 | /* |
217 | * Extract the startoff field from a disk format bmap extent record. | 217 | * Extract the startoff field from a disk format bmap extent record. |
218 | */ | 218 | */ |
219 | xfs_fileoff_t | 219 | xfs_fileoff_t |
220 | xfs_bmbt_disk_get_startoff( | 220 | xfs_bmbt_disk_get_startoff( |
221 | xfs_bmbt_rec_t *r) | 221 | xfs_bmbt_rec_t *r) |
222 | { | 222 | { |
223 | return ((xfs_fileoff_t)be64_to_cpu(r->l0) & | 223 | return ((xfs_fileoff_t)be64_to_cpu(r->l0) & |
224 | xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; | 224 | xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; |
225 | } | 225 | } |
226 | 226 | ||
227 | 227 | ||
228 | /* | 228 | /* |
229 | * Set all the fields in a bmap extent record from the arguments. | 229 | * Set all the fields in a bmap extent record from the arguments. |
230 | */ | 230 | */ |
231 | void | 231 | void |
232 | xfs_bmbt_set_allf( | 232 | xfs_bmbt_set_allf( |
233 | xfs_bmbt_rec_host_t *r, | 233 | xfs_bmbt_rec_host_t *r, |
234 | xfs_fileoff_t startoff, | 234 | xfs_fileoff_t startoff, |
235 | xfs_fsblock_t startblock, | 235 | xfs_fsblock_t startblock, |
236 | xfs_filblks_t blockcount, | 236 | xfs_filblks_t blockcount, |
237 | xfs_exntst_t state) | 237 | xfs_exntst_t state) |
238 | { | 238 | { |
239 | int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; | 239 | int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; |
240 | 240 | ||
241 | ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); | 241 | ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); |
242 | ASSERT((startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)) == 0); | 242 | ASSERT((startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)) == 0); |
243 | ASSERT((blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); | 243 | ASSERT((blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); |
244 | 244 | ||
245 | #if XFS_BIG_BLKNOS | 245 | #if XFS_BIG_BLKNOS |
246 | ASSERT((startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)) == 0); | 246 | ASSERT((startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)) == 0); |
247 | 247 | ||
248 | r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | | 248 | r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
249 | ((xfs_bmbt_rec_base_t)startoff << 9) | | 249 | ((xfs_bmbt_rec_base_t)startoff << 9) | |
250 | ((xfs_bmbt_rec_base_t)startblock >> 43); | 250 | ((xfs_bmbt_rec_base_t)startblock >> 43); |
251 | r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) | | 251 | r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) | |
252 | ((xfs_bmbt_rec_base_t)blockcount & | 252 | ((xfs_bmbt_rec_base_t)blockcount & |
253 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); | 253 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); |
254 | #else /* !XFS_BIG_BLKNOS */ | 254 | #else /* !XFS_BIG_BLKNOS */ |
255 | if (isnullstartblock(startblock)) { | 255 | if (isnullstartblock(startblock)) { |
256 | r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | | 256 | r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
257 | ((xfs_bmbt_rec_base_t)startoff << 9) | | 257 | ((xfs_bmbt_rec_base_t)startoff << 9) | |
258 | (xfs_bmbt_rec_base_t)xfs_mask64lo(9); | 258 | (xfs_bmbt_rec_base_t)xfs_mask64lo(9); |
259 | r->l1 = xfs_mask64hi(11) | | 259 | r->l1 = xfs_mask64hi(11) | |
260 | ((xfs_bmbt_rec_base_t)startblock << 21) | | 260 | ((xfs_bmbt_rec_base_t)startblock << 21) | |
261 | ((xfs_bmbt_rec_base_t)blockcount & | 261 | ((xfs_bmbt_rec_base_t)blockcount & |
262 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); | 262 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); |
263 | } else { | 263 | } else { |
264 | r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | | 264 | r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
265 | ((xfs_bmbt_rec_base_t)startoff << 9); | 265 | ((xfs_bmbt_rec_base_t)startoff << 9); |
266 | r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) | | 266 | r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) | |
267 | ((xfs_bmbt_rec_base_t)blockcount & | 267 | ((xfs_bmbt_rec_base_t)blockcount & |
268 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); | 268 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); |
269 | } | 269 | } |
270 | #endif /* XFS_BIG_BLKNOS */ | 270 | #endif /* XFS_BIG_BLKNOS */ |
271 | } | 271 | } |
272 | 272 | ||
273 | /* | 273 | /* |
274 | * Set all the fields in a bmap extent record from the uncompressed form. | 274 | * Set all the fields in a bmap extent record from the uncompressed form. |
275 | */ | 275 | */ |
276 | void | 276 | void |
277 | xfs_bmbt_set_all( | 277 | xfs_bmbt_set_all( |
278 | xfs_bmbt_rec_host_t *r, | 278 | xfs_bmbt_rec_host_t *r, |
279 | xfs_bmbt_irec_t *s) | 279 | xfs_bmbt_irec_t *s) |
280 | { | 280 | { |
281 | xfs_bmbt_set_allf(r, s->br_startoff, s->br_startblock, | 281 | xfs_bmbt_set_allf(r, s->br_startoff, s->br_startblock, |
282 | s->br_blockcount, s->br_state); | 282 | s->br_blockcount, s->br_state); |
283 | } | 283 | } |
284 | 284 | ||
285 | 285 | ||
286 | /* | 286 | /* |
287 | * Set all the fields in a disk format bmap extent record from the arguments. | 287 | * Set all the fields in a disk format bmap extent record from the arguments. |
288 | */ | 288 | */ |
289 | void | 289 | void |
290 | xfs_bmbt_disk_set_allf( | 290 | xfs_bmbt_disk_set_allf( |
291 | xfs_bmbt_rec_t *r, | 291 | xfs_bmbt_rec_t *r, |
292 | xfs_fileoff_t startoff, | 292 | xfs_fileoff_t startoff, |
293 | xfs_fsblock_t startblock, | 293 | xfs_fsblock_t startblock, |
294 | xfs_filblks_t blockcount, | 294 | xfs_filblks_t blockcount, |
295 | xfs_exntst_t state) | 295 | xfs_exntst_t state) |
296 | { | 296 | { |
297 | int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; | 297 | int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; |
298 | 298 | ||
299 | ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); | 299 | ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); |
300 | ASSERT((startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)) == 0); | 300 | ASSERT((startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)) == 0); |
301 | ASSERT((blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); | 301 | ASSERT((blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); |
302 | 302 | ||
303 | #if XFS_BIG_BLKNOS | 303 | #if XFS_BIG_BLKNOS |
304 | ASSERT((startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)) == 0); | 304 | ASSERT((startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)) == 0); |
305 | 305 | ||
306 | r->l0 = cpu_to_be64( | 306 | r->l0 = cpu_to_be64( |
307 | ((xfs_bmbt_rec_base_t)extent_flag << 63) | | 307 | ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
308 | ((xfs_bmbt_rec_base_t)startoff << 9) | | 308 | ((xfs_bmbt_rec_base_t)startoff << 9) | |
309 | ((xfs_bmbt_rec_base_t)startblock >> 43)); | 309 | ((xfs_bmbt_rec_base_t)startblock >> 43)); |
310 | r->l1 = cpu_to_be64( | 310 | r->l1 = cpu_to_be64( |
311 | ((xfs_bmbt_rec_base_t)startblock << 21) | | 311 | ((xfs_bmbt_rec_base_t)startblock << 21) | |
312 | ((xfs_bmbt_rec_base_t)blockcount & | 312 | ((xfs_bmbt_rec_base_t)blockcount & |
313 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); | 313 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); |
314 | #else /* !XFS_BIG_BLKNOS */ | 314 | #else /* !XFS_BIG_BLKNOS */ |
315 | if (isnullstartblock(startblock)) { | 315 | if (isnullstartblock(startblock)) { |
316 | r->l0 = cpu_to_be64( | 316 | r->l0 = cpu_to_be64( |
317 | ((xfs_bmbt_rec_base_t)extent_flag << 63) | | 317 | ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
318 | ((xfs_bmbt_rec_base_t)startoff << 9) | | 318 | ((xfs_bmbt_rec_base_t)startoff << 9) | |
319 | (xfs_bmbt_rec_base_t)xfs_mask64lo(9)); | 319 | (xfs_bmbt_rec_base_t)xfs_mask64lo(9)); |
320 | r->l1 = cpu_to_be64(xfs_mask64hi(11) | | 320 | r->l1 = cpu_to_be64(xfs_mask64hi(11) | |
321 | ((xfs_bmbt_rec_base_t)startblock << 21) | | 321 | ((xfs_bmbt_rec_base_t)startblock << 21) | |
322 | ((xfs_bmbt_rec_base_t)blockcount & | 322 | ((xfs_bmbt_rec_base_t)blockcount & |
323 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); | 323 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); |
324 | } else { | 324 | } else { |
325 | r->l0 = cpu_to_be64( | 325 | r->l0 = cpu_to_be64( |
326 | ((xfs_bmbt_rec_base_t)extent_flag << 63) | | 326 | ((xfs_bmbt_rec_base_t)extent_flag << 63) | |
327 | ((xfs_bmbt_rec_base_t)startoff << 9)); | 327 | ((xfs_bmbt_rec_base_t)startoff << 9)); |
328 | r->l1 = cpu_to_be64( | 328 | r->l1 = cpu_to_be64( |
329 | ((xfs_bmbt_rec_base_t)startblock << 21) | | 329 | ((xfs_bmbt_rec_base_t)startblock << 21) | |
330 | ((xfs_bmbt_rec_base_t)blockcount & | 330 | ((xfs_bmbt_rec_base_t)blockcount & |
331 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); | 331 | (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); |
332 | } | 332 | } |
333 | #endif /* XFS_BIG_BLKNOS */ | 333 | #endif /* XFS_BIG_BLKNOS */ |
334 | } | 334 | } |
335 | 335 | ||
336 | /* | 336 | /* |
337 | * Set all the fields in a bmap extent record from the uncompressed form. | 337 | * Set all the fields in a bmap extent record from the uncompressed form. |
338 | */ | 338 | */ |
339 | STATIC void | 339 | STATIC void |
340 | xfs_bmbt_disk_set_all( | 340 | xfs_bmbt_disk_set_all( |
341 | xfs_bmbt_rec_t *r, | 341 | xfs_bmbt_rec_t *r, |
342 | xfs_bmbt_irec_t *s) | 342 | xfs_bmbt_irec_t *s) |
343 | { | 343 | { |
344 | xfs_bmbt_disk_set_allf(r, s->br_startoff, s->br_startblock, | 344 | xfs_bmbt_disk_set_allf(r, s->br_startoff, s->br_startblock, |
345 | s->br_blockcount, s->br_state); | 345 | s->br_blockcount, s->br_state); |
346 | } | 346 | } |
347 | 347 | ||
348 | /* | 348 | /* |
349 | * Set the blockcount field in a bmap extent record. | 349 | * Set the blockcount field in a bmap extent record. |
350 | */ | 350 | */ |
351 | void | 351 | void |
352 | xfs_bmbt_set_blockcount( | 352 | xfs_bmbt_set_blockcount( |
353 | xfs_bmbt_rec_host_t *r, | 353 | xfs_bmbt_rec_host_t *r, |
354 | xfs_filblks_t v) | 354 | xfs_filblks_t v) |
355 | { | 355 | { |
356 | ASSERT((v & xfs_mask64hi(43)) == 0); | 356 | ASSERT((v & xfs_mask64hi(43)) == 0); |
357 | r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64hi(43)) | | 357 | r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64hi(43)) | |
358 | (xfs_bmbt_rec_base_t)(v & xfs_mask64lo(21)); | 358 | (xfs_bmbt_rec_base_t)(v & xfs_mask64lo(21)); |
359 | } | 359 | } |
360 | 360 | ||
361 | /* | 361 | /* |
362 | * Set the startblock field in a bmap extent record. | 362 | * Set the startblock field in a bmap extent record. |
363 | */ | 363 | */ |
364 | void | 364 | void |
365 | xfs_bmbt_set_startblock( | 365 | xfs_bmbt_set_startblock( |
366 | xfs_bmbt_rec_host_t *r, | 366 | xfs_bmbt_rec_host_t *r, |
367 | xfs_fsblock_t v) | 367 | xfs_fsblock_t v) |
368 | { | 368 | { |
369 | #if XFS_BIG_BLKNOS | 369 | #if XFS_BIG_BLKNOS |
370 | ASSERT((v & xfs_mask64hi(12)) == 0); | 370 | ASSERT((v & xfs_mask64hi(12)) == 0); |
371 | r->l0 = (r->l0 & (xfs_bmbt_rec_base_t)xfs_mask64hi(55)) | | 371 | r->l0 = (r->l0 & (xfs_bmbt_rec_base_t)xfs_mask64hi(55)) | |
372 | (xfs_bmbt_rec_base_t)(v >> 43); | 372 | (xfs_bmbt_rec_base_t)(v >> 43); |
373 | r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)) | | 373 | r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)) | |
374 | (xfs_bmbt_rec_base_t)(v << 21); | 374 | (xfs_bmbt_rec_base_t)(v << 21); |
375 | #else /* !XFS_BIG_BLKNOS */ | 375 | #else /* !XFS_BIG_BLKNOS */ |
376 | if (isnullstartblock(v)) { | 376 | if (isnullstartblock(v)) { |
377 | r->l0 |= (xfs_bmbt_rec_base_t)xfs_mask64lo(9); | 377 | r->l0 |= (xfs_bmbt_rec_base_t)xfs_mask64lo(9); |
378 | r->l1 = (xfs_bmbt_rec_base_t)xfs_mask64hi(11) | | 378 | r->l1 = (xfs_bmbt_rec_base_t)xfs_mask64hi(11) | |
379 | ((xfs_bmbt_rec_base_t)v << 21) | | 379 | ((xfs_bmbt_rec_base_t)v << 21) | |
380 | (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); | 380 | (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); |
381 | } else { | 381 | } else { |
382 | r->l0 &= ~(xfs_bmbt_rec_base_t)xfs_mask64lo(9); | 382 | r->l0 &= ~(xfs_bmbt_rec_base_t)xfs_mask64lo(9); |
383 | r->l1 = ((xfs_bmbt_rec_base_t)v << 21) | | 383 | r->l1 = ((xfs_bmbt_rec_base_t)v << 21) | |
384 | (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); | 384 | (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); |
385 | } | 385 | } |
386 | #endif /* XFS_BIG_BLKNOS */ | 386 | #endif /* XFS_BIG_BLKNOS */ |
387 | } | 387 | } |
388 | 388 | ||
389 | /* | 389 | /* |
390 | * Set the startoff field in a bmap extent record. | 390 | * Set the startoff field in a bmap extent record. |
391 | */ | 391 | */ |
392 | void | 392 | void |
393 | xfs_bmbt_set_startoff( | 393 | xfs_bmbt_set_startoff( |
394 | xfs_bmbt_rec_host_t *r, | 394 | xfs_bmbt_rec_host_t *r, |
395 | xfs_fileoff_t v) | 395 | xfs_fileoff_t v) |
396 | { | 396 | { |
397 | ASSERT((v & xfs_mask64hi(9)) == 0); | 397 | ASSERT((v & xfs_mask64hi(9)) == 0); |
398 | r->l0 = (r->l0 & (xfs_bmbt_rec_base_t) xfs_mask64hi(1)) | | 398 | r->l0 = (r->l0 & (xfs_bmbt_rec_base_t) xfs_mask64hi(1)) | |
399 | ((xfs_bmbt_rec_base_t)v << 9) | | 399 | ((xfs_bmbt_rec_base_t)v << 9) | |
400 | (r->l0 & (xfs_bmbt_rec_base_t)xfs_mask64lo(9)); | 400 | (r->l0 & (xfs_bmbt_rec_base_t)xfs_mask64lo(9)); |
401 | } | 401 | } |
402 | 402 | ||
403 | /* | 403 | /* |
404 | * Set the extent state field in a bmap extent record. | 404 | * Set the extent state field in a bmap extent record. |
405 | */ | 405 | */ |
406 | void | 406 | void |
407 | xfs_bmbt_set_state( | 407 | xfs_bmbt_set_state( |
408 | xfs_bmbt_rec_host_t *r, | 408 | xfs_bmbt_rec_host_t *r, |
409 | xfs_exntst_t v) | 409 | xfs_exntst_t v) |
410 | { | 410 | { |
411 | ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN); | 411 | ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN); |
412 | if (v == XFS_EXT_NORM) | 412 | if (v == XFS_EXT_NORM) |
413 | r->l0 &= xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN); | 413 | r->l0 &= xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN); |
414 | else | 414 | else |
415 | r->l0 |= xfs_mask64hi(BMBT_EXNTFLAG_BITLEN); | 415 | r->l0 |= xfs_mask64hi(BMBT_EXNTFLAG_BITLEN); |
416 | } | 416 | } |
417 | 417 | ||
418 | /* | 418 | /* |
419 | * Convert in-memory form of btree root to on-disk form. | 419 | * Convert in-memory form of btree root to on-disk form. |
420 | */ | 420 | */ |
421 | void | 421 | void |
422 | xfs_bmbt_to_bmdr( | 422 | xfs_bmbt_to_bmdr( |
423 | struct xfs_mount *mp, | 423 | struct xfs_mount *mp, |
424 | struct xfs_btree_block *rblock, | 424 | struct xfs_btree_block *rblock, |
425 | int rblocklen, | 425 | int rblocklen, |
426 | xfs_bmdr_block_t *dblock, | 426 | xfs_bmdr_block_t *dblock, |
427 | int dblocklen) | 427 | int dblocklen) |
428 | { | 428 | { |
429 | int dmxr; | 429 | int dmxr; |
430 | xfs_bmbt_key_t *fkp; | 430 | xfs_bmbt_key_t *fkp; |
431 | __be64 *fpp; | 431 | __be64 *fpp; |
432 | xfs_bmbt_key_t *tkp; | 432 | xfs_bmbt_key_t *tkp; |
433 | __be64 *tpp; | 433 | __be64 *tpp; |
434 | 434 | ||
435 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | 435 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
436 | ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC)); | 436 | ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC)); |
437 | ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid)); | 437 | ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid)); |
438 | ASSERT(rblock->bb_u.l.bb_blkno == | 438 | ASSERT(rblock->bb_u.l.bb_blkno == |
439 | cpu_to_be64(XFS_BUF_DADDR_NULL)); | 439 | cpu_to_be64(XFS_BUF_DADDR_NULL)); |
440 | } else | 440 | } else |
441 | ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC)); | 441 | ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC)); |
442 | ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO)); | 442 | ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO)); |
443 | ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO)); | 443 | ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO)); |
444 | ASSERT(rblock->bb_level != 0); | 444 | ASSERT(rblock->bb_level != 0); |
445 | dblock->bb_level = rblock->bb_level; | 445 | dblock->bb_level = rblock->bb_level; |
446 | dblock->bb_numrecs = rblock->bb_numrecs; | 446 | dblock->bb_numrecs = rblock->bb_numrecs; |
447 | dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); | 447 | dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); |
448 | fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); | 448 | fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); |
449 | tkp = XFS_BMDR_KEY_ADDR(dblock, 1); | 449 | tkp = XFS_BMDR_KEY_ADDR(dblock, 1); |
450 | fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); | 450 | fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); |
451 | tpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); | 451 | tpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); |
452 | dmxr = be16_to_cpu(dblock->bb_numrecs); | 452 | dmxr = be16_to_cpu(dblock->bb_numrecs); |
453 | memcpy(tkp, fkp, sizeof(*fkp) * dmxr); | 453 | memcpy(tkp, fkp, sizeof(*fkp) * dmxr); |
454 | memcpy(tpp, fpp, sizeof(*fpp) * dmxr); | 454 | memcpy(tpp, fpp, sizeof(*fpp) * dmxr); |
455 | } | 455 | } |
456 | 456 | ||
457 | /* | 457 | /* |
458 | * Check extent records, which have just been read, for | 458 | * Check extent records, which have just been read, for |
459 | * any bit in the extent flag field. ASSERT on debug | 459 | * any bit in the extent flag field. ASSERT on debug |
460 | * kernels, as this condition should not occur. | 460 | * kernels, as this condition should not occur. |
461 | * Return an error condition (1) if any flags found, | 461 | * Return an error condition (1) if any flags found, |
462 | * otherwise return 0. | 462 | * otherwise return 0. |
463 | */ | 463 | */ |
464 | 464 | ||
465 | int | 465 | int |
466 | xfs_check_nostate_extents( | 466 | xfs_check_nostate_extents( |
467 | xfs_ifork_t *ifp, | 467 | xfs_ifork_t *ifp, |
468 | xfs_extnum_t idx, | 468 | xfs_extnum_t idx, |
469 | xfs_extnum_t num) | 469 | xfs_extnum_t num) |
470 | { | 470 | { |
471 | for (; num > 0; num--, idx++) { | 471 | for (; num > 0; num--, idx++) { |
472 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, idx); | 472 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, idx); |
473 | if ((ep->l0 >> | 473 | if ((ep->l0 >> |
474 | (64 - BMBT_EXNTFLAG_BITLEN)) != 0) { | 474 | (64 - BMBT_EXNTFLAG_BITLEN)) != 0) { |
475 | ASSERT(0); | 475 | ASSERT(0); |
476 | return 1; | 476 | return 1; |
477 | } | 477 | } |
478 | } | 478 | } |
479 | return 0; | 479 | return 0; |
480 | } | 480 | } |
481 | 481 | ||
482 | 482 | ||
483 | STATIC struct xfs_btree_cur * | 483 | STATIC struct xfs_btree_cur * |
484 | xfs_bmbt_dup_cursor( | 484 | xfs_bmbt_dup_cursor( |
485 | struct xfs_btree_cur *cur) | 485 | struct xfs_btree_cur *cur) |
486 | { | 486 | { |
487 | struct xfs_btree_cur *new; | 487 | struct xfs_btree_cur *new; |
488 | 488 | ||
489 | new = xfs_bmbt_init_cursor(cur->bc_mp, cur->bc_tp, | 489 | new = xfs_bmbt_init_cursor(cur->bc_mp, cur->bc_tp, |
490 | cur->bc_private.b.ip, cur->bc_private.b.whichfork); | 490 | cur->bc_private.b.ip, cur->bc_private.b.whichfork); |
491 | 491 | ||
492 | /* | 492 | /* |
493 | * Copy the firstblock, flist, and flags values, | 493 | * Copy the firstblock, flist, and flags values, |
494 | * since init cursor doesn't get them. | 494 | * since init cursor doesn't get them. |
495 | */ | 495 | */ |
496 | new->bc_private.b.firstblock = cur->bc_private.b.firstblock; | 496 | new->bc_private.b.firstblock = cur->bc_private.b.firstblock; |
497 | new->bc_private.b.flist = cur->bc_private.b.flist; | 497 | new->bc_private.b.flist = cur->bc_private.b.flist; |
498 | new->bc_private.b.flags = cur->bc_private.b.flags; | 498 | new->bc_private.b.flags = cur->bc_private.b.flags; |
499 | 499 | ||
500 | return new; | 500 | return new; |
501 | } | 501 | } |
502 | 502 | ||
503 | STATIC void | 503 | STATIC void |
504 | xfs_bmbt_update_cursor( | 504 | xfs_bmbt_update_cursor( |
505 | struct xfs_btree_cur *src, | 505 | struct xfs_btree_cur *src, |
506 | struct xfs_btree_cur *dst) | 506 | struct xfs_btree_cur *dst) |
507 | { | 507 | { |
508 | ASSERT((dst->bc_private.b.firstblock != NULLFSBLOCK) || | 508 | ASSERT((dst->bc_private.b.firstblock != NULLFSBLOCK) || |
509 | (dst->bc_private.b.ip->i_d.di_flags & XFS_DIFLAG_REALTIME)); | 509 | (dst->bc_private.b.ip->i_d.di_flags & XFS_DIFLAG_REALTIME)); |
510 | ASSERT(dst->bc_private.b.flist == src->bc_private.b.flist); | 510 | ASSERT(dst->bc_private.b.flist == src->bc_private.b.flist); |
511 | 511 | ||
512 | dst->bc_private.b.allocated += src->bc_private.b.allocated; | 512 | dst->bc_private.b.allocated += src->bc_private.b.allocated; |
513 | dst->bc_private.b.firstblock = src->bc_private.b.firstblock; | 513 | dst->bc_private.b.firstblock = src->bc_private.b.firstblock; |
514 | 514 | ||
515 | src->bc_private.b.allocated = 0; | 515 | src->bc_private.b.allocated = 0; |
516 | } | 516 | } |
517 | 517 | ||
518 | STATIC int | 518 | STATIC int |
519 | xfs_bmbt_alloc_block( | 519 | xfs_bmbt_alloc_block( |
520 | struct xfs_btree_cur *cur, | 520 | struct xfs_btree_cur *cur, |
521 | union xfs_btree_ptr *start, | 521 | union xfs_btree_ptr *start, |
522 | union xfs_btree_ptr *new, | 522 | union xfs_btree_ptr *new, |
523 | int length, | 523 | int length, |
524 | int *stat) | 524 | int *stat) |
525 | { | 525 | { |
526 | xfs_alloc_arg_t args; /* block allocation args */ | 526 | xfs_alloc_arg_t args; /* block allocation args */ |
527 | int error; /* error return value */ | 527 | int error; /* error return value */ |
528 | 528 | ||
529 | memset(&args, 0, sizeof(args)); | 529 | memset(&args, 0, sizeof(args)); |
530 | args.tp = cur->bc_tp; | 530 | args.tp = cur->bc_tp; |
531 | args.mp = cur->bc_mp; | 531 | args.mp = cur->bc_mp; |
532 | args.fsbno = cur->bc_private.b.firstblock; | 532 | args.fsbno = cur->bc_private.b.firstblock; |
533 | args.firstblock = args.fsbno; | 533 | args.firstblock = args.fsbno; |
534 | 534 | ||
535 | if (args.fsbno == NULLFSBLOCK) { | 535 | if (args.fsbno == NULLFSBLOCK) { |
536 | args.fsbno = be64_to_cpu(start->l); | 536 | args.fsbno = be64_to_cpu(start->l); |
537 | args.type = XFS_ALLOCTYPE_START_BNO; | 537 | args.type = XFS_ALLOCTYPE_START_BNO; |
538 | /* | 538 | /* |
539 | * Make sure there is sufficient room left in the AG to | 539 | * Make sure there is sufficient room left in the AG to |
540 | * complete a full tree split for an extent insert. If | 540 | * complete a full tree split for an extent insert. If |
541 | * we are converting the middle part of an extent then | 541 | * we are converting the middle part of an extent then |
542 | * we may need space for two tree splits. | 542 | * we may need space for two tree splits. |
543 | * | 543 | * |
544 | * We are relying on the caller to make the correct block | 544 | * We are relying on the caller to make the correct block |
545 | * reservation for this operation to succeed. If the | 545 | * reservation for this operation to succeed. If the |
546 | * reservation amount is insufficient then we may fail a | 546 | * reservation amount is insufficient then we may fail a |
547 | * block allocation here and corrupt the filesystem. | 547 | * block allocation here and corrupt the filesystem. |
548 | */ | 548 | */ |
549 | args.minleft = xfs_trans_get_block_res(args.tp); | 549 | args.minleft = xfs_trans_get_block_res(args.tp); |
550 | } else if (cur->bc_private.b.flist->xbf_low) { | 550 | } else if (cur->bc_private.b.flist->xbf_low) { |
551 | args.type = XFS_ALLOCTYPE_START_BNO; | 551 | args.type = XFS_ALLOCTYPE_START_BNO; |
552 | } else { | 552 | } else { |
553 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 553 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
554 | } | 554 | } |
555 | 555 | ||
556 | args.minlen = args.maxlen = args.prod = 1; | 556 | args.minlen = args.maxlen = args.prod = 1; |
557 | args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; | 557 | args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; |
558 | if (!args.wasdel && xfs_trans_get_block_res(args.tp) == 0) { | 558 | if (!args.wasdel && xfs_trans_get_block_res(args.tp) == 0) { |
559 | error = XFS_ERROR(ENOSPC); | 559 | error = XFS_ERROR(ENOSPC); |
560 | goto error0; | 560 | goto error0; |
561 | } | 561 | } |
562 | error = xfs_alloc_vextent(&args); | 562 | error = xfs_alloc_vextent(&args); |
563 | if (error) | 563 | if (error) |
564 | goto error0; | 564 | goto error0; |
565 | 565 | ||
566 | if (args.fsbno == NULLFSBLOCK && args.minleft) { | 566 | if (args.fsbno == NULLFSBLOCK && args.minleft) { |
567 | /* | 567 | /* |
568 | * Could not find an AG with enough free space to satisfy | 568 | * Could not find an AG with enough free space to satisfy |
569 | * a full btree split. Try again without minleft and if | 569 | * a full btree split. Try again without minleft and if |
570 | * successful activate the lowspace algorithm. | 570 | * successful activate the lowspace algorithm. |
571 | */ | 571 | */ |
572 | args.fsbno = 0; | 572 | args.fsbno = 0; |
573 | args.type = XFS_ALLOCTYPE_FIRST_AG; | 573 | args.type = XFS_ALLOCTYPE_FIRST_AG; |
574 | args.minleft = 0; | 574 | args.minleft = 0; |
575 | error = xfs_alloc_vextent(&args); | 575 | error = xfs_alloc_vextent(&args); |
576 | if (error) | 576 | if (error) |
577 | goto error0; | 577 | goto error0; |
578 | cur->bc_private.b.flist->xbf_low = 1; | 578 | cur->bc_private.b.flist->xbf_low = 1; |
579 | } | 579 | } |
580 | if (args.fsbno == NULLFSBLOCK) { | 580 | if (args.fsbno == NULLFSBLOCK) { |
581 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | 581 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); |
582 | *stat = 0; | 582 | *stat = 0; |
583 | return 0; | 583 | return 0; |
584 | } | 584 | } |
585 | ASSERT(args.len == 1); | 585 | ASSERT(args.len == 1); |
586 | cur->bc_private.b.firstblock = args.fsbno; | 586 | cur->bc_private.b.firstblock = args.fsbno; |
587 | cur->bc_private.b.allocated++; | 587 | cur->bc_private.b.allocated++; |
588 | cur->bc_private.b.ip->i_d.di_nblocks++; | 588 | cur->bc_private.b.ip->i_d.di_nblocks++; |
589 | xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE); | 589 | xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE); |
590 | xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, | 590 | xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, |
591 | XFS_TRANS_DQ_BCOUNT, 1L); | 591 | XFS_TRANS_DQ_BCOUNT, 1L); |
592 | 592 | ||
593 | new->l = cpu_to_be64(args.fsbno); | 593 | new->l = cpu_to_be64(args.fsbno); |
594 | 594 | ||
595 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | 595 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); |
596 | *stat = 1; | 596 | *stat = 1; |
597 | return 0; | 597 | return 0; |
598 | 598 | ||
599 | error0: | 599 | error0: |
600 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | 600 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); |
601 | return error; | 601 | return error; |
602 | } | 602 | } |
603 | 603 | ||
604 | STATIC int | 604 | STATIC int |
605 | xfs_bmbt_free_block( | 605 | xfs_bmbt_free_block( |
606 | struct xfs_btree_cur *cur, | 606 | struct xfs_btree_cur *cur, |
607 | struct xfs_buf *bp) | 607 | struct xfs_buf *bp) |
608 | { | 608 | { |
609 | struct xfs_mount *mp = cur->bc_mp; | 609 | struct xfs_mount *mp = cur->bc_mp; |
610 | struct xfs_inode *ip = cur->bc_private.b.ip; | 610 | struct xfs_inode *ip = cur->bc_private.b.ip; |
611 | struct xfs_trans *tp = cur->bc_tp; | 611 | struct xfs_trans *tp = cur->bc_tp; |
612 | xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); | 612 | xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); |
613 | 613 | ||
614 | xfs_bmap_add_free(fsbno, 1, cur->bc_private.b.flist, mp); | 614 | xfs_bmap_add_free(fsbno, 1, cur->bc_private.b.flist, mp); |
615 | ip->i_d.di_nblocks--; | 615 | ip->i_d.di_nblocks--; |
616 | 616 | ||
617 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 617 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
618 | xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); | 618 | xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); |
619 | xfs_trans_binval(tp, bp); | 619 | xfs_trans_binval(tp, bp); |
620 | return 0; | 620 | return 0; |
621 | } | 621 | } |
622 | 622 | ||
623 | STATIC int | 623 | STATIC int |
624 | xfs_bmbt_get_minrecs( | 624 | xfs_bmbt_get_minrecs( |
625 | struct xfs_btree_cur *cur, | 625 | struct xfs_btree_cur *cur, |
626 | int level) | 626 | int level) |
627 | { | 627 | { |
628 | if (level == cur->bc_nlevels - 1) { | 628 | if (level == cur->bc_nlevels - 1) { |
629 | struct xfs_ifork *ifp; | 629 | struct xfs_ifork *ifp; |
630 | 630 | ||
631 | ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, | 631 | ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, |
632 | cur->bc_private.b.whichfork); | 632 | cur->bc_private.b.whichfork); |
633 | 633 | ||
634 | return xfs_bmbt_maxrecs(cur->bc_mp, | 634 | return xfs_bmbt_maxrecs(cur->bc_mp, |
635 | ifp->if_broot_bytes, level == 0) / 2; | 635 | ifp->if_broot_bytes, level == 0) / 2; |
636 | } | 636 | } |
637 | 637 | ||
638 | return cur->bc_mp->m_bmap_dmnr[level != 0]; | 638 | return cur->bc_mp->m_bmap_dmnr[level != 0]; |
639 | } | 639 | } |
640 | 640 | ||
641 | int | 641 | int |
642 | xfs_bmbt_get_maxrecs( | 642 | xfs_bmbt_get_maxrecs( |
643 | struct xfs_btree_cur *cur, | 643 | struct xfs_btree_cur *cur, |
644 | int level) | 644 | int level) |
645 | { | 645 | { |
646 | if (level == cur->bc_nlevels - 1) { | 646 | if (level == cur->bc_nlevels - 1) { |
647 | struct xfs_ifork *ifp; | 647 | struct xfs_ifork *ifp; |
648 | 648 | ||
649 | ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, | 649 | ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, |
650 | cur->bc_private.b.whichfork); | 650 | cur->bc_private.b.whichfork); |
651 | 651 | ||
652 | return xfs_bmbt_maxrecs(cur->bc_mp, | 652 | return xfs_bmbt_maxrecs(cur->bc_mp, |
653 | ifp->if_broot_bytes, level == 0); | 653 | ifp->if_broot_bytes, level == 0); |
654 | } | 654 | } |
655 | 655 | ||
656 | return cur->bc_mp->m_bmap_dmxr[level != 0]; | 656 | return cur->bc_mp->m_bmap_dmxr[level != 0]; |
657 | 657 | ||
658 | } | 658 | } |
659 | 659 | ||
660 | /* | 660 | /* |
661 | * Get the maximum records we could store in the on-disk format. | 661 | * Get the maximum records we could store in the on-disk format. |
662 | * | 662 | * |
663 | * For non-root nodes this is equivalent to xfs_bmbt_get_maxrecs, but | 663 | * For non-root nodes this is equivalent to xfs_bmbt_get_maxrecs, but |
664 | * for the root node this checks the available space in the dinode fork | 664 | * for the root node this checks the available space in the dinode fork |
665 | * so that we can resize the in-memory buffer to match it. After a | 665 | * so that we can resize the in-memory buffer to match it. After a |
666 | * resize to the maximum size this function returns the same value | 666 | * resize to the maximum size this function returns the same value |
667 | * as xfs_bmbt_get_maxrecs for the root node, too. | 667 | * as xfs_bmbt_get_maxrecs for the root node, too. |
668 | */ | 668 | */ |
669 | STATIC int | 669 | STATIC int |
670 | xfs_bmbt_get_dmaxrecs( | 670 | xfs_bmbt_get_dmaxrecs( |
671 | struct xfs_btree_cur *cur, | 671 | struct xfs_btree_cur *cur, |
672 | int level) | 672 | int level) |
673 | { | 673 | { |
674 | if (level != cur->bc_nlevels - 1) | 674 | if (level != cur->bc_nlevels - 1) |
675 | return cur->bc_mp->m_bmap_dmxr[level != 0]; | 675 | return cur->bc_mp->m_bmap_dmxr[level != 0]; |
676 | return xfs_bmdr_maxrecs(cur->bc_mp, cur->bc_private.b.forksize, | 676 | return xfs_bmdr_maxrecs(cur->bc_mp, cur->bc_private.b.forksize, |
677 | level == 0); | 677 | level == 0); |
678 | } | 678 | } |
679 | 679 | ||
680 | STATIC void | 680 | STATIC void |
681 | xfs_bmbt_init_key_from_rec( | 681 | xfs_bmbt_init_key_from_rec( |
682 | union xfs_btree_key *key, | 682 | union xfs_btree_key *key, |
683 | union xfs_btree_rec *rec) | 683 | union xfs_btree_rec *rec) |
684 | { | 684 | { |
685 | key->bmbt.br_startoff = | 685 | key->bmbt.br_startoff = |
686 | cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt)); | 686 | cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt)); |
687 | } | 687 | } |
688 | 688 | ||
689 | STATIC void | 689 | STATIC void |
690 | xfs_bmbt_init_rec_from_key( | 690 | xfs_bmbt_init_rec_from_key( |
691 | union xfs_btree_key *key, | 691 | union xfs_btree_key *key, |
692 | union xfs_btree_rec *rec) | 692 | union xfs_btree_rec *rec) |
693 | { | 693 | { |
694 | ASSERT(key->bmbt.br_startoff != 0); | 694 | ASSERT(key->bmbt.br_startoff != 0); |
695 | 695 | ||
696 | xfs_bmbt_disk_set_allf(&rec->bmbt, be64_to_cpu(key->bmbt.br_startoff), | 696 | xfs_bmbt_disk_set_allf(&rec->bmbt, be64_to_cpu(key->bmbt.br_startoff), |
697 | 0, 0, XFS_EXT_NORM); | 697 | 0, 0, XFS_EXT_NORM); |
698 | } | 698 | } |
699 | 699 | ||
700 | STATIC void | 700 | STATIC void |
701 | xfs_bmbt_init_rec_from_cur( | 701 | xfs_bmbt_init_rec_from_cur( |
702 | struct xfs_btree_cur *cur, | 702 | struct xfs_btree_cur *cur, |
703 | union xfs_btree_rec *rec) | 703 | union xfs_btree_rec *rec) |
704 | { | 704 | { |
705 | xfs_bmbt_disk_set_all(&rec->bmbt, &cur->bc_rec.b); | 705 | xfs_bmbt_disk_set_all(&rec->bmbt, &cur->bc_rec.b); |
706 | } | 706 | } |
707 | 707 | ||
708 | STATIC void | 708 | STATIC void |
709 | xfs_bmbt_init_ptr_from_cur( | 709 | xfs_bmbt_init_ptr_from_cur( |
710 | struct xfs_btree_cur *cur, | 710 | struct xfs_btree_cur *cur, |
711 | union xfs_btree_ptr *ptr) | 711 | union xfs_btree_ptr *ptr) |
712 | { | 712 | { |
713 | ptr->l = 0; | 713 | ptr->l = 0; |
714 | } | 714 | } |
715 | 715 | ||
716 | STATIC __int64_t | 716 | STATIC __int64_t |
717 | xfs_bmbt_key_diff( | 717 | xfs_bmbt_key_diff( |
718 | struct xfs_btree_cur *cur, | 718 | struct xfs_btree_cur *cur, |
719 | union xfs_btree_key *key) | 719 | union xfs_btree_key *key) |
720 | { | 720 | { |
721 | return (__int64_t)be64_to_cpu(key->bmbt.br_startoff) - | 721 | return (__int64_t)be64_to_cpu(key->bmbt.br_startoff) - |
722 | cur->bc_rec.b.br_startoff; | 722 | cur->bc_rec.b.br_startoff; |
723 | } | 723 | } |
724 | 724 | ||
725 | static int | 725 | static int |
726 | xfs_bmbt_verify( | 726 | xfs_bmbt_verify( |
727 | struct xfs_buf *bp) | 727 | struct xfs_buf *bp) |
728 | { | 728 | { |
729 | struct xfs_mount *mp = bp->b_target->bt_mount; | 729 | struct xfs_mount *mp = bp->b_target->bt_mount; |
730 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); | 730 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); |
731 | unsigned int level; | 731 | unsigned int level; |
732 | 732 | ||
733 | switch (block->bb_magic) { | 733 | switch (block->bb_magic) { |
734 | case cpu_to_be32(XFS_BMAP_CRC_MAGIC): | 734 | case cpu_to_be32(XFS_BMAP_CRC_MAGIC): |
735 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | 735 | if (!xfs_sb_version_hascrc(&mp->m_sb)) |
736 | return false; | 736 | return false; |
737 | if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid)) | 737 | if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid)) |
738 | return false; | 738 | return false; |
739 | if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn) | 739 | if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn) |
740 | return false; | 740 | return false; |
741 | /* | 741 | /* |
742 | * XXX: need a better way of verifying the owner here. Right now | 742 | * XXX: need a better way of verifying the owner here. Right now |
743 | * just make sure there has been one set. | 743 | * just make sure there has been one set. |
744 | */ | 744 | */ |
745 | if (be64_to_cpu(block->bb_u.l.bb_owner) == 0) | 745 | if (be64_to_cpu(block->bb_u.l.bb_owner) == 0) |
746 | return false; | 746 | return false; |
747 | /* fall through */ | 747 | /* fall through */ |
748 | case cpu_to_be32(XFS_BMAP_MAGIC): | 748 | case cpu_to_be32(XFS_BMAP_MAGIC): |
749 | break; | 749 | break; |
750 | default: | 750 | default: |
751 | return false; | 751 | return false; |
752 | } | 752 | } |
753 | 753 | ||
754 | /* | 754 | /* |
755 | * numrecs and level verification. | 755 | * numrecs and level verification. |
756 | * | 756 | * |
757 | * We don't know what fork we belong to, so just verify that the level | 757 | * We don't know what fork we belong to, so just verify that the level |
758 | * is less than the maximum of the two. Later checks will be more | 758 | * is less than the maximum of the two. Later checks will be more |
759 | * precise. | 759 | * precise. |
760 | */ | 760 | */ |
761 | level = be16_to_cpu(block->bb_level); | 761 | level = be16_to_cpu(block->bb_level); |
762 | if (level > max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1])) | 762 | if (level > max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1])) |
763 | return false; | 763 | return false; |
764 | if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0]) | 764 | if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0]) |
765 | return false; | 765 | return false; |
766 | 766 | ||
767 | /* sibling pointer verification */ | 767 | /* sibling pointer verification */ |
768 | if (!block->bb_u.l.bb_leftsib || | 768 | if (!block->bb_u.l.bb_leftsib || |
769 | (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLDFSBNO) && | 769 | (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLDFSBNO) && |
770 | !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_leftsib)))) | 770 | !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_leftsib)))) |
771 | return false; | 771 | return false; |
772 | if (!block->bb_u.l.bb_rightsib || | 772 | if (!block->bb_u.l.bb_rightsib || |
773 | (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLDFSBNO) && | 773 | (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLDFSBNO) && |
774 | !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_rightsib)))) | 774 | !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_rightsib)))) |
775 | return false; | 775 | return false; |
776 | 776 | ||
777 | return true; | 777 | return true; |
778 | 778 | ||
779 | } | 779 | } |
780 | 780 | ||
781 | static void | 781 | static void |
782 | xfs_bmbt_read_verify( | 782 | xfs_bmbt_read_verify( |
783 | struct xfs_buf *bp) | 783 | struct xfs_buf *bp) |
784 | { | 784 | { |
785 | if (!(xfs_btree_lblock_verify_crc(bp) && | 785 | if (!(xfs_btree_lblock_verify_crc(bp) && |
786 | xfs_bmbt_verify(bp))) { | 786 | xfs_bmbt_verify(bp))) { |
787 | trace_xfs_btree_corrupt(bp, _RET_IP_); | 787 | trace_xfs_btree_corrupt(bp, _RET_IP_); |
788 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, | 788 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, |
789 | bp->b_target->bt_mount, bp->b_addr); | 789 | bp->b_target->bt_mount, bp->b_addr); |
790 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 790 | xfs_buf_ioerror(bp, EFSCORRUPTED); |
791 | } | 791 | } |
792 | 792 | ||
793 | } | 793 | } |
794 | 794 | ||
795 | static void | 795 | static void |
796 | xfs_bmbt_write_verify( | 796 | xfs_bmbt_write_verify( |
797 | struct xfs_buf *bp) | 797 | struct xfs_buf *bp) |
798 | { | 798 | { |
799 | if (!xfs_bmbt_verify(bp)) { | 799 | if (!xfs_bmbt_verify(bp)) { |
800 | xfs_warn(bp->b_target->bt_mount, "bmbt daddr 0x%llx failed", bp->b_bn); | 800 | xfs_warn(bp->b_target->bt_mount, "bmbt daddr 0x%llx failed", bp->b_bn); |
801 | trace_xfs_btree_corrupt(bp, _RET_IP_); | 801 | trace_xfs_btree_corrupt(bp, _RET_IP_); |
802 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, | 802 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, |
803 | bp->b_target->bt_mount, bp->b_addr); | 803 | bp->b_target->bt_mount, bp->b_addr); |
804 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 804 | xfs_buf_ioerror(bp, EFSCORRUPTED); |
805 | return; | 805 | return; |
806 | } | 806 | } |
807 | xfs_btree_lblock_calc_crc(bp); | 807 | xfs_btree_lblock_calc_crc(bp); |
808 | } | 808 | } |
809 | 809 | ||
810 | const struct xfs_buf_ops xfs_bmbt_buf_ops = { | 810 | const struct xfs_buf_ops xfs_bmbt_buf_ops = { |
811 | .verify_read = xfs_bmbt_read_verify, | 811 | .verify_read = xfs_bmbt_read_verify, |
812 | .verify_write = xfs_bmbt_write_verify, | 812 | .verify_write = xfs_bmbt_write_verify, |
813 | }; | 813 | }; |
814 | 814 | ||
815 | 815 | ||
816 | #ifdef DEBUG | 816 | #if defined(DEBUG) || defined(XFS_WARN) |
817 | STATIC int | 817 | STATIC int |
818 | xfs_bmbt_keys_inorder( | 818 | xfs_bmbt_keys_inorder( |
819 | struct xfs_btree_cur *cur, | 819 | struct xfs_btree_cur *cur, |
820 | union xfs_btree_key *k1, | 820 | union xfs_btree_key *k1, |
821 | union xfs_btree_key *k2) | 821 | union xfs_btree_key *k2) |
822 | { | 822 | { |
823 | return be64_to_cpu(k1->bmbt.br_startoff) < | 823 | return be64_to_cpu(k1->bmbt.br_startoff) < |
824 | be64_to_cpu(k2->bmbt.br_startoff); | 824 | be64_to_cpu(k2->bmbt.br_startoff); |
825 | } | 825 | } |
826 | 826 | ||
827 | STATIC int | 827 | STATIC int |
828 | xfs_bmbt_recs_inorder( | 828 | xfs_bmbt_recs_inorder( |
829 | struct xfs_btree_cur *cur, | 829 | struct xfs_btree_cur *cur, |
830 | union xfs_btree_rec *r1, | 830 | union xfs_btree_rec *r1, |
831 | union xfs_btree_rec *r2) | 831 | union xfs_btree_rec *r2) |
832 | { | 832 | { |
833 | return xfs_bmbt_disk_get_startoff(&r1->bmbt) + | 833 | return xfs_bmbt_disk_get_startoff(&r1->bmbt) + |
834 | xfs_bmbt_disk_get_blockcount(&r1->bmbt) <= | 834 | xfs_bmbt_disk_get_blockcount(&r1->bmbt) <= |
835 | xfs_bmbt_disk_get_startoff(&r2->bmbt); | 835 | xfs_bmbt_disk_get_startoff(&r2->bmbt); |
836 | } | 836 | } |
837 | #endif /* DEBUG */ | 837 | #endif /* DEBUG */ |
838 | 838 | ||
839 | static const struct xfs_btree_ops xfs_bmbt_ops = { | 839 | static const struct xfs_btree_ops xfs_bmbt_ops = { |
840 | .rec_len = sizeof(xfs_bmbt_rec_t), | 840 | .rec_len = sizeof(xfs_bmbt_rec_t), |
841 | .key_len = sizeof(xfs_bmbt_key_t), | 841 | .key_len = sizeof(xfs_bmbt_key_t), |
842 | 842 | ||
843 | .dup_cursor = xfs_bmbt_dup_cursor, | 843 | .dup_cursor = xfs_bmbt_dup_cursor, |
844 | .update_cursor = xfs_bmbt_update_cursor, | 844 | .update_cursor = xfs_bmbt_update_cursor, |
845 | .alloc_block = xfs_bmbt_alloc_block, | 845 | .alloc_block = xfs_bmbt_alloc_block, |
846 | .free_block = xfs_bmbt_free_block, | 846 | .free_block = xfs_bmbt_free_block, |
847 | .get_maxrecs = xfs_bmbt_get_maxrecs, | 847 | .get_maxrecs = xfs_bmbt_get_maxrecs, |
848 | .get_minrecs = xfs_bmbt_get_minrecs, | 848 | .get_minrecs = xfs_bmbt_get_minrecs, |
849 | .get_dmaxrecs = xfs_bmbt_get_dmaxrecs, | 849 | .get_dmaxrecs = xfs_bmbt_get_dmaxrecs, |
850 | .init_key_from_rec = xfs_bmbt_init_key_from_rec, | 850 | .init_key_from_rec = xfs_bmbt_init_key_from_rec, |
851 | .init_rec_from_key = xfs_bmbt_init_rec_from_key, | 851 | .init_rec_from_key = xfs_bmbt_init_rec_from_key, |
852 | .init_rec_from_cur = xfs_bmbt_init_rec_from_cur, | 852 | .init_rec_from_cur = xfs_bmbt_init_rec_from_cur, |
853 | .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur, | 853 | .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur, |
854 | .key_diff = xfs_bmbt_key_diff, | 854 | .key_diff = xfs_bmbt_key_diff, |
855 | .buf_ops = &xfs_bmbt_buf_ops, | 855 | .buf_ops = &xfs_bmbt_buf_ops, |
856 | #ifdef DEBUG | 856 | #if defined(DEBUG) || defined(XFS_WARN) |
857 | .keys_inorder = xfs_bmbt_keys_inorder, | 857 | .keys_inorder = xfs_bmbt_keys_inorder, |
858 | .recs_inorder = xfs_bmbt_recs_inorder, | 858 | .recs_inorder = xfs_bmbt_recs_inorder, |
859 | #endif | 859 | #endif |
860 | }; | 860 | }; |
861 | 861 | ||
862 | /* | 862 | /* |
863 | * Allocate a new bmap btree cursor. | 863 | * Allocate a new bmap btree cursor. |
864 | */ | 864 | */ |
865 | struct xfs_btree_cur * /* new bmap btree cursor */ | 865 | struct xfs_btree_cur * /* new bmap btree cursor */ |
866 | xfs_bmbt_init_cursor( | 866 | xfs_bmbt_init_cursor( |
867 | struct xfs_mount *mp, /* file system mount point */ | 867 | struct xfs_mount *mp, /* file system mount point */ |
868 | struct xfs_trans *tp, /* transaction pointer */ | 868 | struct xfs_trans *tp, /* transaction pointer */ |
869 | struct xfs_inode *ip, /* inode owning the btree */ | 869 | struct xfs_inode *ip, /* inode owning the btree */ |
870 | int whichfork) /* data or attr fork */ | 870 | int whichfork) /* data or attr fork */ |
871 | { | 871 | { |
872 | struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); | 872 | struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); |
873 | struct xfs_btree_cur *cur; | 873 | struct xfs_btree_cur *cur; |
874 | 874 | ||
875 | cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); | 875 | cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); |
876 | 876 | ||
877 | cur->bc_tp = tp; | 877 | cur->bc_tp = tp; |
878 | cur->bc_mp = mp; | 878 | cur->bc_mp = mp; |
879 | cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1; | 879 | cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1; |
880 | cur->bc_btnum = XFS_BTNUM_BMAP; | 880 | cur->bc_btnum = XFS_BTNUM_BMAP; |
881 | cur->bc_blocklog = mp->m_sb.sb_blocklog; | 881 | cur->bc_blocklog = mp->m_sb.sb_blocklog; |
882 | 882 | ||
883 | cur->bc_ops = &xfs_bmbt_ops; | 883 | cur->bc_ops = &xfs_bmbt_ops; |
884 | cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE; | 884 | cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE; |
885 | if (xfs_sb_version_hascrc(&mp->m_sb)) | 885 | if (xfs_sb_version_hascrc(&mp->m_sb)) |
886 | cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; | 886 | cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; |
887 | 887 | ||
888 | cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); | 888 | cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); |
889 | cur->bc_private.b.ip = ip; | 889 | cur->bc_private.b.ip = ip; |
890 | cur->bc_private.b.firstblock = NULLFSBLOCK; | 890 | cur->bc_private.b.firstblock = NULLFSBLOCK; |
891 | cur->bc_private.b.flist = NULL; | 891 | cur->bc_private.b.flist = NULL; |
892 | cur->bc_private.b.allocated = 0; | 892 | cur->bc_private.b.allocated = 0; |
893 | cur->bc_private.b.flags = 0; | 893 | cur->bc_private.b.flags = 0; |
894 | cur->bc_private.b.whichfork = whichfork; | 894 | cur->bc_private.b.whichfork = whichfork; |
895 | 895 | ||
896 | return cur; | 896 | return cur; |
897 | } | 897 | } |
898 | 898 | ||
899 | /* | 899 | /* |
900 | * Calculate number of records in a bmap btree block. | 900 | * Calculate number of records in a bmap btree block. |
901 | */ | 901 | */ |
902 | int | 902 | int |
903 | xfs_bmbt_maxrecs( | 903 | xfs_bmbt_maxrecs( |
904 | struct xfs_mount *mp, | 904 | struct xfs_mount *mp, |
905 | int blocklen, | 905 | int blocklen, |
906 | int leaf) | 906 | int leaf) |
907 | { | 907 | { |
908 | blocklen -= XFS_BMBT_BLOCK_LEN(mp); | 908 | blocklen -= XFS_BMBT_BLOCK_LEN(mp); |
909 | 909 | ||
910 | if (leaf) | 910 | if (leaf) |
911 | return blocklen / sizeof(xfs_bmbt_rec_t); | 911 | return blocklen / sizeof(xfs_bmbt_rec_t); |
912 | return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)); | 912 | return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)); |
913 | } | 913 | } |
914 | 914 | ||
915 | /* | 915 | /* |
916 | * Calculate number of records in a bmap btree inode root. | 916 | * Calculate number of records in a bmap btree inode root. |
917 | */ | 917 | */ |
918 | int | 918 | int |
919 | xfs_bmdr_maxrecs( | 919 | xfs_bmdr_maxrecs( |
920 | struct xfs_mount *mp, | 920 | struct xfs_mount *mp, |
921 | int blocklen, | 921 | int blocklen, |
922 | int leaf) | 922 | int leaf) |
923 | { | 923 | { |
924 | blocklen -= sizeof(xfs_bmdr_block_t); | 924 | blocklen -= sizeof(xfs_bmdr_block_t); |
925 | 925 | ||
926 | if (leaf) | 926 | if (leaf) |
927 | return blocklen / sizeof(xfs_bmdr_rec_t); | 927 | return blocklen / sizeof(xfs_bmdr_rec_t); |
928 | return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t)); | 928 | return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t)); |
929 | } | 929 | } |
930 | 930 |
fs/xfs/xfs_btree.h
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | 6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | * | 8 | * |
9 | * This program is distributed in the hope that it would be useful, | 9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | #ifndef __XFS_BTREE_H__ | 18 | #ifndef __XFS_BTREE_H__ |
19 | #define __XFS_BTREE_H__ | 19 | #define __XFS_BTREE_H__ |
20 | 20 | ||
21 | struct xfs_buf; | 21 | struct xfs_buf; |
22 | struct xfs_bmap_free; | 22 | struct xfs_bmap_free; |
23 | struct xfs_inode; | 23 | struct xfs_inode; |
24 | struct xfs_mount; | 24 | struct xfs_mount; |
25 | struct xfs_trans; | 25 | struct xfs_trans; |
26 | 26 | ||
27 | extern kmem_zone_t *xfs_btree_cur_zone; | 27 | extern kmem_zone_t *xfs_btree_cur_zone; |
28 | 28 | ||
29 | /* | 29 | /* |
30 | * This nonsense is to make -wlint happy. | 30 | * This nonsense is to make -wlint happy. |
31 | */ | 31 | */ |
32 | #define XFS_LOOKUP_EQ ((xfs_lookup_t)XFS_LOOKUP_EQi) | 32 | #define XFS_LOOKUP_EQ ((xfs_lookup_t)XFS_LOOKUP_EQi) |
33 | #define XFS_LOOKUP_LE ((xfs_lookup_t)XFS_LOOKUP_LEi) | 33 | #define XFS_LOOKUP_LE ((xfs_lookup_t)XFS_LOOKUP_LEi) |
34 | #define XFS_LOOKUP_GE ((xfs_lookup_t)XFS_LOOKUP_GEi) | 34 | #define XFS_LOOKUP_GE ((xfs_lookup_t)XFS_LOOKUP_GEi) |
35 | 35 | ||
36 | #define XFS_BTNUM_BNO ((xfs_btnum_t)XFS_BTNUM_BNOi) | 36 | #define XFS_BTNUM_BNO ((xfs_btnum_t)XFS_BTNUM_BNOi) |
37 | #define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi) | 37 | #define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi) |
38 | #define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi) | 38 | #define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi) |
39 | #define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi) | 39 | #define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi) |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * Generic btree header. | 42 | * Generic btree header. |
43 | * | 43 | * |
44 | * This is a combination of the actual format used on disk for short and long | 44 | * This is a combination of the actual format used on disk for short and long |
45 | * format btrees. The first three fields are shared by both format, but the | 45 | * format btrees. The first three fields are shared by both format, but the |
46 | * pointers are different and should be used with care. | 46 | * pointers are different and should be used with care. |
47 | * | 47 | * |
48 | * To get the size of the actual short or long form headers please use the size | 48 | * To get the size of the actual short or long form headers please use the size |
49 | * macros below. Never use sizeof(xfs_btree_block). | 49 | * macros below. Never use sizeof(xfs_btree_block). |
50 | * | 50 | * |
51 | * The blkno, crc, lsn, owner and uuid fields are only available in filesystems | 51 | * The blkno, crc, lsn, owner and uuid fields are only available in filesystems |
52 | * with the crc feature bit, and all accesses to them must be conditional on | 52 | * with the crc feature bit, and all accesses to them must be conditional on |
53 | * that flag. | 53 | * that flag. |
54 | */ | 54 | */ |
55 | struct xfs_btree_block { | 55 | struct xfs_btree_block { |
56 | __be32 bb_magic; /* magic number for block type */ | 56 | __be32 bb_magic; /* magic number for block type */ |
57 | __be16 bb_level; /* 0 is a leaf */ | 57 | __be16 bb_level; /* 0 is a leaf */ |
58 | __be16 bb_numrecs; /* current # of data records */ | 58 | __be16 bb_numrecs; /* current # of data records */ |
59 | union { | 59 | union { |
60 | struct { | 60 | struct { |
61 | __be32 bb_leftsib; | 61 | __be32 bb_leftsib; |
62 | __be32 bb_rightsib; | 62 | __be32 bb_rightsib; |
63 | 63 | ||
64 | __be64 bb_blkno; | 64 | __be64 bb_blkno; |
65 | __be64 bb_lsn; | 65 | __be64 bb_lsn; |
66 | uuid_t bb_uuid; | 66 | uuid_t bb_uuid; |
67 | __be32 bb_owner; | 67 | __be32 bb_owner; |
68 | __le32 bb_crc; | 68 | __le32 bb_crc; |
69 | } s; /* short form pointers */ | 69 | } s; /* short form pointers */ |
70 | struct { | 70 | struct { |
71 | __be64 bb_leftsib; | 71 | __be64 bb_leftsib; |
72 | __be64 bb_rightsib; | 72 | __be64 bb_rightsib; |
73 | 73 | ||
74 | __be64 bb_blkno; | 74 | __be64 bb_blkno; |
75 | __be64 bb_lsn; | 75 | __be64 bb_lsn; |
76 | uuid_t bb_uuid; | 76 | uuid_t bb_uuid; |
77 | __be64 bb_owner; | 77 | __be64 bb_owner; |
78 | __le32 bb_crc; | 78 | __le32 bb_crc; |
79 | __be32 bb_pad; /* padding for alignment */ | 79 | __be32 bb_pad; /* padding for alignment */ |
80 | } l; /* long form pointers */ | 80 | } l; /* long form pointers */ |
81 | } bb_u; /* rest */ | 81 | } bb_u; /* rest */ |
82 | }; | 82 | }; |
83 | 83 | ||
84 | #define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */ | 84 | #define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */ |
85 | #define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */ | 85 | #define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */ |
86 | 86 | ||
87 | /* sizes of CRC enabled btree blocks */ | 87 | /* sizes of CRC enabled btree blocks */ |
88 | #define XFS_BTREE_SBLOCK_CRC_LEN (XFS_BTREE_SBLOCK_LEN + 40) | 88 | #define XFS_BTREE_SBLOCK_CRC_LEN (XFS_BTREE_SBLOCK_LEN + 40) |
89 | #define XFS_BTREE_LBLOCK_CRC_LEN (XFS_BTREE_LBLOCK_LEN + 48) | 89 | #define XFS_BTREE_LBLOCK_CRC_LEN (XFS_BTREE_LBLOCK_LEN + 48) |
90 | 90 | ||
91 | 91 | ||
92 | #define XFS_BTREE_SBLOCK_CRC_OFF \ | 92 | #define XFS_BTREE_SBLOCK_CRC_OFF \ |
93 | offsetof(struct xfs_btree_block, bb_u.s.bb_crc) | 93 | offsetof(struct xfs_btree_block, bb_u.s.bb_crc) |
94 | #define XFS_BTREE_LBLOCK_CRC_OFF \ | 94 | #define XFS_BTREE_LBLOCK_CRC_OFF \ |
95 | offsetof(struct xfs_btree_block, bb_u.l.bb_crc) | 95 | offsetof(struct xfs_btree_block, bb_u.l.bb_crc) |
96 | 96 | ||
97 | 97 | ||
98 | /* | 98 | /* |
99 | * Generic key, ptr and record wrapper structures. | 99 | * Generic key, ptr and record wrapper structures. |
100 | * | 100 | * |
101 | * These are disk format structures, and are converted where necessary | 101 | * These are disk format structures, and are converted where necessary |
102 | * by the btree specific code that needs to interpret them. | 102 | * by the btree specific code that needs to interpret them. |
103 | */ | 103 | */ |
104 | union xfs_btree_ptr { | 104 | union xfs_btree_ptr { |
105 | __be32 s; /* short form ptr */ | 105 | __be32 s; /* short form ptr */ |
106 | __be64 l; /* long form ptr */ | 106 | __be64 l; /* long form ptr */ |
107 | }; | 107 | }; |
108 | 108 | ||
109 | union xfs_btree_key { | 109 | union xfs_btree_key { |
110 | xfs_bmbt_key_t bmbt; | 110 | xfs_bmbt_key_t bmbt; |
111 | xfs_bmdr_key_t bmbr; /* bmbt root block */ | 111 | xfs_bmdr_key_t bmbr; /* bmbt root block */ |
112 | xfs_alloc_key_t alloc; | 112 | xfs_alloc_key_t alloc; |
113 | xfs_inobt_key_t inobt; | 113 | xfs_inobt_key_t inobt; |
114 | }; | 114 | }; |
115 | 115 | ||
116 | union xfs_btree_rec { | 116 | union xfs_btree_rec { |
117 | xfs_bmbt_rec_t bmbt; | 117 | xfs_bmbt_rec_t bmbt; |
118 | xfs_bmdr_rec_t bmbr; /* bmbt root block */ | 118 | xfs_bmdr_rec_t bmbr; /* bmbt root block */ |
119 | xfs_alloc_rec_t alloc; | 119 | xfs_alloc_rec_t alloc; |
120 | xfs_inobt_rec_t inobt; | 120 | xfs_inobt_rec_t inobt; |
121 | }; | 121 | }; |
122 | 122 | ||
123 | /* | 123 | /* |
124 | * For logging record fields. | 124 | * For logging record fields. |
125 | */ | 125 | */ |
126 | #define XFS_BB_MAGIC 0x01 | 126 | #define XFS_BB_MAGIC 0x01 |
127 | #define XFS_BB_LEVEL 0x02 | 127 | #define XFS_BB_LEVEL 0x02 |
128 | #define XFS_BB_NUMRECS 0x04 | 128 | #define XFS_BB_NUMRECS 0x04 |
129 | #define XFS_BB_LEFTSIB 0x08 | 129 | #define XFS_BB_LEFTSIB 0x08 |
130 | #define XFS_BB_RIGHTSIB 0x10 | 130 | #define XFS_BB_RIGHTSIB 0x10 |
131 | #define XFS_BB_BLKNO 0x20 | 131 | #define XFS_BB_BLKNO 0x20 |
132 | #define XFS_BB_NUM_BITS 5 | 132 | #define XFS_BB_NUM_BITS 5 |
133 | #define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) | 133 | #define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) |
134 | #define XFS_BB_NUM_BITS_CRC 8 | 134 | #define XFS_BB_NUM_BITS_CRC 8 |
135 | #define XFS_BB_ALL_BITS_CRC ((1 << XFS_BB_NUM_BITS_CRC) - 1) | 135 | #define XFS_BB_ALL_BITS_CRC ((1 << XFS_BB_NUM_BITS_CRC) - 1) |
136 | 136 | ||
137 | /* | 137 | /* |
138 | * Generic stats interface | 138 | * Generic stats interface |
139 | */ | 139 | */ |
140 | #define __XFS_BTREE_STATS_INC(type, stat) \ | 140 | #define __XFS_BTREE_STATS_INC(type, stat) \ |
141 | XFS_STATS_INC(xs_ ## type ## _2_ ## stat) | 141 | XFS_STATS_INC(xs_ ## type ## _2_ ## stat) |
142 | #define XFS_BTREE_STATS_INC(cur, stat) \ | 142 | #define XFS_BTREE_STATS_INC(cur, stat) \ |
143 | do { \ | 143 | do { \ |
144 | switch (cur->bc_btnum) { \ | 144 | switch (cur->bc_btnum) { \ |
145 | case XFS_BTNUM_BNO: __XFS_BTREE_STATS_INC(abtb, stat); break; \ | 145 | case XFS_BTNUM_BNO: __XFS_BTREE_STATS_INC(abtb, stat); break; \ |
146 | case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break; \ | 146 | case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break; \ |
147 | case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break; \ | 147 | case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break; \ |
148 | case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break; \ | 148 | case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break; \ |
149 | case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ | 149 | case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ |
150 | } \ | 150 | } \ |
151 | } while (0) | 151 | } while (0) |
152 | 152 | ||
153 | #define __XFS_BTREE_STATS_ADD(type, stat, val) \ | 153 | #define __XFS_BTREE_STATS_ADD(type, stat, val) \ |
154 | XFS_STATS_ADD(xs_ ## type ## _2_ ## stat, val) | 154 | XFS_STATS_ADD(xs_ ## type ## _2_ ## stat, val) |
155 | #define XFS_BTREE_STATS_ADD(cur, stat, val) \ | 155 | #define XFS_BTREE_STATS_ADD(cur, stat, val) \ |
156 | do { \ | 156 | do { \ |
157 | switch (cur->bc_btnum) { \ | 157 | switch (cur->bc_btnum) { \ |
158 | case XFS_BTNUM_BNO: __XFS_BTREE_STATS_ADD(abtb, stat, val); break; \ | 158 | case XFS_BTNUM_BNO: __XFS_BTREE_STATS_ADD(abtb, stat, val); break; \ |
159 | case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \ | 159 | case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \ |
160 | case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \ | 160 | case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \ |
161 | case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \ | 161 | case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \ |
162 | case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ | 162 | case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ |
163 | } \ | 163 | } \ |
164 | } while (0) | 164 | } while (0) |
165 | 165 | ||
166 | #define XFS_BTREE_MAXLEVELS 8 /* max of all btrees */ | 166 | #define XFS_BTREE_MAXLEVELS 8 /* max of all btrees */ |
167 | 167 | ||
168 | struct xfs_btree_ops { | 168 | struct xfs_btree_ops { |
169 | /* size of the key and record structures */ | 169 | /* size of the key and record structures */ |
170 | size_t key_len; | 170 | size_t key_len; |
171 | size_t rec_len; | 171 | size_t rec_len; |
172 | 172 | ||
173 | /* cursor operations */ | 173 | /* cursor operations */ |
174 | struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *); | 174 | struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *); |
175 | void (*update_cursor)(struct xfs_btree_cur *src, | 175 | void (*update_cursor)(struct xfs_btree_cur *src, |
176 | struct xfs_btree_cur *dst); | 176 | struct xfs_btree_cur *dst); |
177 | 177 | ||
178 | /* update btree root pointer */ | 178 | /* update btree root pointer */ |
179 | void (*set_root)(struct xfs_btree_cur *cur, | 179 | void (*set_root)(struct xfs_btree_cur *cur, |
180 | union xfs_btree_ptr *nptr, int level_change); | 180 | union xfs_btree_ptr *nptr, int level_change); |
181 | 181 | ||
182 | /* block allocation / freeing */ | 182 | /* block allocation / freeing */ |
183 | int (*alloc_block)(struct xfs_btree_cur *cur, | 183 | int (*alloc_block)(struct xfs_btree_cur *cur, |
184 | union xfs_btree_ptr *start_bno, | 184 | union xfs_btree_ptr *start_bno, |
185 | union xfs_btree_ptr *new_bno, | 185 | union xfs_btree_ptr *new_bno, |
186 | int length, int *stat); | 186 | int length, int *stat); |
187 | int (*free_block)(struct xfs_btree_cur *cur, struct xfs_buf *bp); | 187 | int (*free_block)(struct xfs_btree_cur *cur, struct xfs_buf *bp); |
188 | 188 | ||
189 | /* update last record information */ | 189 | /* update last record information */ |
190 | void (*update_lastrec)(struct xfs_btree_cur *cur, | 190 | void (*update_lastrec)(struct xfs_btree_cur *cur, |
191 | struct xfs_btree_block *block, | 191 | struct xfs_btree_block *block, |
192 | union xfs_btree_rec *rec, | 192 | union xfs_btree_rec *rec, |
193 | int ptr, int reason); | 193 | int ptr, int reason); |
194 | 194 | ||
195 | /* records in block/level */ | 195 | /* records in block/level */ |
196 | int (*get_minrecs)(struct xfs_btree_cur *cur, int level); | 196 | int (*get_minrecs)(struct xfs_btree_cur *cur, int level); |
197 | int (*get_maxrecs)(struct xfs_btree_cur *cur, int level); | 197 | int (*get_maxrecs)(struct xfs_btree_cur *cur, int level); |
198 | 198 | ||
199 | /* records on disk. Matter for the root in inode case. */ | 199 | /* records on disk. Matter for the root in inode case. */ |
200 | int (*get_dmaxrecs)(struct xfs_btree_cur *cur, int level); | 200 | int (*get_dmaxrecs)(struct xfs_btree_cur *cur, int level); |
201 | 201 | ||
202 | /* init values of btree structures */ | 202 | /* init values of btree structures */ |
203 | void (*init_key_from_rec)(union xfs_btree_key *key, | 203 | void (*init_key_from_rec)(union xfs_btree_key *key, |
204 | union xfs_btree_rec *rec); | 204 | union xfs_btree_rec *rec); |
205 | void (*init_rec_from_key)(union xfs_btree_key *key, | 205 | void (*init_rec_from_key)(union xfs_btree_key *key, |
206 | union xfs_btree_rec *rec); | 206 | union xfs_btree_rec *rec); |
207 | void (*init_rec_from_cur)(struct xfs_btree_cur *cur, | 207 | void (*init_rec_from_cur)(struct xfs_btree_cur *cur, |
208 | union xfs_btree_rec *rec); | 208 | union xfs_btree_rec *rec); |
209 | void (*init_ptr_from_cur)(struct xfs_btree_cur *cur, | 209 | void (*init_ptr_from_cur)(struct xfs_btree_cur *cur, |
210 | union xfs_btree_ptr *ptr); | 210 | union xfs_btree_ptr *ptr); |
211 | 211 | ||
212 | /* difference between key value and cursor value */ | 212 | /* difference between key value and cursor value */ |
213 | __int64_t (*key_diff)(struct xfs_btree_cur *cur, | 213 | __int64_t (*key_diff)(struct xfs_btree_cur *cur, |
214 | union xfs_btree_key *key); | 214 | union xfs_btree_key *key); |
215 | 215 | ||
216 | const struct xfs_buf_ops *buf_ops; | 216 | const struct xfs_buf_ops *buf_ops; |
217 | 217 | ||
218 | #ifdef DEBUG | 218 | #if defined(DEBUG) || defined(XFS_WARN) |
219 | /* check that k1 is lower than k2 */ | 219 | /* check that k1 is lower than k2 */ |
220 | int (*keys_inorder)(struct xfs_btree_cur *cur, | 220 | int (*keys_inorder)(struct xfs_btree_cur *cur, |
221 | union xfs_btree_key *k1, | 221 | union xfs_btree_key *k1, |
222 | union xfs_btree_key *k2); | 222 | union xfs_btree_key *k2); |
223 | 223 | ||
224 | /* check that r1 is lower than r2 */ | 224 | /* check that r1 is lower than r2 */ |
225 | int (*recs_inorder)(struct xfs_btree_cur *cur, | 225 | int (*recs_inorder)(struct xfs_btree_cur *cur, |
226 | union xfs_btree_rec *r1, | 226 | union xfs_btree_rec *r1, |
227 | union xfs_btree_rec *r2); | 227 | union xfs_btree_rec *r2); |
228 | #endif | 228 | #endif |
229 | }; | 229 | }; |
230 | 230 | ||
231 | /* | 231 | /* |
232 | * Reasons for the update_lastrec method to be called. | 232 | * Reasons for the update_lastrec method to be called. |
233 | */ | 233 | */ |
234 | #define LASTREC_UPDATE 0 | 234 | #define LASTREC_UPDATE 0 |
235 | #define LASTREC_INSREC 1 | 235 | #define LASTREC_INSREC 1 |
236 | #define LASTREC_DELREC 2 | 236 | #define LASTREC_DELREC 2 |
237 | 237 | ||
238 | 238 | ||
239 | /* | 239 | /* |
240 | * Btree cursor structure. | 240 | * Btree cursor structure. |
241 | * This collects all information needed by the btree code in one place. | 241 | * This collects all information needed by the btree code in one place. |
242 | */ | 242 | */ |
243 | typedef struct xfs_btree_cur | 243 | typedef struct xfs_btree_cur |
244 | { | 244 | { |
245 | struct xfs_trans *bc_tp; /* transaction we're in, if any */ | 245 | struct xfs_trans *bc_tp; /* transaction we're in, if any */ |
246 | struct xfs_mount *bc_mp; /* file system mount struct */ | 246 | struct xfs_mount *bc_mp; /* file system mount struct */ |
247 | const struct xfs_btree_ops *bc_ops; | 247 | const struct xfs_btree_ops *bc_ops; |
248 | uint bc_flags; /* btree features - below */ | 248 | uint bc_flags; /* btree features - below */ |
249 | union { | 249 | union { |
250 | xfs_alloc_rec_incore_t a; | 250 | xfs_alloc_rec_incore_t a; |
251 | xfs_bmbt_irec_t b; | 251 | xfs_bmbt_irec_t b; |
252 | xfs_inobt_rec_incore_t i; | 252 | xfs_inobt_rec_incore_t i; |
253 | } bc_rec; /* current insert/search record value */ | 253 | } bc_rec; /* current insert/search record value */ |
254 | struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */ | 254 | struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */ |
255 | int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */ | 255 | int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */ |
256 | __uint8_t bc_ra[XFS_BTREE_MAXLEVELS]; /* readahead bits */ | 256 | __uint8_t bc_ra[XFS_BTREE_MAXLEVELS]; /* readahead bits */ |
257 | #define XFS_BTCUR_LEFTRA 1 /* left sibling has been read-ahead */ | 257 | #define XFS_BTCUR_LEFTRA 1 /* left sibling has been read-ahead */ |
258 | #define XFS_BTCUR_RIGHTRA 2 /* right sibling has been read-ahead */ | 258 | #define XFS_BTCUR_RIGHTRA 2 /* right sibling has been read-ahead */ |
259 | __uint8_t bc_nlevels; /* number of levels in the tree */ | 259 | __uint8_t bc_nlevels; /* number of levels in the tree */ |
260 | __uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ | 260 | __uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ |
261 | xfs_btnum_t bc_btnum; /* identifies which btree type */ | 261 | xfs_btnum_t bc_btnum; /* identifies which btree type */ |
262 | union { | 262 | union { |
263 | struct { /* needed for BNO, CNT, INO */ | 263 | struct { /* needed for BNO, CNT, INO */ |
264 | struct xfs_buf *agbp; /* agf/agi buffer pointer */ | 264 | struct xfs_buf *agbp; /* agf/agi buffer pointer */ |
265 | xfs_agnumber_t agno; /* ag number */ | 265 | xfs_agnumber_t agno; /* ag number */ |
266 | } a; | 266 | } a; |
267 | struct { /* needed for BMAP */ | 267 | struct { /* needed for BMAP */ |
268 | struct xfs_inode *ip; /* pointer to our inode */ | 268 | struct xfs_inode *ip; /* pointer to our inode */ |
269 | struct xfs_bmap_free *flist; /* list to free after */ | 269 | struct xfs_bmap_free *flist; /* list to free after */ |
270 | xfs_fsblock_t firstblock; /* 1st blk allocated */ | 270 | xfs_fsblock_t firstblock; /* 1st blk allocated */ |
271 | int allocated; /* count of alloced */ | 271 | int allocated; /* count of alloced */ |
272 | short forksize; /* fork's inode space */ | 272 | short forksize; /* fork's inode space */ |
273 | char whichfork; /* data or attr fork */ | 273 | char whichfork; /* data or attr fork */ |
274 | char flags; /* flags */ | 274 | char flags; /* flags */ |
275 | #define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */ | 275 | #define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */ |
276 | } b; | 276 | } b; |
277 | } bc_private; /* per-btree type data */ | 277 | } bc_private; /* per-btree type data */ |
278 | } xfs_btree_cur_t; | 278 | } xfs_btree_cur_t; |
279 | 279 | ||
280 | /* cursor flags */ | 280 | /* cursor flags */ |
281 | #define XFS_BTREE_LONG_PTRS (1<<0) /* pointers are 64bits long */ | 281 | #define XFS_BTREE_LONG_PTRS (1<<0) /* pointers are 64bits long */ |
282 | #define XFS_BTREE_ROOT_IN_INODE (1<<1) /* root may be variable size */ | 282 | #define XFS_BTREE_ROOT_IN_INODE (1<<1) /* root may be variable size */ |
283 | #define XFS_BTREE_LASTREC_UPDATE (1<<2) /* track last rec externally */ | 283 | #define XFS_BTREE_LASTREC_UPDATE (1<<2) /* track last rec externally */ |
284 | #define XFS_BTREE_CRC_BLOCKS (1<<3) /* uses extended btree blocks */ | 284 | #define XFS_BTREE_CRC_BLOCKS (1<<3) /* uses extended btree blocks */ |
285 | 285 | ||
286 | 286 | ||
287 | #define XFS_BTREE_NOERROR 0 | 287 | #define XFS_BTREE_NOERROR 0 |
288 | #define XFS_BTREE_ERROR 1 | 288 | #define XFS_BTREE_ERROR 1 |
289 | 289 | ||
290 | /* | 290 | /* |
291 | * Convert from buffer to btree block header. | 291 | * Convert from buffer to btree block header. |
292 | */ | 292 | */ |
293 | #define XFS_BUF_TO_BLOCK(bp) ((struct xfs_btree_block *)((bp)->b_addr)) | 293 | #define XFS_BUF_TO_BLOCK(bp) ((struct xfs_btree_block *)((bp)->b_addr)) |
294 | 294 | ||
295 | 295 | ||
296 | /* | 296 | /* |
297 | * Check that block header is ok. | 297 | * Check that block header is ok. |
298 | */ | 298 | */ |
299 | int | 299 | int |
300 | xfs_btree_check_block( | 300 | xfs_btree_check_block( |
301 | struct xfs_btree_cur *cur, /* btree cursor */ | 301 | struct xfs_btree_cur *cur, /* btree cursor */ |
302 | struct xfs_btree_block *block, /* generic btree block pointer */ | 302 | struct xfs_btree_block *block, /* generic btree block pointer */ |
303 | int level, /* level of the btree block */ | 303 | int level, /* level of the btree block */ |
304 | struct xfs_buf *bp); /* buffer containing block, if any */ | 304 | struct xfs_buf *bp); /* buffer containing block, if any */ |
305 | 305 | ||
306 | /* | 306 | /* |
307 | * Check that (long) pointer is ok. | 307 | * Check that (long) pointer is ok. |
308 | */ | 308 | */ |
309 | int /* error (0 or EFSCORRUPTED) */ | 309 | int /* error (0 or EFSCORRUPTED) */ |
310 | xfs_btree_check_lptr( | 310 | xfs_btree_check_lptr( |
311 | struct xfs_btree_cur *cur, /* btree cursor */ | 311 | struct xfs_btree_cur *cur, /* btree cursor */ |
312 | xfs_dfsbno_t ptr, /* btree block disk address */ | 312 | xfs_dfsbno_t ptr, /* btree block disk address */ |
313 | int level); /* btree block level */ | 313 | int level); /* btree block level */ |
314 | 314 | ||
315 | /* | 315 | /* |
316 | * Delete the btree cursor. | 316 | * Delete the btree cursor. |
317 | */ | 317 | */ |
318 | void | 318 | void |
319 | xfs_btree_del_cursor( | 319 | xfs_btree_del_cursor( |
320 | xfs_btree_cur_t *cur, /* btree cursor */ | 320 | xfs_btree_cur_t *cur, /* btree cursor */ |
321 | int error); /* del because of error */ | 321 | int error); /* del because of error */ |
322 | 322 | ||
323 | /* | 323 | /* |
324 | * Duplicate the btree cursor. | 324 | * Duplicate the btree cursor. |
325 | * Allocate a new one, copy the record, re-get the buffers. | 325 | * Allocate a new one, copy the record, re-get the buffers. |
326 | */ | 326 | */ |
327 | int /* error */ | 327 | int /* error */ |
328 | xfs_btree_dup_cursor( | 328 | xfs_btree_dup_cursor( |
329 | xfs_btree_cur_t *cur, /* input cursor */ | 329 | xfs_btree_cur_t *cur, /* input cursor */ |
330 | xfs_btree_cur_t **ncur);/* output cursor */ | 330 | xfs_btree_cur_t **ncur);/* output cursor */ |
331 | 331 | ||
332 | /* | 332 | /* |
333 | * Get a buffer for the block, return it with no data read. | 333 | * Get a buffer for the block, return it with no data read. |
334 | * Long-form addressing. | 334 | * Long-form addressing. |
335 | */ | 335 | */ |
336 | struct xfs_buf * /* buffer for fsbno */ | 336 | struct xfs_buf * /* buffer for fsbno */ |
337 | xfs_btree_get_bufl( | 337 | xfs_btree_get_bufl( |
338 | struct xfs_mount *mp, /* file system mount point */ | 338 | struct xfs_mount *mp, /* file system mount point */ |
339 | struct xfs_trans *tp, /* transaction pointer */ | 339 | struct xfs_trans *tp, /* transaction pointer */ |
340 | xfs_fsblock_t fsbno, /* file system block number */ | 340 | xfs_fsblock_t fsbno, /* file system block number */ |
341 | uint lock); /* lock flags for get_buf */ | 341 | uint lock); /* lock flags for get_buf */ |
342 | 342 | ||
343 | /* | 343 | /* |
344 | * Get a buffer for the block, return it with no data read. | 344 | * Get a buffer for the block, return it with no data read. |
345 | * Short-form addressing. | 345 | * Short-form addressing. |
346 | */ | 346 | */ |
347 | struct xfs_buf * /* buffer for agno/agbno */ | 347 | struct xfs_buf * /* buffer for agno/agbno */ |
348 | xfs_btree_get_bufs( | 348 | xfs_btree_get_bufs( |
349 | struct xfs_mount *mp, /* file system mount point */ | 349 | struct xfs_mount *mp, /* file system mount point */ |
350 | struct xfs_trans *tp, /* transaction pointer */ | 350 | struct xfs_trans *tp, /* transaction pointer */ |
351 | xfs_agnumber_t agno, /* allocation group number */ | 351 | xfs_agnumber_t agno, /* allocation group number */ |
352 | xfs_agblock_t agbno, /* allocation group block number */ | 352 | xfs_agblock_t agbno, /* allocation group block number */ |
353 | uint lock); /* lock flags for get_buf */ | 353 | uint lock); /* lock flags for get_buf */ |
354 | 354 | ||
355 | /* | 355 | /* |
356 | * Check for the cursor referring to the last block at the given level. | 356 | * Check for the cursor referring to the last block at the given level. |
357 | */ | 357 | */ |
358 | int /* 1=is last block, 0=not last block */ | 358 | int /* 1=is last block, 0=not last block */ |
359 | xfs_btree_islastblock( | 359 | xfs_btree_islastblock( |
360 | xfs_btree_cur_t *cur, /* btree cursor */ | 360 | xfs_btree_cur_t *cur, /* btree cursor */ |
361 | int level); /* level to check */ | 361 | int level); /* level to check */ |
362 | 362 | ||
363 | /* | 363 | /* |
364 | * Compute first and last byte offsets for the fields given. | 364 | * Compute first and last byte offsets for the fields given. |
365 | * Interprets the offsets table, which contains struct field offsets. | 365 | * Interprets the offsets table, which contains struct field offsets. |
366 | */ | 366 | */ |
367 | void | 367 | void |
368 | xfs_btree_offsets( | 368 | xfs_btree_offsets( |
369 | __int64_t fields, /* bitmask of fields */ | 369 | __int64_t fields, /* bitmask of fields */ |
370 | const short *offsets,/* table of field offsets */ | 370 | const short *offsets,/* table of field offsets */ |
371 | int nbits, /* number of bits to inspect */ | 371 | int nbits, /* number of bits to inspect */ |
372 | int *first, /* output: first byte offset */ | 372 | int *first, /* output: first byte offset */ |
373 | int *last); /* output: last byte offset */ | 373 | int *last); /* output: last byte offset */ |
374 | 374 | ||
375 | /* | 375 | /* |
376 | * Get a buffer for the block, return it read in. | 376 | * Get a buffer for the block, return it read in. |
377 | * Long-form addressing. | 377 | * Long-form addressing. |
378 | */ | 378 | */ |
379 | int /* error */ | 379 | int /* error */ |
380 | xfs_btree_read_bufl( | 380 | xfs_btree_read_bufl( |
381 | struct xfs_mount *mp, /* file system mount point */ | 381 | struct xfs_mount *mp, /* file system mount point */ |
382 | struct xfs_trans *tp, /* transaction pointer */ | 382 | struct xfs_trans *tp, /* transaction pointer */ |
383 | xfs_fsblock_t fsbno, /* file system block number */ | 383 | xfs_fsblock_t fsbno, /* file system block number */ |
384 | uint lock, /* lock flags for read_buf */ | 384 | uint lock, /* lock flags for read_buf */ |
385 | struct xfs_buf **bpp, /* buffer for fsbno */ | 385 | struct xfs_buf **bpp, /* buffer for fsbno */ |
386 | int refval, /* ref count value for buffer */ | 386 | int refval, /* ref count value for buffer */ |
387 | const struct xfs_buf_ops *ops); | 387 | const struct xfs_buf_ops *ops); |
388 | 388 | ||
389 | /* | 389 | /* |
390 | * Read-ahead the block, don't wait for it, don't return a buffer. | 390 | * Read-ahead the block, don't wait for it, don't return a buffer. |
391 | * Long-form addressing. | 391 | * Long-form addressing. |
392 | */ | 392 | */ |
393 | void /* error */ | 393 | void /* error */ |
394 | xfs_btree_reada_bufl( | 394 | xfs_btree_reada_bufl( |
395 | struct xfs_mount *mp, /* file system mount point */ | 395 | struct xfs_mount *mp, /* file system mount point */ |
396 | xfs_fsblock_t fsbno, /* file system block number */ | 396 | xfs_fsblock_t fsbno, /* file system block number */ |
397 | xfs_extlen_t count, /* count of filesystem blocks */ | 397 | xfs_extlen_t count, /* count of filesystem blocks */ |
398 | const struct xfs_buf_ops *ops); | 398 | const struct xfs_buf_ops *ops); |
399 | 399 | ||
400 | /* | 400 | /* |
401 | * Read-ahead the block, don't wait for it, don't return a buffer. | 401 | * Read-ahead the block, don't wait for it, don't return a buffer. |
402 | * Short-form addressing. | 402 | * Short-form addressing. |
403 | */ | 403 | */ |
404 | void /* error */ | 404 | void /* error */ |
405 | xfs_btree_reada_bufs( | 405 | xfs_btree_reada_bufs( |
406 | struct xfs_mount *mp, /* file system mount point */ | 406 | struct xfs_mount *mp, /* file system mount point */ |
407 | xfs_agnumber_t agno, /* allocation group number */ | 407 | xfs_agnumber_t agno, /* allocation group number */ |
408 | xfs_agblock_t agbno, /* allocation group block number */ | 408 | xfs_agblock_t agbno, /* allocation group block number */ |
409 | xfs_extlen_t count, /* count of filesystem blocks */ | 409 | xfs_extlen_t count, /* count of filesystem blocks */ |
410 | const struct xfs_buf_ops *ops); | 410 | const struct xfs_buf_ops *ops); |
411 | 411 | ||
412 | /* | 412 | /* |
413 | * Initialise a new btree block header | 413 | * Initialise a new btree block header |
414 | */ | 414 | */ |
415 | void | 415 | void |
416 | xfs_btree_init_block( | 416 | xfs_btree_init_block( |
417 | struct xfs_mount *mp, | 417 | struct xfs_mount *mp, |
418 | struct xfs_buf *bp, | 418 | struct xfs_buf *bp, |
419 | __u32 magic, | 419 | __u32 magic, |
420 | __u16 level, | 420 | __u16 level, |
421 | __u16 numrecs, | 421 | __u16 numrecs, |
422 | __u64 owner, | 422 | __u64 owner, |
423 | unsigned int flags); | 423 | unsigned int flags); |
424 | 424 | ||
425 | void | 425 | void |
426 | xfs_btree_init_block_int( | 426 | xfs_btree_init_block_int( |
427 | struct xfs_mount *mp, | 427 | struct xfs_mount *mp, |
428 | struct xfs_btree_block *buf, | 428 | struct xfs_btree_block *buf, |
429 | xfs_daddr_t blkno, | 429 | xfs_daddr_t blkno, |
430 | __u32 magic, | 430 | __u32 magic, |
431 | __u16 level, | 431 | __u16 level, |
432 | __u16 numrecs, | 432 | __u16 numrecs, |
433 | __u64 owner, | 433 | __u64 owner, |
434 | unsigned int flags); | 434 | unsigned int flags); |
435 | 435 | ||
436 | /* | 436 | /* |
437 | * Common btree core entry points. | 437 | * Common btree core entry points. |
438 | */ | 438 | */ |
439 | int xfs_btree_increment(struct xfs_btree_cur *, int, int *); | 439 | int xfs_btree_increment(struct xfs_btree_cur *, int, int *); |
440 | int xfs_btree_decrement(struct xfs_btree_cur *, int, int *); | 440 | int xfs_btree_decrement(struct xfs_btree_cur *, int, int *); |
441 | int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *); | 441 | int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *); |
442 | int xfs_btree_update(struct xfs_btree_cur *, union xfs_btree_rec *); | 442 | int xfs_btree_update(struct xfs_btree_cur *, union xfs_btree_rec *); |
443 | int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); | 443 | int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); |
444 | int xfs_btree_insert(struct xfs_btree_cur *, int *); | 444 | int xfs_btree_insert(struct xfs_btree_cur *, int *); |
445 | int xfs_btree_delete(struct xfs_btree_cur *, int *); | 445 | int xfs_btree_delete(struct xfs_btree_cur *, int *); |
446 | int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); | 446 | int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); |
447 | 447 | ||
448 | /* | 448 | /* |
449 | * btree block CRC helpers | 449 | * btree block CRC helpers |
450 | */ | 450 | */ |
451 | void xfs_btree_lblock_calc_crc(struct xfs_buf *); | 451 | void xfs_btree_lblock_calc_crc(struct xfs_buf *); |
452 | bool xfs_btree_lblock_verify_crc(struct xfs_buf *); | 452 | bool xfs_btree_lblock_verify_crc(struct xfs_buf *); |
453 | void xfs_btree_sblock_calc_crc(struct xfs_buf *); | 453 | void xfs_btree_sblock_calc_crc(struct xfs_buf *); |
454 | bool xfs_btree_sblock_verify_crc(struct xfs_buf *); | 454 | bool xfs_btree_sblock_verify_crc(struct xfs_buf *); |
455 | 455 | ||
456 | /* | 456 | /* |
457 | * Internal btree helpers also used by xfs_bmap.c. | 457 | * Internal btree helpers also used by xfs_bmap.c. |
458 | */ | 458 | */ |
459 | void xfs_btree_log_block(struct xfs_btree_cur *, struct xfs_buf *, int); | 459 | void xfs_btree_log_block(struct xfs_btree_cur *, struct xfs_buf *, int); |
460 | void xfs_btree_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int, int); | 460 | void xfs_btree_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int, int); |
461 | 461 | ||
462 | /* | 462 | /* |
463 | * Helpers. | 463 | * Helpers. |
464 | */ | 464 | */ |
465 | static inline int xfs_btree_get_numrecs(struct xfs_btree_block *block) | 465 | static inline int xfs_btree_get_numrecs(struct xfs_btree_block *block) |
466 | { | 466 | { |
467 | return be16_to_cpu(block->bb_numrecs); | 467 | return be16_to_cpu(block->bb_numrecs); |
468 | } | 468 | } |
469 | 469 | ||
470 | static inline void xfs_btree_set_numrecs(struct xfs_btree_block *block, | 470 | static inline void xfs_btree_set_numrecs(struct xfs_btree_block *block, |
471 | __uint16_t numrecs) | 471 | __uint16_t numrecs) |
472 | { | 472 | { |
473 | block->bb_numrecs = cpu_to_be16(numrecs); | 473 | block->bb_numrecs = cpu_to_be16(numrecs); |
474 | } | 474 | } |
475 | 475 | ||
476 | static inline int xfs_btree_get_level(struct xfs_btree_block *block) | 476 | static inline int xfs_btree_get_level(struct xfs_btree_block *block) |
477 | { | 477 | { |
478 | return be16_to_cpu(block->bb_level); | 478 | return be16_to_cpu(block->bb_level); |
479 | } | 479 | } |
480 | 480 | ||
481 | 481 | ||
482 | /* | 482 | /* |
483 | * Min and max functions for extlen, agblock, fileoff, and filblks types. | 483 | * Min and max functions for extlen, agblock, fileoff, and filblks types. |
484 | */ | 484 | */ |
485 | #define XFS_EXTLEN_MIN(a,b) min_t(xfs_extlen_t, (a), (b)) | 485 | #define XFS_EXTLEN_MIN(a,b) min_t(xfs_extlen_t, (a), (b)) |
486 | #define XFS_EXTLEN_MAX(a,b) max_t(xfs_extlen_t, (a), (b)) | 486 | #define XFS_EXTLEN_MAX(a,b) max_t(xfs_extlen_t, (a), (b)) |
487 | #define XFS_AGBLOCK_MIN(a,b) min_t(xfs_agblock_t, (a), (b)) | 487 | #define XFS_AGBLOCK_MIN(a,b) min_t(xfs_agblock_t, (a), (b)) |
488 | #define XFS_AGBLOCK_MAX(a,b) max_t(xfs_agblock_t, (a), (b)) | 488 | #define XFS_AGBLOCK_MAX(a,b) max_t(xfs_agblock_t, (a), (b)) |
489 | #define XFS_FILEOFF_MIN(a,b) min_t(xfs_fileoff_t, (a), (b)) | 489 | #define XFS_FILEOFF_MIN(a,b) min_t(xfs_fileoff_t, (a), (b)) |
490 | #define XFS_FILEOFF_MAX(a,b) max_t(xfs_fileoff_t, (a), (b)) | 490 | #define XFS_FILEOFF_MAX(a,b) max_t(xfs_fileoff_t, (a), (b)) |
491 | #define XFS_FILBLKS_MIN(a,b) min_t(xfs_filblks_t, (a), (b)) | 491 | #define XFS_FILBLKS_MIN(a,b) min_t(xfs_filblks_t, (a), (b)) |
492 | #define XFS_FILBLKS_MAX(a,b) max_t(xfs_filblks_t, (a), (b)) | 492 | #define XFS_FILBLKS_MAX(a,b) max_t(xfs_filblks_t, (a), (b)) |
493 | 493 | ||
494 | #define XFS_FSB_SANITY_CHECK(mp,fsb) \ | 494 | #define XFS_FSB_SANITY_CHECK(mp,fsb) \ |
495 | (XFS_FSB_TO_AGNO(mp, fsb) < mp->m_sb.sb_agcount && \ | 495 | (XFS_FSB_TO_AGNO(mp, fsb) < mp->m_sb.sb_agcount && \ |
496 | XFS_FSB_TO_AGBNO(mp, fsb) < mp->m_sb.sb_agblocks) | 496 | XFS_FSB_TO_AGBNO(mp, fsb) < mp->m_sb.sb_agblocks) |
497 | 497 | ||
498 | /* | 498 | /* |
499 | * Trace hooks. Currently not implemented as they need to be ported | 499 | * Trace hooks. Currently not implemented as they need to be ported |
500 | * over to the generic tracing functionality, which is some effort. | 500 | * over to the generic tracing functionality, which is some effort. |
501 | * | 501 | * |
502 | * i,j = integer (32 bit) | 502 | * i,j = integer (32 bit) |
503 | * b = btree block buffer (xfs_buf_t) | 503 | * b = btree block buffer (xfs_buf_t) |
504 | * p = btree ptr | 504 | * p = btree ptr |
505 | * r = btree record | 505 | * r = btree record |
506 | * k = btree key | 506 | * k = btree key |
507 | */ | 507 | */ |
508 | #define XFS_BTREE_TRACE_ARGBI(c, b, i) | 508 | #define XFS_BTREE_TRACE_ARGBI(c, b, i) |
509 | #define XFS_BTREE_TRACE_ARGBII(c, b, i, j) | 509 | #define XFS_BTREE_TRACE_ARGBII(c, b, i, j) |
510 | #define XFS_BTREE_TRACE_ARGI(c, i) | 510 | #define XFS_BTREE_TRACE_ARGI(c, i) |
511 | #define XFS_BTREE_TRACE_ARGIPK(c, i, p, s) | 511 | #define XFS_BTREE_TRACE_ARGIPK(c, i, p, s) |
512 | #define XFS_BTREE_TRACE_ARGIPR(c, i, p, r) | 512 | #define XFS_BTREE_TRACE_ARGIPR(c, i, p, r) |
513 | #define XFS_BTREE_TRACE_ARGIK(c, i, k) | 513 | #define XFS_BTREE_TRACE_ARGIK(c, i, k) |
514 | #define XFS_BTREE_TRACE_ARGR(c, r) | 514 | #define XFS_BTREE_TRACE_ARGR(c, r) |
515 | #define XFS_BTREE_TRACE_CURSOR(c, t) | 515 | #define XFS_BTREE_TRACE_CURSOR(c, t) |
516 | 516 | ||
517 | #endif /* __XFS_BTREE_H__ */ | 517 | #endif /* __XFS_BTREE_H__ */ |
518 | 518 |
fs/xfs/xfs_dir2_node.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. |
3 | * Copyright (c) 2013 Red Hat, Inc. | 3 | * Copyright (c) 2013 Red Hat, Inc. |
4 | * All Rights Reserved. | 4 | * All Rights Reserved. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as | 7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it would be useful, | 10 | * This program is distributed in the hope that it would be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write the Free Software Foundation, | 16 | * along with this program; if not, write the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
18 | */ | 18 | */ |
19 | #include "xfs.h" | 19 | #include "xfs.h" |
20 | #include "xfs_fs.h" | 20 | #include "xfs_fs.h" |
21 | #include "xfs_types.h" | 21 | #include "xfs_types.h" |
22 | #include "xfs_log.h" | 22 | #include "xfs_log.h" |
23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
26 | #include "xfs_mount.h" | 26 | #include "xfs_mount.h" |
27 | #include "xfs_da_btree.h" | 27 | #include "xfs_da_btree.h" |
28 | #include "xfs_bmap_btree.h" | 28 | #include "xfs_bmap_btree.h" |
29 | #include "xfs_dinode.h" | 29 | #include "xfs_dinode.h" |
30 | #include "xfs_inode.h" | 30 | #include "xfs_inode.h" |
31 | #include "xfs_bmap.h" | 31 | #include "xfs_bmap.h" |
32 | #include "xfs_dir2_format.h" | 32 | #include "xfs_dir2_format.h" |
33 | #include "xfs_dir2_priv.h" | 33 | #include "xfs_dir2_priv.h" |
34 | #include "xfs_error.h" | 34 | #include "xfs_error.h" |
35 | #include "xfs_trace.h" | 35 | #include "xfs_trace.h" |
36 | #include "xfs_buf_item.h" | 36 | #include "xfs_buf_item.h" |
37 | #include "xfs_cksum.h" | 37 | #include "xfs_cksum.h" |
38 | 38 | ||
39 | /* | 39 | /* |
40 | * Function declarations. | 40 | * Function declarations. |
41 | */ | 41 | */ |
42 | static int xfs_dir2_leafn_add(struct xfs_buf *bp, xfs_da_args_t *args, | 42 | static int xfs_dir2_leafn_add(struct xfs_buf *bp, xfs_da_args_t *args, |
43 | int index); | 43 | int index); |
44 | static void xfs_dir2_leafn_rebalance(xfs_da_state_t *state, | 44 | static void xfs_dir2_leafn_rebalance(xfs_da_state_t *state, |
45 | xfs_da_state_blk_t *blk1, | 45 | xfs_da_state_blk_t *blk1, |
46 | xfs_da_state_blk_t *blk2); | 46 | xfs_da_state_blk_t *blk2); |
47 | static int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp, | 47 | static int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp, |
48 | int index, xfs_da_state_blk_t *dblk, | 48 | int index, xfs_da_state_blk_t *dblk, |
49 | int *rval); | 49 | int *rval); |
50 | static int xfs_dir2_node_addname_int(xfs_da_args_t *args, | 50 | static int xfs_dir2_node_addname_int(xfs_da_args_t *args, |
51 | xfs_da_state_blk_t *fblk); | 51 | xfs_da_state_blk_t *fblk); |
52 | 52 | ||
53 | /* | 53 | /* |
54 | * Check internal consistency of a leafn block. | 54 | * Check internal consistency of a leafn block. |
55 | */ | 55 | */ |
56 | #ifdef DEBUG | 56 | #ifdef DEBUG |
57 | #define xfs_dir3_leaf_check(mp, bp) \ | 57 | #define xfs_dir3_leaf_check(mp, bp) \ |
58 | do { \ | 58 | do { \ |
59 | if (!xfs_dir3_leafn_check((mp), (bp))) \ | 59 | if (!xfs_dir3_leafn_check((mp), (bp))) \ |
60 | ASSERT(0); \ | 60 | ASSERT(0); \ |
61 | } while (0); | 61 | } while (0); |
62 | 62 | ||
63 | static bool | 63 | static bool |
64 | xfs_dir3_leafn_check( | 64 | xfs_dir3_leafn_check( |
65 | struct xfs_mount *mp, | 65 | struct xfs_mount *mp, |
66 | struct xfs_buf *bp) | 66 | struct xfs_buf *bp) |
67 | { | 67 | { |
68 | struct xfs_dir2_leaf *leaf = bp->b_addr; | 68 | struct xfs_dir2_leaf *leaf = bp->b_addr; |
69 | struct xfs_dir3_icleaf_hdr leafhdr; | 69 | struct xfs_dir3_icleaf_hdr leafhdr; |
70 | 70 | ||
71 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); | 71 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); |
72 | 72 | ||
73 | if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC) { | 73 | if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC) { |
74 | struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; | 74 | struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; |
75 | if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) | 75 | if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) |
76 | return false; | 76 | return false; |
77 | } else if (leafhdr.magic != XFS_DIR2_LEAFN_MAGIC) | 77 | } else if (leafhdr.magic != XFS_DIR2_LEAFN_MAGIC) |
78 | return false; | 78 | return false; |
79 | 79 | ||
80 | return xfs_dir3_leaf_check_int(mp, &leafhdr, leaf); | 80 | return xfs_dir3_leaf_check_int(mp, &leafhdr, leaf); |
81 | } | 81 | } |
82 | #else | 82 | #else |
83 | #define xfs_dir3_leaf_check(mp, bp) | 83 | #define xfs_dir3_leaf_check(mp, bp) |
84 | #endif | 84 | #endif |
85 | 85 | ||
86 | static bool | 86 | static bool |
87 | xfs_dir3_free_verify( | 87 | xfs_dir3_free_verify( |
88 | struct xfs_buf *bp) | 88 | struct xfs_buf *bp) |
89 | { | 89 | { |
90 | struct xfs_mount *mp = bp->b_target->bt_mount; | 90 | struct xfs_mount *mp = bp->b_target->bt_mount; |
91 | struct xfs_dir2_free_hdr *hdr = bp->b_addr; | 91 | struct xfs_dir2_free_hdr *hdr = bp->b_addr; |
92 | 92 | ||
93 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | 93 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
94 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; | 94 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; |
95 | 95 | ||
96 | if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC)) | 96 | if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC)) |
97 | return false; | 97 | return false; |
98 | if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid)) | 98 | if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid)) |
99 | return false; | 99 | return false; |
100 | if (be64_to_cpu(hdr3->blkno) != bp->b_bn) | 100 | if (be64_to_cpu(hdr3->blkno) != bp->b_bn) |
101 | return false; | 101 | return false; |
102 | } else { | 102 | } else { |
103 | if (hdr->magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)) | 103 | if (hdr->magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)) |
104 | return false; | 104 | return false; |
105 | } | 105 | } |
106 | 106 | ||
107 | /* XXX: should bounds check the xfs_dir3_icfree_hdr here */ | 107 | /* XXX: should bounds check the xfs_dir3_icfree_hdr here */ |
108 | 108 | ||
109 | return true; | 109 | return true; |
110 | } | 110 | } |
111 | 111 | ||
112 | static void | 112 | static void |
113 | xfs_dir3_free_read_verify( | 113 | xfs_dir3_free_read_verify( |
114 | struct xfs_buf *bp) | 114 | struct xfs_buf *bp) |
115 | { | 115 | { |
116 | struct xfs_mount *mp = bp->b_target->bt_mount; | 116 | struct xfs_mount *mp = bp->b_target->bt_mount; |
117 | 117 | ||
118 | if ((xfs_sb_version_hascrc(&mp->m_sb) && | 118 | if ((xfs_sb_version_hascrc(&mp->m_sb) && |
119 | !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), | 119 | !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), |
120 | XFS_DIR3_FREE_CRC_OFF)) || | 120 | XFS_DIR3_FREE_CRC_OFF)) || |
121 | !xfs_dir3_free_verify(bp)) { | 121 | !xfs_dir3_free_verify(bp)) { |
122 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | 122 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); |
123 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 123 | xfs_buf_ioerror(bp, EFSCORRUPTED); |
124 | } | 124 | } |
125 | } | 125 | } |
126 | 126 | ||
127 | static void | 127 | static void |
128 | xfs_dir3_free_write_verify( | 128 | xfs_dir3_free_write_verify( |
129 | struct xfs_buf *bp) | 129 | struct xfs_buf *bp) |
130 | { | 130 | { |
131 | struct xfs_mount *mp = bp->b_target->bt_mount; | 131 | struct xfs_mount *mp = bp->b_target->bt_mount; |
132 | struct xfs_buf_log_item *bip = bp->b_fspriv; | 132 | struct xfs_buf_log_item *bip = bp->b_fspriv; |
133 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; | 133 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; |
134 | 134 | ||
135 | if (!xfs_dir3_free_verify(bp)) { | 135 | if (!xfs_dir3_free_verify(bp)) { |
136 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | 136 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); |
137 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 137 | xfs_buf_ioerror(bp, EFSCORRUPTED); |
138 | return; | 138 | return; |
139 | } | 139 | } |
140 | 140 | ||
141 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | 141 | if (!xfs_sb_version_hascrc(&mp->m_sb)) |
142 | return; | 142 | return; |
143 | 143 | ||
144 | if (bip) | 144 | if (bip) |
145 | hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); | 145 | hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); |
146 | 146 | ||
147 | xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_FREE_CRC_OFF); | 147 | xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_FREE_CRC_OFF); |
148 | } | 148 | } |
149 | 149 | ||
150 | const struct xfs_buf_ops xfs_dir3_free_buf_ops = { | 150 | const struct xfs_buf_ops xfs_dir3_free_buf_ops = { |
151 | .verify_read = xfs_dir3_free_read_verify, | 151 | .verify_read = xfs_dir3_free_read_verify, |
152 | .verify_write = xfs_dir3_free_write_verify, | 152 | .verify_write = xfs_dir3_free_write_verify, |
153 | }; | 153 | }; |
154 | 154 | ||
155 | 155 | ||
156 | static int | 156 | static int |
157 | __xfs_dir3_free_read( | 157 | __xfs_dir3_free_read( |
158 | struct xfs_trans *tp, | 158 | struct xfs_trans *tp, |
159 | struct xfs_inode *dp, | 159 | struct xfs_inode *dp, |
160 | xfs_dablk_t fbno, | 160 | xfs_dablk_t fbno, |
161 | xfs_daddr_t mappedbno, | 161 | xfs_daddr_t mappedbno, |
162 | struct xfs_buf **bpp) | 162 | struct xfs_buf **bpp) |
163 | { | 163 | { |
164 | int err; | 164 | int err; |
165 | 165 | ||
166 | err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, | 166 | err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, |
167 | XFS_DATA_FORK, &xfs_dir3_free_buf_ops); | 167 | XFS_DATA_FORK, &xfs_dir3_free_buf_ops); |
168 | 168 | ||
169 | /* try read returns without an error or *bpp if it lands in a hole */ | 169 | /* try read returns without an error or *bpp if it lands in a hole */ |
170 | if (!err && tp && *bpp) | 170 | if (!err && tp && *bpp) |
171 | xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF); | 171 | xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF); |
172 | return err; | 172 | return err; |
173 | } | 173 | } |
174 | 174 | ||
175 | int | 175 | int |
176 | xfs_dir2_free_read( | 176 | xfs_dir2_free_read( |
177 | struct xfs_trans *tp, | 177 | struct xfs_trans *tp, |
178 | struct xfs_inode *dp, | 178 | struct xfs_inode *dp, |
179 | xfs_dablk_t fbno, | 179 | xfs_dablk_t fbno, |
180 | struct xfs_buf **bpp) | 180 | struct xfs_buf **bpp) |
181 | { | 181 | { |
182 | return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp); | 182 | return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp); |
183 | } | 183 | } |
184 | 184 | ||
185 | static int | 185 | static int |
186 | xfs_dir2_free_try_read( | 186 | xfs_dir2_free_try_read( |
187 | struct xfs_trans *tp, | 187 | struct xfs_trans *tp, |
188 | struct xfs_inode *dp, | 188 | struct xfs_inode *dp, |
189 | xfs_dablk_t fbno, | 189 | xfs_dablk_t fbno, |
190 | struct xfs_buf **bpp) | 190 | struct xfs_buf **bpp) |
191 | { | 191 | { |
192 | return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp); | 192 | return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp); |
193 | } | 193 | } |
194 | 194 | ||
195 | 195 | ||
196 | void | 196 | void |
197 | xfs_dir3_free_hdr_from_disk( | 197 | xfs_dir3_free_hdr_from_disk( |
198 | struct xfs_dir3_icfree_hdr *to, | 198 | struct xfs_dir3_icfree_hdr *to, |
199 | struct xfs_dir2_free *from) | 199 | struct xfs_dir2_free *from) |
200 | { | 200 | { |
201 | if (from->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC)) { | 201 | if (from->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC)) { |
202 | to->magic = be32_to_cpu(from->hdr.magic); | 202 | to->magic = be32_to_cpu(from->hdr.magic); |
203 | to->firstdb = be32_to_cpu(from->hdr.firstdb); | 203 | to->firstdb = be32_to_cpu(from->hdr.firstdb); |
204 | to->nvalid = be32_to_cpu(from->hdr.nvalid); | 204 | to->nvalid = be32_to_cpu(from->hdr.nvalid); |
205 | to->nused = be32_to_cpu(from->hdr.nused); | 205 | to->nused = be32_to_cpu(from->hdr.nused); |
206 | } else { | 206 | } else { |
207 | struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)from; | 207 | struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)from; |
208 | 208 | ||
209 | to->magic = be32_to_cpu(hdr3->hdr.magic); | 209 | to->magic = be32_to_cpu(hdr3->hdr.magic); |
210 | to->firstdb = be32_to_cpu(hdr3->firstdb); | 210 | to->firstdb = be32_to_cpu(hdr3->firstdb); |
211 | to->nvalid = be32_to_cpu(hdr3->nvalid); | 211 | to->nvalid = be32_to_cpu(hdr3->nvalid); |
212 | to->nused = be32_to_cpu(hdr3->nused); | 212 | to->nused = be32_to_cpu(hdr3->nused); |
213 | } | 213 | } |
214 | 214 | ||
215 | ASSERT(to->magic == XFS_DIR2_FREE_MAGIC || | 215 | ASSERT(to->magic == XFS_DIR2_FREE_MAGIC || |
216 | to->magic == XFS_DIR3_FREE_MAGIC); | 216 | to->magic == XFS_DIR3_FREE_MAGIC); |
217 | } | 217 | } |
218 | 218 | ||
219 | static void | 219 | static void |
220 | xfs_dir3_free_hdr_to_disk( | 220 | xfs_dir3_free_hdr_to_disk( |
221 | struct xfs_dir2_free *to, | 221 | struct xfs_dir2_free *to, |
222 | struct xfs_dir3_icfree_hdr *from) | 222 | struct xfs_dir3_icfree_hdr *from) |
223 | { | 223 | { |
224 | ASSERT(from->magic == XFS_DIR2_FREE_MAGIC || | 224 | ASSERT(from->magic == XFS_DIR2_FREE_MAGIC || |
225 | from->magic == XFS_DIR3_FREE_MAGIC); | 225 | from->magic == XFS_DIR3_FREE_MAGIC); |
226 | 226 | ||
227 | if (from->magic == XFS_DIR2_FREE_MAGIC) { | 227 | if (from->magic == XFS_DIR2_FREE_MAGIC) { |
228 | to->hdr.magic = cpu_to_be32(from->magic); | 228 | to->hdr.magic = cpu_to_be32(from->magic); |
229 | to->hdr.firstdb = cpu_to_be32(from->firstdb); | 229 | to->hdr.firstdb = cpu_to_be32(from->firstdb); |
230 | to->hdr.nvalid = cpu_to_be32(from->nvalid); | 230 | to->hdr.nvalid = cpu_to_be32(from->nvalid); |
231 | to->hdr.nused = cpu_to_be32(from->nused); | 231 | to->hdr.nused = cpu_to_be32(from->nused); |
232 | } else { | 232 | } else { |
233 | struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)to; | 233 | struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)to; |
234 | 234 | ||
235 | hdr3->hdr.magic = cpu_to_be32(from->magic); | 235 | hdr3->hdr.magic = cpu_to_be32(from->magic); |
236 | hdr3->firstdb = cpu_to_be32(from->firstdb); | 236 | hdr3->firstdb = cpu_to_be32(from->firstdb); |
237 | hdr3->nvalid = cpu_to_be32(from->nvalid); | 237 | hdr3->nvalid = cpu_to_be32(from->nvalid); |
238 | hdr3->nused = cpu_to_be32(from->nused); | 238 | hdr3->nused = cpu_to_be32(from->nused); |
239 | } | 239 | } |
240 | } | 240 | } |
241 | 241 | ||
242 | static int | 242 | static int |
243 | xfs_dir3_free_get_buf( | 243 | xfs_dir3_free_get_buf( |
244 | struct xfs_trans *tp, | 244 | struct xfs_trans *tp, |
245 | struct xfs_inode *dp, | 245 | struct xfs_inode *dp, |
246 | xfs_dir2_db_t fbno, | 246 | xfs_dir2_db_t fbno, |
247 | struct xfs_buf **bpp) | 247 | struct xfs_buf **bpp) |
248 | { | 248 | { |
249 | struct xfs_mount *mp = dp->i_mount; | 249 | struct xfs_mount *mp = dp->i_mount; |
250 | struct xfs_buf *bp; | 250 | struct xfs_buf *bp; |
251 | int error; | 251 | int error; |
252 | struct xfs_dir3_icfree_hdr hdr; | 252 | struct xfs_dir3_icfree_hdr hdr; |
253 | 253 | ||
254 | error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, fbno), | 254 | error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, fbno), |
255 | -1, &bp, XFS_DATA_FORK); | 255 | -1, &bp, XFS_DATA_FORK); |
256 | if (error) | 256 | if (error) |
257 | return error; | 257 | return error; |
258 | 258 | ||
259 | xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_FREE_BUF); | 259 | xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_FREE_BUF); |
260 | bp->b_ops = &xfs_dir3_free_buf_ops; | 260 | bp->b_ops = &xfs_dir3_free_buf_ops; |
261 | 261 | ||
262 | /* | 262 | /* |
263 | * Initialize the new block to be empty, and remember | 263 | * Initialize the new block to be empty, and remember |
264 | * its first slot as our empty slot. | 264 | * its first slot as our empty slot. |
265 | */ | 265 | */ |
266 | hdr.magic = XFS_DIR2_FREE_MAGIC; | 266 | hdr.magic = XFS_DIR2_FREE_MAGIC; |
267 | hdr.firstdb = 0; | 267 | hdr.firstdb = 0; |
268 | hdr.nused = 0; | 268 | hdr.nused = 0; |
269 | hdr.nvalid = 0; | 269 | hdr.nvalid = 0; |
270 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | 270 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
271 | struct xfs_dir3_free_hdr *hdr3 = bp->b_addr; | 271 | struct xfs_dir3_free_hdr *hdr3 = bp->b_addr; |
272 | 272 | ||
273 | hdr.magic = XFS_DIR3_FREE_MAGIC; | 273 | hdr.magic = XFS_DIR3_FREE_MAGIC; |
274 | hdr3->hdr.blkno = cpu_to_be64(bp->b_bn); | 274 | hdr3->hdr.blkno = cpu_to_be64(bp->b_bn); |
275 | hdr3->hdr.owner = cpu_to_be64(dp->i_ino); | 275 | hdr3->hdr.owner = cpu_to_be64(dp->i_ino); |
276 | uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid); | 276 | uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid); |
277 | } | 277 | } |
278 | xfs_dir3_free_hdr_to_disk(bp->b_addr, &hdr); | 278 | xfs_dir3_free_hdr_to_disk(bp->b_addr, &hdr); |
279 | *bpp = bp; | 279 | *bpp = bp; |
280 | return 0; | 280 | return 0; |
281 | } | 281 | } |
282 | 282 | ||
283 | /* | 283 | /* |
284 | * Log entries from a freespace block. | 284 | * Log entries from a freespace block. |
285 | */ | 285 | */ |
286 | STATIC void | 286 | STATIC void |
287 | xfs_dir2_free_log_bests( | 287 | xfs_dir2_free_log_bests( |
288 | struct xfs_trans *tp, | 288 | struct xfs_trans *tp, |
289 | struct xfs_buf *bp, | 289 | struct xfs_buf *bp, |
290 | int first, /* first entry to log */ | 290 | int first, /* first entry to log */ |
291 | int last) /* last entry to log */ | 291 | int last) /* last entry to log */ |
292 | { | 292 | { |
293 | xfs_dir2_free_t *free; /* freespace structure */ | 293 | xfs_dir2_free_t *free; /* freespace structure */ |
294 | __be16 *bests; | 294 | __be16 *bests; |
295 | 295 | ||
296 | free = bp->b_addr; | 296 | free = bp->b_addr; |
297 | bests = xfs_dir3_free_bests_p(tp->t_mountp, free); | 297 | bests = xfs_dir3_free_bests_p(tp->t_mountp, free); |
298 | ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || | 298 | ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || |
299 | free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); | 299 | free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); |
300 | xfs_trans_log_buf(tp, bp, | 300 | xfs_trans_log_buf(tp, bp, |
301 | (uint)((char *)&bests[first] - (char *)free), | 301 | (uint)((char *)&bests[first] - (char *)free), |
302 | (uint)((char *)&bests[last] - (char *)free + | 302 | (uint)((char *)&bests[last] - (char *)free + |
303 | sizeof(bests[0]) - 1)); | 303 | sizeof(bests[0]) - 1)); |
304 | } | 304 | } |
305 | 305 | ||
306 | /* | 306 | /* |
307 | * Log header from a freespace block. | 307 | * Log header from a freespace block. |
308 | */ | 308 | */ |
309 | static void | 309 | static void |
310 | xfs_dir2_free_log_header( | 310 | xfs_dir2_free_log_header( |
311 | struct xfs_trans *tp, | 311 | struct xfs_trans *tp, |
312 | struct xfs_buf *bp) | 312 | struct xfs_buf *bp) |
313 | { | 313 | { |
314 | xfs_dir2_free_t *free; /* freespace structure */ | 314 | xfs_dir2_free_t *free; /* freespace structure */ |
315 | 315 | ||
316 | free = bp->b_addr; | 316 | free = bp->b_addr; |
317 | ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || | 317 | ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || |
318 | free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); | 318 | free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); |
319 | xfs_trans_log_buf(tp, bp, 0, xfs_dir3_free_hdr_size(tp->t_mountp) - 1); | 319 | xfs_trans_log_buf(tp, bp, 0, xfs_dir3_free_hdr_size(tp->t_mountp) - 1); |
320 | } | 320 | } |
321 | 321 | ||
322 | /* | 322 | /* |
323 | * Convert a leaf-format directory to a node-format directory. | 323 | * Convert a leaf-format directory to a node-format directory. |
324 | * We need to change the magic number of the leaf block, and copy | 324 | * We need to change the magic number of the leaf block, and copy |
325 | * the freespace table out of the leaf block into its own block. | 325 | * the freespace table out of the leaf block into its own block. |
326 | */ | 326 | */ |
327 | int /* error */ | 327 | int /* error */ |
328 | xfs_dir2_leaf_to_node( | 328 | xfs_dir2_leaf_to_node( |
329 | xfs_da_args_t *args, /* operation arguments */ | 329 | xfs_da_args_t *args, /* operation arguments */ |
330 | struct xfs_buf *lbp) /* leaf buffer */ | 330 | struct xfs_buf *lbp) /* leaf buffer */ |
331 | { | 331 | { |
332 | xfs_inode_t *dp; /* incore directory inode */ | 332 | xfs_inode_t *dp; /* incore directory inode */ |
333 | int error; /* error return value */ | 333 | int error; /* error return value */ |
334 | struct xfs_buf *fbp; /* freespace buffer */ | 334 | struct xfs_buf *fbp; /* freespace buffer */ |
335 | xfs_dir2_db_t fdb; /* freespace block number */ | 335 | xfs_dir2_db_t fdb; /* freespace block number */ |
336 | xfs_dir2_free_t *free; /* freespace structure */ | 336 | xfs_dir2_free_t *free; /* freespace structure */ |
337 | __be16 *from; /* pointer to freespace entry */ | 337 | __be16 *from; /* pointer to freespace entry */ |
338 | int i; /* leaf freespace index */ | 338 | int i; /* leaf freespace index */ |
339 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | 339 | xfs_dir2_leaf_t *leaf; /* leaf structure */ |
340 | xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ | 340 | xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ |
341 | xfs_mount_t *mp; /* filesystem mount point */ | 341 | xfs_mount_t *mp; /* filesystem mount point */ |
342 | int n; /* count of live freespc ents */ | 342 | int n; /* count of live freespc ents */ |
343 | xfs_dir2_data_off_t off; /* freespace entry value */ | 343 | xfs_dir2_data_off_t off; /* freespace entry value */ |
344 | __be16 *to; /* pointer to freespace entry */ | 344 | __be16 *to; /* pointer to freespace entry */ |
345 | xfs_trans_t *tp; /* transaction pointer */ | 345 | xfs_trans_t *tp; /* transaction pointer */ |
346 | struct xfs_dir3_icfree_hdr freehdr; | 346 | struct xfs_dir3_icfree_hdr freehdr; |
347 | 347 | ||
348 | trace_xfs_dir2_leaf_to_node(args); | 348 | trace_xfs_dir2_leaf_to_node(args); |
349 | 349 | ||
350 | dp = args->dp; | 350 | dp = args->dp; |
351 | mp = dp->i_mount; | 351 | mp = dp->i_mount; |
352 | tp = args->trans; | 352 | tp = args->trans; |
353 | /* | 353 | /* |
354 | * Add a freespace block to the directory. | 354 | * Add a freespace block to the directory. |
355 | */ | 355 | */ |
356 | if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) { | 356 | if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) { |
357 | return error; | 357 | return error; |
358 | } | 358 | } |
359 | ASSERT(fdb == XFS_DIR2_FREE_FIRSTDB(mp)); | 359 | ASSERT(fdb == XFS_DIR2_FREE_FIRSTDB(mp)); |
360 | /* | 360 | /* |
361 | * Get the buffer for the new freespace block. | 361 | * Get the buffer for the new freespace block. |
362 | */ | 362 | */ |
363 | error = xfs_dir3_free_get_buf(tp, dp, fdb, &fbp); | 363 | error = xfs_dir3_free_get_buf(tp, dp, fdb, &fbp); |
364 | if (error) | 364 | if (error) |
365 | return error; | 365 | return error; |
366 | 366 | ||
367 | free = fbp->b_addr; | 367 | free = fbp->b_addr; |
368 | xfs_dir3_free_hdr_from_disk(&freehdr, free); | 368 | xfs_dir3_free_hdr_from_disk(&freehdr, free); |
369 | leaf = lbp->b_addr; | 369 | leaf = lbp->b_addr; |
370 | ltp = xfs_dir2_leaf_tail_p(mp, leaf); | 370 | ltp = xfs_dir2_leaf_tail_p(mp, leaf); |
371 | ASSERT(be32_to_cpu(ltp->bestcount) <= | 371 | ASSERT(be32_to_cpu(ltp->bestcount) <= |
372 | (uint)dp->i_d.di_size / mp->m_dirblksize); | 372 | (uint)dp->i_d.di_size / mp->m_dirblksize); |
373 | 373 | ||
374 | /* | 374 | /* |
375 | * Copy freespace entries from the leaf block to the new block. | 375 | * Copy freespace entries from the leaf block to the new block. |
376 | * Count active entries. | 376 | * Count active entries. |
377 | */ | 377 | */ |
378 | from = xfs_dir2_leaf_bests_p(ltp); | 378 | from = xfs_dir2_leaf_bests_p(ltp); |
379 | to = xfs_dir3_free_bests_p(mp, free); | 379 | to = xfs_dir3_free_bests_p(mp, free); |
380 | for (i = n = 0; i < be32_to_cpu(ltp->bestcount); i++, from++, to++) { | 380 | for (i = n = 0; i < be32_to_cpu(ltp->bestcount); i++, from++, to++) { |
381 | if ((off = be16_to_cpu(*from)) != NULLDATAOFF) | 381 | if ((off = be16_to_cpu(*from)) != NULLDATAOFF) |
382 | n++; | 382 | n++; |
383 | *to = cpu_to_be16(off); | 383 | *to = cpu_to_be16(off); |
384 | } | 384 | } |
385 | 385 | ||
386 | /* | 386 | /* |
387 | * Now initialize the freespace block header. | 387 | * Now initialize the freespace block header. |
388 | */ | 388 | */ |
389 | freehdr.nused = n; | 389 | freehdr.nused = n; |
390 | freehdr.nvalid = be32_to_cpu(ltp->bestcount); | 390 | freehdr.nvalid = be32_to_cpu(ltp->bestcount); |
391 | 391 | ||
392 | xfs_dir3_free_hdr_to_disk(fbp->b_addr, &freehdr); | 392 | xfs_dir3_free_hdr_to_disk(fbp->b_addr, &freehdr); |
393 | xfs_dir2_free_log_bests(tp, fbp, 0, freehdr.nvalid - 1); | 393 | xfs_dir2_free_log_bests(tp, fbp, 0, freehdr.nvalid - 1); |
394 | xfs_dir2_free_log_header(tp, fbp); | 394 | xfs_dir2_free_log_header(tp, fbp); |
395 | 395 | ||
396 | /* | 396 | /* |
397 | * Converting the leaf to a leafnode is just a matter of changing the | 397 | * Converting the leaf to a leafnode is just a matter of changing the |
398 | * magic number and the ops. Do the change directly to the buffer as | 398 | * magic number and the ops. Do the change directly to the buffer as |
399 | * it's less work (and less code) than decoding the header to host | 399 | * it's less work (and less code) than decoding the header to host |
400 | * format and back again. | 400 | * format and back again. |
401 | */ | 401 | */ |
402 | if (leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC)) | 402 | if (leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC)) |
403 | leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC); | 403 | leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC); |
404 | else | 404 | else |
405 | leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC); | 405 | leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC); |
406 | lbp->b_ops = &xfs_dir3_leafn_buf_ops; | 406 | lbp->b_ops = &xfs_dir3_leafn_buf_ops; |
407 | xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAFN_BUF); | 407 | xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAFN_BUF); |
408 | xfs_dir3_leaf_log_header(tp, lbp); | 408 | xfs_dir3_leaf_log_header(tp, lbp); |
409 | xfs_dir3_leaf_check(mp, lbp); | 409 | xfs_dir3_leaf_check(mp, lbp); |
410 | return 0; | 410 | return 0; |
411 | } | 411 | } |
412 | 412 | ||
413 | /* | 413 | /* |
414 | * Add a leaf entry to a leaf block in a node-form directory. | 414 | * Add a leaf entry to a leaf block in a node-form directory. |
415 | * The other work necessary is done from the caller. | 415 | * The other work necessary is done from the caller. |
416 | */ | 416 | */ |
417 | static int /* error */ | 417 | static int /* error */ |
418 | xfs_dir2_leafn_add( | 418 | xfs_dir2_leafn_add( |
419 | struct xfs_buf *bp, /* leaf buffer */ | 419 | struct xfs_buf *bp, /* leaf buffer */ |
420 | xfs_da_args_t *args, /* operation arguments */ | 420 | xfs_da_args_t *args, /* operation arguments */ |
421 | int index) /* insertion pt for new entry */ | 421 | int index) /* insertion pt for new entry */ |
422 | { | 422 | { |
423 | int compact; /* compacting stale leaves */ | 423 | int compact; /* compacting stale leaves */ |
424 | xfs_inode_t *dp; /* incore directory inode */ | 424 | xfs_inode_t *dp; /* incore directory inode */ |
425 | int highstale; /* next stale entry */ | 425 | int highstale; /* next stale entry */ |
426 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | 426 | xfs_dir2_leaf_t *leaf; /* leaf structure */ |
427 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ | 427 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ |
428 | int lfloghigh; /* high leaf entry logging */ | 428 | int lfloghigh; /* high leaf entry logging */ |
429 | int lfloglow; /* low leaf entry logging */ | 429 | int lfloglow; /* low leaf entry logging */ |
430 | int lowstale; /* previous stale entry */ | 430 | int lowstale; /* previous stale entry */ |
431 | xfs_mount_t *mp; /* filesystem mount point */ | 431 | xfs_mount_t *mp; /* filesystem mount point */ |
432 | xfs_trans_t *tp; /* transaction pointer */ | 432 | xfs_trans_t *tp; /* transaction pointer */ |
433 | struct xfs_dir3_icleaf_hdr leafhdr; | 433 | struct xfs_dir3_icleaf_hdr leafhdr; |
434 | struct xfs_dir2_leaf_entry *ents; | 434 | struct xfs_dir2_leaf_entry *ents; |
435 | 435 | ||
436 | trace_xfs_dir2_leafn_add(args, index); | 436 | trace_xfs_dir2_leafn_add(args, index); |
437 | 437 | ||
438 | dp = args->dp; | 438 | dp = args->dp; |
439 | mp = dp->i_mount; | 439 | mp = dp->i_mount; |
440 | tp = args->trans; | 440 | tp = args->trans; |
441 | leaf = bp->b_addr; | 441 | leaf = bp->b_addr; |
442 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); | 442 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); |
443 | ents = xfs_dir3_leaf_ents_p(leaf); | 443 | ents = xfs_dir3_leaf_ents_p(leaf); |
444 | 444 | ||
445 | /* | 445 | /* |
446 | * Quick check just to make sure we are not going to index | 446 | * Quick check just to make sure we are not going to index |
447 | * into other peoples memory | 447 | * into other peoples memory |
448 | */ | 448 | */ |
449 | if (index < 0) | 449 | if (index < 0) |
450 | return XFS_ERROR(EFSCORRUPTED); | 450 | return XFS_ERROR(EFSCORRUPTED); |
451 | 451 | ||
452 | /* | 452 | /* |
453 | * If there are already the maximum number of leaf entries in | 453 | * If there are already the maximum number of leaf entries in |
454 | * the block, if there are no stale entries it won't fit. | 454 | * the block, if there are no stale entries it won't fit. |
455 | * Caller will do a split. If there are stale entries we'll do | 455 | * Caller will do a split. If there are stale entries we'll do |
456 | * a compact. | 456 | * a compact. |
457 | */ | 457 | */ |
458 | 458 | ||
459 | if (leafhdr.count == xfs_dir3_max_leaf_ents(mp, leaf)) { | 459 | if (leafhdr.count == xfs_dir3_max_leaf_ents(mp, leaf)) { |
460 | if (!leafhdr.stale) | 460 | if (!leafhdr.stale) |
461 | return XFS_ERROR(ENOSPC); | 461 | return XFS_ERROR(ENOSPC); |
462 | compact = leafhdr.stale > 1; | 462 | compact = leafhdr.stale > 1; |
463 | } else | 463 | } else |
464 | compact = 0; | 464 | compact = 0; |
465 | ASSERT(index == 0 || be32_to_cpu(ents[index - 1].hashval) <= args->hashval); | 465 | ASSERT(index == 0 || be32_to_cpu(ents[index - 1].hashval) <= args->hashval); |
466 | ASSERT(index == leafhdr.count || | 466 | ASSERT(index == leafhdr.count || |
467 | be32_to_cpu(ents[index].hashval) >= args->hashval); | 467 | be32_to_cpu(ents[index].hashval) >= args->hashval); |
468 | 468 | ||
469 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) | 469 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) |
470 | return 0; | 470 | return 0; |
471 | 471 | ||
472 | /* | 472 | /* |
473 | * Compact out all but one stale leaf entry. Leaves behind | 473 | * Compact out all but one stale leaf entry. Leaves behind |
474 | * the entry closest to index. | 474 | * the entry closest to index. |
475 | */ | 475 | */ |
476 | if (compact) | 476 | if (compact) |
477 | xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale, | 477 | xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale, |
478 | &highstale, &lfloglow, &lfloghigh); | 478 | &highstale, &lfloglow, &lfloghigh); |
479 | else if (leafhdr.stale) { | 479 | else if (leafhdr.stale) { |
480 | /* | 480 | /* |
481 | * Set impossible logging indices for this case. | 481 | * Set impossible logging indices for this case. |
482 | */ | 482 | */ |
483 | lfloglow = leafhdr.count; | 483 | lfloglow = leafhdr.count; |
484 | lfloghigh = -1; | 484 | lfloghigh = -1; |
485 | } | 485 | } |
486 | 486 | ||
487 | /* | 487 | /* |
488 | * Insert the new entry, log everything. | 488 | * Insert the new entry, log everything. |
489 | */ | 489 | */ |
490 | lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale, | 490 | lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale, |
491 | highstale, &lfloglow, &lfloghigh); | 491 | highstale, &lfloglow, &lfloghigh); |
492 | 492 | ||
493 | lep->hashval = cpu_to_be32(args->hashval); | 493 | lep->hashval = cpu_to_be32(args->hashval); |
494 | lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp, | 494 | lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp, |
495 | args->blkno, args->index)); | 495 | args->blkno, args->index)); |
496 | 496 | ||
497 | xfs_dir3_leaf_hdr_to_disk(leaf, &leafhdr); | 497 | xfs_dir3_leaf_hdr_to_disk(leaf, &leafhdr); |
498 | xfs_dir3_leaf_log_header(tp, bp); | 498 | xfs_dir3_leaf_log_header(tp, bp); |
499 | xfs_dir3_leaf_log_ents(tp, bp, lfloglow, lfloghigh); | 499 | xfs_dir3_leaf_log_ents(tp, bp, lfloglow, lfloghigh); |
500 | xfs_dir3_leaf_check(mp, bp); | 500 | xfs_dir3_leaf_check(mp, bp); |
501 | return 0; | 501 | return 0; |
502 | } | 502 | } |
503 | 503 | ||
504 | #ifdef DEBUG | 504 | #ifdef DEBUG |
505 | static void | 505 | static void |
506 | xfs_dir2_free_hdr_check( | 506 | xfs_dir2_free_hdr_check( |
507 | struct xfs_mount *mp, | 507 | struct xfs_mount *mp, |
508 | struct xfs_buf *bp, | 508 | struct xfs_buf *bp, |
509 | xfs_dir2_db_t db) | 509 | xfs_dir2_db_t db) |
510 | { | 510 | { |
511 | struct xfs_dir3_icfree_hdr hdr; | 511 | struct xfs_dir3_icfree_hdr hdr; |
512 | 512 | ||
513 | xfs_dir3_free_hdr_from_disk(&hdr, bp->b_addr); | 513 | xfs_dir3_free_hdr_from_disk(&hdr, bp->b_addr); |
514 | 514 | ||
515 | ASSERT((hdr.firstdb % xfs_dir3_free_max_bests(mp)) == 0); | 515 | ASSERT((hdr.firstdb % xfs_dir3_free_max_bests(mp)) == 0); |
516 | ASSERT(hdr.firstdb <= db); | 516 | ASSERT(hdr.firstdb <= db); |
517 | ASSERT(db < hdr.firstdb + hdr.nvalid); | 517 | ASSERT(db < hdr.firstdb + hdr.nvalid); |
518 | } | 518 | } |
519 | #else | 519 | #else |
520 | #define xfs_dir2_free_hdr_check(mp, dp, db) | 520 | #define xfs_dir2_free_hdr_check(mp, dp, db) |
521 | #endif /* DEBUG */ | 521 | #endif /* DEBUG */ |
522 | 522 | ||
523 | /* | 523 | /* |
524 | * Return the last hash value in the leaf. | 524 | * Return the last hash value in the leaf. |
525 | * Stale entries are ok. | 525 | * Stale entries are ok. |
526 | */ | 526 | */ |
527 | xfs_dahash_t /* hash value */ | 527 | xfs_dahash_t /* hash value */ |
528 | xfs_dir2_leafn_lasthash( | 528 | xfs_dir2_leafn_lasthash( |
529 | struct xfs_buf *bp, /* leaf buffer */ | 529 | struct xfs_buf *bp, /* leaf buffer */ |
530 | int *count) /* count of entries in leaf */ | 530 | int *count) /* count of entries in leaf */ |
531 | { | 531 | { |
532 | struct xfs_dir2_leaf *leaf = bp->b_addr; | 532 | struct xfs_dir2_leaf *leaf = bp->b_addr; |
533 | struct xfs_dir2_leaf_entry *ents; | 533 | struct xfs_dir2_leaf_entry *ents; |
534 | struct xfs_dir3_icleaf_hdr leafhdr; | 534 | struct xfs_dir3_icleaf_hdr leafhdr; |
535 | 535 | ||
536 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); | 536 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); |
537 | 537 | ||
538 | ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || | 538 | ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || |
539 | leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); | 539 | leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); |
540 | 540 | ||
541 | if (count) | 541 | if (count) |
542 | *count = leafhdr.count; | 542 | *count = leafhdr.count; |
543 | if (!leafhdr.count) | 543 | if (!leafhdr.count) |
544 | return 0; | 544 | return 0; |
545 | 545 | ||
546 | ents = xfs_dir3_leaf_ents_p(leaf); | 546 | ents = xfs_dir3_leaf_ents_p(leaf); |
547 | return be32_to_cpu(ents[leafhdr.count - 1].hashval); | 547 | return be32_to_cpu(ents[leafhdr.count - 1].hashval); |
548 | } | 548 | } |
549 | 549 | ||
550 | /* | 550 | /* |
551 | * Look up a leaf entry for space to add a name in a node-format leaf block. | 551 | * Look up a leaf entry for space to add a name in a node-format leaf block. |
552 | * The extrablk in state is a freespace block. | 552 | * The extrablk in state is a freespace block. |
553 | */ | 553 | */ |
554 | STATIC int | 554 | STATIC int |
555 | xfs_dir2_leafn_lookup_for_addname( | 555 | xfs_dir2_leafn_lookup_for_addname( |
556 | struct xfs_buf *bp, /* leaf buffer */ | 556 | struct xfs_buf *bp, /* leaf buffer */ |
557 | xfs_da_args_t *args, /* operation arguments */ | 557 | xfs_da_args_t *args, /* operation arguments */ |
558 | int *indexp, /* out: leaf entry index */ | 558 | int *indexp, /* out: leaf entry index */ |
559 | xfs_da_state_t *state) /* state to fill in */ | 559 | xfs_da_state_t *state) /* state to fill in */ |
560 | { | 560 | { |
561 | struct xfs_buf *curbp = NULL; /* current data/free buffer */ | 561 | struct xfs_buf *curbp = NULL; /* current data/free buffer */ |
562 | xfs_dir2_db_t curdb = -1; /* current data block number */ | 562 | xfs_dir2_db_t curdb = -1; /* current data block number */ |
563 | xfs_dir2_db_t curfdb = -1; /* current free block number */ | 563 | xfs_dir2_db_t curfdb = -1; /* current free block number */ |
564 | xfs_inode_t *dp; /* incore directory inode */ | 564 | xfs_inode_t *dp; /* incore directory inode */ |
565 | int error; /* error return value */ | 565 | int error; /* error return value */ |
566 | int fi; /* free entry index */ | 566 | int fi; /* free entry index */ |
567 | xfs_dir2_free_t *free = NULL; /* free block structure */ | 567 | xfs_dir2_free_t *free = NULL; /* free block structure */ |
568 | int index; /* leaf entry index */ | 568 | int index; /* leaf entry index */ |
569 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | 569 | xfs_dir2_leaf_t *leaf; /* leaf structure */ |
570 | int length; /* length of new data entry */ | 570 | int length; /* length of new data entry */ |
571 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ | 571 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ |
572 | xfs_mount_t *mp; /* filesystem mount point */ | 572 | xfs_mount_t *mp; /* filesystem mount point */ |
573 | xfs_dir2_db_t newdb; /* new data block number */ | 573 | xfs_dir2_db_t newdb; /* new data block number */ |
574 | xfs_dir2_db_t newfdb; /* new free block number */ | 574 | xfs_dir2_db_t newfdb; /* new free block number */ |
575 | xfs_trans_t *tp; /* transaction pointer */ | 575 | xfs_trans_t *tp; /* transaction pointer */ |
576 | struct xfs_dir2_leaf_entry *ents; | 576 | struct xfs_dir2_leaf_entry *ents; |
577 | struct xfs_dir3_icleaf_hdr leafhdr; | 577 | struct xfs_dir3_icleaf_hdr leafhdr; |
578 | 578 | ||
579 | dp = args->dp; | 579 | dp = args->dp; |
580 | tp = args->trans; | 580 | tp = args->trans; |
581 | mp = dp->i_mount; | 581 | mp = dp->i_mount; |
582 | leaf = bp->b_addr; | 582 | leaf = bp->b_addr; |
583 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); | 583 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); |
584 | ents = xfs_dir3_leaf_ents_p(leaf); | 584 | ents = xfs_dir3_leaf_ents_p(leaf); |
585 | 585 | ||
586 | xfs_dir3_leaf_check(mp, bp); | 586 | xfs_dir3_leaf_check(mp, bp); |
587 | ASSERT(leafhdr.count > 0); | 587 | ASSERT(leafhdr.count > 0); |
588 | 588 | ||
589 | /* | 589 | /* |
590 | * Look up the hash value in the leaf entries. | 590 | * Look up the hash value in the leaf entries. |
591 | */ | 591 | */ |
592 | index = xfs_dir2_leaf_search_hash(args, bp); | 592 | index = xfs_dir2_leaf_search_hash(args, bp); |
593 | /* | 593 | /* |
594 | * Do we have a buffer coming in? | 594 | * Do we have a buffer coming in? |
595 | */ | 595 | */ |
596 | if (state->extravalid) { | 596 | if (state->extravalid) { |
597 | /* If so, it's a free block buffer, get the block number. */ | 597 | /* If so, it's a free block buffer, get the block number. */ |
598 | curbp = state->extrablk.bp; | 598 | curbp = state->extrablk.bp; |
599 | curfdb = state->extrablk.blkno; | 599 | curfdb = state->extrablk.blkno; |
600 | free = curbp->b_addr; | 600 | free = curbp->b_addr; |
601 | ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || | 601 | ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || |
602 | free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); | 602 | free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); |
603 | } | 603 | } |
604 | length = xfs_dir2_data_entsize(args->namelen); | 604 | length = xfs_dir2_data_entsize(args->namelen); |
605 | /* | 605 | /* |
606 | * Loop over leaf entries with the right hash value. | 606 | * Loop over leaf entries with the right hash value. |
607 | */ | 607 | */ |
608 | for (lep = &ents[index]; | 608 | for (lep = &ents[index]; |
609 | index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; | 609 | index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; |
610 | lep++, index++) { | 610 | lep++, index++) { |
611 | /* | 611 | /* |
612 | * Skip stale leaf entries. | 612 | * Skip stale leaf entries. |
613 | */ | 613 | */ |
614 | if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) | 614 | if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) |
615 | continue; | 615 | continue; |
616 | /* | 616 | /* |
617 | * Pull the data block number from the entry. | 617 | * Pull the data block number from the entry. |
618 | */ | 618 | */ |
619 | newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address)); | 619 | newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address)); |
620 | /* | 620 | /* |
621 | * For addname, we're looking for a place to put the new entry. | 621 | * For addname, we're looking for a place to put the new entry. |
622 | * We want to use a data block with an entry of equal | 622 | * We want to use a data block with an entry of equal |
623 | * hash value to ours if there is one with room. | 623 | * hash value to ours if there is one with room. |
624 | * | 624 | * |
625 | * If this block isn't the data block we already have | 625 | * If this block isn't the data block we already have |
626 | * in hand, take a look at it. | 626 | * in hand, take a look at it. |
627 | */ | 627 | */ |
628 | if (newdb != curdb) { | 628 | if (newdb != curdb) { |
629 | __be16 *bests; | 629 | __be16 *bests; |
630 | 630 | ||
631 | curdb = newdb; | 631 | curdb = newdb; |
632 | /* | 632 | /* |
633 | * Convert the data block to the free block | 633 | * Convert the data block to the free block |
634 | * holding its freespace information. | 634 | * holding its freespace information. |
635 | */ | 635 | */ |
636 | newfdb = xfs_dir2_db_to_fdb(mp, newdb); | 636 | newfdb = xfs_dir2_db_to_fdb(mp, newdb); |
637 | /* | 637 | /* |
638 | * If it's not the one we have in hand, read it in. | 638 | * If it's not the one we have in hand, read it in. |
639 | */ | 639 | */ |
640 | if (newfdb != curfdb) { | 640 | if (newfdb != curfdb) { |
641 | /* | 641 | /* |
642 | * If we had one before, drop it. | 642 | * If we had one before, drop it. |
643 | */ | 643 | */ |
644 | if (curbp) | 644 | if (curbp) |
645 | xfs_trans_brelse(tp, curbp); | 645 | xfs_trans_brelse(tp, curbp); |
646 | 646 | ||
647 | error = xfs_dir2_free_read(tp, dp, | 647 | error = xfs_dir2_free_read(tp, dp, |
648 | xfs_dir2_db_to_da(mp, newfdb), | 648 | xfs_dir2_db_to_da(mp, newfdb), |
649 | &curbp); | 649 | &curbp); |
650 | if (error) | 650 | if (error) |
651 | return error; | 651 | return error; |
652 | free = curbp->b_addr; | 652 | free = curbp->b_addr; |
653 | 653 | ||
654 | xfs_dir2_free_hdr_check(mp, curbp, curdb); | 654 | xfs_dir2_free_hdr_check(mp, curbp, curdb); |
655 | } | 655 | } |
656 | /* | 656 | /* |
657 | * Get the index for our entry. | 657 | * Get the index for our entry. |
658 | */ | 658 | */ |
659 | fi = xfs_dir2_db_to_fdindex(mp, curdb); | 659 | fi = xfs_dir2_db_to_fdindex(mp, curdb); |
660 | /* | 660 | /* |
661 | * If it has room, return it. | 661 | * If it has room, return it. |
662 | */ | 662 | */ |
663 | bests = xfs_dir3_free_bests_p(mp, free); | 663 | bests = xfs_dir3_free_bests_p(mp, free); |
664 | if (unlikely(bests[fi] == cpu_to_be16(NULLDATAOFF))) { | 664 | if (unlikely(bests[fi] == cpu_to_be16(NULLDATAOFF))) { |
665 | XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", | 665 | XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", |
666 | XFS_ERRLEVEL_LOW, mp); | 666 | XFS_ERRLEVEL_LOW, mp); |
667 | if (curfdb != newfdb) | 667 | if (curfdb != newfdb) |
668 | xfs_trans_brelse(tp, curbp); | 668 | xfs_trans_brelse(tp, curbp); |
669 | return XFS_ERROR(EFSCORRUPTED); | 669 | return XFS_ERROR(EFSCORRUPTED); |
670 | } | 670 | } |
671 | curfdb = newfdb; | 671 | curfdb = newfdb; |
672 | if (be16_to_cpu(bests[fi]) >= length) | 672 | if (be16_to_cpu(bests[fi]) >= length) |
673 | goto out; | 673 | goto out; |
674 | } | 674 | } |
675 | } | 675 | } |
676 | /* Didn't find any space */ | 676 | /* Didn't find any space */ |
677 | fi = -1; | 677 | fi = -1; |
678 | out: | 678 | out: |
679 | ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); | 679 | ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); |
680 | if (curbp) { | 680 | if (curbp) { |
681 | /* Giving back a free block. */ | 681 | /* Giving back a free block. */ |
682 | state->extravalid = 1; | 682 | state->extravalid = 1; |
683 | state->extrablk.bp = curbp; | 683 | state->extrablk.bp = curbp; |
684 | state->extrablk.index = fi; | 684 | state->extrablk.index = fi; |
685 | state->extrablk.blkno = curfdb; | 685 | state->extrablk.blkno = curfdb; |
686 | 686 | ||
687 | /* | 687 | /* |
688 | * Important: this magic number is not in the buffer - it's for | 688 | * Important: this magic number is not in the buffer - it's for |
689 | * buffer type information and therefore only the free/data type | 689 | * buffer type information and therefore only the free/data type |
690 | * matters here, not whether CRCs are enabled or not. | 690 | * matters here, not whether CRCs are enabled or not. |
691 | */ | 691 | */ |
692 | state->extrablk.magic = XFS_DIR2_FREE_MAGIC; | 692 | state->extrablk.magic = XFS_DIR2_FREE_MAGIC; |
693 | } else { | 693 | } else { |
694 | state->extravalid = 0; | 694 | state->extravalid = 0; |
695 | } | 695 | } |
696 | /* | 696 | /* |
697 | * Return the index, that will be the insertion point. | 697 | * Return the index, that will be the insertion point. |
698 | */ | 698 | */ |
699 | *indexp = index; | 699 | *indexp = index; |
700 | return XFS_ERROR(ENOENT); | 700 | return XFS_ERROR(ENOENT); |
701 | } | 701 | } |
702 | 702 | ||
703 | /* | 703 | /* |
704 | * Look up a leaf entry in a node-format leaf block. | 704 | * Look up a leaf entry in a node-format leaf block. |
705 | * The extrablk in state a data block. | 705 | * The extrablk in state a data block. |
706 | */ | 706 | */ |
707 | STATIC int | 707 | STATIC int |
708 | xfs_dir2_leafn_lookup_for_entry( | 708 | xfs_dir2_leafn_lookup_for_entry( |
709 | struct xfs_buf *bp, /* leaf buffer */ | 709 | struct xfs_buf *bp, /* leaf buffer */ |
710 | xfs_da_args_t *args, /* operation arguments */ | 710 | xfs_da_args_t *args, /* operation arguments */ |
711 | int *indexp, /* out: leaf entry index */ | 711 | int *indexp, /* out: leaf entry index */ |
712 | xfs_da_state_t *state) /* state to fill in */ | 712 | xfs_da_state_t *state) /* state to fill in */ |
713 | { | 713 | { |
714 | struct xfs_buf *curbp = NULL; /* current data/free buffer */ | 714 | struct xfs_buf *curbp = NULL; /* current data/free buffer */ |
715 | xfs_dir2_db_t curdb = -1; /* current data block number */ | 715 | xfs_dir2_db_t curdb = -1; /* current data block number */ |
716 | xfs_dir2_data_entry_t *dep; /* data block entry */ | 716 | xfs_dir2_data_entry_t *dep; /* data block entry */ |
717 | xfs_inode_t *dp; /* incore directory inode */ | 717 | xfs_inode_t *dp; /* incore directory inode */ |
718 | int error; /* error return value */ | 718 | int error; /* error return value */ |
719 | int index; /* leaf entry index */ | 719 | int index; /* leaf entry index */ |
720 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | 720 | xfs_dir2_leaf_t *leaf; /* leaf structure */ |
721 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ | 721 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ |
722 | xfs_mount_t *mp; /* filesystem mount point */ | 722 | xfs_mount_t *mp; /* filesystem mount point */ |
723 | xfs_dir2_db_t newdb; /* new data block number */ | 723 | xfs_dir2_db_t newdb; /* new data block number */ |
724 | xfs_trans_t *tp; /* transaction pointer */ | 724 | xfs_trans_t *tp; /* transaction pointer */ |
725 | enum xfs_dacmp cmp; /* comparison result */ | 725 | enum xfs_dacmp cmp; /* comparison result */ |
726 | struct xfs_dir2_leaf_entry *ents; | 726 | struct xfs_dir2_leaf_entry *ents; |
727 | struct xfs_dir3_icleaf_hdr leafhdr; | 727 | struct xfs_dir3_icleaf_hdr leafhdr; |
728 | 728 | ||
729 | dp = args->dp; | 729 | dp = args->dp; |
730 | tp = args->trans; | 730 | tp = args->trans; |
731 | mp = dp->i_mount; | 731 | mp = dp->i_mount; |
732 | leaf = bp->b_addr; | 732 | leaf = bp->b_addr; |
733 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); | 733 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); |
734 | ents = xfs_dir3_leaf_ents_p(leaf); | 734 | ents = xfs_dir3_leaf_ents_p(leaf); |
735 | 735 | ||
736 | xfs_dir3_leaf_check(mp, bp); | 736 | xfs_dir3_leaf_check(mp, bp); |
737 | ASSERT(leafhdr.count > 0); | 737 | ASSERT(leafhdr.count > 0); |
738 | 738 | ||
739 | /* | 739 | /* |
740 | * Look up the hash value in the leaf entries. | 740 | * Look up the hash value in the leaf entries. |
741 | */ | 741 | */ |
742 | index = xfs_dir2_leaf_search_hash(args, bp); | 742 | index = xfs_dir2_leaf_search_hash(args, bp); |
743 | /* | 743 | /* |
744 | * Do we have a buffer coming in? | 744 | * Do we have a buffer coming in? |
745 | */ | 745 | */ |
746 | if (state->extravalid) { | 746 | if (state->extravalid) { |
747 | curbp = state->extrablk.bp; | 747 | curbp = state->extrablk.bp; |
748 | curdb = state->extrablk.blkno; | 748 | curdb = state->extrablk.blkno; |
749 | } | 749 | } |
750 | /* | 750 | /* |
751 | * Loop over leaf entries with the right hash value. | 751 | * Loop over leaf entries with the right hash value. |
752 | */ | 752 | */ |
753 | for (lep = &ents[index]; | 753 | for (lep = &ents[index]; |
754 | index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; | 754 | index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; |
755 | lep++, index++) { | 755 | lep++, index++) { |
756 | /* | 756 | /* |
757 | * Skip stale leaf entries. | 757 | * Skip stale leaf entries. |
758 | */ | 758 | */ |
759 | if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) | 759 | if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) |
760 | continue; | 760 | continue; |
761 | /* | 761 | /* |
762 | * Pull the data block number from the entry. | 762 | * Pull the data block number from the entry. |
763 | */ | 763 | */ |
764 | newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address)); | 764 | newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address)); |
765 | /* | 765 | /* |
766 | * Not adding a new entry, so we really want to find | 766 | * Not adding a new entry, so we really want to find |
767 | * the name given to us. | 767 | * the name given to us. |
768 | * | 768 | * |
769 | * If it's a different data block, go get it. | 769 | * If it's a different data block, go get it. |
770 | */ | 770 | */ |
771 | if (newdb != curdb) { | 771 | if (newdb != curdb) { |
772 | /* | 772 | /* |
773 | * If we had a block before that we aren't saving | 773 | * If we had a block before that we aren't saving |
774 | * for a CI name, drop it | 774 | * for a CI name, drop it |
775 | */ | 775 | */ |
776 | if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT || | 776 | if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT || |
777 | curdb != state->extrablk.blkno)) | 777 | curdb != state->extrablk.blkno)) |
778 | xfs_trans_brelse(tp, curbp); | 778 | xfs_trans_brelse(tp, curbp); |
779 | /* | 779 | /* |
780 | * If needing the block that is saved with a CI match, | 780 | * If needing the block that is saved with a CI match, |
781 | * use it otherwise read in the new data block. | 781 | * use it otherwise read in the new data block. |
782 | */ | 782 | */ |
783 | if (args->cmpresult != XFS_CMP_DIFFERENT && | 783 | if (args->cmpresult != XFS_CMP_DIFFERENT && |
784 | newdb == state->extrablk.blkno) { | 784 | newdb == state->extrablk.blkno) { |
785 | ASSERT(state->extravalid); | 785 | ASSERT(state->extravalid); |
786 | curbp = state->extrablk.bp; | 786 | curbp = state->extrablk.bp; |
787 | } else { | 787 | } else { |
788 | error = xfs_dir3_data_read(tp, dp, | 788 | error = xfs_dir3_data_read(tp, dp, |
789 | xfs_dir2_db_to_da(mp, newdb), | 789 | xfs_dir2_db_to_da(mp, newdb), |
790 | -1, &curbp); | 790 | -1, &curbp); |
791 | if (error) | 791 | if (error) |
792 | return error; | 792 | return error; |
793 | } | 793 | } |
794 | xfs_dir3_data_check(dp, curbp); | 794 | xfs_dir3_data_check(dp, curbp); |
795 | curdb = newdb; | 795 | curdb = newdb; |
796 | } | 796 | } |
797 | /* | 797 | /* |
798 | * Point to the data entry. | 798 | * Point to the data entry. |
799 | */ | 799 | */ |
800 | dep = (xfs_dir2_data_entry_t *)((char *)curbp->b_addr + | 800 | dep = (xfs_dir2_data_entry_t *)((char *)curbp->b_addr + |
801 | xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); | 801 | xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); |
802 | /* | 802 | /* |
803 | * Compare the entry and if it's an exact match, return | 803 | * Compare the entry and if it's an exact match, return |
804 | * EEXIST immediately. If it's the first case-insensitive | 804 | * EEXIST immediately. If it's the first case-insensitive |
805 | * match, store the block & inode number and continue looking. | 805 | * match, store the block & inode number and continue looking. |
806 | */ | 806 | */ |
807 | cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); | 807 | cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); |
808 | if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { | 808 | if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { |
809 | /* If there is a CI match block, drop it */ | 809 | /* If there is a CI match block, drop it */ |
810 | if (args->cmpresult != XFS_CMP_DIFFERENT && | 810 | if (args->cmpresult != XFS_CMP_DIFFERENT && |
811 | curdb != state->extrablk.blkno) | 811 | curdb != state->extrablk.blkno) |
812 | xfs_trans_brelse(tp, state->extrablk.bp); | 812 | xfs_trans_brelse(tp, state->extrablk.bp); |
813 | args->cmpresult = cmp; | 813 | args->cmpresult = cmp; |
814 | args->inumber = be64_to_cpu(dep->inumber); | 814 | args->inumber = be64_to_cpu(dep->inumber); |
815 | *indexp = index; | 815 | *indexp = index; |
816 | state->extravalid = 1; | 816 | state->extravalid = 1; |
817 | state->extrablk.bp = curbp; | 817 | state->extrablk.bp = curbp; |
818 | state->extrablk.blkno = curdb; | 818 | state->extrablk.blkno = curdb; |
819 | state->extrablk.index = (int)((char *)dep - | 819 | state->extrablk.index = (int)((char *)dep - |
820 | (char *)curbp->b_addr); | 820 | (char *)curbp->b_addr); |
821 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; | 821 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; |
822 | curbp->b_ops = &xfs_dir3_data_buf_ops; | 822 | curbp->b_ops = &xfs_dir3_data_buf_ops; |
823 | xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); | 823 | xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); |
824 | if (cmp == XFS_CMP_EXACT) | 824 | if (cmp == XFS_CMP_EXACT) |
825 | return XFS_ERROR(EEXIST); | 825 | return XFS_ERROR(EEXIST); |
826 | } | 826 | } |
827 | } | 827 | } |
828 | ASSERT(index == leafhdr.count || (args->op_flags & XFS_DA_OP_OKNOENT)); | 828 | ASSERT(index == leafhdr.count || (args->op_flags & XFS_DA_OP_OKNOENT)); |
829 | if (curbp) { | 829 | if (curbp) { |
830 | if (args->cmpresult == XFS_CMP_DIFFERENT) { | 830 | if (args->cmpresult == XFS_CMP_DIFFERENT) { |
831 | /* Giving back last used data block. */ | 831 | /* Giving back last used data block. */ |
832 | state->extravalid = 1; | 832 | state->extravalid = 1; |
833 | state->extrablk.bp = curbp; | 833 | state->extrablk.bp = curbp; |
834 | state->extrablk.index = -1; | 834 | state->extrablk.index = -1; |
835 | state->extrablk.blkno = curdb; | 835 | state->extrablk.blkno = curdb; |
836 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; | 836 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; |
837 | curbp->b_ops = &xfs_dir3_data_buf_ops; | 837 | curbp->b_ops = &xfs_dir3_data_buf_ops; |
838 | xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); | 838 | xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); |
839 | } else { | 839 | } else { |
840 | /* If the curbp is not the CI match block, drop it */ | 840 | /* If the curbp is not the CI match block, drop it */ |
841 | if (state->extrablk.bp != curbp) | 841 | if (state->extrablk.bp != curbp) |
842 | xfs_trans_brelse(tp, curbp); | 842 | xfs_trans_brelse(tp, curbp); |
843 | } | 843 | } |
844 | } else { | 844 | } else { |
845 | state->extravalid = 0; | 845 | state->extravalid = 0; |
846 | } | 846 | } |
847 | *indexp = index; | 847 | *indexp = index; |
848 | return XFS_ERROR(ENOENT); | 848 | return XFS_ERROR(ENOENT); |
849 | } | 849 | } |
850 | 850 | ||
851 | /* | 851 | /* |
852 | * Look up a leaf entry in a node-format leaf block. | 852 | * Look up a leaf entry in a node-format leaf block. |
853 | * If this is an addname then the extrablk in state is a freespace block, | 853 | * If this is an addname then the extrablk in state is a freespace block, |
854 | * otherwise it's a data block. | 854 | * otherwise it's a data block. |
855 | */ | 855 | */ |
856 | int | 856 | int |
857 | xfs_dir2_leafn_lookup_int( | 857 | xfs_dir2_leafn_lookup_int( |
858 | struct xfs_buf *bp, /* leaf buffer */ | 858 | struct xfs_buf *bp, /* leaf buffer */ |
859 | xfs_da_args_t *args, /* operation arguments */ | 859 | xfs_da_args_t *args, /* operation arguments */ |
860 | int *indexp, /* out: leaf entry index */ | 860 | int *indexp, /* out: leaf entry index */ |
861 | xfs_da_state_t *state) /* state to fill in */ | 861 | xfs_da_state_t *state) /* state to fill in */ |
862 | { | 862 | { |
863 | if (args->op_flags & XFS_DA_OP_ADDNAME) | 863 | if (args->op_flags & XFS_DA_OP_ADDNAME) |
864 | return xfs_dir2_leafn_lookup_for_addname(bp, args, indexp, | 864 | return xfs_dir2_leafn_lookup_for_addname(bp, args, indexp, |
865 | state); | 865 | state); |
866 | return xfs_dir2_leafn_lookup_for_entry(bp, args, indexp, state); | 866 | return xfs_dir2_leafn_lookup_for_entry(bp, args, indexp, state); |
867 | } | 867 | } |
868 | 868 | ||
869 | /* | 869 | /* |
870 | * Move count leaf entries from source to destination leaf. | 870 | * Move count leaf entries from source to destination leaf. |
871 | * Log entries and headers. Stale entries are preserved. | 871 | * Log entries and headers. Stale entries are preserved. |
872 | */ | 872 | */ |
873 | static void | 873 | static void |
874 | xfs_dir3_leafn_moveents( | 874 | xfs_dir3_leafn_moveents( |
875 | xfs_da_args_t *args, /* operation arguments */ | 875 | xfs_da_args_t *args, /* operation arguments */ |
876 | struct xfs_buf *bp_s, /* source */ | 876 | struct xfs_buf *bp_s, /* source */ |
877 | struct xfs_dir3_icleaf_hdr *shdr, | 877 | struct xfs_dir3_icleaf_hdr *shdr, |
878 | struct xfs_dir2_leaf_entry *sents, | 878 | struct xfs_dir2_leaf_entry *sents, |
879 | int start_s,/* source leaf index */ | 879 | int start_s,/* source leaf index */ |
880 | struct xfs_buf *bp_d, /* destination */ | 880 | struct xfs_buf *bp_d, /* destination */ |
881 | struct xfs_dir3_icleaf_hdr *dhdr, | 881 | struct xfs_dir3_icleaf_hdr *dhdr, |
882 | struct xfs_dir2_leaf_entry *dents, | 882 | struct xfs_dir2_leaf_entry *dents, |
883 | int start_d,/* destination leaf index */ | 883 | int start_d,/* destination leaf index */ |
884 | int count) /* count of leaves to copy */ | 884 | int count) /* count of leaves to copy */ |
885 | { | 885 | { |
886 | struct xfs_trans *tp = args->trans; | 886 | struct xfs_trans *tp = args->trans; |
887 | int stale; /* count stale leaves copied */ | 887 | int stale; /* count stale leaves copied */ |
888 | 888 | ||
889 | trace_xfs_dir2_leafn_moveents(args, start_s, start_d, count); | 889 | trace_xfs_dir2_leafn_moveents(args, start_s, start_d, count); |
890 | 890 | ||
891 | /* | 891 | /* |
892 | * Silently return if nothing to do. | 892 | * Silently return if nothing to do. |
893 | */ | 893 | */ |
894 | if (count == 0) | 894 | if (count == 0) |
895 | return; | 895 | return; |
896 | 896 | ||
897 | /* | 897 | /* |
898 | * If the destination index is not the end of the current | 898 | * If the destination index is not the end of the current |
899 | * destination leaf entries, open up a hole in the destination | 899 | * destination leaf entries, open up a hole in the destination |
900 | * to hold the new entries. | 900 | * to hold the new entries. |
901 | */ | 901 | */ |
902 | if (start_d < dhdr->count) { | 902 | if (start_d < dhdr->count) { |
903 | memmove(&dents[start_d + count], &dents[start_d], | 903 | memmove(&dents[start_d + count], &dents[start_d], |
904 | (dhdr->count - start_d) * sizeof(xfs_dir2_leaf_entry_t)); | 904 | (dhdr->count - start_d) * sizeof(xfs_dir2_leaf_entry_t)); |
905 | xfs_dir3_leaf_log_ents(tp, bp_d, start_d + count, | 905 | xfs_dir3_leaf_log_ents(tp, bp_d, start_d + count, |
906 | count + dhdr->count - 1); | 906 | count + dhdr->count - 1); |
907 | } | 907 | } |
908 | /* | 908 | /* |
909 | * If the source has stale leaves, count the ones in the copy range | 909 | * If the source has stale leaves, count the ones in the copy range |
910 | * so we can update the header correctly. | 910 | * so we can update the header correctly. |
911 | */ | 911 | */ |
912 | if (shdr->stale) { | 912 | if (shdr->stale) { |
913 | int i; /* temp leaf index */ | 913 | int i; /* temp leaf index */ |
914 | 914 | ||
915 | for (i = start_s, stale = 0; i < start_s + count; i++) { | 915 | for (i = start_s, stale = 0; i < start_s + count; i++) { |
916 | if (sents[i].address == | 916 | if (sents[i].address == |
917 | cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) | 917 | cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) |
918 | stale++; | 918 | stale++; |
919 | } | 919 | } |
920 | } else | 920 | } else |
921 | stale = 0; | 921 | stale = 0; |
922 | /* | 922 | /* |
923 | * Copy the leaf entries from source to destination. | 923 | * Copy the leaf entries from source to destination. |
924 | */ | 924 | */ |
925 | memcpy(&dents[start_d], &sents[start_s], | 925 | memcpy(&dents[start_d], &sents[start_s], |
926 | count * sizeof(xfs_dir2_leaf_entry_t)); | 926 | count * sizeof(xfs_dir2_leaf_entry_t)); |
927 | xfs_dir3_leaf_log_ents(tp, bp_d, start_d, start_d + count - 1); | 927 | xfs_dir3_leaf_log_ents(tp, bp_d, start_d, start_d + count - 1); |
928 | 928 | ||
929 | /* | 929 | /* |
930 | * If there are source entries after the ones we copied, | 930 | * If there are source entries after the ones we copied, |
931 | * delete the ones we copied by sliding the next ones down. | 931 | * delete the ones we copied by sliding the next ones down. |
932 | */ | 932 | */ |
933 | if (start_s + count < shdr->count) { | 933 | if (start_s + count < shdr->count) { |
934 | memmove(&sents[start_s], &sents[start_s + count], | 934 | memmove(&sents[start_s], &sents[start_s + count], |
935 | count * sizeof(xfs_dir2_leaf_entry_t)); | 935 | count * sizeof(xfs_dir2_leaf_entry_t)); |
936 | xfs_dir3_leaf_log_ents(tp, bp_s, start_s, start_s + count - 1); | 936 | xfs_dir3_leaf_log_ents(tp, bp_s, start_s, start_s + count - 1); |
937 | } | 937 | } |
938 | 938 | ||
939 | /* | 939 | /* |
940 | * Update the headers and log them. | 940 | * Update the headers and log them. |
941 | */ | 941 | */ |
942 | shdr->count -= count; | 942 | shdr->count -= count; |
943 | shdr->stale -= stale; | 943 | shdr->stale -= stale; |
944 | dhdr->count += count; | 944 | dhdr->count += count; |
945 | dhdr->stale += stale; | 945 | dhdr->stale += stale; |
946 | } | 946 | } |
947 | 947 | ||
948 | /* | 948 | /* |
949 | * Determine the sort order of two leaf blocks. | 949 | * Determine the sort order of two leaf blocks. |
950 | * Returns 1 if both are valid and leaf2 should be before leaf1, else 0. | 950 | * Returns 1 if both are valid and leaf2 should be before leaf1, else 0. |
951 | */ | 951 | */ |
952 | int /* sort order */ | 952 | int /* sort order */ |
953 | xfs_dir2_leafn_order( | 953 | xfs_dir2_leafn_order( |
954 | struct xfs_buf *leaf1_bp, /* leaf1 buffer */ | 954 | struct xfs_buf *leaf1_bp, /* leaf1 buffer */ |
955 | struct xfs_buf *leaf2_bp) /* leaf2 buffer */ | 955 | struct xfs_buf *leaf2_bp) /* leaf2 buffer */ |
956 | { | 956 | { |
957 | struct xfs_dir2_leaf *leaf1 = leaf1_bp->b_addr; | 957 | struct xfs_dir2_leaf *leaf1 = leaf1_bp->b_addr; |
958 | struct xfs_dir2_leaf *leaf2 = leaf2_bp->b_addr; | 958 | struct xfs_dir2_leaf *leaf2 = leaf2_bp->b_addr; |
959 | struct xfs_dir2_leaf_entry *ents1; | 959 | struct xfs_dir2_leaf_entry *ents1; |
960 | struct xfs_dir2_leaf_entry *ents2; | 960 | struct xfs_dir2_leaf_entry *ents2; |
961 | struct xfs_dir3_icleaf_hdr hdr1; | 961 | struct xfs_dir3_icleaf_hdr hdr1; |
962 | struct xfs_dir3_icleaf_hdr hdr2; | 962 | struct xfs_dir3_icleaf_hdr hdr2; |
963 | 963 | ||
964 | xfs_dir3_leaf_hdr_from_disk(&hdr1, leaf1); | 964 | xfs_dir3_leaf_hdr_from_disk(&hdr1, leaf1); |
965 | xfs_dir3_leaf_hdr_from_disk(&hdr2, leaf2); | 965 | xfs_dir3_leaf_hdr_from_disk(&hdr2, leaf2); |
966 | ents1 = xfs_dir3_leaf_ents_p(leaf1); | 966 | ents1 = xfs_dir3_leaf_ents_p(leaf1); |
967 | ents2 = xfs_dir3_leaf_ents_p(leaf2); | 967 | ents2 = xfs_dir3_leaf_ents_p(leaf2); |
968 | 968 | ||
969 | if (hdr1.count > 0 && hdr2.count > 0 && | 969 | if (hdr1.count > 0 && hdr2.count > 0 && |
970 | (be32_to_cpu(ents2[0].hashval) < be32_to_cpu(ents1[0].hashval) || | 970 | (be32_to_cpu(ents2[0].hashval) < be32_to_cpu(ents1[0].hashval) || |
971 | be32_to_cpu(ents2[hdr2.count - 1].hashval) < | 971 | be32_to_cpu(ents2[hdr2.count - 1].hashval) < |
972 | be32_to_cpu(ents1[hdr1.count - 1].hashval))) | 972 | be32_to_cpu(ents1[hdr1.count - 1].hashval))) |
973 | return 1; | 973 | return 1; |
974 | return 0; | 974 | return 0; |
975 | } | 975 | } |
976 | 976 | ||
977 | /* | 977 | /* |
978 | * Rebalance leaf entries between two leaf blocks. | 978 | * Rebalance leaf entries between two leaf blocks. |
979 | * This is actually only called when the second block is new, | 979 | * This is actually only called when the second block is new, |
980 | * though the code deals with the general case. | 980 | * though the code deals with the general case. |
981 | * A new entry will be inserted in one of the blocks, and that | 981 | * A new entry will be inserted in one of the blocks, and that |
982 | * entry is taken into account when balancing. | 982 | * entry is taken into account when balancing. |
983 | */ | 983 | */ |
984 | static void | 984 | static void |
985 | xfs_dir2_leafn_rebalance( | 985 | xfs_dir2_leafn_rebalance( |
986 | xfs_da_state_t *state, /* btree cursor */ | 986 | xfs_da_state_t *state, /* btree cursor */ |
987 | xfs_da_state_blk_t *blk1, /* first btree block */ | 987 | xfs_da_state_blk_t *blk1, /* first btree block */ |
988 | xfs_da_state_blk_t *blk2) /* second btree block */ | 988 | xfs_da_state_blk_t *blk2) /* second btree block */ |
989 | { | 989 | { |
990 | xfs_da_args_t *args; /* operation arguments */ | 990 | xfs_da_args_t *args; /* operation arguments */ |
991 | int count; /* count (& direction) leaves */ | 991 | int count; /* count (& direction) leaves */ |
992 | int isleft; /* new goes in left leaf */ | 992 | int isleft; /* new goes in left leaf */ |
993 | xfs_dir2_leaf_t *leaf1; /* first leaf structure */ | 993 | xfs_dir2_leaf_t *leaf1; /* first leaf structure */ |
994 | xfs_dir2_leaf_t *leaf2; /* second leaf structure */ | 994 | xfs_dir2_leaf_t *leaf2; /* second leaf structure */ |
995 | int mid; /* midpoint leaf index */ | 995 | int mid; /* midpoint leaf index */ |
996 | #ifdef DEBUG | 996 | #if defined(DEBUG) || defined(XFS_WARN) |
997 | int oldstale; /* old count of stale leaves */ | 997 | int oldstale; /* old count of stale leaves */ |
998 | #endif | 998 | #endif |
999 | int oldsum; /* old total leaf count */ | 999 | int oldsum; /* old total leaf count */ |
1000 | int swap; /* swapped leaf blocks */ | 1000 | int swap; /* swapped leaf blocks */ |
1001 | struct xfs_dir2_leaf_entry *ents1; | 1001 | struct xfs_dir2_leaf_entry *ents1; |
1002 | struct xfs_dir2_leaf_entry *ents2; | 1002 | struct xfs_dir2_leaf_entry *ents2; |
1003 | struct xfs_dir3_icleaf_hdr hdr1; | 1003 | struct xfs_dir3_icleaf_hdr hdr1; |
1004 | struct xfs_dir3_icleaf_hdr hdr2; | 1004 | struct xfs_dir3_icleaf_hdr hdr2; |
1005 | 1005 | ||
1006 | args = state->args; | 1006 | args = state->args; |
1007 | /* | 1007 | /* |
1008 | * If the block order is wrong, swap the arguments. | 1008 | * If the block order is wrong, swap the arguments. |
1009 | */ | 1009 | */ |
1010 | if ((swap = xfs_dir2_leafn_order(blk1->bp, blk2->bp))) { | 1010 | if ((swap = xfs_dir2_leafn_order(blk1->bp, blk2->bp))) { |
1011 | xfs_da_state_blk_t *tmp; /* temp for block swap */ | 1011 | xfs_da_state_blk_t *tmp; /* temp for block swap */ |
1012 | 1012 | ||
1013 | tmp = blk1; | 1013 | tmp = blk1; |
1014 | blk1 = blk2; | 1014 | blk1 = blk2; |
1015 | blk2 = tmp; | 1015 | blk2 = tmp; |
1016 | } | 1016 | } |
1017 | leaf1 = blk1->bp->b_addr; | 1017 | leaf1 = blk1->bp->b_addr; |
1018 | leaf2 = blk2->bp->b_addr; | 1018 | leaf2 = blk2->bp->b_addr; |
1019 | xfs_dir3_leaf_hdr_from_disk(&hdr1, leaf1); | 1019 | xfs_dir3_leaf_hdr_from_disk(&hdr1, leaf1); |
1020 | xfs_dir3_leaf_hdr_from_disk(&hdr2, leaf2); | 1020 | xfs_dir3_leaf_hdr_from_disk(&hdr2, leaf2); |
1021 | ents1 = xfs_dir3_leaf_ents_p(leaf1); | 1021 | ents1 = xfs_dir3_leaf_ents_p(leaf1); |
1022 | ents2 = xfs_dir3_leaf_ents_p(leaf2); | 1022 | ents2 = xfs_dir3_leaf_ents_p(leaf2); |
1023 | 1023 | ||
1024 | oldsum = hdr1.count + hdr2.count; | 1024 | oldsum = hdr1.count + hdr2.count; |
1025 | #ifdef DEBUG | 1025 | #if defined(DEBUG) || defined(XFS_WARN) |
1026 | oldstale = hdr1.stale + hdr2.stale; | 1026 | oldstale = hdr1.stale + hdr2.stale; |
1027 | #endif | 1027 | #endif |
1028 | mid = oldsum >> 1; | 1028 | mid = oldsum >> 1; |
1029 | 1029 | ||
1030 | /* | 1030 | /* |
1031 | * If the old leaf count was odd then the new one will be even, | 1031 | * If the old leaf count was odd then the new one will be even, |
1032 | * so we need to divide the new count evenly. | 1032 | * so we need to divide the new count evenly. |
1033 | */ | 1033 | */ |
1034 | if (oldsum & 1) { | 1034 | if (oldsum & 1) { |
1035 | xfs_dahash_t midhash; /* middle entry hash value */ | 1035 | xfs_dahash_t midhash; /* middle entry hash value */ |
1036 | 1036 | ||
1037 | if (mid >= hdr1.count) | 1037 | if (mid >= hdr1.count) |
1038 | midhash = be32_to_cpu(ents2[mid - hdr1.count].hashval); | 1038 | midhash = be32_to_cpu(ents2[mid - hdr1.count].hashval); |
1039 | else | 1039 | else |
1040 | midhash = be32_to_cpu(ents1[mid].hashval); | 1040 | midhash = be32_to_cpu(ents1[mid].hashval); |
1041 | isleft = args->hashval <= midhash; | 1041 | isleft = args->hashval <= midhash; |
1042 | } | 1042 | } |
1043 | /* | 1043 | /* |
1044 | * If the old count is even then the new count is odd, so there's | 1044 | * If the old count is even then the new count is odd, so there's |
1045 | * no preferred side for the new entry. | 1045 | * no preferred side for the new entry. |
1046 | * Pick the left one. | 1046 | * Pick the left one. |
1047 | */ | 1047 | */ |
1048 | else | 1048 | else |
1049 | isleft = 1; | 1049 | isleft = 1; |
1050 | /* | 1050 | /* |
1051 | * Calculate moved entry count. Positive means left-to-right, | 1051 | * Calculate moved entry count. Positive means left-to-right, |
1052 | * negative means right-to-left. Then move the entries. | 1052 | * negative means right-to-left. Then move the entries. |
1053 | */ | 1053 | */ |
1054 | count = hdr1.count - mid + (isleft == 0); | 1054 | count = hdr1.count - mid + (isleft == 0); |
1055 | if (count > 0) | 1055 | if (count > 0) |
1056 | xfs_dir3_leafn_moveents(args, blk1->bp, &hdr1, ents1, | 1056 | xfs_dir3_leafn_moveents(args, blk1->bp, &hdr1, ents1, |
1057 | hdr1.count - count, blk2->bp, | 1057 | hdr1.count - count, blk2->bp, |
1058 | &hdr2, ents2, 0, count); | 1058 | &hdr2, ents2, 0, count); |
1059 | else if (count < 0) | 1059 | else if (count < 0) |
1060 | xfs_dir3_leafn_moveents(args, blk2->bp, &hdr2, ents2, 0, | 1060 | xfs_dir3_leafn_moveents(args, blk2->bp, &hdr2, ents2, 0, |
1061 | blk1->bp, &hdr1, ents1, | 1061 | blk1->bp, &hdr1, ents1, |
1062 | hdr1.count, count); | 1062 | hdr1.count, count); |
1063 | 1063 | ||
1064 | ASSERT(hdr1.count + hdr2.count == oldsum); | 1064 | ASSERT(hdr1.count + hdr2.count == oldsum); |
1065 | ASSERT(hdr1.stale + hdr2.stale == oldstale); | 1065 | ASSERT(hdr1.stale + hdr2.stale == oldstale); |
1066 | 1066 | ||
1067 | /* log the changes made when moving the entries */ | 1067 | /* log the changes made when moving the entries */ |
1068 | xfs_dir3_leaf_hdr_to_disk(leaf1, &hdr1); | 1068 | xfs_dir3_leaf_hdr_to_disk(leaf1, &hdr1); |
1069 | xfs_dir3_leaf_hdr_to_disk(leaf2, &hdr2); | 1069 | xfs_dir3_leaf_hdr_to_disk(leaf2, &hdr2); |
1070 | xfs_dir3_leaf_log_header(args->trans, blk1->bp); | 1070 | xfs_dir3_leaf_log_header(args->trans, blk1->bp); |
1071 | xfs_dir3_leaf_log_header(args->trans, blk2->bp); | 1071 | xfs_dir3_leaf_log_header(args->trans, blk2->bp); |
1072 | 1072 | ||
1073 | xfs_dir3_leaf_check(args->dp->i_mount, blk1->bp); | 1073 | xfs_dir3_leaf_check(args->dp->i_mount, blk1->bp); |
1074 | xfs_dir3_leaf_check(args->dp->i_mount, blk2->bp); | 1074 | xfs_dir3_leaf_check(args->dp->i_mount, blk2->bp); |
1075 | 1075 | ||
1076 | /* | 1076 | /* |
1077 | * Mark whether we're inserting into the old or new leaf. | 1077 | * Mark whether we're inserting into the old or new leaf. |
1078 | */ | 1078 | */ |
1079 | if (hdr1.count < hdr2.count) | 1079 | if (hdr1.count < hdr2.count) |
1080 | state->inleaf = swap; | 1080 | state->inleaf = swap; |
1081 | else if (hdr1.count > hdr2.count) | 1081 | else if (hdr1.count > hdr2.count) |
1082 | state->inleaf = !swap; | 1082 | state->inleaf = !swap; |
1083 | else | 1083 | else |
1084 | state->inleaf = swap ^ (blk1->index <= hdr1.count); | 1084 | state->inleaf = swap ^ (blk1->index <= hdr1.count); |
1085 | /* | 1085 | /* |
1086 | * Adjust the expected index for insertion. | 1086 | * Adjust the expected index for insertion. |
1087 | */ | 1087 | */ |
1088 | if (!state->inleaf) | 1088 | if (!state->inleaf) |
1089 | blk2->index = blk1->index - hdr1.count; | 1089 | blk2->index = blk1->index - hdr1.count; |
1090 | 1090 | ||
1091 | /* | 1091 | /* |
1092 | * Finally sanity check just to make sure we are not returning a | 1092 | * Finally sanity check just to make sure we are not returning a |
1093 | * negative index | 1093 | * negative index |
1094 | */ | 1094 | */ |
1095 | if(blk2->index < 0) { | 1095 | if(blk2->index < 0) { |
1096 | state->inleaf = 1; | 1096 | state->inleaf = 1; |
1097 | blk2->index = 0; | 1097 | blk2->index = 0; |
1098 | xfs_alert(args->dp->i_mount, | 1098 | xfs_alert(args->dp->i_mount, |
1099 | "%s: picked the wrong leaf? reverting original leaf: blk1->index %d\n", | 1099 | "%s: picked the wrong leaf? reverting original leaf: blk1->index %d\n", |
1100 | __func__, blk1->index); | 1100 | __func__, blk1->index); |
1101 | } | 1101 | } |
1102 | } | 1102 | } |
1103 | 1103 | ||
1104 | static int | 1104 | static int |
1105 | xfs_dir3_data_block_free( | 1105 | xfs_dir3_data_block_free( |
1106 | xfs_da_args_t *args, | 1106 | xfs_da_args_t *args, |
1107 | struct xfs_dir2_data_hdr *hdr, | 1107 | struct xfs_dir2_data_hdr *hdr, |
1108 | struct xfs_dir2_free *free, | 1108 | struct xfs_dir2_free *free, |
1109 | xfs_dir2_db_t fdb, | 1109 | xfs_dir2_db_t fdb, |
1110 | int findex, | 1110 | int findex, |
1111 | struct xfs_buf *fbp, | 1111 | struct xfs_buf *fbp, |
1112 | int longest) | 1112 | int longest) |
1113 | { | 1113 | { |
1114 | struct xfs_trans *tp = args->trans; | 1114 | struct xfs_trans *tp = args->trans; |
1115 | int logfree = 0; | 1115 | int logfree = 0; |
1116 | __be16 *bests; | 1116 | __be16 *bests; |
1117 | struct xfs_dir3_icfree_hdr freehdr; | 1117 | struct xfs_dir3_icfree_hdr freehdr; |
1118 | 1118 | ||
1119 | xfs_dir3_free_hdr_from_disk(&freehdr, free); | 1119 | xfs_dir3_free_hdr_from_disk(&freehdr, free); |
1120 | 1120 | ||
1121 | bests = xfs_dir3_free_bests_p(tp->t_mountp, free); | 1121 | bests = xfs_dir3_free_bests_p(tp->t_mountp, free); |
1122 | if (hdr) { | 1122 | if (hdr) { |
1123 | /* | 1123 | /* |
1124 | * Data block is not empty, just set the free entry to the new | 1124 | * Data block is not empty, just set the free entry to the new |
1125 | * value. | 1125 | * value. |
1126 | */ | 1126 | */ |
1127 | bests[findex] = cpu_to_be16(longest); | 1127 | bests[findex] = cpu_to_be16(longest); |
1128 | xfs_dir2_free_log_bests(tp, fbp, findex, findex); | 1128 | xfs_dir2_free_log_bests(tp, fbp, findex, findex); |
1129 | return 0; | 1129 | return 0; |
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | /* One less used entry in the free table. */ | 1132 | /* One less used entry in the free table. */ |
1133 | freehdr.nused--; | 1133 | freehdr.nused--; |
1134 | 1134 | ||
1135 | /* | 1135 | /* |
1136 | * If this was the last entry in the table, we can trim the table size | 1136 | * If this was the last entry in the table, we can trim the table size |
1137 | * back. There might be other entries at the end referring to | 1137 | * back. There might be other entries at the end referring to |
1138 | * non-existent data blocks, get those too. | 1138 | * non-existent data blocks, get those too. |
1139 | */ | 1139 | */ |
1140 | if (findex == freehdr.nvalid - 1) { | 1140 | if (findex == freehdr.nvalid - 1) { |
1141 | int i; /* free entry index */ | 1141 | int i; /* free entry index */ |
1142 | 1142 | ||
1143 | for (i = findex - 1; i >= 0; i--) { | 1143 | for (i = findex - 1; i >= 0; i--) { |
1144 | if (bests[i] != cpu_to_be16(NULLDATAOFF)) | 1144 | if (bests[i] != cpu_to_be16(NULLDATAOFF)) |
1145 | break; | 1145 | break; |
1146 | } | 1146 | } |
1147 | freehdr.nvalid = i + 1; | 1147 | freehdr.nvalid = i + 1; |
1148 | logfree = 0; | 1148 | logfree = 0; |
1149 | } else { | 1149 | } else { |
1150 | /* Not the last entry, just punch it out. */ | 1150 | /* Not the last entry, just punch it out. */ |
1151 | bests[findex] = cpu_to_be16(NULLDATAOFF); | 1151 | bests[findex] = cpu_to_be16(NULLDATAOFF); |
1152 | logfree = 1; | 1152 | logfree = 1; |
1153 | } | 1153 | } |
1154 | 1154 | ||
1155 | xfs_dir3_free_hdr_to_disk(free, &freehdr); | 1155 | xfs_dir3_free_hdr_to_disk(free, &freehdr); |
1156 | xfs_dir2_free_log_header(tp, fbp); | 1156 | xfs_dir2_free_log_header(tp, fbp); |
1157 | 1157 | ||
1158 | /* | 1158 | /* |
1159 | * If there are no useful entries left in the block, get rid of the | 1159 | * If there are no useful entries left in the block, get rid of the |
1160 | * block if we can. | 1160 | * block if we can. |
1161 | */ | 1161 | */ |
1162 | if (!freehdr.nused) { | 1162 | if (!freehdr.nused) { |
1163 | int error; | 1163 | int error; |
1164 | 1164 | ||
1165 | error = xfs_dir2_shrink_inode(args, fdb, fbp); | 1165 | error = xfs_dir2_shrink_inode(args, fdb, fbp); |
1166 | if (error == 0) { | 1166 | if (error == 0) { |
1167 | fbp = NULL; | 1167 | fbp = NULL; |
1168 | logfree = 0; | 1168 | logfree = 0; |
1169 | } else if (error != ENOSPC || args->total != 0) | 1169 | } else if (error != ENOSPC || args->total != 0) |
1170 | return error; | 1170 | return error; |
1171 | /* | 1171 | /* |
1172 | * It's possible to get ENOSPC if there is no | 1172 | * It's possible to get ENOSPC if there is no |
1173 | * space reservation. In this case some one | 1173 | * space reservation. In this case some one |
1174 | * else will eventually get rid of this block. | 1174 | * else will eventually get rid of this block. |
1175 | */ | 1175 | */ |
1176 | } | 1176 | } |
1177 | 1177 | ||
1178 | /* Log the free entry that changed, unless we got rid of it. */ | 1178 | /* Log the free entry that changed, unless we got rid of it. */ |
1179 | if (logfree) | 1179 | if (logfree) |
1180 | xfs_dir2_free_log_bests(tp, fbp, findex, findex); | 1180 | xfs_dir2_free_log_bests(tp, fbp, findex, findex); |
1181 | return 0; | 1181 | return 0; |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | /* | 1184 | /* |
1185 | * Remove an entry from a node directory. | 1185 | * Remove an entry from a node directory. |
1186 | * This removes the leaf entry and the data entry, | 1186 | * This removes the leaf entry and the data entry, |
1187 | * and updates the free block if necessary. | 1187 | * and updates the free block if necessary. |
1188 | */ | 1188 | */ |
1189 | static int /* error */ | 1189 | static int /* error */ |
1190 | xfs_dir2_leafn_remove( | 1190 | xfs_dir2_leafn_remove( |
1191 | xfs_da_args_t *args, /* operation arguments */ | 1191 | xfs_da_args_t *args, /* operation arguments */ |
1192 | struct xfs_buf *bp, /* leaf buffer */ | 1192 | struct xfs_buf *bp, /* leaf buffer */ |
1193 | int index, /* leaf entry index */ | 1193 | int index, /* leaf entry index */ |
1194 | xfs_da_state_blk_t *dblk, /* data block */ | 1194 | xfs_da_state_blk_t *dblk, /* data block */ |
1195 | int *rval) /* resulting block needs join */ | 1195 | int *rval) /* resulting block needs join */ |
1196 | { | 1196 | { |
1197 | xfs_dir2_data_hdr_t *hdr; /* data block header */ | 1197 | xfs_dir2_data_hdr_t *hdr; /* data block header */ |
1198 | xfs_dir2_db_t db; /* data block number */ | 1198 | xfs_dir2_db_t db; /* data block number */ |
1199 | struct xfs_buf *dbp; /* data block buffer */ | 1199 | struct xfs_buf *dbp; /* data block buffer */ |
1200 | xfs_dir2_data_entry_t *dep; /* data block entry */ | 1200 | xfs_dir2_data_entry_t *dep; /* data block entry */ |
1201 | xfs_inode_t *dp; /* incore directory inode */ | 1201 | xfs_inode_t *dp; /* incore directory inode */ |
1202 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | 1202 | xfs_dir2_leaf_t *leaf; /* leaf structure */ |
1203 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ | 1203 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ |
1204 | int longest; /* longest data free entry */ | 1204 | int longest; /* longest data free entry */ |
1205 | int off; /* data block entry offset */ | 1205 | int off; /* data block entry offset */ |
1206 | xfs_mount_t *mp; /* filesystem mount point */ | 1206 | xfs_mount_t *mp; /* filesystem mount point */ |
1207 | int needlog; /* need to log data header */ | 1207 | int needlog; /* need to log data header */ |
1208 | int needscan; /* need to rescan data frees */ | 1208 | int needscan; /* need to rescan data frees */ |
1209 | xfs_trans_t *tp; /* transaction pointer */ | 1209 | xfs_trans_t *tp; /* transaction pointer */ |
1210 | struct xfs_dir2_data_free *bf; /* bestfree table */ | 1210 | struct xfs_dir2_data_free *bf; /* bestfree table */ |
1211 | struct xfs_dir3_icleaf_hdr leafhdr; | 1211 | struct xfs_dir3_icleaf_hdr leafhdr; |
1212 | struct xfs_dir2_leaf_entry *ents; | 1212 | struct xfs_dir2_leaf_entry *ents; |
1213 | 1213 | ||
1214 | trace_xfs_dir2_leafn_remove(args, index); | 1214 | trace_xfs_dir2_leafn_remove(args, index); |
1215 | 1215 | ||
1216 | dp = args->dp; | 1216 | dp = args->dp; |
1217 | tp = args->trans; | 1217 | tp = args->trans; |
1218 | mp = dp->i_mount; | 1218 | mp = dp->i_mount; |
1219 | leaf = bp->b_addr; | 1219 | leaf = bp->b_addr; |
1220 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); | 1220 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); |
1221 | ents = xfs_dir3_leaf_ents_p(leaf); | 1221 | ents = xfs_dir3_leaf_ents_p(leaf); |
1222 | 1222 | ||
1223 | /* | 1223 | /* |
1224 | * Point to the entry we're removing. | 1224 | * Point to the entry we're removing. |
1225 | */ | 1225 | */ |
1226 | lep = &ents[index]; | 1226 | lep = &ents[index]; |
1227 | 1227 | ||
1228 | /* | 1228 | /* |
1229 | * Extract the data block and offset from the entry. | 1229 | * Extract the data block and offset from the entry. |
1230 | */ | 1230 | */ |
1231 | db = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address)); | 1231 | db = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address)); |
1232 | ASSERT(dblk->blkno == db); | 1232 | ASSERT(dblk->blkno == db); |
1233 | off = xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)); | 1233 | off = xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)); |
1234 | ASSERT(dblk->index == off); | 1234 | ASSERT(dblk->index == off); |
1235 | 1235 | ||
1236 | /* | 1236 | /* |
1237 | * Kill the leaf entry by marking it stale. | 1237 | * Kill the leaf entry by marking it stale. |
1238 | * Log the leaf block changes. | 1238 | * Log the leaf block changes. |
1239 | */ | 1239 | */ |
1240 | leafhdr.stale++; | 1240 | leafhdr.stale++; |
1241 | xfs_dir3_leaf_hdr_to_disk(leaf, &leafhdr); | 1241 | xfs_dir3_leaf_hdr_to_disk(leaf, &leafhdr); |
1242 | xfs_dir3_leaf_log_header(tp, bp); | 1242 | xfs_dir3_leaf_log_header(tp, bp); |
1243 | 1243 | ||
1244 | lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); | 1244 | lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); |
1245 | xfs_dir3_leaf_log_ents(tp, bp, index, index); | 1245 | xfs_dir3_leaf_log_ents(tp, bp, index, index); |
1246 | 1246 | ||
1247 | /* | 1247 | /* |
1248 | * Make the data entry free. Keep track of the longest freespace | 1248 | * Make the data entry free. Keep track of the longest freespace |
1249 | * in the data block in case it changes. | 1249 | * in the data block in case it changes. |
1250 | */ | 1250 | */ |
1251 | dbp = dblk->bp; | 1251 | dbp = dblk->bp; |
1252 | hdr = dbp->b_addr; | 1252 | hdr = dbp->b_addr; |
1253 | dep = (xfs_dir2_data_entry_t *)((char *)hdr + off); | 1253 | dep = (xfs_dir2_data_entry_t *)((char *)hdr + off); |
1254 | bf = xfs_dir3_data_bestfree_p(hdr); | 1254 | bf = xfs_dir3_data_bestfree_p(hdr); |
1255 | longest = be16_to_cpu(bf[0].length); | 1255 | longest = be16_to_cpu(bf[0].length); |
1256 | needlog = needscan = 0; | 1256 | needlog = needscan = 0; |
1257 | xfs_dir2_data_make_free(tp, dbp, off, | 1257 | xfs_dir2_data_make_free(tp, dbp, off, |
1258 | xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan); | 1258 | xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan); |
1259 | /* | 1259 | /* |
1260 | * Rescan the data block freespaces for bestfree. | 1260 | * Rescan the data block freespaces for bestfree. |
1261 | * Log the data block header if needed. | 1261 | * Log the data block header if needed. |
1262 | */ | 1262 | */ |
1263 | if (needscan) | 1263 | if (needscan) |
1264 | xfs_dir2_data_freescan(mp, hdr, &needlog); | 1264 | xfs_dir2_data_freescan(mp, hdr, &needlog); |
1265 | if (needlog) | 1265 | if (needlog) |
1266 | xfs_dir2_data_log_header(tp, dbp); | 1266 | xfs_dir2_data_log_header(tp, dbp); |
1267 | xfs_dir3_data_check(dp, dbp); | 1267 | xfs_dir3_data_check(dp, dbp); |
1268 | /* | 1268 | /* |
1269 | * If the longest data block freespace changes, need to update | 1269 | * If the longest data block freespace changes, need to update |
1270 | * the corresponding freeblock entry. | 1270 | * the corresponding freeblock entry. |
1271 | */ | 1271 | */ |
1272 | if (longest < be16_to_cpu(bf[0].length)) { | 1272 | if (longest < be16_to_cpu(bf[0].length)) { |
1273 | int error; /* error return value */ | 1273 | int error; /* error return value */ |
1274 | struct xfs_buf *fbp; /* freeblock buffer */ | 1274 | struct xfs_buf *fbp; /* freeblock buffer */ |
1275 | xfs_dir2_db_t fdb; /* freeblock block number */ | 1275 | xfs_dir2_db_t fdb; /* freeblock block number */ |
1276 | int findex; /* index in freeblock entries */ | 1276 | int findex; /* index in freeblock entries */ |
1277 | xfs_dir2_free_t *free; /* freeblock structure */ | 1277 | xfs_dir2_free_t *free; /* freeblock structure */ |
1278 | 1278 | ||
1279 | /* | 1279 | /* |
1280 | * Convert the data block number to a free block, | 1280 | * Convert the data block number to a free block, |
1281 | * read in the free block. | 1281 | * read in the free block. |
1282 | */ | 1282 | */ |
1283 | fdb = xfs_dir2_db_to_fdb(mp, db); | 1283 | fdb = xfs_dir2_db_to_fdb(mp, db); |
1284 | error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(mp, fdb), | 1284 | error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(mp, fdb), |
1285 | &fbp); | 1285 | &fbp); |
1286 | if (error) | 1286 | if (error) |
1287 | return error; | 1287 | return error; |
1288 | free = fbp->b_addr; | 1288 | free = fbp->b_addr; |
1289 | #ifdef DEBUG | 1289 | #ifdef DEBUG |
1290 | { | 1290 | { |
1291 | struct xfs_dir3_icfree_hdr freehdr; | 1291 | struct xfs_dir3_icfree_hdr freehdr; |
1292 | xfs_dir3_free_hdr_from_disk(&freehdr, free); | 1292 | xfs_dir3_free_hdr_from_disk(&freehdr, free); |
1293 | ASSERT(freehdr.firstdb == xfs_dir3_free_max_bests(mp) * | 1293 | ASSERT(freehdr.firstdb == xfs_dir3_free_max_bests(mp) * |
1294 | (fdb - XFS_DIR2_FREE_FIRSTDB(mp))); | 1294 | (fdb - XFS_DIR2_FREE_FIRSTDB(mp))); |
1295 | } | 1295 | } |
1296 | #endif | 1296 | #endif |
1297 | /* | 1297 | /* |
1298 | * Calculate which entry we need to fix. | 1298 | * Calculate which entry we need to fix. |
1299 | */ | 1299 | */ |
1300 | findex = xfs_dir2_db_to_fdindex(mp, db); | 1300 | findex = xfs_dir2_db_to_fdindex(mp, db); |
1301 | longest = be16_to_cpu(bf[0].length); | 1301 | longest = be16_to_cpu(bf[0].length); |
1302 | /* | 1302 | /* |
1303 | * If the data block is now empty we can get rid of it | 1303 | * If the data block is now empty we can get rid of it |
1304 | * (usually). | 1304 | * (usually). |
1305 | */ | 1305 | */ |
1306 | if (longest == mp->m_dirblksize - | 1306 | if (longest == mp->m_dirblksize - |
1307 | xfs_dir3_data_entry_offset(hdr)) { | 1307 | xfs_dir3_data_entry_offset(hdr)) { |
1308 | /* | 1308 | /* |
1309 | * Try to punch out the data block. | 1309 | * Try to punch out the data block. |
1310 | */ | 1310 | */ |
1311 | error = xfs_dir2_shrink_inode(args, db, dbp); | 1311 | error = xfs_dir2_shrink_inode(args, db, dbp); |
1312 | if (error == 0) { | 1312 | if (error == 0) { |
1313 | dblk->bp = NULL; | 1313 | dblk->bp = NULL; |
1314 | hdr = NULL; | 1314 | hdr = NULL; |
1315 | } | 1315 | } |
1316 | /* | 1316 | /* |
1317 | * We can get ENOSPC if there's no space reservation. | 1317 | * We can get ENOSPC if there's no space reservation. |
1318 | * In this case just drop the buffer and some one else | 1318 | * In this case just drop the buffer and some one else |
1319 | * will eventually get rid of the empty block. | 1319 | * will eventually get rid of the empty block. |
1320 | */ | 1320 | */ |
1321 | else if (!(error == ENOSPC && args->total == 0)) | 1321 | else if (!(error == ENOSPC && args->total == 0)) |
1322 | return error; | 1322 | return error; |
1323 | } | 1323 | } |
1324 | /* | 1324 | /* |
1325 | * If we got rid of the data block, we can eliminate that entry | 1325 | * If we got rid of the data block, we can eliminate that entry |
1326 | * in the free block. | 1326 | * in the free block. |
1327 | */ | 1327 | */ |
1328 | error = xfs_dir3_data_block_free(args, hdr, free, | 1328 | error = xfs_dir3_data_block_free(args, hdr, free, |
1329 | fdb, findex, fbp, longest); | 1329 | fdb, findex, fbp, longest); |
1330 | if (error) | 1330 | if (error) |
1331 | return error; | 1331 | return error; |
1332 | } | 1332 | } |
1333 | 1333 | ||
1334 | xfs_dir3_leaf_check(mp, bp); | 1334 | xfs_dir3_leaf_check(mp, bp); |
1335 | /* | 1335 | /* |
1336 | * Return indication of whether this leaf block is empty enough | 1336 | * Return indication of whether this leaf block is empty enough |
1337 | * to justify trying to join it with a neighbor. | 1337 | * to justify trying to join it with a neighbor. |
1338 | */ | 1338 | */ |
1339 | *rval = (xfs_dir3_leaf_hdr_size(leaf) + | 1339 | *rval = (xfs_dir3_leaf_hdr_size(leaf) + |
1340 | (uint)sizeof(ents[0]) * (leafhdr.count - leafhdr.stale)) < | 1340 | (uint)sizeof(ents[0]) * (leafhdr.count - leafhdr.stale)) < |
1341 | mp->m_dir_magicpct; | 1341 | mp->m_dir_magicpct; |
1342 | return 0; | 1342 | return 0; |
1343 | } | 1343 | } |
1344 | 1344 | ||
1345 | /* | 1345 | /* |
1346 | * Split the leaf entries in the old block into old and new blocks. | 1346 | * Split the leaf entries in the old block into old and new blocks. |
1347 | */ | 1347 | */ |
1348 | int /* error */ | 1348 | int /* error */ |
1349 | xfs_dir2_leafn_split( | 1349 | xfs_dir2_leafn_split( |
1350 | xfs_da_state_t *state, /* btree cursor */ | 1350 | xfs_da_state_t *state, /* btree cursor */ |
1351 | xfs_da_state_blk_t *oldblk, /* original block */ | 1351 | xfs_da_state_blk_t *oldblk, /* original block */ |
1352 | xfs_da_state_blk_t *newblk) /* newly created block */ | 1352 | xfs_da_state_blk_t *newblk) /* newly created block */ |
1353 | { | 1353 | { |
1354 | xfs_da_args_t *args; /* operation arguments */ | 1354 | xfs_da_args_t *args; /* operation arguments */ |
1355 | xfs_dablk_t blkno; /* new leaf block number */ | 1355 | xfs_dablk_t blkno; /* new leaf block number */ |
1356 | int error; /* error return value */ | 1356 | int error; /* error return value */ |
1357 | xfs_mount_t *mp; /* filesystem mount point */ | 1357 | xfs_mount_t *mp; /* filesystem mount point */ |
1358 | 1358 | ||
1359 | /* | 1359 | /* |
1360 | * Allocate space for a new leaf node. | 1360 | * Allocate space for a new leaf node. |
1361 | */ | 1361 | */ |
1362 | args = state->args; | 1362 | args = state->args; |
1363 | mp = args->dp->i_mount; | 1363 | mp = args->dp->i_mount; |
1364 | ASSERT(args != NULL); | 1364 | ASSERT(args != NULL); |
1365 | ASSERT(oldblk->magic == XFS_DIR2_LEAFN_MAGIC); | 1365 | ASSERT(oldblk->magic == XFS_DIR2_LEAFN_MAGIC); |
1366 | error = xfs_da_grow_inode(args, &blkno); | 1366 | error = xfs_da_grow_inode(args, &blkno); |
1367 | if (error) { | 1367 | if (error) { |
1368 | return error; | 1368 | return error; |
1369 | } | 1369 | } |
1370 | /* | 1370 | /* |
1371 | * Initialize the new leaf block. | 1371 | * Initialize the new leaf block. |
1372 | */ | 1372 | */ |
1373 | error = xfs_dir3_leaf_get_buf(args, xfs_dir2_da_to_db(mp, blkno), | 1373 | error = xfs_dir3_leaf_get_buf(args, xfs_dir2_da_to_db(mp, blkno), |
1374 | &newblk->bp, XFS_DIR2_LEAFN_MAGIC); | 1374 | &newblk->bp, XFS_DIR2_LEAFN_MAGIC); |
1375 | if (error) | 1375 | if (error) |
1376 | return error; | 1376 | return error; |
1377 | 1377 | ||
1378 | newblk->blkno = blkno; | 1378 | newblk->blkno = blkno; |
1379 | newblk->magic = XFS_DIR2_LEAFN_MAGIC; | 1379 | newblk->magic = XFS_DIR2_LEAFN_MAGIC; |
1380 | /* | 1380 | /* |
1381 | * Rebalance the entries across the two leaves, link the new | 1381 | * Rebalance the entries across the two leaves, link the new |
1382 | * block into the leaves. | 1382 | * block into the leaves. |
1383 | */ | 1383 | */ |
1384 | xfs_dir2_leafn_rebalance(state, oldblk, newblk); | 1384 | xfs_dir2_leafn_rebalance(state, oldblk, newblk); |
1385 | error = xfs_da3_blk_link(state, oldblk, newblk); | 1385 | error = xfs_da3_blk_link(state, oldblk, newblk); |
1386 | if (error) { | 1386 | if (error) { |
1387 | return error; | 1387 | return error; |
1388 | } | 1388 | } |
1389 | /* | 1389 | /* |
1390 | * Insert the new entry in the correct block. | 1390 | * Insert the new entry in the correct block. |
1391 | */ | 1391 | */ |
1392 | if (state->inleaf) | 1392 | if (state->inleaf) |
1393 | error = xfs_dir2_leafn_add(oldblk->bp, args, oldblk->index); | 1393 | error = xfs_dir2_leafn_add(oldblk->bp, args, oldblk->index); |
1394 | else | 1394 | else |
1395 | error = xfs_dir2_leafn_add(newblk->bp, args, newblk->index); | 1395 | error = xfs_dir2_leafn_add(newblk->bp, args, newblk->index); |
1396 | /* | 1396 | /* |
1397 | * Update last hashval in each block since we added the name. | 1397 | * Update last hashval in each block since we added the name. |
1398 | */ | 1398 | */ |
1399 | oldblk->hashval = xfs_dir2_leafn_lasthash(oldblk->bp, NULL); | 1399 | oldblk->hashval = xfs_dir2_leafn_lasthash(oldblk->bp, NULL); |
1400 | newblk->hashval = xfs_dir2_leafn_lasthash(newblk->bp, NULL); | 1400 | newblk->hashval = xfs_dir2_leafn_lasthash(newblk->bp, NULL); |
1401 | xfs_dir3_leaf_check(mp, oldblk->bp); | 1401 | xfs_dir3_leaf_check(mp, oldblk->bp); |
1402 | xfs_dir3_leaf_check(mp, newblk->bp); | 1402 | xfs_dir3_leaf_check(mp, newblk->bp); |
1403 | return error; | 1403 | return error; |
1404 | } | 1404 | } |
1405 | 1405 | ||
1406 | /* | 1406 | /* |
1407 | * Check a leaf block and its neighbors to see if the block should be | 1407 | * Check a leaf block and its neighbors to see if the block should be |
1408 | * collapsed into one or the other neighbor. Always keep the block | 1408 | * collapsed into one or the other neighbor. Always keep the block |
1409 | * with the smaller block number. | 1409 | * with the smaller block number. |
1410 | * If the current block is over 50% full, don't try to join it, return 0. | 1410 | * If the current block is over 50% full, don't try to join it, return 0. |
1411 | * If the block is empty, fill in the state structure and return 2. | 1411 | * If the block is empty, fill in the state structure and return 2. |
1412 | * If it can be collapsed, fill in the state structure and return 1. | 1412 | * If it can be collapsed, fill in the state structure and return 1. |
1413 | * If nothing can be done, return 0. | 1413 | * If nothing can be done, return 0. |
1414 | */ | 1414 | */ |
1415 | int /* error */ | 1415 | int /* error */ |
1416 | xfs_dir2_leafn_toosmall( | 1416 | xfs_dir2_leafn_toosmall( |
1417 | xfs_da_state_t *state, /* btree cursor */ | 1417 | xfs_da_state_t *state, /* btree cursor */ |
1418 | int *action) /* resulting action to take */ | 1418 | int *action) /* resulting action to take */ |
1419 | { | 1419 | { |
1420 | xfs_da_state_blk_t *blk; /* leaf block */ | 1420 | xfs_da_state_blk_t *blk; /* leaf block */ |
1421 | xfs_dablk_t blkno; /* leaf block number */ | 1421 | xfs_dablk_t blkno; /* leaf block number */ |
1422 | struct xfs_buf *bp; /* leaf buffer */ | 1422 | struct xfs_buf *bp; /* leaf buffer */ |
1423 | int bytes; /* bytes in use */ | 1423 | int bytes; /* bytes in use */ |
1424 | int count; /* leaf live entry count */ | 1424 | int count; /* leaf live entry count */ |
1425 | int error; /* error return value */ | 1425 | int error; /* error return value */ |
1426 | int forward; /* sibling block direction */ | 1426 | int forward; /* sibling block direction */ |
1427 | int i; /* sibling counter */ | 1427 | int i; /* sibling counter */ |
1428 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | 1428 | xfs_dir2_leaf_t *leaf; /* leaf structure */ |
1429 | int rval; /* result from path_shift */ | 1429 | int rval; /* result from path_shift */ |
1430 | struct xfs_dir3_icleaf_hdr leafhdr; | 1430 | struct xfs_dir3_icleaf_hdr leafhdr; |
1431 | struct xfs_dir2_leaf_entry *ents; | 1431 | struct xfs_dir2_leaf_entry *ents; |
1432 | 1432 | ||
1433 | /* | 1433 | /* |
1434 | * Check for the degenerate case of the block being over 50% full. | 1434 | * Check for the degenerate case of the block being over 50% full. |
1435 | * If so, it's not worth even looking to see if we might be able | 1435 | * If so, it's not worth even looking to see if we might be able |
1436 | * to coalesce with a sibling. | 1436 | * to coalesce with a sibling. |
1437 | */ | 1437 | */ |
1438 | blk = &state->path.blk[state->path.active - 1]; | 1438 | blk = &state->path.blk[state->path.active - 1]; |
1439 | leaf = blk->bp->b_addr; | 1439 | leaf = blk->bp->b_addr; |
1440 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); | 1440 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); |
1441 | ents = xfs_dir3_leaf_ents_p(leaf); | 1441 | ents = xfs_dir3_leaf_ents_p(leaf); |
1442 | xfs_dir3_leaf_check(state->args->dp->i_mount, blk->bp); | 1442 | xfs_dir3_leaf_check(state->args->dp->i_mount, blk->bp); |
1443 | 1443 | ||
1444 | count = leafhdr.count - leafhdr.stale; | 1444 | count = leafhdr.count - leafhdr.stale; |
1445 | bytes = xfs_dir3_leaf_hdr_size(leaf) + count * sizeof(ents[0]); | 1445 | bytes = xfs_dir3_leaf_hdr_size(leaf) + count * sizeof(ents[0]); |
1446 | if (bytes > (state->blocksize >> 1)) { | 1446 | if (bytes > (state->blocksize >> 1)) { |
1447 | /* | 1447 | /* |
1448 | * Blk over 50%, don't try to join. | 1448 | * Blk over 50%, don't try to join. |
1449 | */ | 1449 | */ |
1450 | *action = 0; | 1450 | *action = 0; |
1451 | return 0; | 1451 | return 0; |
1452 | } | 1452 | } |
1453 | /* | 1453 | /* |
1454 | * Check for the degenerate case of the block being empty. | 1454 | * Check for the degenerate case of the block being empty. |
1455 | * If the block is empty, we'll simply delete it, no need to | 1455 | * If the block is empty, we'll simply delete it, no need to |
1456 | * coalesce it with a sibling block. We choose (arbitrarily) | 1456 | * coalesce it with a sibling block. We choose (arbitrarily) |
1457 | * to merge with the forward block unless it is NULL. | 1457 | * to merge with the forward block unless it is NULL. |
1458 | */ | 1458 | */ |
1459 | if (count == 0) { | 1459 | if (count == 0) { |
1460 | /* | 1460 | /* |
1461 | * Make altpath point to the block we want to keep and | 1461 | * Make altpath point to the block we want to keep and |
1462 | * path point to the block we want to drop (this one). | 1462 | * path point to the block we want to drop (this one). |
1463 | */ | 1463 | */ |
1464 | forward = (leafhdr.forw != 0); | 1464 | forward = (leafhdr.forw != 0); |
1465 | memcpy(&state->altpath, &state->path, sizeof(state->path)); | 1465 | memcpy(&state->altpath, &state->path, sizeof(state->path)); |
1466 | error = xfs_da3_path_shift(state, &state->altpath, forward, 0, | 1466 | error = xfs_da3_path_shift(state, &state->altpath, forward, 0, |
1467 | &rval); | 1467 | &rval); |
1468 | if (error) | 1468 | if (error) |
1469 | return error; | 1469 | return error; |
1470 | *action = rval ? 2 : 0; | 1470 | *action = rval ? 2 : 0; |
1471 | return 0; | 1471 | return 0; |
1472 | } | 1472 | } |
1473 | /* | 1473 | /* |
1474 | * Examine each sibling block to see if we can coalesce with | 1474 | * Examine each sibling block to see if we can coalesce with |
1475 | * at least 25% free space to spare. We need to figure out | 1475 | * at least 25% free space to spare. We need to figure out |
1476 | * whether to merge with the forward or the backward block. | 1476 | * whether to merge with the forward or the backward block. |
1477 | * We prefer coalescing with the lower numbered sibling so as | 1477 | * We prefer coalescing with the lower numbered sibling so as |
1478 | * to shrink a directory over time. | 1478 | * to shrink a directory over time. |
1479 | */ | 1479 | */ |
1480 | forward = leafhdr.forw < leafhdr.back; | 1480 | forward = leafhdr.forw < leafhdr.back; |
1481 | for (i = 0, bp = NULL; i < 2; forward = !forward, i++) { | 1481 | for (i = 0, bp = NULL; i < 2; forward = !forward, i++) { |
1482 | struct xfs_dir3_icleaf_hdr hdr2; | 1482 | struct xfs_dir3_icleaf_hdr hdr2; |
1483 | 1483 | ||
1484 | blkno = forward ? leafhdr.forw : leafhdr.back; | 1484 | blkno = forward ? leafhdr.forw : leafhdr.back; |
1485 | if (blkno == 0) | 1485 | if (blkno == 0) |
1486 | continue; | 1486 | continue; |
1487 | /* | 1487 | /* |
1488 | * Read the sibling leaf block. | 1488 | * Read the sibling leaf block. |
1489 | */ | 1489 | */ |
1490 | error = xfs_dir3_leafn_read(state->args->trans, state->args->dp, | 1490 | error = xfs_dir3_leafn_read(state->args->trans, state->args->dp, |
1491 | blkno, -1, &bp); | 1491 | blkno, -1, &bp); |
1492 | if (error) | 1492 | if (error) |
1493 | return error; | 1493 | return error; |
1494 | 1494 | ||
1495 | /* | 1495 | /* |
1496 | * Count bytes in the two blocks combined. | 1496 | * Count bytes in the two blocks combined. |
1497 | */ | 1497 | */ |
1498 | count = leafhdr.count - leafhdr.stale; | 1498 | count = leafhdr.count - leafhdr.stale; |
1499 | bytes = state->blocksize - (state->blocksize >> 2); | 1499 | bytes = state->blocksize - (state->blocksize >> 2); |
1500 | 1500 | ||
1501 | leaf = bp->b_addr; | 1501 | leaf = bp->b_addr; |
1502 | xfs_dir3_leaf_hdr_from_disk(&hdr2, leaf); | 1502 | xfs_dir3_leaf_hdr_from_disk(&hdr2, leaf); |
1503 | ents = xfs_dir3_leaf_ents_p(leaf); | 1503 | ents = xfs_dir3_leaf_ents_p(leaf); |
1504 | count += hdr2.count - hdr2.stale; | 1504 | count += hdr2.count - hdr2.stale; |
1505 | bytes -= count * sizeof(ents[0]); | 1505 | bytes -= count * sizeof(ents[0]); |
1506 | 1506 | ||
1507 | /* | 1507 | /* |
1508 | * Fits with at least 25% to spare. | 1508 | * Fits with at least 25% to spare. |
1509 | */ | 1509 | */ |
1510 | if (bytes >= 0) | 1510 | if (bytes >= 0) |
1511 | break; | 1511 | break; |
1512 | xfs_trans_brelse(state->args->trans, bp); | 1512 | xfs_trans_brelse(state->args->trans, bp); |
1513 | } | 1513 | } |
1514 | /* | 1514 | /* |
1515 | * Didn't like either block, give up. | 1515 | * Didn't like either block, give up. |
1516 | */ | 1516 | */ |
1517 | if (i >= 2) { | 1517 | if (i >= 2) { |
1518 | *action = 0; | 1518 | *action = 0; |
1519 | return 0; | 1519 | return 0; |
1520 | } | 1520 | } |
1521 | 1521 | ||
1522 | /* | 1522 | /* |
1523 | * Make altpath point to the block we want to keep (the lower | 1523 | * Make altpath point to the block we want to keep (the lower |
1524 | * numbered block) and path point to the block we want to drop. | 1524 | * numbered block) and path point to the block we want to drop. |
1525 | */ | 1525 | */ |
1526 | memcpy(&state->altpath, &state->path, sizeof(state->path)); | 1526 | memcpy(&state->altpath, &state->path, sizeof(state->path)); |
1527 | if (blkno < blk->blkno) | 1527 | if (blkno < blk->blkno) |
1528 | error = xfs_da3_path_shift(state, &state->altpath, forward, 0, | 1528 | error = xfs_da3_path_shift(state, &state->altpath, forward, 0, |
1529 | &rval); | 1529 | &rval); |
1530 | else | 1530 | else |
1531 | error = xfs_da3_path_shift(state, &state->path, forward, 0, | 1531 | error = xfs_da3_path_shift(state, &state->path, forward, 0, |
1532 | &rval); | 1532 | &rval); |
1533 | if (error) { | 1533 | if (error) { |
1534 | return error; | 1534 | return error; |
1535 | } | 1535 | } |
1536 | *action = rval ? 0 : 1; | 1536 | *action = rval ? 0 : 1; |
1537 | return 0; | 1537 | return 0; |
1538 | } | 1538 | } |
1539 | 1539 | ||
1540 | /* | 1540 | /* |
1541 | * Move all the leaf entries from drop_blk to save_blk. | 1541 | * Move all the leaf entries from drop_blk to save_blk. |
1542 | * This is done as part of a join operation. | 1542 | * This is done as part of a join operation. |
1543 | */ | 1543 | */ |
1544 | void | 1544 | void |
1545 | xfs_dir2_leafn_unbalance( | 1545 | xfs_dir2_leafn_unbalance( |
1546 | xfs_da_state_t *state, /* cursor */ | 1546 | xfs_da_state_t *state, /* cursor */ |
1547 | xfs_da_state_blk_t *drop_blk, /* dead block */ | 1547 | xfs_da_state_blk_t *drop_blk, /* dead block */ |
1548 | xfs_da_state_blk_t *save_blk) /* surviving block */ | 1548 | xfs_da_state_blk_t *save_blk) /* surviving block */ |
1549 | { | 1549 | { |
1550 | xfs_da_args_t *args; /* operation arguments */ | 1550 | xfs_da_args_t *args; /* operation arguments */ |
1551 | xfs_dir2_leaf_t *drop_leaf; /* dead leaf structure */ | 1551 | xfs_dir2_leaf_t *drop_leaf; /* dead leaf structure */ |
1552 | xfs_dir2_leaf_t *save_leaf; /* surviving leaf structure */ | 1552 | xfs_dir2_leaf_t *save_leaf; /* surviving leaf structure */ |
1553 | struct xfs_dir3_icleaf_hdr savehdr; | 1553 | struct xfs_dir3_icleaf_hdr savehdr; |
1554 | struct xfs_dir3_icleaf_hdr drophdr; | 1554 | struct xfs_dir3_icleaf_hdr drophdr; |
1555 | struct xfs_dir2_leaf_entry *sents; | 1555 | struct xfs_dir2_leaf_entry *sents; |
1556 | struct xfs_dir2_leaf_entry *dents; | 1556 | struct xfs_dir2_leaf_entry *dents; |
1557 | 1557 | ||
1558 | args = state->args; | 1558 | args = state->args; |
1559 | ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); | 1559 | ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); |
1560 | ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC); | 1560 | ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC); |
1561 | drop_leaf = drop_blk->bp->b_addr; | 1561 | drop_leaf = drop_blk->bp->b_addr; |
1562 | save_leaf = save_blk->bp->b_addr; | 1562 | save_leaf = save_blk->bp->b_addr; |
1563 | 1563 | ||
1564 | xfs_dir3_leaf_hdr_from_disk(&savehdr, save_leaf); | 1564 | xfs_dir3_leaf_hdr_from_disk(&savehdr, save_leaf); |
1565 | xfs_dir3_leaf_hdr_from_disk(&drophdr, drop_leaf); | 1565 | xfs_dir3_leaf_hdr_from_disk(&drophdr, drop_leaf); |
1566 | sents = xfs_dir3_leaf_ents_p(save_leaf); | 1566 | sents = xfs_dir3_leaf_ents_p(save_leaf); |
1567 | dents = xfs_dir3_leaf_ents_p(drop_leaf); | 1567 | dents = xfs_dir3_leaf_ents_p(drop_leaf); |
1568 | 1568 | ||
1569 | /* | 1569 | /* |
1570 | * If there are any stale leaf entries, take this opportunity | 1570 | * If there are any stale leaf entries, take this opportunity |
1571 | * to purge them. | 1571 | * to purge them. |
1572 | */ | 1572 | */ |
1573 | if (drophdr.stale) | 1573 | if (drophdr.stale) |
1574 | xfs_dir3_leaf_compact(args, &drophdr, drop_blk->bp); | 1574 | xfs_dir3_leaf_compact(args, &drophdr, drop_blk->bp); |
1575 | if (savehdr.stale) | 1575 | if (savehdr.stale) |
1576 | xfs_dir3_leaf_compact(args, &savehdr, save_blk->bp); | 1576 | xfs_dir3_leaf_compact(args, &savehdr, save_blk->bp); |
1577 | 1577 | ||
1578 | /* | 1578 | /* |
1579 | * Move the entries from drop to the appropriate end of save. | 1579 | * Move the entries from drop to the appropriate end of save. |
1580 | */ | 1580 | */ |
1581 | drop_blk->hashval = be32_to_cpu(dents[drophdr.count - 1].hashval); | 1581 | drop_blk->hashval = be32_to_cpu(dents[drophdr.count - 1].hashval); |
1582 | if (xfs_dir2_leafn_order(save_blk->bp, drop_blk->bp)) | 1582 | if (xfs_dir2_leafn_order(save_blk->bp, drop_blk->bp)) |
1583 | xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, | 1583 | xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, |
1584 | save_blk->bp, &savehdr, sents, 0, | 1584 | save_blk->bp, &savehdr, sents, 0, |
1585 | drophdr.count); | 1585 | drophdr.count); |
1586 | else | 1586 | else |
1587 | xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, | 1587 | xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, |
1588 | save_blk->bp, &savehdr, sents, | 1588 | save_blk->bp, &savehdr, sents, |
1589 | savehdr.count, drophdr.count); | 1589 | savehdr.count, drophdr.count); |
1590 | save_blk->hashval = be32_to_cpu(sents[savehdr.count - 1].hashval); | 1590 | save_blk->hashval = be32_to_cpu(sents[savehdr.count - 1].hashval); |
1591 | 1591 | ||
1592 | /* log the changes made when moving the entries */ | 1592 | /* log the changes made when moving the entries */ |
1593 | xfs_dir3_leaf_hdr_to_disk(save_leaf, &savehdr); | 1593 | xfs_dir3_leaf_hdr_to_disk(save_leaf, &savehdr); |
1594 | xfs_dir3_leaf_hdr_to_disk(drop_leaf, &drophdr); | 1594 | xfs_dir3_leaf_hdr_to_disk(drop_leaf, &drophdr); |
1595 | xfs_dir3_leaf_log_header(args->trans, save_blk->bp); | 1595 | xfs_dir3_leaf_log_header(args->trans, save_blk->bp); |
1596 | xfs_dir3_leaf_log_header(args->trans, drop_blk->bp); | 1596 | xfs_dir3_leaf_log_header(args->trans, drop_blk->bp); |
1597 | 1597 | ||
1598 | xfs_dir3_leaf_check(args->dp->i_mount, save_blk->bp); | 1598 | xfs_dir3_leaf_check(args->dp->i_mount, save_blk->bp); |
1599 | xfs_dir3_leaf_check(args->dp->i_mount, drop_blk->bp); | 1599 | xfs_dir3_leaf_check(args->dp->i_mount, drop_blk->bp); |
1600 | } | 1600 | } |
1601 | 1601 | ||
1602 | /* | 1602 | /* |
1603 | * Top-level node form directory addname routine. | 1603 | * Top-level node form directory addname routine. |
1604 | */ | 1604 | */ |
1605 | int /* error */ | 1605 | int /* error */ |
1606 | xfs_dir2_node_addname( | 1606 | xfs_dir2_node_addname( |
1607 | xfs_da_args_t *args) /* operation arguments */ | 1607 | xfs_da_args_t *args) /* operation arguments */ |
1608 | { | 1608 | { |
1609 | xfs_da_state_blk_t *blk; /* leaf block for insert */ | 1609 | xfs_da_state_blk_t *blk; /* leaf block for insert */ |
1610 | int error; /* error return value */ | 1610 | int error; /* error return value */ |
1611 | int rval; /* sub-return value */ | 1611 | int rval; /* sub-return value */ |
1612 | xfs_da_state_t *state; /* btree cursor */ | 1612 | xfs_da_state_t *state; /* btree cursor */ |
1613 | 1613 | ||
1614 | trace_xfs_dir2_node_addname(args); | 1614 | trace_xfs_dir2_node_addname(args); |
1615 | 1615 | ||
1616 | /* | 1616 | /* |
1617 | * Allocate and initialize the state (btree cursor). | 1617 | * Allocate and initialize the state (btree cursor). |
1618 | */ | 1618 | */ |
1619 | state = xfs_da_state_alloc(); | 1619 | state = xfs_da_state_alloc(); |
1620 | state->args = args; | 1620 | state->args = args; |
1621 | state->mp = args->dp->i_mount; | 1621 | state->mp = args->dp->i_mount; |
1622 | state->blocksize = state->mp->m_dirblksize; | 1622 | state->blocksize = state->mp->m_dirblksize; |
1623 | state->node_ents = state->mp->m_dir_node_ents; | 1623 | state->node_ents = state->mp->m_dir_node_ents; |
1624 | /* | 1624 | /* |
1625 | * Look up the name. We're not supposed to find it, but | 1625 | * Look up the name. We're not supposed to find it, but |
1626 | * this gives us the insertion point. | 1626 | * this gives us the insertion point. |
1627 | */ | 1627 | */ |
1628 | error = xfs_da3_node_lookup_int(state, &rval); | 1628 | error = xfs_da3_node_lookup_int(state, &rval); |
1629 | if (error) | 1629 | if (error) |
1630 | rval = error; | 1630 | rval = error; |
1631 | if (rval != ENOENT) { | 1631 | if (rval != ENOENT) { |
1632 | goto done; | 1632 | goto done; |
1633 | } | 1633 | } |
1634 | /* | 1634 | /* |
1635 | * Add the data entry to a data block. | 1635 | * Add the data entry to a data block. |
1636 | * Extravalid is set to a freeblock found by lookup. | 1636 | * Extravalid is set to a freeblock found by lookup. |
1637 | */ | 1637 | */ |
1638 | rval = xfs_dir2_node_addname_int(args, | 1638 | rval = xfs_dir2_node_addname_int(args, |
1639 | state->extravalid ? &state->extrablk : NULL); | 1639 | state->extravalid ? &state->extrablk : NULL); |
1640 | if (rval) { | 1640 | if (rval) { |
1641 | goto done; | 1641 | goto done; |
1642 | } | 1642 | } |
1643 | blk = &state->path.blk[state->path.active - 1]; | 1643 | blk = &state->path.blk[state->path.active - 1]; |
1644 | ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); | 1644 | ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); |
1645 | /* | 1645 | /* |
1646 | * Add the new leaf entry. | 1646 | * Add the new leaf entry. |
1647 | */ | 1647 | */ |
1648 | rval = xfs_dir2_leafn_add(blk->bp, args, blk->index); | 1648 | rval = xfs_dir2_leafn_add(blk->bp, args, blk->index); |
1649 | if (rval == 0) { | 1649 | if (rval == 0) { |
1650 | /* | 1650 | /* |
1651 | * It worked, fix the hash values up the btree. | 1651 | * It worked, fix the hash values up the btree. |
1652 | */ | 1652 | */ |
1653 | if (!(args->op_flags & XFS_DA_OP_JUSTCHECK)) | 1653 | if (!(args->op_flags & XFS_DA_OP_JUSTCHECK)) |
1654 | xfs_da3_fixhashpath(state, &state->path); | 1654 | xfs_da3_fixhashpath(state, &state->path); |
1655 | } else { | 1655 | } else { |
1656 | /* | 1656 | /* |
1657 | * It didn't work, we need to split the leaf block. | 1657 | * It didn't work, we need to split the leaf block. |
1658 | */ | 1658 | */ |
1659 | if (args->total == 0) { | 1659 | if (args->total == 0) { |
1660 | ASSERT(rval == ENOSPC); | 1660 | ASSERT(rval == ENOSPC); |
1661 | goto done; | 1661 | goto done; |
1662 | } | 1662 | } |
1663 | /* | 1663 | /* |
1664 | * Split the leaf block and insert the new entry. | 1664 | * Split the leaf block and insert the new entry. |
1665 | */ | 1665 | */ |
1666 | rval = xfs_da3_split(state); | 1666 | rval = xfs_da3_split(state); |
1667 | } | 1667 | } |
1668 | done: | 1668 | done: |
1669 | xfs_da_state_free(state); | 1669 | xfs_da_state_free(state); |
1670 | return rval; | 1670 | return rval; |
1671 | } | 1671 | } |
1672 | 1672 | ||
1673 | /* | 1673 | /* |
1674 | * Add the data entry for a node-format directory name addition. | 1674 | * Add the data entry for a node-format directory name addition. |
1675 | * The leaf entry is added in xfs_dir2_leafn_add. | 1675 | * The leaf entry is added in xfs_dir2_leafn_add. |
1676 | * We may enter with a freespace block that the lookup found. | 1676 | * We may enter with a freespace block that the lookup found. |
1677 | */ | 1677 | */ |
1678 | static int /* error */ | 1678 | static int /* error */ |
1679 | xfs_dir2_node_addname_int( | 1679 | xfs_dir2_node_addname_int( |
1680 | xfs_da_args_t *args, /* operation arguments */ | 1680 | xfs_da_args_t *args, /* operation arguments */ |
1681 | xfs_da_state_blk_t *fblk) /* optional freespace block */ | 1681 | xfs_da_state_blk_t *fblk) /* optional freespace block */ |
1682 | { | 1682 | { |
1683 | xfs_dir2_data_hdr_t *hdr; /* data block header */ | 1683 | xfs_dir2_data_hdr_t *hdr; /* data block header */ |
1684 | xfs_dir2_db_t dbno; /* data block number */ | 1684 | xfs_dir2_db_t dbno; /* data block number */ |
1685 | struct xfs_buf *dbp; /* data block buffer */ | 1685 | struct xfs_buf *dbp; /* data block buffer */ |
1686 | xfs_dir2_data_entry_t *dep; /* data entry pointer */ | 1686 | xfs_dir2_data_entry_t *dep; /* data entry pointer */ |
1687 | xfs_inode_t *dp; /* incore directory inode */ | 1687 | xfs_inode_t *dp; /* incore directory inode */ |
1688 | xfs_dir2_data_unused_t *dup; /* data unused entry pointer */ | 1688 | xfs_dir2_data_unused_t *dup; /* data unused entry pointer */ |
1689 | int error; /* error return value */ | 1689 | int error; /* error return value */ |
1690 | xfs_dir2_db_t fbno; /* freespace block number */ | 1690 | xfs_dir2_db_t fbno; /* freespace block number */ |
1691 | struct xfs_buf *fbp; /* freespace buffer */ | 1691 | struct xfs_buf *fbp; /* freespace buffer */ |
1692 | int findex; /* freespace entry index */ | 1692 | int findex; /* freespace entry index */ |
1693 | xfs_dir2_free_t *free=NULL; /* freespace block structure */ | 1693 | xfs_dir2_free_t *free=NULL; /* freespace block structure */ |
1694 | xfs_dir2_db_t ifbno; /* initial freespace block no */ | 1694 | xfs_dir2_db_t ifbno; /* initial freespace block no */ |
1695 | xfs_dir2_db_t lastfbno=0; /* highest freespace block no */ | 1695 | xfs_dir2_db_t lastfbno=0; /* highest freespace block no */ |
1696 | int length; /* length of the new entry */ | 1696 | int length; /* length of the new entry */ |
1697 | int logfree; /* need to log free entry */ | 1697 | int logfree; /* need to log free entry */ |
1698 | xfs_mount_t *mp; /* filesystem mount point */ | 1698 | xfs_mount_t *mp; /* filesystem mount point */ |
1699 | int needlog; /* need to log data header */ | 1699 | int needlog; /* need to log data header */ |
1700 | int needscan; /* need to rescan data frees */ | 1700 | int needscan; /* need to rescan data frees */ |
1701 | __be16 *tagp; /* data entry tag pointer */ | 1701 | __be16 *tagp; /* data entry tag pointer */ |
1702 | xfs_trans_t *tp; /* transaction pointer */ | 1702 | xfs_trans_t *tp; /* transaction pointer */ |
1703 | __be16 *bests; | 1703 | __be16 *bests; |
1704 | struct xfs_dir3_icfree_hdr freehdr; | 1704 | struct xfs_dir3_icfree_hdr freehdr; |
1705 | struct xfs_dir2_data_free *bf; | 1705 | struct xfs_dir2_data_free *bf; |
1706 | 1706 | ||
1707 | dp = args->dp; | 1707 | dp = args->dp; |
1708 | mp = dp->i_mount; | 1708 | mp = dp->i_mount; |
1709 | tp = args->trans; | 1709 | tp = args->trans; |
1710 | length = xfs_dir2_data_entsize(args->namelen); | 1710 | length = xfs_dir2_data_entsize(args->namelen); |
1711 | /* | 1711 | /* |
1712 | * If we came in with a freespace block that means that lookup | 1712 | * If we came in with a freespace block that means that lookup |
1713 | * found an entry with our hash value. This is the freespace | 1713 | * found an entry with our hash value. This is the freespace |
1714 | * block for that data entry. | 1714 | * block for that data entry. |
1715 | */ | 1715 | */ |
1716 | if (fblk) { | 1716 | if (fblk) { |
1717 | fbp = fblk->bp; | 1717 | fbp = fblk->bp; |
1718 | /* | 1718 | /* |
1719 | * Remember initial freespace block number. | 1719 | * Remember initial freespace block number. |
1720 | */ | 1720 | */ |
1721 | ifbno = fblk->blkno; | 1721 | ifbno = fblk->blkno; |
1722 | free = fbp->b_addr; | 1722 | free = fbp->b_addr; |
1723 | findex = fblk->index; | 1723 | findex = fblk->index; |
1724 | bests = xfs_dir3_free_bests_p(mp, free); | 1724 | bests = xfs_dir3_free_bests_p(mp, free); |
1725 | xfs_dir3_free_hdr_from_disk(&freehdr, free); | 1725 | xfs_dir3_free_hdr_from_disk(&freehdr, free); |
1726 | 1726 | ||
1727 | /* | 1727 | /* |
1728 | * This means the free entry showed that the data block had | 1728 | * This means the free entry showed that the data block had |
1729 | * space for our entry, so we remembered it. | 1729 | * space for our entry, so we remembered it. |
1730 | * Use that data block. | 1730 | * Use that data block. |
1731 | */ | 1731 | */ |
1732 | if (findex >= 0) { | 1732 | if (findex >= 0) { |
1733 | ASSERT(findex < freehdr.nvalid); | 1733 | ASSERT(findex < freehdr.nvalid); |
1734 | ASSERT(be16_to_cpu(bests[findex]) != NULLDATAOFF); | 1734 | ASSERT(be16_to_cpu(bests[findex]) != NULLDATAOFF); |
1735 | ASSERT(be16_to_cpu(bests[findex]) >= length); | 1735 | ASSERT(be16_to_cpu(bests[findex]) >= length); |
1736 | dbno = freehdr.firstdb + findex; | 1736 | dbno = freehdr.firstdb + findex; |
1737 | } else { | 1737 | } else { |
1738 | /* | 1738 | /* |
1739 | * The data block looked at didn't have enough room. | 1739 | * The data block looked at didn't have enough room. |
1740 | * We'll start at the beginning of the freespace entries. | 1740 | * We'll start at the beginning of the freespace entries. |
1741 | */ | 1741 | */ |
1742 | dbno = -1; | 1742 | dbno = -1; |
1743 | findex = 0; | 1743 | findex = 0; |
1744 | } | 1744 | } |
1745 | } else { | 1745 | } else { |
1746 | /* | 1746 | /* |
1747 | * Didn't come in with a freespace block, so no data block. | 1747 | * Didn't come in with a freespace block, so no data block. |
1748 | */ | 1748 | */ |
1749 | ifbno = dbno = -1; | 1749 | ifbno = dbno = -1; |
1750 | fbp = NULL; | 1750 | fbp = NULL; |
1751 | findex = 0; | 1751 | findex = 0; |
1752 | } | 1752 | } |
1753 | 1753 | ||
1754 | /* | 1754 | /* |
1755 | * If we don't have a data block yet, we're going to scan the | 1755 | * If we don't have a data block yet, we're going to scan the |
1756 | * freespace blocks looking for one. Figure out what the | 1756 | * freespace blocks looking for one. Figure out what the |
1757 | * highest freespace block number is. | 1757 | * highest freespace block number is. |
1758 | */ | 1758 | */ |
1759 | if (dbno == -1) { | 1759 | if (dbno == -1) { |
1760 | xfs_fileoff_t fo; /* freespace block number */ | 1760 | xfs_fileoff_t fo; /* freespace block number */ |
1761 | 1761 | ||
1762 | if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) | 1762 | if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) |
1763 | return error; | 1763 | return error; |
1764 | lastfbno = xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo); | 1764 | lastfbno = xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo); |
1765 | fbno = ifbno; | 1765 | fbno = ifbno; |
1766 | } | 1766 | } |
1767 | /* | 1767 | /* |
1768 | * While we haven't identified a data block, search the freeblock | 1768 | * While we haven't identified a data block, search the freeblock |
1769 | * data for a good data block. If we find a null freeblock entry, | 1769 | * data for a good data block. If we find a null freeblock entry, |
1770 | * indicating a hole in the data blocks, remember that. | 1770 | * indicating a hole in the data blocks, remember that. |
1771 | */ | 1771 | */ |
1772 | while (dbno == -1) { | 1772 | while (dbno == -1) { |
1773 | /* | 1773 | /* |
1774 | * If we don't have a freeblock in hand, get the next one. | 1774 | * If we don't have a freeblock in hand, get the next one. |
1775 | */ | 1775 | */ |
1776 | if (fbp == NULL) { | 1776 | if (fbp == NULL) { |
1777 | /* | 1777 | /* |
1778 | * Happens the first time through unless lookup gave | 1778 | * Happens the first time through unless lookup gave |
1779 | * us a freespace block to start with. | 1779 | * us a freespace block to start with. |
1780 | */ | 1780 | */ |
1781 | if (++fbno == 0) | 1781 | if (++fbno == 0) |
1782 | fbno = XFS_DIR2_FREE_FIRSTDB(mp); | 1782 | fbno = XFS_DIR2_FREE_FIRSTDB(mp); |
1783 | /* | 1783 | /* |
1784 | * If it's ifbno we already looked at it. | 1784 | * If it's ifbno we already looked at it. |
1785 | */ | 1785 | */ |
1786 | if (fbno == ifbno) | 1786 | if (fbno == ifbno) |
1787 | fbno++; | 1787 | fbno++; |
1788 | /* | 1788 | /* |
1789 | * If it's off the end we're done. | 1789 | * If it's off the end we're done. |
1790 | */ | 1790 | */ |
1791 | if (fbno >= lastfbno) | 1791 | if (fbno >= lastfbno) |
1792 | break; | 1792 | break; |
1793 | /* | 1793 | /* |
1794 | * Read the block. There can be holes in the | 1794 | * Read the block. There can be holes in the |
1795 | * freespace blocks, so this might not succeed. | 1795 | * freespace blocks, so this might not succeed. |
1796 | * This should be really rare, so there's no reason | 1796 | * This should be really rare, so there's no reason |
1797 | * to avoid it. | 1797 | * to avoid it. |
1798 | */ | 1798 | */ |
1799 | error = xfs_dir2_free_try_read(tp, dp, | 1799 | error = xfs_dir2_free_try_read(tp, dp, |
1800 | xfs_dir2_db_to_da(mp, fbno), | 1800 | xfs_dir2_db_to_da(mp, fbno), |
1801 | &fbp); | 1801 | &fbp); |
1802 | if (error) | 1802 | if (error) |
1803 | return error; | 1803 | return error; |
1804 | if (!fbp) | 1804 | if (!fbp) |
1805 | continue; | 1805 | continue; |
1806 | free = fbp->b_addr; | 1806 | free = fbp->b_addr; |
1807 | findex = 0; | 1807 | findex = 0; |
1808 | } | 1808 | } |
1809 | /* | 1809 | /* |
1810 | * Look at the current free entry. Is it good enough? | 1810 | * Look at the current free entry. Is it good enough? |
1811 | * | 1811 | * |
1812 | * The bests initialisation should be where the bufer is read in | 1812 | * The bests initialisation should be where the bufer is read in |
1813 | * the above branch. But gcc is too stupid to realise that bests | 1813 | * the above branch. But gcc is too stupid to realise that bests |
1814 | * and the freehdr are actually initialised if they are placed | 1814 | * and the freehdr are actually initialised if they are placed |
1815 | * there, so we have to do it here to avoid warnings. Blech. | 1815 | * there, so we have to do it here to avoid warnings. Blech. |
1816 | */ | 1816 | */ |
1817 | bests = xfs_dir3_free_bests_p(mp, free); | 1817 | bests = xfs_dir3_free_bests_p(mp, free); |
1818 | xfs_dir3_free_hdr_from_disk(&freehdr, free); | 1818 | xfs_dir3_free_hdr_from_disk(&freehdr, free); |
1819 | if (be16_to_cpu(bests[findex]) != NULLDATAOFF && | 1819 | if (be16_to_cpu(bests[findex]) != NULLDATAOFF && |
1820 | be16_to_cpu(bests[findex]) >= length) | 1820 | be16_to_cpu(bests[findex]) >= length) |
1821 | dbno = freehdr.firstdb + findex; | 1821 | dbno = freehdr.firstdb + findex; |
1822 | else { | 1822 | else { |
1823 | /* | 1823 | /* |
1824 | * Are we done with the freeblock? | 1824 | * Are we done with the freeblock? |
1825 | */ | 1825 | */ |
1826 | if (++findex == freehdr.nvalid) { | 1826 | if (++findex == freehdr.nvalid) { |
1827 | /* | 1827 | /* |
1828 | * Drop the block. | 1828 | * Drop the block. |
1829 | */ | 1829 | */ |
1830 | xfs_trans_brelse(tp, fbp); | 1830 | xfs_trans_brelse(tp, fbp); |
1831 | fbp = NULL; | 1831 | fbp = NULL; |
1832 | if (fblk && fblk->bp) | 1832 | if (fblk && fblk->bp) |
1833 | fblk->bp = NULL; | 1833 | fblk->bp = NULL; |
1834 | } | 1834 | } |
1835 | } | 1835 | } |
1836 | } | 1836 | } |
1837 | /* | 1837 | /* |
1838 | * If we don't have a data block, we need to allocate one and make | 1838 | * If we don't have a data block, we need to allocate one and make |
1839 | * the freespace entries refer to it. | 1839 | * the freespace entries refer to it. |
1840 | */ | 1840 | */ |
1841 | if (unlikely(dbno == -1)) { | 1841 | if (unlikely(dbno == -1)) { |
1842 | /* | 1842 | /* |
1843 | * Not allowed to allocate, return failure. | 1843 | * Not allowed to allocate, return failure. |
1844 | */ | 1844 | */ |
1845 | if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) | 1845 | if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) |
1846 | return XFS_ERROR(ENOSPC); | 1846 | return XFS_ERROR(ENOSPC); |
1847 | 1847 | ||
1848 | /* | 1848 | /* |
1849 | * Allocate and initialize the new data block. | 1849 | * Allocate and initialize the new data block. |
1850 | */ | 1850 | */ |
1851 | if (unlikely((error = xfs_dir2_grow_inode(args, | 1851 | if (unlikely((error = xfs_dir2_grow_inode(args, |
1852 | XFS_DIR2_DATA_SPACE, | 1852 | XFS_DIR2_DATA_SPACE, |
1853 | &dbno)) || | 1853 | &dbno)) || |
1854 | (error = xfs_dir3_data_init(args, dbno, &dbp)))) | 1854 | (error = xfs_dir3_data_init(args, dbno, &dbp)))) |
1855 | return error; | 1855 | return error; |
1856 | 1856 | ||
1857 | /* | 1857 | /* |
1858 | * If (somehow) we have a freespace block, get rid of it. | 1858 | * If (somehow) we have a freespace block, get rid of it. |
1859 | */ | 1859 | */ |
1860 | if (fbp) | 1860 | if (fbp) |
1861 | xfs_trans_brelse(tp, fbp); | 1861 | xfs_trans_brelse(tp, fbp); |
1862 | if (fblk && fblk->bp) | 1862 | if (fblk && fblk->bp) |
1863 | fblk->bp = NULL; | 1863 | fblk->bp = NULL; |
1864 | 1864 | ||
1865 | /* | 1865 | /* |
1866 | * Get the freespace block corresponding to the data block | 1866 | * Get the freespace block corresponding to the data block |
1867 | * that was just allocated. | 1867 | * that was just allocated. |
1868 | */ | 1868 | */ |
1869 | fbno = xfs_dir2_db_to_fdb(mp, dbno); | 1869 | fbno = xfs_dir2_db_to_fdb(mp, dbno); |
1870 | error = xfs_dir2_free_try_read(tp, dp, | 1870 | error = xfs_dir2_free_try_read(tp, dp, |
1871 | xfs_dir2_db_to_da(mp, fbno), | 1871 | xfs_dir2_db_to_da(mp, fbno), |
1872 | &fbp); | 1872 | &fbp); |
1873 | if (error) | 1873 | if (error) |
1874 | return error; | 1874 | return error; |
1875 | 1875 | ||
1876 | /* | 1876 | /* |
1877 | * If there wasn't a freespace block, the read will | 1877 | * If there wasn't a freespace block, the read will |
1878 | * return a NULL fbp. Allocate and initialize a new one. | 1878 | * return a NULL fbp. Allocate and initialize a new one. |
1879 | */ | 1879 | */ |
1880 | if (!fbp) { | 1880 | if (!fbp) { |
1881 | error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, | 1881 | error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, |
1882 | &fbno); | 1882 | &fbno); |
1883 | if (error) | 1883 | if (error) |
1884 | return error; | 1884 | return error; |
1885 | 1885 | ||
1886 | if (unlikely(xfs_dir2_db_to_fdb(mp, dbno) != fbno)) { | 1886 | if (unlikely(xfs_dir2_db_to_fdb(mp, dbno) != fbno)) { |
1887 | xfs_alert(mp, | 1887 | xfs_alert(mp, |
1888 | "%s: dir ino %llu needed freesp block %lld for\n" | 1888 | "%s: dir ino %llu needed freesp block %lld for\n" |
1889 | " data block %lld, got %lld ifbno %llu lastfbno %d", | 1889 | " data block %lld, got %lld ifbno %llu lastfbno %d", |
1890 | __func__, (unsigned long long)dp->i_ino, | 1890 | __func__, (unsigned long long)dp->i_ino, |
1891 | (long long)xfs_dir2_db_to_fdb(mp, dbno), | 1891 | (long long)xfs_dir2_db_to_fdb(mp, dbno), |
1892 | (long long)dbno, (long long)fbno, | 1892 | (long long)dbno, (long long)fbno, |
1893 | (unsigned long long)ifbno, lastfbno); | 1893 | (unsigned long long)ifbno, lastfbno); |
1894 | if (fblk) { | 1894 | if (fblk) { |
1895 | xfs_alert(mp, | 1895 | xfs_alert(mp, |
1896 | " fblk 0x%p blkno %llu index %d magic 0x%x", | 1896 | " fblk 0x%p blkno %llu index %d magic 0x%x", |
1897 | fblk, | 1897 | fblk, |
1898 | (unsigned long long)fblk->blkno, | 1898 | (unsigned long long)fblk->blkno, |
1899 | fblk->index, | 1899 | fblk->index, |
1900 | fblk->magic); | 1900 | fblk->magic); |
1901 | } else { | 1901 | } else { |
1902 | xfs_alert(mp, " ... fblk is NULL"); | 1902 | xfs_alert(mp, " ... fblk is NULL"); |
1903 | } | 1903 | } |
1904 | XFS_ERROR_REPORT("xfs_dir2_node_addname_int", | 1904 | XFS_ERROR_REPORT("xfs_dir2_node_addname_int", |
1905 | XFS_ERRLEVEL_LOW, mp); | 1905 | XFS_ERRLEVEL_LOW, mp); |
1906 | return XFS_ERROR(EFSCORRUPTED); | 1906 | return XFS_ERROR(EFSCORRUPTED); |
1907 | } | 1907 | } |
1908 | 1908 | ||
1909 | /* | 1909 | /* |
1910 | * Get a buffer for the new block. | 1910 | * Get a buffer for the new block. |
1911 | */ | 1911 | */ |
1912 | error = xfs_dir3_free_get_buf(tp, dp, fbno, &fbp); | 1912 | error = xfs_dir3_free_get_buf(tp, dp, fbno, &fbp); |
1913 | if (error) | 1913 | if (error) |
1914 | return error; | 1914 | return error; |
1915 | free = fbp->b_addr; | 1915 | free = fbp->b_addr; |
1916 | bests = xfs_dir3_free_bests_p(mp, free); | 1916 | bests = xfs_dir3_free_bests_p(mp, free); |
1917 | xfs_dir3_free_hdr_from_disk(&freehdr, free); | 1917 | xfs_dir3_free_hdr_from_disk(&freehdr, free); |
1918 | 1918 | ||
1919 | /* | 1919 | /* |
1920 | * Remember the first slot as our empty slot. | 1920 | * Remember the first slot as our empty slot. |
1921 | */ | 1921 | */ |
1922 | freehdr.firstdb = (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) * | 1922 | freehdr.firstdb = (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) * |
1923 | xfs_dir3_free_max_bests(mp); | 1923 | xfs_dir3_free_max_bests(mp); |
1924 | free->hdr.nvalid = 0; | 1924 | free->hdr.nvalid = 0; |
1925 | free->hdr.nused = 0; | 1925 | free->hdr.nused = 0; |
1926 | } else { | 1926 | } else { |
1927 | free = fbp->b_addr; | 1927 | free = fbp->b_addr; |
1928 | bests = xfs_dir3_free_bests_p(mp, free); | 1928 | bests = xfs_dir3_free_bests_p(mp, free); |
1929 | xfs_dir3_free_hdr_from_disk(&freehdr, free); | 1929 | xfs_dir3_free_hdr_from_disk(&freehdr, free); |
1930 | } | 1930 | } |
1931 | 1931 | ||
1932 | /* | 1932 | /* |
1933 | * Set the freespace block index from the data block number. | 1933 | * Set the freespace block index from the data block number. |
1934 | */ | 1934 | */ |
1935 | findex = xfs_dir2_db_to_fdindex(mp, dbno); | 1935 | findex = xfs_dir2_db_to_fdindex(mp, dbno); |
1936 | /* | 1936 | /* |
1937 | * If it's after the end of the current entries in the | 1937 | * If it's after the end of the current entries in the |
1938 | * freespace block, extend that table. | 1938 | * freespace block, extend that table. |
1939 | */ | 1939 | */ |
1940 | if (findex >= freehdr.nvalid) { | 1940 | if (findex >= freehdr.nvalid) { |
1941 | ASSERT(findex < xfs_dir3_free_max_bests(mp)); | 1941 | ASSERT(findex < xfs_dir3_free_max_bests(mp)); |
1942 | freehdr.nvalid = findex + 1; | 1942 | freehdr.nvalid = findex + 1; |
1943 | /* | 1943 | /* |
1944 | * Tag new entry so nused will go up. | 1944 | * Tag new entry so nused will go up. |
1945 | */ | 1945 | */ |
1946 | bests[findex] = cpu_to_be16(NULLDATAOFF); | 1946 | bests[findex] = cpu_to_be16(NULLDATAOFF); |
1947 | } | 1947 | } |
1948 | /* | 1948 | /* |
1949 | * If this entry was for an empty data block | 1949 | * If this entry was for an empty data block |
1950 | * (this should always be true) then update the header. | 1950 | * (this should always be true) then update the header. |
1951 | */ | 1951 | */ |
1952 | if (bests[findex] == cpu_to_be16(NULLDATAOFF)) { | 1952 | if (bests[findex] == cpu_to_be16(NULLDATAOFF)) { |
1953 | freehdr.nused++; | 1953 | freehdr.nused++; |
1954 | xfs_dir3_free_hdr_to_disk(fbp->b_addr, &freehdr); | 1954 | xfs_dir3_free_hdr_to_disk(fbp->b_addr, &freehdr); |
1955 | xfs_dir2_free_log_header(tp, fbp); | 1955 | xfs_dir2_free_log_header(tp, fbp); |
1956 | } | 1956 | } |
1957 | /* | 1957 | /* |
1958 | * Update the real value in the table. | 1958 | * Update the real value in the table. |
1959 | * We haven't allocated the data entry yet so this will | 1959 | * We haven't allocated the data entry yet so this will |
1960 | * change again. | 1960 | * change again. |
1961 | */ | 1961 | */ |
1962 | hdr = dbp->b_addr; | 1962 | hdr = dbp->b_addr; |
1963 | bf = xfs_dir3_data_bestfree_p(hdr); | 1963 | bf = xfs_dir3_data_bestfree_p(hdr); |
1964 | bests[findex] = bf[0].length; | 1964 | bests[findex] = bf[0].length; |
1965 | logfree = 1; | 1965 | logfree = 1; |
1966 | } | 1966 | } |
1967 | /* | 1967 | /* |
1968 | * We had a data block so we don't have to make a new one. | 1968 | * We had a data block so we don't have to make a new one. |
1969 | */ | 1969 | */ |
1970 | else { | 1970 | else { |
1971 | /* | 1971 | /* |
1972 | * If just checking, we succeeded. | 1972 | * If just checking, we succeeded. |
1973 | */ | 1973 | */ |
1974 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) | 1974 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) |
1975 | return 0; | 1975 | return 0; |
1976 | 1976 | ||
1977 | /* | 1977 | /* |
1978 | * Read the data block in. | 1978 | * Read the data block in. |
1979 | */ | 1979 | */ |
1980 | error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(mp, dbno), | 1980 | error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(mp, dbno), |
1981 | -1, &dbp); | 1981 | -1, &dbp); |
1982 | if (error) | 1982 | if (error) |
1983 | return error; | 1983 | return error; |
1984 | hdr = dbp->b_addr; | 1984 | hdr = dbp->b_addr; |
1985 | bf = xfs_dir3_data_bestfree_p(hdr); | 1985 | bf = xfs_dir3_data_bestfree_p(hdr); |
1986 | logfree = 0; | 1986 | logfree = 0; |
1987 | } | 1987 | } |
1988 | ASSERT(be16_to_cpu(bf[0].length) >= length); | 1988 | ASSERT(be16_to_cpu(bf[0].length) >= length); |
1989 | /* | 1989 | /* |
1990 | * Point to the existing unused space. | 1990 | * Point to the existing unused space. |
1991 | */ | 1991 | */ |
1992 | dup = (xfs_dir2_data_unused_t *) | 1992 | dup = (xfs_dir2_data_unused_t *) |
1993 | ((char *)hdr + be16_to_cpu(bf[0].offset)); | 1993 | ((char *)hdr + be16_to_cpu(bf[0].offset)); |
1994 | needscan = needlog = 0; | 1994 | needscan = needlog = 0; |
1995 | /* | 1995 | /* |
1996 | * Mark the first part of the unused space, inuse for us. | 1996 | * Mark the first part of the unused space, inuse for us. |
1997 | */ | 1997 | */ |
1998 | xfs_dir2_data_use_free(tp, dbp, dup, | 1998 | xfs_dir2_data_use_free(tp, dbp, dup, |
1999 | (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length, | 1999 | (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length, |
2000 | &needlog, &needscan); | 2000 | &needlog, &needscan); |
2001 | /* | 2001 | /* |
2002 | * Fill in the new entry and log it. | 2002 | * Fill in the new entry and log it. |
2003 | */ | 2003 | */ |
2004 | dep = (xfs_dir2_data_entry_t *)dup; | 2004 | dep = (xfs_dir2_data_entry_t *)dup; |
2005 | dep->inumber = cpu_to_be64(args->inumber); | 2005 | dep->inumber = cpu_to_be64(args->inumber); |
2006 | dep->namelen = args->namelen; | 2006 | dep->namelen = args->namelen; |
2007 | memcpy(dep->name, args->name, dep->namelen); | 2007 | memcpy(dep->name, args->name, dep->namelen); |
2008 | tagp = xfs_dir2_data_entry_tag_p(dep); | 2008 | tagp = xfs_dir2_data_entry_tag_p(dep); |
2009 | *tagp = cpu_to_be16((char *)dep - (char *)hdr); | 2009 | *tagp = cpu_to_be16((char *)dep - (char *)hdr); |
2010 | xfs_dir2_data_log_entry(tp, dbp, dep); | 2010 | xfs_dir2_data_log_entry(tp, dbp, dep); |
2011 | /* | 2011 | /* |
2012 | * Rescan the block for bestfree if needed. | 2012 | * Rescan the block for bestfree if needed. |
2013 | */ | 2013 | */ |
2014 | if (needscan) | 2014 | if (needscan) |
2015 | xfs_dir2_data_freescan(mp, hdr, &needlog); | 2015 | xfs_dir2_data_freescan(mp, hdr, &needlog); |
2016 | /* | 2016 | /* |
2017 | * Log the data block header if needed. | 2017 | * Log the data block header if needed. |
2018 | */ | 2018 | */ |
2019 | if (needlog) | 2019 | if (needlog) |
2020 | xfs_dir2_data_log_header(tp, dbp); | 2020 | xfs_dir2_data_log_header(tp, dbp); |
2021 | /* | 2021 | /* |
2022 | * If the freespace entry is now wrong, update it. | 2022 | * If the freespace entry is now wrong, update it. |
2023 | */ | 2023 | */ |
2024 | bests = xfs_dir3_free_bests_p(mp, free); /* gcc is so stupid */ | 2024 | bests = xfs_dir3_free_bests_p(mp, free); /* gcc is so stupid */ |
2025 | if (be16_to_cpu(bests[findex]) != be16_to_cpu(bf[0].length)) { | 2025 | if (be16_to_cpu(bests[findex]) != be16_to_cpu(bf[0].length)) { |
2026 | bests[findex] = bf[0].length; | 2026 | bests[findex] = bf[0].length; |
2027 | logfree = 1; | 2027 | logfree = 1; |
2028 | } | 2028 | } |
2029 | /* | 2029 | /* |
2030 | * Log the freespace entry if needed. | 2030 | * Log the freespace entry if needed. |
2031 | */ | 2031 | */ |
2032 | if (logfree) | 2032 | if (logfree) |
2033 | xfs_dir2_free_log_bests(tp, fbp, findex, findex); | 2033 | xfs_dir2_free_log_bests(tp, fbp, findex, findex); |
2034 | /* | 2034 | /* |
2035 | * Return the data block and offset in args, then drop the data block. | 2035 | * Return the data block and offset in args, then drop the data block. |
2036 | */ | 2036 | */ |
2037 | args->blkno = (xfs_dablk_t)dbno; | 2037 | args->blkno = (xfs_dablk_t)dbno; |
2038 | args->index = be16_to_cpu(*tagp); | 2038 | args->index = be16_to_cpu(*tagp); |
2039 | return 0; | 2039 | return 0; |
2040 | } | 2040 | } |
2041 | 2041 | ||
2042 | /* | 2042 | /* |
2043 | * Lookup an entry in a node-format directory. | 2043 | * Lookup an entry in a node-format directory. |
2044 | * All the real work happens in xfs_da3_node_lookup_int. | 2044 | * All the real work happens in xfs_da3_node_lookup_int. |
2045 | * The only real output is the inode number of the entry. | 2045 | * The only real output is the inode number of the entry. |
2046 | */ | 2046 | */ |
2047 | int /* error */ | 2047 | int /* error */ |
2048 | xfs_dir2_node_lookup( | 2048 | xfs_dir2_node_lookup( |
2049 | xfs_da_args_t *args) /* operation arguments */ | 2049 | xfs_da_args_t *args) /* operation arguments */ |
2050 | { | 2050 | { |
2051 | int error; /* error return value */ | 2051 | int error; /* error return value */ |
2052 | int i; /* btree level */ | 2052 | int i; /* btree level */ |
2053 | int rval; /* operation return value */ | 2053 | int rval; /* operation return value */ |
2054 | xfs_da_state_t *state; /* btree cursor */ | 2054 | xfs_da_state_t *state; /* btree cursor */ |
2055 | 2055 | ||
2056 | trace_xfs_dir2_node_lookup(args); | 2056 | trace_xfs_dir2_node_lookup(args); |
2057 | 2057 | ||
2058 | /* | 2058 | /* |
2059 | * Allocate and initialize the btree cursor. | 2059 | * Allocate and initialize the btree cursor. |
2060 | */ | 2060 | */ |
2061 | state = xfs_da_state_alloc(); | 2061 | state = xfs_da_state_alloc(); |
2062 | state->args = args; | 2062 | state->args = args; |
2063 | state->mp = args->dp->i_mount; | 2063 | state->mp = args->dp->i_mount; |
2064 | state->blocksize = state->mp->m_dirblksize; | 2064 | state->blocksize = state->mp->m_dirblksize; |
2065 | state->node_ents = state->mp->m_dir_node_ents; | 2065 | state->node_ents = state->mp->m_dir_node_ents; |
2066 | /* | 2066 | /* |
2067 | * Fill in the path to the entry in the cursor. | 2067 | * Fill in the path to the entry in the cursor. |
2068 | */ | 2068 | */ |
2069 | error = xfs_da3_node_lookup_int(state, &rval); | 2069 | error = xfs_da3_node_lookup_int(state, &rval); |
2070 | if (error) | 2070 | if (error) |
2071 | rval = error; | 2071 | rval = error; |
2072 | else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE) { | 2072 | else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE) { |
2073 | /* If a CI match, dup the actual name and return EEXIST */ | 2073 | /* If a CI match, dup the actual name and return EEXIST */ |
2074 | xfs_dir2_data_entry_t *dep; | 2074 | xfs_dir2_data_entry_t *dep; |
2075 | 2075 | ||
2076 | dep = (xfs_dir2_data_entry_t *) | 2076 | dep = (xfs_dir2_data_entry_t *) |
2077 | ((char *)state->extrablk.bp->b_addr + | 2077 | ((char *)state->extrablk.bp->b_addr + |
2078 | state->extrablk.index); | 2078 | state->extrablk.index); |
2079 | rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen); | 2079 | rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen); |
2080 | } | 2080 | } |
2081 | /* | 2081 | /* |
2082 | * Release the btree blocks and leaf block. | 2082 | * Release the btree blocks and leaf block. |
2083 | */ | 2083 | */ |
2084 | for (i = 0; i < state->path.active; i++) { | 2084 | for (i = 0; i < state->path.active; i++) { |
2085 | xfs_trans_brelse(args->trans, state->path.blk[i].bp); | 2085 | xfs_trans_brelse(args->trans, state->path.blk[i].bp); |
2086 | state->path.blk[i].bp = NULL; | 2086 | state->path.blk[i].bp = NULL; |
2087 | } | 2087 | } |
2088 | /* | 2088 | /* |
2089 | * Release the data block if we have it. | 2089 | * Release the data block if we have it. |
2090 | */ | 2090 | */ |
2091 | if (state->extravalid && state->extrablk.bp) { | 2091 | if (state->extravalid && state->extrablk.bp) { |
2092 | xfs_trans_brelse(args->trans, state->extrablk.bp); | 2092 | xfs_trans_brelse(args->trans, state->extrablk.bp); |
2093 | state->extrablk.bp = NULL; | 2093 | state->extrablk.bp = NULL; |
2094 | } | 2094 | } |
2095 | xfs_da_state_free(state); | 2095 | xfs_da_state_free(state); |
2096 | return rval; | 2096 | return rval; |
2097 | } | 2097 | } |
2098 | 2098 | ||
2099 | /* | 2099 | /* |
2100 | * Remove an entry from a node-format directory. | 2100 | * Remove an entry from a node-format directory. |
2101 | */ | 2101 | */ |
2102 | int /* error */ | 2102 | int /* error */ |
2103 | xfs_dir2_node_removename( | 2103 | xfs_dir2_node_removename( |
2104 | xfs_da_args_t *args) /* operation arguments */ | 2104 | xfs_da_args_t *args) /* operation arguments */ |
2105 | { | 2105 | { |
2106 | xfs_da_state_blk_t *blk; /* leaf block */ | 2106 | xfs_da_state_blk_t *blk; /* leaf block */ |
2107 | int error; /* error return value */ | 2107 | int error; /* error return value */ |
2108 | int rval; /* operation return value */ | 2108 | int rval; /* operation return value */ |
2109 | xfs_da_state_t *state; /* btree cursor */ | 2109 | xfs_da_state_t *state; /* btree cursor */ |
2110 | 2110 | ||
2111 | trace_xfs_dir2_node_removename(args); | 2111 | trace_xfs_dir2_node_removename(args); |
2112 | 2112 | ||
2113 | /* | 2113 | /* |
2114 | * Allocate and initialize the btree cursor. | 2114 | * Allocate and initialize the btree cursor. |
2115 | */ | 2115 | */ |
2116 | state = xfs_da_state_alloc(); | 2116 | state = xfs_da_state_alloc(); |
2117 | state->args = args; | 2117 | state->args = args; |
2118 | state->mp = args->dp->i_mount; | 2118 | state->mp = args->dp->i_mount; |
2119 | state->blocksize = state->mp->m_dirblksize; | 2119 | state->blocksize = state->mp->m_dirblksize; |
2120 | state->node_ents = state->mp->m_dir_node_ents; | 2120 | state->node_ents = state->mp->m_dir_node_ents; |
2121 | /* | 2121 | /* |
2122 | * Look up the entry we're deleting, set up the cursor. | 2122 | * Look up the entry we're deleting, set up the cursor. |
2123 | */ | 2123 | */ |
2124 | error = xfs_da3_node_lookup_int(state, &rval); | 2124 | error = xfs_da3_node_lookup_int(state, &rval); |
2125 | if (error) | 2125 | if (error) |
2126 | rval = error; | 2126 | rval = error; |
2127 | /* | 2127 | /* |
2128 | * Didn't find it, upper layer screwed up. | 2128 | * Didn't find it, upper layer screwed up. |
2129 | */ | 2129 | */ |
2130 | if (rval != EEXIST) { | 2130 | if (rval != EEXIST) { |
2131 | xfs_da_state_free(state); | 2131 | xfs_da_state_free(state); |
2132 | return rval; | 2132 | return rval; |
2133 | } | 2133 | } |
2134 | blk = &state->path.blk[state->path.active - 1]; | 2134 | blk = &state->path.blk[state->path.active - 1]; |
2135 | ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); | 2135 | ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); |
2136 | ASSERT(state->extravalid); | 2136 | ASSERT(state->extravalid); |
2137 | /* | 2137 | /* |
2138 | * Remove the leaf and data entries. | 2138 | * Remove the leaf and data entries. |
2139 | * Extrablk refers to the data block. | 2139 | * Extrablk refers to the data block. |
2140 | */ | 2140 | */ |
2141 | error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, | 2141 | error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, |
2142 | &state->extrablk, &rval); | 2142 | &state->extrablk, &rval); |
2143 | if (error) | 2143 | if (error) |
2144 | return error; | 2144 | return error; |
2145 | /* | 2145 | /* |
2146 | * Fix the hash values up the btree. | 2146 | * Fix the hash values up the btree. |
2147 | */ | 2147 | */ |
2148 | xfs_da3_fixhashpath(state, &state->path); | 2148 | xfs_da3_fixhashpath(state, &state->path); |
2149 | /* | 2149 | /* |
2150 | * If we need to join leaf blocks, do it. | 2150 | * If we need to join leaf blocks, do it. |
2151 | */ | 2151 | */ |
2152 | if (rval && state->path.active > 1) | 2152 | if (rval && state->path.active > 1) |
2153 | error = xfs_da3_join(state); | 2153 | error = xfs_da3_join(state); |
2154 | /* | 2154 | /* |
2155 | * If no errors so far, try conversion to leaf format. | 2155 | * If no errors so far, try conversion to leaf format. |
2156 | */ | 2156 | */ |
2157 | if (!error) | 2157 | if (!error) |
2158 | error = xfs_dir2_node_to_leaf(state); | 2158 | error = xfs_dir2_node_to_leaf(state); |
2159 | xfs_da_state_free(state); | 2159 | xfs_da_state_free(state); |
2160 | return error; | 2160 | return error; |
2161 | } | 2161 | } |
2162 | 2162 | ||
2163 | /* | 2163 | /* |
2164 | * Replace an entry's inode number in a node-format directory. | 2164 | * Replace an entry's inode number in a node-format directory. |
2165 | */ | 2165 | */ |
2166 | int /* error */ | 2166 | int /* error */ |
2167 | xfs_dir2_node_replace( | 2167 | xfs_dir2_node_replace( |
2168 | xfs_da_args_t *args) /* operation arguments */ | 2168 | xfs_da_args_t *args) /* operation arguments */ |
2169 | { | 2169 | { |
2170 | xfs_da_state_blk_t *blk; /* leaf block */ | 2170 | xfs_da_state_blk_t *blk; /* leaf block */ |
2171 | xfs_dir2_data_hdr_t *hdr; /* data block header */ | 2171 | xfs_dir2_data_hdr_t *hdr; /* data block header */ |
2172 | xfs_dir2_data_entry_t *dep; /* data entry changed */ | 2172 | xfs_dir2_data_entry_t *dep; /* data entry changed */ |
2173 | int error; /* error return value */ | 2173 | int error; /* error return value */ |
2174 | int i; /* btree level */ | 2174 | int i; /* btree level */ |
2175 | xfs_ino_t inum; /* new inode number */ | 2175 | xfs_ino_t inum; /* new inode number */ |
2176 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | 2176 | xfs_dir2_leaf_t *leaf; /* leaf structure */ |
2177 | xfs_dir2_leaf_entry_t *lep; /* leaf entry being changed */ | 2177 | xfs_dir2_leaf_entry_t *lep; /* leaf entry being changed */ |
2178 | int rval; /* internal return value */ | 2178 | int rval; /* internal return value */ |
2179 | xfs_da_state_t *state; /* btree cursor */ | 2179 | xfs_da_state_t *state; /* btree cursor */ |
2180 | 2180 | ||
2181 | trace_xfs_dir2_node_replace(args); | 2181 | trace_xfs_dir2_node_replace(args); |
2182 | 2182 | ||
2183 | /* | 2183 | /* |
2184 | * Allocate and initialize the btree cursor. | 2184 | * Allocate and initialize the btree cursor. |
2185 | */ | 2185 | */ |
2186 | state = xfs_da_state_alloc(); | 2186 | state = xfs_da_state_alloc(); |
2187 | state->args = args; | 2187 | state->args = args; |
2188 | state->mp = args->dp->i_mount; | 2188 | state->mp = args->dp->i_mount; |
2189 | state->blocksize = state->mp->m_dirblksize; | 2189 | state->blocksize = state->mp->m_dirblksize; |
2190 | state->node_ents = state->mp->m_dir_node_ents; | 2190 | state->node_ents = state->mp->m_dir_node_ents; |
2191 | inum = args->inumber; | 2191 | inum = args->inumber; |
2192 | /* | 2192 | /* |
2193 | * Lookup the entry to change in the btree. | 2193 | * Lookup the entry to change in the btree. |
2194 | */ | 2194 | */ |
2195 | error = xfs_da3_node_lookup_int(state, &rval); | 2195 | error = xfs_da3_node_lookup_int(state, &rval); |
2196 | if (error) { | 2196 | if (error) { |
2197 | rval = error; | 2197 | rval = error; |
2198 | } | 2198 | } |
2199 | /* | 2199 | /* |
2200 | * It should be found, since the vnodeops layer has looked it up | 2200 | * It should be found, since the vnodeops layer has looked it up |
2201 | * and locked it. But paranoia is good. | 2201 | * and locked it. But paranoia is good. |
2202 | */ | 2202 | */ |
2203 | if (rval == EEXIST) { | 2203 | if (rval == EEXIST) { |
2204 | struct xfs_dir2_leaf_entry *ents; | 2204 | struct xfs_dir2_leaf_entry *ents; |
2205 | /* | 2205 | /* |
2206 | * Find the leaf entry. | 2206 | * Find the leaf entry. |
2207 | */ | 2207 | */ |
2208 | blk = &state->path.blk[state->path.active - 1]; | 2208 | blk = &state->path.blk[state->path.active - 1]; |
2209 | ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); | 2209 | ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); |
2210 | leaf = blk->bp->b_addr; | 2210 | leaf = blk->bp->b_addr; |
2211 | ents = xfs_dir3_leaf_ents_p(leaf); | 2211 | ents = xfs_dir3_leaf_ents_p(leaf); |
2212 | lep = &ents[blk->index]; | 2212 | lep = &ents[blk->index]; |
2213 | ASSERT(state->extravalid); | 2213 | ASSERT(state->extravalid); |
2214 | /* | 2214 | /* |
2215 | * Point to the data entry. | 2215 | * Point to the data entry. |
2216 | */ | 2216 | */ |
2217 | hdr = state->extrablk.bp->b_addr; | 2217 | hdr = state->extrablk.bp->b_addr; |
2218 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || | 2218 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || |
2219 | hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); | 2219 | hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); |
2220 | dep = (xfs_dir2_data_entry_t *) | 2220 | dep = (xfs_dir2_data_entry_t *) |
2221 | ((char *)hdr + | 2221 | ((char *)hdr + |
2222 | xfs_dir2_dataptr_to_off(state->mp, be32_to_cpu(lep->address))); | 2222 | xfs_dir2_dataptr_to_off(state->mp, be32_to_cpu(lep->address))); |
2223 | ASSERT(inum != be64_to_cpu(dep->inumber)); | 2223 | ASSERT(inum != be64_to_cpu(dep->inumber)); |
2224 | /* | 2224 | /* |
2225 | * Fill in the new inode number and log the entry. | 2225 | * Fill in the new inode number and log the entry. |
2226 | */ | 2226 | */ |
2227 | dep->inumber = cpu_to_be64(inum); | 2227 | dep->inumber = cpu_to_be64(inum); |
2228 | xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep); | 2228 | xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep); |
2229 | rval = 0; | 2229 | rval = 0; |
2230 | } | 2230 | } |
2231 | /* | 2231 | /* |
2232 | * Didn't find it, and we're holding a data block. Drop it. | 2232 | * Didn't find it, and we're holding a data block. Drop it. |
2233 | */ | 2233 | */ |
2234 | else if (state->extravalid) { | 2234 | else if (state->extravalid) { |
2235 | xfs_trans_brelse(args->trans, state->extrablk.bp); | 2235 | xfs_trans_brelse(args->trans, state->extrablk.bp); |
2236 | state->extrablk.bp = NULL; | 2236 | state->extrablk.bp = NULL; |
2237 | } | 2237 | } |
2238 | /* | 2238 | /* |
2239 | * Release all the buffers in the cursor. | 2239 | * Release all the buffers in the cursor. |
2240 | */ | 2240 | */ |
2241 | for (i = 0; i < state->path.active; i++) { | 2241 | for (i = 0; i < state->path.active; i++) { |
2242 | xfs_trans_brelse(args->trans, state->path.blk[i].bp); | 2242 | xfs_trans_brelse(args->trans, state->path.blk[i].bp); |
2243 | state->path.blk[i].bp = NULL; | 2243 | state->path.blk[i].bp = NULL; |
2244 | } | 2244 | } |
2245 | xfs_da_state_free(state); | 2245 | xfs_da_state_free(state); |
2246 | return rval; | 2246 | return rval; |
2247 | } | 2247 | } |
2248 | 2248 | ||
2249 | /* | 2249 | /* |
2250 | * Trim off a trailing empty freespace block. | 2250 | * Trim off a trailing empty freespace block. |
2251 | * Return (in rvalp) 1 if we did it, 0 if not. | 2251 | * Return (in rvalp) 1 if we did it, 0 if not. |
2252 | */ | 2252 | */ |
2253 | int /* error */ | 2253 | int /* error */ |
2254 | xfs_dir2_node_trim_free( | 2254 | xfs_dir2_node_trim_free( |
2255 | xfs_da_args_t *args, /* operation arguments */ | 2255 | xfs_da_args_t *args, /* operation arguments */ |
2256 | xfs_fileoff_t fo, /* free block number */ | 2256 | xfs_fileoff_t fo, /* free block number */ |
2257 | int *rvalp) /* out: did something */ | 2257 | int *rvalp) /* out: did something */ |
2258 | { | 2258 | { |
2259 | struct xfs_buf *bp; /* freespace buffer */ | 2259 | struct xfs_buf *bp; /* freespace buffer */ |
2260 | xfs_inode_t *dp; /* incore directory inode */ | 2260 | xfs_inode_t *dp; /* incore directory inode */ |
2261 | int error; /* error return code */ | 2261 | int error; /* error return code */ |
2262 | xfs_dir2_free_t *free; /* freespace structure */ | 2262 | xfs_dir2_free_t *free; /* freespace structure */ |
2263 | xfs_mount_t *mp; /* filesystem mount point */ | 2263 | xfs_mount_t *mp; /* filesystem mount point */ |
2264 | xfs_trans_t *tp; /* transaction pointer */ | 2264 | xfs_trans_t *tp; /* transaction pointer */ |
2265 | struct xfs_dir3_icfree_hdr freehdr; | 2265 | struct xfs_dir3_icfree_hdr freehdr; |
2266 | 2266 | ||
2267 | dp = args->dp; | 2267 | dp = args->dp; |
2268 | mp = dp->i_mount; | 2268 | mp = dp->i_mount; |
2269 | tp = args->trans; | 2269 | tp = args->trans; |
2270 | /* | 2270 | /* |
2271 | * Read the freespace block. | 2271 | * Read the freespace block. |
2272 | */ | 2272 | */ |
2273 | error = xfs_dir2_free_try_read(tp, dp, fo, &bp); | 2273 | error = xfs_dir2_free_try_read(tp, dp, fo, &bp); |
2274 | if (error) | 2274 | if (error) |
2275 | return error; | 2275 | return error; |
2276 | /* | 2276 | /* |
2277 | * There can be holes in freespace. If fo is a hole, there's | 2277 | * There can be holes in freespace. If fo is a hole, there's |
2278 | * nothing to do. | 2278 | * nothing to do. |
2279 | */ | 2279 | */ |
2280 | if (!bp) | 2280 | if (!bp) |
2281 | return 0; | 2281 | return 0; |
2282 | free = bp->b_addr; | 2282 | free = bp->b_addr; |
2283 | xfs_dir3_free_hdr_from_disk(&freehdr, free); | 2283 | xfs_dir3_free_hdr_from_disk(&freehdr, free); |
2284 | 2284 | ||
2285 | /* | 2285 | /* |
2286 | * If there are used entries, there's nothing to do. | 2286 | * If there are used entries, there's nothing to do. |
2287 | */ | 2287 | */ |
2288 | if (freehdr.nused > 0) { | 2288 | if (freehdr.nused > 0) { |
2289 | xfs_trans_brelse(tp, bp); | 2289 | xfs_trans_brelse(tp, bp); |
2290 | *rvalp = 0; | 2290 | *rvalp = 0; |
2291 | return 0; | 2291 | return 0; |
2292 | } | 2292 | } |
2293 | /* | 2293 | /* |
2294 | * Blow the block away. | 2294 | * Blow the block away. |
2295 | */ | 2295 | */ |
2296 | if ((error = | 2296 | if ((error = |
2297 | xfs_dir2_shrink_inode(args, xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo), | 2297 | xfs_dir2_shrink_inode(args, xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo), |
2298 | bp))) { | 2298 | bp))) { |
2299 | /* | 2299 | /* |
2300 | * Can't fail with ENOSPC since that only happens with no | 2300 | * Can't fail with ENOSPC since that only happens with no |
2301 | * space reservation, when breaking up an extent into two | 2301 | * space reservation, when breaking up an extent into two |
2302 | * pieces. This is the last block of an extent. | 2302 | * pieces. This is the last block of an extent. |
2303 | */ | 2303 | */ |
2304 | ASSERT(error != ENOSPC); | 2304 | ASSERT(error != ENOSPC); |
2305 | xfs_trans_brelse(tp, bp); | 2305 | xfs_trans_brelse(tp, bp); |
2306 | return error; | 2306 | return error; |
2307 | } | 2307 | } |
2308 | /* | 2308 | /* |
2309 | * Return that we succeeded. | 2309 | * Return that we succeeded. |
2310 | */ | 2310 | */ |
2311 | *rvalp = 1; | 2311 | *rvalp = 1; |
2312 | return 0; | 2312 | return 0; |
2313 | } | 2313 | } |
2314 | 2314 |
fs/xfs/xfs_ialloc_btree.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | 6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | * | 8 | * |
9 | * This program is distributed in the hope that it would be useful, | 9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | #include "xfs.h" | 18 | #include "xfs.h" |
19 | #include "xfs_fs.h" | 19 | #include "xfs_fs.h" |
20 | #include "xfs_types.h" | 20 | #include "xfs_types.h" |
21 | #include "xfs_bit.h" | 21 | #include "xfs_bit.h" |
22 | #include "xfs_log.h" | 22 | #include "xfs_log.h" |
23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
26 | #include "xfs_mount.h" | 26 | #include "xfs_mount.h" |
27 | #include "xfs_bmap_btree.h" | 27 | #include "xfs_bmap_btree.h" |
28 | #include "xfs_alloc_btree.h" | 28 | #include "xfs_alloc_btree.h" |
29 | #include "xfs_ialloc_btree.h" | 29 | #include "xfs_ialloc_btree.h" |
30 | #include "xfs_dinode.h" | 30 | #include "xfs_dinode.h" |
31 | #include "xfs_inode.h" | 31 | #include "xfs_inode.h" |
32 | #include "xfs_btree.h" | 32 | #include "xfs_btree.h" |
33 | #include "xfs_ialloc.h" | 33 | #include "xfs_ialloc.h" |
34 | #include "xfs_alloc.h" | 34 | #include "xfs_alloc.h" |
35 | #include "xfs_error.h" | 35 | #include "xfs_error.h" |
36 | #include "xfs_trace.h" | 36 | #include "xfs_trace.h" |
37 | #include "xfs_cksum.h" | 37 | #include "xfs_cksum.h" |
38 | 38 | ||
39 | 39 | ||
40 | STATIC int | 40 | STATIC int |
41 | xfs_inobt_get_minrecs( | 41 | xfs_inobt_get_minrecs( |
42 | struct xfs_btree_cur *cur, | 42 | struct xfs_btree_cur *cur, |
43 | int level) | 43 | int level) |
44 | { | 44 | { |
45 | return cur->bc_mp->m_inobt_mnr[level != 0]; | 45 | return cur->bc_mp->m_inobt_mnr[level != 0]; |
46 | } | 46 | } |
47 | 47 | ||
48 | STATIC struct xfs_btree_cur * | 48 | STATIC struct xfs_btree_cur * |
49 | xfs_inobt_dup_cursor( | 49 | xfs_inobt_dup_cursor( |
50 | struct xfs_btree_cur *cur) | 50 | struct xfs_btree_cur *cur) |
51 | { | 51 | { |
52 | return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp, | 52 | return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp, |
53 | cur->bc_private.a.agbp, cur->bc_private.a.agno); | 53 | cur->bc_private.a.agbp, cur->bc_private.a.agno); |
54 | } | 54 | } |
55 | 55 | ||
56 | STATIC void | 56 | STATIC void |
57 | xfs_inobt_set_root( | 57 | xfs_inobt_set_root( |
58 | struct xfs_btree_cur *cur, | 58 | struct xfs_btree_cur *cur, |
59 | union xfs_btree_ptr *nptr, | 59 | union xfs_btree_ptr *nptr, |
60 | int inc) /* level change */ | 60 | int inc) /* level change */ |
61 | { | 61 | { |
62 | struct xfs_buf *agbp = cur->bc_private.a.agbp; | 62 | struct xfs_buf *agbp = cur->bc_private.a.agbp; |
63 | struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); | 63 | struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); |
64 | 64 | ||
65 | agi->agi_root = nptr->s; | 65 | agi->agi_root = nptr->s; |
66 | be32_add_cpu(&agi->agi_level, inc); | 66 | be32_add_cpu(&agi->agi_level, inc); |
67 | xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL); | 67 | xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL); |
68 | } | 68 | } |
69 | 69 | ||
70 | STATIC int | 70 | STATIC int |
71 | xfs_inobt_alloc_block( | 71 | xfs_inobt_alloc_block( |
72 | struct xfs_btree_cur *cur, | 72 | struct xfs_btree_cur *cur, |
73 | union xfs_btree_ptr *start, | 73 | union xfs_btree_ptr *start, |
74 | union xfs_btree_ptr *new, | 74 | union xfs_btree_ptr *new, |
75 | int length, | 75 | int length, |
76 | int *stat) | 76 | int *stat) |
77 | { | 77 | { |
78 | xfs_alloc_arg_t args; /* block allocation args */ | 78 | xfs_alloc_arg_t args; /* block allocation args */ |
79 | int error; /* error return value */ | 79 | int error; /* error return value */ |
80 | xfs_agblock_t sbno = be32_to_cpu(start->s); | 80 | xfs_agblock_t sbno = be32_to_cpu(start->s); |
81 | 81 | ||
82 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); | 82 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); |
83 | 83 | ||
84 | memset(&args, 0, sizeof(args)); | 84 | memset(&args, 0, sizeof(args)); |
85 | args.tp = cur->bc_tp; | 85 | args.tp = cur->bc_tp; |
86 | args.mp = cur->bc_mp; | 86 | args.mp = cur->bc_mp; |
87 | args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, sbno); | 87 | args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, sbno); |
88 | args.minlen = 1; | 88 | args.minlen = 1; |
89 | args.maxlen = 1; | 89 | args.maxlen = 1; |
90 | args.prod = 1; | 90 | args.prod = 1; |
91 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 91 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
92 | 92 | ||
93 | error = xfs_alloc_vextent(&args); | 93 | error = xfs_alloc_vextent(&args); |
94 | if (error) { | 94 | if (error) { |
95 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | 95 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); |
96 | return error; | 96 | return error; |
97 | } | 97 | } |
98 | if (args.fsbno == NULLFSBLOCK) { | 98 | if (args.fsbno == NULLFSBLOCK) { |
99 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | 99 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); |
100 | *stat = 0; | 100 | *stat = 0; |
101 | return 0; | 101 | return 0; |
102 | } | 102 | } |
103 | ASSERT(args.len == 1); | 103 | ASSERT(args.len == 1); |
104 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | 104 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); |
105 | 105 | ||
106 | new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno)); | 106 | new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno)); |
107 | *stat = 1; | 107 | *stat = 1; |
108 | return 0; | 108 | return 0; |
109 | } | 109 | } |
110 | 110 | ||
111 | STATIC int | 111 | STATIC int |
112 | xfs_inobt_free_block( | 112 | xfs_inobt_free_block( |
113 | struct xfs_btree_cur *cur, | 113 | struct xfs_btree_cur *cur, |
114 | struct xfs_buf *bp) | 114 | struct xfs_buf *bp) |
115 | { | 115 | { |
116 | xfs_fsblock_t fsbno; | 116 | xfs_fsblock_t fsbno; |
117 | int error; | 117 | int error; |
118 | 118 | ||
119 | fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp)); | 119 | fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp)); |
120 | error = xfs_free_extent(cur->bc_tp, fsbno, 1); | 120 | error = xfs_free_extent(cur->bc_tp, fsbno, 1); |
121 | if (error) | 121 | if (error) |
122 | return error; | 122 | return error; |
123 | 123 | ||
124 | xfs_trans_binval(cur->bc_tp, bp); | 124 | xfs_trans_binval(cur->bc_tp, bp); |
125 | return error; | 125 | return error; |
126 | } | 126 | } |
127 | 127 | ||
128 | STATIC int | 128 | STATIC int |
129 | xfs_inobt_get_maxrecs( | 129 | xfs_inobt_get_maxrecs( |
130 | struct xfs_btree_cur *cur, | 130 | struct xfs_btree_cur *cur, |
131 | int level) | 131 | int level) |
132 | { | 132 | { |
133 | return cur->bc_mp->m_inobt_mxr[level != 0]; | 133 | return cur->bc_mp->m_inobt_mxr[level != 0]; |
134 | } | 134 | } |
135 | 135 | ||
136 | STATIC void | 136 | STATIC void |
137 | xfs_inobt_init_key_from_rec( | 137 | xfs_inobt_init_key_from_rec( |
138 | union xfs_btree_key *key, | 138 | union xfs_btree_key *key, |
139 | union xfs_btree_rec *rec) | 139 | union xfs_btree_rec *rec) |
140 | { | 140 | { |
141 | key->inobt.ir_startino = rec->inobt.ir_startino; | 141 | key->inobt.ir_startino = rec->inobt.ir_startino; |
142 | } | 142 | } |
143 | 143 | ||
144 | STATIC void | 144 | STATIC void |
145 | xfs_inobt_init_rec_from_key( | 145 | xfs_inobt_init_rec_from_key( |
146 | union xfs_btree_key *key, | 146 | union xfs_btree_key *key, |
147 | union xfs_btree_rec *rec) | 147 | union xfs_btree_rec *rec) |
148 | { | 148 | { |
149 | rec->inobt.ir_startino = key->inobt.ir_startino; | 149 | rec->inobt.ir_startino = key->inobt.ir_startino; |
150 | } | 150 | } |
151 | 151 | ||
152 | STATIC void | 152 | STATIC void |
153 | xfs_inobt_init_rec_from_cur( | 153 | xfs_inobt_init_rec_from_cur( |
154 | struct xfs_btree_cur *cur, | 154 | struct xfs_btree_cur *cur, |
155 | union xfs_btree_rec *rec) | 155 | union xfs_btree_rec *rec) |
156 | { | 156 | { |
157 | rec->inobt.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino); | 157 | rec->inobt.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino); |
158 | rec->inobt.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount); | 158 | rec->inobt.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount); |
159 | rec->inobt.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free); | 159 | rec->inobt.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free); |
160 | } | 160 | } |
161 | 161 | ||
162 | /* | 162 | /* |
163 | * initial value of ptr for lookup | 163 | * initial value of ptr for lookup |
164 | */ | 164 | */ |
165 | STATIC void | 165 | STATIC void |
166 | xfs_inobt_init_ptr_from_cur( | 166 | xfs_inobt_init_ptr_from_cur( |
167 | struct xfs_btree_cur *cur, | 167 | struct xfs_btree_cur *cur, |
168 | union xfs_btree_ptr *ptr) | 168 | union xfs_btree_ptr *ptr) |
169 | { | 169 | { |
170 | struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); | 170 | struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); |
171 | 171 | ||
172 | ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno)); | 172 | ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno)); |
173 | 173 | ||
174 | ptr->s = agi->agi_root; | 174 | ptr->s = agi->agi_root; |
175 | } | 175 | } |
176 | 176 | ||
177 | STATIC __int64_t | 177 | STATIC __int64_t |
178 | xfs_inobt_key_diff( | 178 | xfs_inobt_key_diff( |
179 | struct xfs_btree_cur *cur, | 179 | struct xfs_btree_cur *cur, |
180 | union xfs_btree_key *key) | 180 | union xfs_btree_key *key) |
181 | { | 181 | { |
182 | return (__int64_t)be32_to_cpu(key->inobt.ir_startino) - | 182 | return (__int64_t)be32_to_cpu(key->inobt.ir_startino) - |
183 | cur->bc_rec.i.ir_startino; | 183 | cur->bc_rec.i.ir_startino; |
184 | } | 184 | } |
185 | 185 | ||
186 | static int | 186 | static int |
187 | xfs_inobt_verify( | 187 | xfs_inobt_verify( |
188 | struct xfs_buf *bp) | 188 | struct xfs_buf *bp) |
189 | { | 189 | { |
190 | struct xfs_mount *mp = bp->b_target->bt_mount; | 190 | struct xfs_mount *mp = bp->b_target->bt_mount; |
191 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); | 191 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); |
192 | struct xfs_perag *pag = bp->b_pag; | 192 | struct xfs_perag *pag = bp->b_pag; |
193 | unsigned int level; | 193 | unsigned int level; |
194 | 194 | ||
195 | /* | 195 | /* |
196 | * During growfs operations, we can't verify the exact owner as the | 196 | * During growfs operations, we can't verify the exact owner as the |
197 | * perag is not fully initialised and hence not attached to the buffer. | 197 | * perag is not fully initialised and hence not attached to the buffer. |
198 | * | 198 | * |
199 | * Similarly, during log recovery we will have a perag structure | 199 | * Similarly, during log recovery we will have a perag structure |
200 | * attached, but the agi information will not yet have been initialised | 200 | * attached, but the agi information will not yet have been initialised |
201 | * from the on disk AGI. We don't currently use any of this information, | 201 | * from the on disk AGI. We don't currently use any of this information, |
202 | * but beware of the landmine (i.e. need to check pag->pagi_init) if we | 202 | * but beware of the landmine (i.e. need to check pag->pagi_init) if we |
203 | * ever do. | 203 | * ever do. |
204 | */ | 204 | */ |
205 | switch (block->bb_magic) { | 205 | switch (block->bb_magic) { |
206 | case cpu_to_be32(XFS_IBT_CRC_MAGIC): | 206 | case cpu_to_be32(XFS_IBT_CRC_MAGIC): |
207 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | 207 | if (!xfs_sb_version_hascrc(&mp->m_sb)) |
208 | return false; | 208 | return false; |
209 | if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid)) | 209 | if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid)) |
210 | return false; | 210 | return false; |
211 | if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) | 211 | if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) |
212 | return false; | 212 | return false; |
213 | if (pag && | 213 | if (pag && |
214 | be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) | 214 | be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) |
215 | return false; | 215 | return false; |
216 | /* fall through */ | 216 | /* fall through */ |
217 | case cpu_to_be32(XFS_IBT_MAGIC): | 217 | case cpu_to_be32(XFS_IBT_MAGIC): |
218 | break; | 218 | break; |
219 | default: | 219 | default: |
220 | return 0; | 220 | return 0; |
221 | } | 221 | } |
222 | 222 | ||
223 | /* numrecs and level verification */ | 223 | /* numrecs and level verification */ |
224 | level = be16_to_cpu(block->bb_level); | 224 | level = be16_to_cpu(block->bb_level); |
225 | if (level >= mp->m_in_maxlevels) | 225 | if (level >= mp->m_in_maxlevels) |
226 | return false; | 226 | return false; |
227 | if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[level != 0]) | 227 | if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[level != 0]) |
228 | return false; | 228 | return false; |
229 | 229 | ||
230 | /* sibling pointer verification */ | 230 | /* sibling pointer verification */ |
231 | if (!block->bb_u.s.bb_leftsib || | 231 | if (!block->bb_u.s.bb_leftsib || |
232 | (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks && | 232 | (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks && |
233 | block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK))) | 233 | block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK))) |
234 | return false; | 234 | return false; |
235 | if (!block->bb_u.s.bb_rightsib || | 235 | if (!block->bb_u.s.bb_rightsib || |
236 | (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks && | 236 | (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks && |
237 | block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK))) | 237 | block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK))) |
238 | return false; | 238 | return false; |
239 | 239 | ||
240 | return true; | 240 | return true; |
241 | } | 241 | } |
242 | 242 | ||
243 | static void | 243 | static void |
244 | xfs_inobt_read_verify( | 244 | xfs_inobt_read_verify( |
245 | struct xfs_buf *bp) | 245 | struct xfs_buf *bp) |
246 | { | 246 | { |
247 | if (!(xfs_btree_sblock_verify_crc(bp) && | 247 | if (!(xfs_btree_sblock_verify_crc(bp) && |
248 | xfs_inobt_verify(bp))) { | 248 | xfs_inobt_verify(bp))) { |
249 | trace_xfs_btree_corrupt(bp, _RET_IP_); | 249 | trace_xfs_btree_corrupt(bp, _RET_IP_); |
250 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, | 250 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, |
251 | bp->b_target->bt_mount, bp->b_addr); | 251 | bp->b_target->bt_mount, bp->b_addr); |
252 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 252 | xfs_buf_ioerror(bp, EFSCORRUPTED); |
253 | } | 253 | } |
254 | } | 254 | } |
255 | 255 | ||
256 | static void | 256 | static void |
257 | xfs_inobt_write_verify( | 257 | xfs_inobt_write_verify( |
258 | struct xfs_buf *bp) | 258 | struct xfs_buf *bp) |
259 | { | 259 | { |
260 | if (!xfs_inobt_verify(bp)) { | 260 | if (!xfs_inobt_verify(bp)) { |
261 | trace_xfs_btree_corrupt(bp, _RET_IP_); | 261 | trace_xfs_btree_corrupt(bp, _RET_IP_); |
262 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, | 262 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, |
263 | bp->b_target->bt_mount, bp->b_addr); | 263 | bp->b_target->bt_mount, bp->b_addr); |
264 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 264 | xfs_buf_ioerror(bp, EFSCORRUPTED); |
265 | } | 265 | } |
266 | xfs_btree_sblock_calc_crc(bp); | 266 | xfs_btree_sblock_calc_crc(bp); |
267 | 267 | ||
268 | } | 268 | } |
269 | 269 | ||
270 | const struct xfs_buf_ops xfs_inobt_buf_ops = { | 270 | const struct xfs_buf_ops xfs_inobt_buf_ops = { |
271 | .verify_read = xfs_inobt_read_verify, | 271 | .verify_read = xfs_inobt_read_verify, |
272 | .verify_write = xfs_inobt_write_verify, | 272 | .verify_write = xfs_inobt_write_verify, |
273 | }; | 273 | }; |
274 | 274 | ||
275 | #ifdef DEBUG | 275 | #if defined(DEBUG) || defined(XFS_WARN) |
276 | STATIC int | 276 | STATIC int |
277 | xfs_inobt_keys_inorder( | 277 | xfs_inobt_keys_inorder( |
278 | struct xfs_btree_cur *cur, | 278 | struct xfs_btree_cur *cur, |
279 | union xfs_btree_key *k1, | 279 | union xfs_btree_key *k1, |
280 | union xfs_btree_key *k2) | 280 | union xfs_btree_key *k2) |
281 | { | 281 | { |
282 | return be32_to_cpu(k1->inobt.ir_startino) < | 282 | return be32_to_cpu(k1->inobt.ir_startino) < |
283 | be32_to_cpu(k2->inobt.ir_startino); | 283 | be32_to_cpu(k2->inobt.ir_startino); |
284 | } | 284 | } |
285 | 285 | ||
286 | STATIC int | 286 | STATIC int |
287 | xfs_inobt_recs_inorder( | 287 | xfs_inobt_recs_inorder( |
288 | struct xfs_btree_cur *cur, | 288 | struct xfs_btree_cur *cur, |
289 | union xfs_btree_rec *r1, | 289 | union xfs_btree_rec *r1, |
290 | union xfs_btree_rec *r2) | 290 | union xfs_btree_rec *r2) |
291 | { | 291 | { |
292 | return be32_to_cpu(r1->inobt.ir_startino) + XFS_INODES_PER_CHUNK <= | 292 | return be32_to_cpu(r1->inobt.ir_startino) + XFS_INODES_PER_CHUNK <= |
293 | be32_to_cpu(r2->inobt.ir_startino); | 293 | be32_to_cpu(r2->inobt.ir_startino); |
294 | } | 294 | } |
295 | #endif /* DEBUG */ | 295 | #endif /* DEBUG */ |
296 | 296 | ||
297 | static const struct xfs_btree_ops xfs_inobt_ops = { | 297 | static const struct xfs_btree_ops xfs_inobt_ops = { |
298 | .rec_len = sizeof(xfs_inobt_rec_t), | 298 | .rec_len = sizeof(xfs_inobt_rec_t), |
299 | .key_len = sizeof(xfs_inobt_key_t), | 299 | .key_len = sizeof(xfs_inobt_key_t), |
300 | 300 | ||
301 | .dup_cursor = xfs_inobt_dup_cursor, | 301 | .dup_cursor = xfs_inobt_dup_cursor, |
302 | .set_root = xfs_inobt_set_root, | 302 | .set_root = xfs_inobt_set_root, |
303 | .alloc_block = xfs_inobt_alloc_block, | 303 | .alloc_block = xfs_inobt_alloc_block, |
304 | .free_block = xfs_inobt_free_block, | 304 | .free_block = xfs_inobt_free_block, |
305 | .get_minrecs = xfs_inobt_get_minrecs, | 305 | .get_minrecs = xfs_inobt_get_minrecs, |
306 | .get_maxrecs = xfs_inobt_get_maxrecs, | 306 | .get_maxrecs = xfs_inobt_get_maxrecs, |
307 | .init_key_from_rec = xfs_inobt_init_key_from_rec, | 307 | .init_key_from_rec = xfs_inobt_init_key_from_rec, |
308 | .init_rec_from_key = xfs_inobt_init_rec_from_key, | 308 | .init_rec_from_key = xfs_inobt_init_rec_from_key, |
309 | .init_rec_from_cur = xfs_inobt_init_rec_from_cur, | 309 | .init_rec_from_cur = xfs_inobt_init_rec_from_cur, |
310 | .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, | 310 | .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, |
311 | .key_diff = xfs_inobt_key_diff, | 311 | .key_diff = xfs_inobt_key_diff, |
312 | .buf_ops = &xfs_inobt_buf_ops, | 312 | .buf_ops = &xfs_inobt_buf_ops, |
313 | #ifdef DEBUG | 313 | #if defined(DEBUG) || defined(XFS_WARN) |
314 | .keys_inorder = xfs_inobt_keys_inorder, | 314 | .keys_inorder = xfs_inobt_keys_inorder, |
315 | .recs_inorder = xfs_inobt_recs_inorder, | 315 | .recs_inorder = xfs_inobt_recs_inorder, |
316 | #endif | 316 | #endif |
317 | }; | 317 | }; |
318 | 318 | ||
319 | /* | 319 | /* |
320 | * Allocate a new inode btree cursor. | 320 | * Allocate a new inode btree cursor. |
321 | */ | 321 | */ |
322 | struct xfs_btree_cur * /* new inode btree cursor */ | 322 | struct xfs_btree_cur * /* new inode btree cursor */ |
323 | xfs_inobt_init_cursor( | 323 | xfs_inobt_init_cursor( |
324 | struct xfs_mount *mp, /* file system mount point */ | 324 | struct xfs_mount *mp, /* file system mount point */ |
325 | struct xfs_trans *tp, /* transaction pointer */ | 325 | struct xfs_trans *tp, /* transaction pointer */ |
326 | struct xfs_buf *agbp, /* buffer for agi structure */ | 326 | struct xfs_buf *agbp, /* buffer for agi structure */ |
327 | xfs_agnumber_t agno) /* allocation group number */ | 327 | xfs_agnumber_t agno) /* allocation group number */ |
328 | { | 328 | { |
329 | struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); | 329 | struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); |
330 | struct xfs_btree_cur *cur; | 330 | struct xfs_btree_cur *cur; |
331 | 331 | ||
332 | cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); | 332 | cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); |
333 | 333 | ||
334 | cur->bc_tp = tp; | 334 | cur->bc_tp = tp; |
335 | cur->bc_mp = mp; | 335 | cur->bc_mp = mp; |
336 | cur->bc_nlevels = be32_to_cpu(agi->agi_level); | 336 | cur->bc_nlevels = be32_to_cpu(agi->agi_level); |
337 | cur->bc_btnum = XFS_BTNUM_INO; | 337 | cur->bc_btnum = XFS_BTNUM_INO; |
338 | cur->bc_blocklog = mp->m_sb.sb_blocklog; | 338 | cur->bc_blocklog = mp->m_sb.sb_blocklog; |
339 | 339 | ||
340 | cur->bc_ops = &xfs_inobt_ops; | 340 | cur->bc_ops = &xfs_inobt_ops; |
341 | if (xfs_sb_version_hascrc(&mp->m_sb)) | 341 | if (xfs_sb_version_hascrc(&mp->m_sb)) |
342 | cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; | 342 | cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; |
343 | 343 | ||
344 | cur->bc_private.a.agbp = agbp; | 344 | cur->bc_private.a.agbp = agbp; |
345 | cur->bc_private.a.agno = agno; | 345 | cur->bc_private.a.agno = agno; |
346 | 346 | ||
347 | return cur; | 347 | return cur; |
348 | } | 348 | } |
349 | 349 | ||
350 | /* | 350 | /* |
351 | * Calculate number of records in an inobt btree block. | 351 | * Calculate number of records in an inobt btree block. |
352 | */ | 352 | */ |
353 | int | 353 | int |
354 | xfs_inobt_maxrecs( | 354 | xfs_inobt_maxrecs( |
355 | struct xfs_mount *mp, | 355 | struct xfs_mount *mp, |
356 | int blocklen, | 356 | int blocklen, |
357 | int leaf) | 357 | int leaf) |
358 | { | 358 | { |
359 | blocklen -= XFS_INOBT_BLOCK_LEN(mp); | 359 | blocklen -= XFS_INOBT_BLOCK_LEN(mp); |
360 | 360 | ||
361 | if (leaf) | 361 | if (leaf) |
362 | return blocklen / sizeof(xfs_inobt_rec_t); | 362 | return blocklen / sizeof(xfs_inobt_rec_t); |
363 | return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t)); | 363 | return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t)); |
364 | } | 364 | } |
365 | 365 |
fs/xfs/xfs_inode.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | 6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | * | 8 | * |
9 | * This program is distributed in the hope that it would be useful, | 9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | #include <linux/log2.h> | 18 | #include <linux/log2.h> |
19 | 19 | ||
20 | #include "xfs.h" | 20 | #include "xfs.h" |
21 | #include "xfs_fs.h" | 21 | #include "xfs_fs.h" |
22 | #include "xfs_types.h" | 22 | #include "xfs_types.h" |
23 | #include "xfs_log.h" | 23 | #include "xfs_log.h" |
24 | #include "xfs_inum.h" | 24 | #include "xfs_inum.h" |
25 | #include "xfs_trans.h" | 25 | #include "xfs_trans.h" |
26 | #include "xfs_trans_priv.h" | 26 | #include "xfs_trans_priv.h" |
27 | #include "xfs_sb.h" | 27 | #include "xfs_sb.h" |
28 | #include "xfs_ag.h" | 28 | #include "xfs_ag.h" |
29 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
30 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
31 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
32 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
33 | #include "xfs_attr_sf.h" | 33 | #include "xfs_attr_sf.h" |
34 | #include "xfs_dinode.h" | 34 | #include "xfs_dinode.h" |
35 | #include "xfs_inode.h" | 35 | #include "xfs_inode.h" |
36 | #include "xfs_buf_item.h" | 36 | #include "xfs_buf_item.h" |
37 | #include "xfs_inode_item.h" | 37 | #include "xfs_inode_item.h" |
38 | #include "xfs_btree.h" | 38 | #include "xfs_btree.h" |
39 | #include "xfs_alloc.h" | 39 | #include "xfs_alloc.h" |
40 | #include "xfs_ialloc.h" | 40 | #include "xfs_ialloc.h" |
41 | #include "xfs_bmap.h" | 41 | #include "xfs_bmap.h" |
42 | #include "xfs_error.h" | 42 | #include "xfs_error.h" |
43 | #include "xfs_utils.h" | 43 | #include "xfs_utils.h" |
44 | #include "xfs_quota.h" | 44 | #include "xfs_quota.h" |
45 | #include "xfs_filestream.h" | 45 | #include "xfs_filestream.h" |
46 | #include "xfs_vnodeops.h" | 46 | #include "xfs_vnodeops.h" |
47 | #include "xfs_cksum.h" | 47 | #include "xfs_cksum.h" |
48 | #include "xfs_trace.h" | 48 | #include "xfs_trace.h" |
49 | #include "xfs_icache.h" | 49 | #include "xfs_icache.h" |
50 | 50 | ||
51 | kmem_zone_t *xfs_ifork_zone; | 51 | kmem_zone_t *xfs_ifork_zone; |
52 | kmem_zone_t *xfs_inode_zone; | 52 | kmem_zone_t *xfs_inode_zone; |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * Used in xfs_itruncate_extents(). This is the maximum number of extents | 55 | * Used in xfs_itruncate_extents(). This is the maximum number of extents |
56 | * freed from a file in a single transaction. | 56 | * freed from a file in a single transaction. |
57 | */ | 57 | */ |
58 | #define XFS_ITRUNC_MAX_EXTENTS 2 | 58 | #define XFS_ITRUNC_MAX_EXTENTS 2 |
59 | 59 | ||
60 | STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *); | 60 | STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *); |
61 | STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int); | 61 | STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int); |
62 | STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int); | 62 | STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int); |
63 | STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int); | 63 | STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int); |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * helper function to extract extent size hint from inode | 66 | * helper function to extract extent size hint from inode |
67 | */ | 67 | */ |
68 | xfs_extlen_t | 68 | xfs_extlen_t |
69 | xfs_get_extsz_hint( | 69 | xfs_get_extsz_hint( |
70 | struct xfs_inode *ip) | 70 | struct xfs_inode *ip) |
71 | { | 71 | { |
72 | if ((ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) && ip->i_d.di_extsize) | 72 | if ((ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) && ip->i_d.di_extsize) |
73 | return ip->i_d.di_extsize; | 73 | return ip->i_d.di_extsize; |
74 | if (XFS_IS_REALTIME_INODE(ip)) | 74 | if (XFS_IS_REALTIME_INODE(ip)) |
75 | return ip->i_mount->m_sb.sb_rextsize; | 75 | return ip->i_mount->m_sb.sb_rextsize; |
76 | return 0; | 76 | return 0; |
77 | } | 77 | } |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * This is a wrapper routine around the xfs_ilock() routine used to centralize | 80 | * This is a wrapper routine around the xfs_ilock() routine used to centralize |
81 | * some grungy code. It is used in places that wish to lock the inode solely | 81 | * some grungy code. It is used in places that wish to lock the inode solely |
82 | * for reading the extents. The reason these places can't just call | 82 | * for reading the extents. The reason these places can't just call |
83 | * xfs_ilock(SHARED) is that the inode lock also guards to bringing in of the | 83 | * xfs_ilock(SHARED) is that the inode lock also guards to bringing in of the |
84 | * extents from disk for a file in b-tree format. If the inode is in b-tree | 84 | * extents from disk for a file in b-tree format. If the inode is in b-tree |
85 | * format, then we need to lock the inode exclusively until the extents are read | 85 | * format, then we need to lock the inode exclusively until the extents are read |
86 | * in. Locking it exclusively all the time would limit our parallelism | 86 | * in. Locking it exclusively all the time would limit our parallelism |
87 | * unnecessarily, though. What we do instead is check to see if the extents | 87 | * unnecessarily, though. What we do instead is check to see if the extents |
88 | * have been read in yet, and only lock the inode exclusively if they have not. | 88 | * have been read in yet, and only lock the inode exclusively if they have not. |
89 | * | 89 | * |
90 | * The function returns a value which should be given to the corresponding | 90 | * The function returns a value which should be given to the corresponding |
91 | * xfs_iunlock_map_shared(). This value is the mode in which the lock was | 91 | * xfs_iunlock_map_shared(). This value is the mode in which the lock was |
92 | * actually taken. | 92 | * actually taken. |
93 | */ | 93 | */ |
94 | uint | 94 | uint |
95 | xfs_ilock_map_shared( | 95 | xfs_ilock_map_shared( |
96 | xfs_inode_t *ip) | 96 | xfs_inode_t *ip) |
97 | { | 97 | { |
98 | uint lock_mode; | 98 | uint lock_mode; |
99 | 99 | ||
100 | if ((ip->i_d.di_format == XFS_DINODE_FMT_BTREE) && | 100 | if ((ip->i_d.di_format == XFS_DINODE_FMT_BTREE) && |
101 | ((ip->i_df.if_flags & XFS_IFEXTENTS) == 0)) { | 101 | ((ip->i_df.if_flags & XFS_IFEXTENTS) == 0)) { |
102 | lock_mode = XFS_ILOCK_EXCL; | 102 | lock_mode = XFS_ILOCK_EXCL; |
103 | } else { | 103 | } else { |
104 | lock_mode = XFS_ILOCK_SHARED; | 104 | lock_mode = XFS_ILOCK_SHARED; |
105 | } | 105 | } |
106 | 106 | ||
107 | xfs_ilock(ip, lock_mode); | 107 | xfs_ilock(ip, lock_mode); |
108 | 108 | ||
109 | return lock_mode; | 109 | return lock_mode; |
110 | } | 110 | } |
111 | 111 | ||
112 | /* | 112 | /* |
113 | * This is simply the unlock routine to go with xfs_ilock_map_shared(). | 113 | * This is simply the unlock routine to go with xfs_ilock_map_shared(). |
114 | * All it does is call xfs_iunlock() with the given lock_mode. | 114 | * All it does is call xfs_iunlock() with the given lock_mode. |
115 | */ | 115 | */ |
116 | void | 116 | void |
117 | xfs_iunlock_map_shared( | 117 | xfs_iunlock_map_shared( |
118 | xfs_inode_t *ip, | 118 | xfs_inode_t *ip, |
119 | unsigned int lock_mode) | 119 | unsigned int lock_mode) |
120 | { | 120 | { |
121 | xfs_iunlock(ip, lock_mode); | 121 | xfs_iunlock(ip, lock_mode); |
122 | } | 122 | } |
123 | 123 | ||
124 | /* | 124 | /* |
125 | * The xfs inode contains 2 locks: a multi-reader lock called the | 125 | * The xfs inode contains 2 locks: a multi-reader lock called the |
126 | * i_iolock and a multi-reader lock called the i_lock. This routine | 126 | * i_iolock and a multi-reader lock called the i_lock. This routine |
127 | * allows either or both of the locks to be obtained. | 127 | * allows either or both of the locks to be obtained. |
128 | * | 128 | * |
129 | * The 2 locks should always be ordered so that the IO lock is | 129 | * The 2 locks should always be ordered so that the IO lock is |
130 | * obtained first in order to prevent deadlock. | 130 | * obtained first in order to prevent deadlock. |
131 | * | 131 | * |
132 | * ip -- the inode being locked | 132 | * ip -- the inode being locked |
133 | * lock_flags -- this parameter indicates the inode's locks | 133 | * lock_flags -- this parameter indicates the inode's locks |
134 | * to be locked. It can be: | 134 | * to be locked. It can be: |
135 | * XFS_IOLOCK_SHARED, | 135 | * XFS_IOLOCK_SHARED, |
136 | * XFS_IOLOCK_EXCL, | 136 | * XFS_IOLOCK_EXCL, |
137 | * XFS_ILOCK_SHARED, | 137 | * XFS_ILOCK_SHARED, |
138 | * XFS_ILOCK_EXCL, | 138 | * XFS_ILOCK_EXCL, |
139 | * XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED, | 139 | * XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED, |
140 | * XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL, | 140 | * XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL, |
141 | * XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED, | 141 | * XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED, |
142 | * XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL | 142 | * XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL |
143 | */ | 143 | */ |
144 | void | 144 | void |
145 | xfs_ilock( | 145 | xfs_ilock( |
146 | xfs_inode_t *ip, | 146 | xfs_inode_t *ip, |
147 | uint lock_flags) | 147 | uint lock_flags) |
148 | { | 148 | { |
149 | trace_xfs_ilock(ip, lock_flags, _RET_IP_); | 149 | trace_xfs_ilock(ip, lock_flags, _RET_IP_); |
150 | 150 | ||
151 | /* | 151 | /* |
152 | * You can't set both SHARED and EXCL for the same lock, | 152 | * You can't set both SHARED and EXCL for the same lock, |
153 | * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, | 153 | * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, |
154 | * and XFS_ILOCK_EXCL are valid values to set in lock_flags. | 154 | * and XFS_ILOCK_EXCL are valid values to set in lock_flags. |
155 | */ | 155 | */ |
156 | ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != | 156 | ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != |
157 | (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); | 157 | (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); |
158 | ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != | 158 | ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != |
159 | (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); | 159 | (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); |
160 | ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0); | 160 | ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0); |
161 | 161 | ||
162 | if (lock_flags & XFS_IOLOCK_EXCL) | 162 | if (lock_flags & XFS_IOLOCK_EXCL) |
163 | mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags)); | 163 | mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags)); |
164 | else if (lock_flags & XFS_IOLOCK_SHARED) | 164 | else if (lock_flags & XFS_IOLOCK_SHARED) |
165 | mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags)); | 165 | mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags)); |
166 | 166 | ||
167 | if (lock_flags & XFS_ILOCK_EXCL) | 167 | if (lock_flags & XFS_ILOCK_EXCL) |
168 | mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags)); | 168 | mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags)); |
169 | else if (lock_flags & XFS_ILOCK_SHARED) | 169 | else if (lock_flags & XFS_ILOCK_SHARED) |
170 | mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags)); | 170 | mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags)); |
171 | } | 171 | } |
172 | 172 | ||
173 | /* | 173 | /* |
174 | * This is just like xfs_ilock(), except that the caller | 174 | * This is just like xfs_ilock(), except that the caller |
175 | * is guaranteed not to sleep. It returns 1 if it gets | 175 | * is guaranteed not to sleep. It returns 1 if it gets |
176 | * the requested locks and 0 otherwise. If the IO lock is | 176 | * the requested locks and 0 otherwise. If the IO lock is |
177 | * obtained but the inode lock cannot be, then the IO lock | 177 | * obtained but the inode lock cannot be, then the IO lock |
178 | * is dropped before returning. | 178 | * is dropped before returning. |
179 | * | 179 | * |
180 | * ip -- the inode being locked | 180 | * ip -- the inode being locked |
181 | * lock_flags -- this parameter indicates the inode's locks to be | 181 | * lock_flags -- this parameter indicates the inode's locks to be |
182 | * to be locked. See the comment for xfs_ilock() for a list | 182 | * to be locked. See the comment for xfs_ilock() for a list |
183 | * of valid values. | 183 | * of valid values. |
184 | */ | 184 | */ |
185 | int | 185 | int |
186 | xfs_ilock_nowait( | 186 | xfs_ilock_nowait( |
187 | xfs_inode_t *ip, | 187 | xfs_inode_t *ip, |
188 | uint lock_flags) | 188 | uint lock_flags) |
189 | { | 189 | { |
190 | trace_xfs_ilock_nowait(ip, lock_flags, _RET_IP_); | 190 | trace_xfs_ilock_nowait(ip, lock_flags, _RET_IP_); |
191 | 191 | ||
192 | /* | 192 | /* |
193 | * You can't set both SHARED and EXCL for the same lock, | 193 | * You can't set both SHARED and EXCL for the same lock, |
194 | * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, | 194 | * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, |
195 | * and XFS_ILOCK_EXCL are valid values to set in lock_flags. | 195 | * and XFS_ILOCK_EXCL are valid values to set in lock_flags. |
196 | */ | 196 | */ |
197 | ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != | 197 | ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != |
198 | (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); | 198 | (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); |
199 | ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != | 199 | ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != |
200 | (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); | 200 | (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); |
201 | ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0); | 201 | ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0); |
202 | 202 | ||
203 | if (lock_flags & XFS_IOLOCK_EXCL) { | 203 | if (lock_flags & XFS_IOLOCK_EXCL) { |
204 | if (!mrtryupdate(&ip->i_iolock)) | 204 | if (!mrtryupdate(&ip->i_iolock)) |
205 | goto out; | 205 | goto out; |
206 | } else if (lock_flags & XFS_IOLOCK_SHARED) { | 206 | } else if (lock_flags & XFS_IOLOCK_SHARED) { |
207 | if (!mrtryaccess(&ip->i_iolock)) | 207 | if (!mrtryaccess(&ip->i_iolock)) |
208 | goto out; | 208 | goto out; |
209 | } | 209 | } |
210 | if (lock_flags & XFS_ILOCK_EXCL) { | 210 | if (lock_flags & XFS_ILOCK_EXCL) { |
211 | if (!mrtryupdate(&ip->i_lock)) | 211 | if (!mrtryupdate(&ip->i_lock)) |
212 | goto out_undo_iolock; | 212 | goto out_undo_iolock; |
213 | } else if (lock_flags & XFS_ILOCK_SHARED) { | 213 | } else if (lock_flags & XFS_ILOCK_SHARED) { |
214 | if (!mrtryaccess(&ip->i_lock)) | 214 | if (!mrtryaccess(&ip->i_lock)) |
215 | goto out_undo_iolock; | 215 | goto out_undo_iolock; |
216 | } | 216 | } |
217 | return 1; | 217 | return 1; |
218 | 218 | ||
219 | out_undo_iolock: | 219 | out_undo_iolock: |
220 | if (lock_flags & XFS_IOLOCK_EXCL) | 220 | if (lock_flags & XFS_IOLOCK_EXCL) |
221 | mrunlock_excl(&ip->i_iolock); | 221 | mrunlock_excl(&ip->i_iolock); |
222 | else if (lock_flags & XFS_IOLOCK_SHARED) | 222 | else if (lock_flags & XFS_IOLOCK_SHARED) |
223 | mrunlock_shared(&ip->i_iolock); | 223 | mrunlock_shared(&ip->i_iolock); |
224 | out: | 224 | out: |
225 | return 0; | 225 | return 0; |
226 | } | 226 | } |
227 | 227 | ||
228 | /* | 228 | /* |
229 | * xfs_iunlock() is used to drop the inode locks acquired with | 229 | * xfs_iunlock() is used to drop the inode locks acquired with |
230 | * xfs_ilock() and xfs_ilock_nowait(). The caller must pass | 230 | * xfs_ilock() and xfs_ilock_nowait(). The caller must pass |
231 | * in the flags given to xfs_ilock() or xfs_ilock_nowait() so | 231 | * in the flags given to xfs_ilock() or xfs_ilock_nowait() so |
232 | * that we know which locks to drop. | 232 | * that we know which locks to drop. |
233 | * | 233 | * |
234 | * ip -- the inode being unlocked | 234 | * ip -- the inode being unlocked |
235 | * lock_flags -- this parameter indicates the inode's locks to be | 235 | * lock_flags -- this parameter indicates the inode's locks to be |
236 | * to be unlocked. See the comment for xfs_ilock() for a list | 236 | * to be unlocked. See the comment for xfs_ilock() for a list |
237 | * of valid values for this parameter. | 237 | * of valid values for this parameter. |
238 | * | 238 | * |
239 | */ | 239 | */ |
240 | void | 240 | void |
241 | xfs_iunlock( | 241 | xfs_iunlock( |
242 | xfs_inode_t *ip, | 242 | xfs_inode_t *ip, |
243 | uint lock_flags) | 243 | uint lock_flags) |
244 | { | 244 | { |
245 | /* | 245 | /* |
246 | * You can't set both SHARED and EXCL for the same lock, | 246 | * You can't set both SHARED and EXCL for the same lock, |
247 | * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, | 247 | * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, |
248 | * and XFS_ILOCK_EXCL are valid values to set in lock_flags. | 248 | * and XFS_ILOCK_EXCL are valid values to set in lock_flags. |
249 | */ | 249 | */ |
250 | ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != | 250 | ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != |
251 | (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); | 251 | (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); |
252 | ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != | 252 | ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != |
253 | (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); | 253 | (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); |
254 | ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0); | 254 | ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0); |
255 | ASSERT(lock_flags != 0); | 255 | ASSERT(lock_flags != 0); |
256 | 256 | ||
257 | if (lock_flags & XFS_IOLOCK_EXCL) | 257 | if (lock_flags & XFS_IOLOCK_EXCL) |
258 | mrunlock_excl(&ip->i_iolock); | 258 | mrunlock_excl(&ip->i_iolock); |
259 | else if (lock_flags & XFS_IOLOCK_SHARED) | 259 | else if (lock_flags & XFS_IOLOCK_SHARED) |
260 | mrunlock_shared(&ip->i_iolock); | 260 | mrunlock_shared(&ip->i_iolock); |
261 | 261 | ||
262 | if (lock_flags & XFS_ILOCK_EXCL) | 262 | if (lock_flags & XFS_ILOCK_EXCL) |
263 | mrunlock_excl(&ip->i_lock); | 263 | mrunlock_excl(&ip->i_lock); |
264 | else if (lock_flags & XFS_ILOCK_SHARED) | 264 | else if (lock_flags & XFS_ILOCK_SHARED) |
265 | mrunlock_shared(&ip->i_lock); | 265 | mrunlock_shared(&ip->i_lock); |
266 | 266 | ||
267 | trace_xfs_iunlock(ip, lock_flags, _RET_IP_); | 267 | trace_xfs_iunlock(ip, lock_flags, _RET_IP_); |
268 | } | 268 | } |
269 | 269 | ||
270 | /* | 270 | /* |
271 | * give up write locks. the i/o lock cannot be held nested | 271 | * give up write locks. the i/o lock cannot be held nested |
272 | * if it is being demoted. | 272 | * if it is being demoted. |
273 | */ | 273 | */ |
274 | void | 274 | void |
275 | xfs_ilock_demote( | 275 | xfs_ilock_demote( |
276 | xfs_inode_t *ip, | 276 | xfs_inode_t *ip, |
277 | uint lock_flags) | 277 | uint lock_flags) |
278 | { | 278 | { |
279 | ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)); | 279 | ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)); |
280 | ASSERT((lock_flags & ~(XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)) == 0); | 280 | ASSERT((lock_flags & ~(XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)) == 0); |
281 | 281 | ||
282 | if (lock_flags & XFS_ILOCK_EXCL) | 282 | if (lock_flags & XFS_ILOCK_EXCL) |
283 | mrdemote(&ip->i_lock); | 283 | mrdemote(&ip->i_lock); |
284 | if (lock_flags & XFS_IOLOCK_EXCL) | 284 | if (lock_flags & XFS_IOLOCK_EXCL) |
285 | mrdemote(&ip->i_iolock); | 285 | mrdemote(&ip->i_iolock); |
286 | 286 | ||
287 | trace_xfs_ilock_demote(ip, lock_flags, _RET_IP_); | 287 | trace_xfs_ilock_demote(ip, lock_flags, _RET_IP_); |
288 | } | 288 | } |
289 | 289 | ||
290 | #ifdef DEBUG | 290 | #if defined(DEBUG) || defined(XFS_WARN) |
291 | int | 291 | int |
292 | xfs_isilocked( | 292 | xfs_isilocked( |
293 | xfs_inode_t *ip, | 293 | xfs_inode_t *ip, |
294 | uint lock_flags) | 294 | uint lock_flags) |
295 | { | 295 | { |
296 | if (lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) { | 296 | if (lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) { |
297 | if (!(lock_flags & XFS_ILOCK_SHARED)) | 297 | if (!(lock_flags & XFS_ILOCK_SHARED)) |
298 | return !!ip->i_lock.mr_writer; | 298 | return !!ip->i_lock.mr_writer; |
299 | return rwsem_is_locked(&ip->i_lock.mr_lock); | 299 | return rwsem_is_locked(&ip->i_lock.mr_lock); |
300 | } | 300 | } |
301 | 301 | ||
302 | if (lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) { | 302 | if (lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) { |
303 | if (!(lock_flags & XFS_IOLOCK_SHARED)) | 303 | if (!(lock_flags & XFS_IOLOCK_SHARED)) |
304 | return !!ip->i_iolock.mr_writer; | 304 | return !!ip->i_iolock.mr_writer; |
305 | return rwsem_is_locked(&ip->i_iolock.mr_lock); | 305 | return rwsem_is_locked(&ip->i_iolock.mr_lock); |
306 | } | 306 | } |
307 | 307 | ||
308 | ASSERT(0); | 308 | ASSERT(0); |
309 | return 0; | 309 | return 0; |
310 | } | 310 | } |
311 | #endif | 311 | #endif |
312 | 312 | ||
313 | void | 313 | void |
314 | __xfs_iflock( | 314 | __xfs_iflock( |
315 | struct xfs_inode *ip) | 315 | struct xfs_inode *ip) |
316 | { | 316 | { |
317 | wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IFLOCK_BIT); | 317 | wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IFLOCK_BIT); |
318 | DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IFLOCK_BIT); | 318 | DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IFLOCK_BIT); |
319 | 319 | ||
320 | do { | 320 | do { |
321 | prepare_to_wait_exclusive(wq, &wait.wait, TASK_UNINTERRUPTIBLE); | 321 | prepare_to_wait_exclusive(wq, &wait.wait, TASK_UNINTERRUPTIBLE); |
322 | if (xfs_isiflocked(ip)) | 322 | if (xfs_isiflocked(ip)) |
323 | io_schedule(); | 323 | io_schedule(); |
324 | } while (!xfs_iflock_nowait(ip)); | 324 | } while (!xfs_iflock_nowait(ip)); |
325 | 325 | ||
326 | finish_wait(wq, &wait.wait); | 326 | finish_wait(wq, &wait.wait); |
327 | } | 327 | } |
328 | 328 | ||
329 | #ifdef DEBUG | 329 | #ifdef DEBUG |
330 | /* | 330 | /* |
331 | * Make sure that the extents in the given memory buffer | 331 | * Make sure that the extents in the given memory buffer |
332 | * are valid. | 332 | * are valid. |
333 | */ | 333 | */ |
334 | STATIC void | 334 | STATIC void |
335 | xfs_validate_extents( | 335 | xfs_validate_extents( |
336 | xfs_ifork_t *ifp, | 336 | xfs_ifork_t *ifp, |
337 | int nrecs, | 337 | int nrecs, |
338 | xfs_exntfmt_t fmt) | 338 | xfs_exntfmt_t fmt) |
339 | { | 339 | { |
340 | xfs_bmbt_irec_t irec; | 340 | xfs_bmbt_irec_t irec; |
341 | xfs_bmbt_rec_host_t rec; | 341 | xfs_bmbt_rec_host_t rec; |
342 | int i; | 342 | int i; |
343 | 343 | ||
344 | for (i = 0; i < nrecs; i++) { | 344 | for (i = 0; i < nrecs; i++) { |
345 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); | 345 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); |
346 | rec.l0 = get_unaligned(&ep->l0); | 346 | rec.l0 = get_unaligned(&ep->l0); |
347 | rec.l1 = get_unaligned(&ep->l1); | 347 | rec.l1 = get_unaligned(&ep->l1); |
348 | xfs_bmbt_get_all(&rec, &irec); | 348 | xfs_bmbt_get_all(&rec, &irec); |
349 | if (fmt == XFS_EXTFMT_NOSTATE) | 349 | if (fmt == XFS_EXTFMT_NOSTATE) |
350 | ASSERT(irec.br_state == XFS_EXT_NORM); | 350 | ASSERT(irec.br_state == XFS_EXT_NORM); |
351 | } | 351 | } |
352 | } | 352 | } |
353 | #else /* DEBUG */ | 353 | #else /* DEBUG */ |
354 | #define xfs_validate_extents(ifp, nrecs, fmt) | 354 | #define xfs_validate_extents(ifp, nrecs, fmt) |
355 | #endif /* DEBUG */ | 355 | #endif /* DEBUG */ |
356 | 356 | ||
357 | /* | 357 | /* |
358 | * Check that none of the inode's in the buffer have a next | 358 | * Check that none of the inode's in the buffer have a next |
359 | * unlinked field of 0. | 359 | * unlinked field of 0. |
360 | */ | 360 | */ |
361 | #if defined(DEBUG) | 361 | #if defined(DEBUG) |
362 | void | 362 | void |
363 | xfs_inobp_check( | 363 | xfs_inobp_check( |
364 | xfs_mount_t *mp, | 364 | xfs_mount_t *mp, |
365 | xfs_buf_t *bp) | 365 | xfs_buf_t *bp) |
366 | { | 366 | { |
367 | int i; | 367 | int i; |
368 | int j; | 368 | int j; |
369 | xfs_dinode_t *dip; | 369 | xfs_dinode_t *dip; |
370 | 370 | ||
371 | j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; | 371 | j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; |
372 | 372 | ||
373 | for (i = 0; i < j; i++) { | 373 | for (i = 0; i < j; i++) { |
374 | dip = (xfs_dinode_t *)xfs_buf_offset(bp, | 374 | dip = (xfs_dinode_t *)xfs_buf_offset(bp, |
375 | i * mp->m_sb.sb_inodesize); | 375 | i * mp->m_sb.sb_inodesize); |
376 | if (!dip->di_next_unlinked) { | 376 | if (!dip->di_next_unlinked) { |
377 | xfs_alert(mp, | 377 | xfs_alert(mp, |
378 | "Detected bogus zero next_unlinked field in incore inode buffer 0x%p.", | 378 | "Detected bogus zero next_unlinked field in incore inode buffer 0x%p.", |
379 | bp); | 379 | bp); |
380 | ASSERT(dip->di_next_unlinked); | 380 | ASSERT(dip->di_next_unlinked); |
381 | } | 381 | } |
382 | } | 382 | } |
383 | } | 383 | } |
384 | #endif | 384 | #endif |
385 | 385 | ||
386 | static void | 386 | static void |
387 | xfs_inode_buf_verify( | 387 | xfs_inode_buf_verify( |
388 | struct xfs_buf *bp) | 388 | struct xfs_buf *bp) |
389 | { | 389 | { |
390 | struct xfs_mount *mp = bp->b_target->bt_mount; | 390 | struct xfs_mount *mp = bp->b_target->bt_mount; |
391 | int i; | 391 | int i; |
392 | int ni; | 392 | int ni; |
393 | 393 | ||
394 | /* | 394 | /* |
395 | * Validate the magic number and version of every inode in the buffer | 395 | * Validate the magic number and version of every inode in the buffer |
396 | */ | 396 | */ |
397 | ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock; | 397 | ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock; |
398 | for (i = 0; i < ni; i++) { | 398 | for (i = 0; i < ni; i++) { |
399 | int di_ok; | 399 | int di_ok; |
400 | xfs_dinode_t *dip; | 400 | xfs_dinode_t *dip; |
401 | 401 | ||
402 | dip = (struct xfs_dinode *)xfs_buf_offset(bp, | 402 | dip = (struct xfs_dinode *)xfs_buf_offset(bp, |
403 | (i << mp->m_sb.sb_inodelog)); | 403 | (i << mp->m_sb.sb_inodelog)); |
404 | di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) && | 404 | di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) && |
405 | XFS_DINODE_GOOD_VERSION(dip->di_version); | 405 | XFS_DINODE_GOOD_VERSION(dip->di_version); |
406 | if (unlikely(XFS_TEST_ERROR(!di_ok, mp, | 406 | if (unlikely(XFS_TEST_ERROR(!di_ok, mp, |
407 | XFS_ERRTAG_ITOBP_INOTOBP, | 407 | XFS_ERRTAG_ITOBP_INOTOBP, |
408 | XFS_RANDOM_ITOBP_INOTOBP))) { | 408 | XFS_RANDOM_ITOBP_INOTOBP))) { |
409 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 409 | xfs_buf_ioerror(bp, EFSCORRUPTED); |
410 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH, | 410 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH, |
411 | mp, dip); | 411 | mp, dip); |
412 | #ifdef DEBUG | 412 | #ifdef DEBUG |
413 | xfs_emerg(mp, | 413 | xfs_emerg(mp, |
414 | "bad inode magic/vsn daddr %lld #%d (magic=%x)", | 414 | "bad inode magic/vsn daddr %lld #%d (magic=%x)", |
415 | (unsigned long long)bp->b_bn, i, | 415 | (unsigned long long)bp->b_bn, i, |
416 | be16_to_cpu(dip->di_magic)); | 416 | be16_to_cpu(dip->di_magic)); |
417 | ASSERT(0); | 417 | ASSERT(0); |
418 | #endif | 418 | #endif |
419 | } | 419 | } |
420 | } | 420 | } |
421 | xfs_inobp_check(mp, bp); | 421 | xfs_inobp_check(mp, bp); |
422 | } | 422 | } |
423 | 423 | ||
424 | 424 | ||
425 | static void | 425 | static void |
426 | xfs_inode_buf_read_verify( | 426 | xfs_inode_buf_read_verify( |
427 | struct xfs_buf *bp) | 427 | struct xfs_buf *bp) |
428 | { | 428 | { |
429 | xfs_inode_buf_verify(bp); | 429 | xfs_inode_buf_verify(bp); |
430 | } | 430 | } |
431 | 431 | ||
432 | static void | 432 | static void |
433 | xfs_inode_buf_write_verify( | 433 | xfs_inode_buf_write_verify( |
434 | struct xfs_buf *bp) | 434 | struct xfs_buf *bp) |
435 | { | 435 | { |
436 | xfs_inode_buf_verify(bp); | 436 | xfs_inode_buf_verify(bp); |
437 | } | 437 | } |
438 | 438 | ||
439 | const struct xfs_buf_ops xfs_inode_buf_ops = { | 439 | const struct xfs_buf_ops xfs_inode_buf_ops = { |
440 | .verify_read = xfs_inode_buf_read_verify, | 440 | .verify_read = xfs_inode_buf_read_verify, |
441 | .verify_write = xfs_inode_buf_write_verify, | 441 | .verify_write = xfs_inode_buf_write_verify, |
442 | }; | 442 | }; |
443 | 443 | ||
444 | 444 | ||
445 | /* | 445 | /* |
446 | * This routine is called to map an inode to the buffer containing the on-disk | 446 | * This routine is called to map an inode to the buffer containing the on-disk |
447 | * version of the inode. It returns a pointer to the buffer containing the | 447 | * version of the inode. It returns a pointer to the buffer containing the |
448 | * on-disk inode in the bpp parameter, and in the dipp parameter it returns a | 448 | * on-disk inode in the bpp parameter, and in the dipp parameter it returns a |
449 | * pointer to the on-disk inode within that buffer. | 449 | * pointer to the on-disk inode within that buffer. |
450 | * | 450 | * |
451 | * If a non-zero error is returned, then the contents of bpp and dipp are | 451 | * If a non-zero error is returned, then the contents of bpp and dipp are |
452 | * undefined. | 452 | * undefined. |
453 | */ | 453 | */ |
454 | int | 454 | int |
455 | xfs_imap_to_bp( | 455 | xfs_imap_to_bp( |
456 | struct xfs_mount *mp, | 456 | struct xfs_mount *mp, |
457 | struct xfs_trans *tp, | 457 | struct xfs_trans *tp, |
458 | struct xfs_imap *imap, | 458 | struct xfs_imap *imap, |
459 | struct xfs_dinode **dipp, | 459 | struct xfs_dinode **dipp, |
460 | struct xfs_buf **bpp, | 460 | struct xfs_buf **bpp, |
461 | uint buf_flags, | 461 | uint buf_flags, |
462 | uint iget_flags) | 462 | uint iget_flags) |
463 | { | 463 | { |
464 | struct xfs_buf *bp; | 464 | struct xfs_buf *bp; |
465 | int error; | 465 | int error; |
466 | 466 | ||
467 | buf_flags |= XBF_UNMAPPED; | 467 | buf_flags |= XBF_UNMAPPED; |
468 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno, | 468 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno, |
469 | (int)imap->im_len, buf_flags, &bp, | 469 | (int)imap->im_len, buf_flags, &bp, |
470 | &xfs_inode_buf_ops); | 470 | &xfs_inode_buf_ops); |
471 | if (error) { | 471 | if (error) { |
472 | if (error == EAGAIN) { | 472 | if (error == EAGAIN) { |
473 | ASSERT(buf_flags & XBF_TRYLOCK); | 473 | ASSERT(buf_flags & XBF_TRYLOCK); |
474 | return error; | 474 | return error; |
475 | } | 475 | } |
476 | 476 | ||
477 | if (error == EFSCORRUPTED && | 477 | if (error == EFSCORRUPTED && |
478 | (iget_flags & XFS_IGET_UNTRUSTED)) | 478 | (iget_flags & XFS_IGET_UNTRUSTED)) |
479 | return XFS_ERROR(EINVAL); | 479 | return XFS_ERROR(EINVAL); |
480 | 480 | ||
481 | xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.", | 481 | xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.", |
482 | __func__, error); | 482 | __func__, error); |
483 | return error; | 483 | return error; |
484 | } | 484 | } |
485 | 485 | ||
486 | *bpp = bp; | 486 | *bpp = bp; |
487 | *dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset); | 487 | *dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset); |
488 | return 0; | 488 | return 0; |
489 | } | 489 | } |
490 | 490 | ||
491 | /* | 491 | /* |
492 | * Move inode type and inode format specific information from the | 492 | * Move inode type and inode format specific information from the |
493 | * on-disk inode to the in-core inode. For fifos, devs, and sockets | 493 | * on-disk inode to the in-core inode. For fifos, devs, and sockets |
494 | * this means set if_rdev to the proper value. For files, directories, | 494 | * this means set if_rdev to the proper value. For files, directories, |
495 | * and symlinks this means to bring in the in-line data or extent | 495 | * and symlinks this means to bring in the in-line data or extent |
496 | * pointers. For a file in B-tree format, only the root is immediately | 496 | * pointers. For a file in B-tree format, only the root is immediately |
497 | * brought in-core. The rest will be in-lined in if_extents when it | 497 | * brought in-core. The rest will be in-lined in if_extents when it |
498 | * is first referenced (see xfs_iread_extents()). | 498 | * is first referenced (see xfs_iread_extents()). |
499 | */ | 499 | */ |
500 | STATIC int | 500 | STATIC int |
501 | xfs_iformat( | 501 | xfs_iformat( |
502 | xfs_inode_t *ip, | 502 | xfs_inode_t *ip, |
503 | xfs_dinode_t *dip) | 503 | xfs_dinode_t *dip) |
504 | { | 504 | { |
505 | xfs_attr_shortform_t *atp; | 505 | xfs_attr_shortform_t *atp; |
506 | int size; | 506 | int size; |
507 | int error = 0; | 507 | int error = 0; |
508 | xfs_fsize_t di_size; | 508 | xfs_fsize_t di_size; |
509 | 509 | ||
510 | if (unlikely(be32_to_cpu(dip->di_nextents) + | 510 | if (unlikely(be32_to_cpu(dip->di_nextents) + |
511 | be16_to_cpu(dip->di_anextents) > | 511 | be16_to_cpu(dip->di_anextents) > |
512 | be64_to_cpu(dip->di_nblocks))) { | 512 | be64_to_cpu(dip->di_nblocks))) { |
513 | xfs_warn(ip->i_mount, | 513 | xfs_warn(ip->i_mount, |
514 | "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.", | 514 | "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.", |
515 | (unsigned long long)ip->i_ino, | 515 | (unsigned long long)ip->i_ino, |
516 | (int)(be32_to_cpu(dip->di_nextents) + | 516 | (int)(be32_to_cpu(dip->di_nextents) + |
517 | be16_to_cpu(dip->di_anextents)), | 517 | be16_to_cpu(dip->di_anextents)), |
518 | (unsigned long long) | 518 | (unsigned long long) |
519 | be64_to_cpu(dip->di_nblocks)); | 519 | be64_to_cpu(dip->di_nblocks)); |
520 | XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW, | 520 | XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW, |
521 | ip->i_mount, dip); | 521 | ip->i_mount, dip); |
522 | return XFS_ERROR(EFSCORRUPTED); | 522 | return XFS_ERROR(EFSCORRUPTED); |
523 | } | 523 | } |
524 | 524 | ||
525 | if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) { | 525 | if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) { |
526 | xfs_warn(ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.", | 526 | xfs_warn(ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.", |
527 | (unsigned long long)ip->i_ino, | 527 | (unsigned long long)ip->i_ino, |
528 | dip->di_forkoff); | 528 | dip->di_forkoff); |
529 | XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW, | 529 | XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW, |
530 | ip->i_mount, dip); | 530 | ip->i_mount, dip); |
531 | return XFS_ERROR(EFSCORRUPTED); | 531 | return XFS_ERROR(EFSCORRUPTED); |
532 | } | 532 | } |
533 | 533 | ||
534 | if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && | 534 | if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && |
535 | !ip->i_mount->m_rtdev_targp)) { | 535 | !ip->i_mount->m_rtdev_targp)) { |
536 | xfs_warn(ip->i_mount, | 536 | xfs_warn(ip->i_mount, |
537 | "corrupt dinode %Lu, has realtime flag set.", | 537 | "corrupt dinode %Lu, has realtime flag set.", |
538 | ip->i_ino); | 538 | ip->i_ino); |
539 | XFS_CORRUPTION_ERROR("xfs_iformat(realtime)", | 539 | XFS_CORRUPTION_ERROR("xfs_iformat(realtime)", |
540 | XFS_ERRLEVEL_LOW, ip->i_mount, dip); | 540 | XFS_ERRLEVEL_LOW, ip->i_mount, dip); |
541 | return XFS_ERROR(EFSCORRUPTED); | 541 | return XFS_ERROR(EFSCORRUPTED); |
542 | } | 542 | } |
543 | 543 | ||
544 | switch (ip->i_d.di_mode & S_IFMT) { | 544 | switch (ip->i_d.di_mode & S_IFMT) { |
545 | case S_IFIFO: | 545 | case S_IFIFO: |
546 | case S_IFCHR: | 546 | case S_IFCHR: |
547 | case S_IFBLK: | 547 | case S_IFBLK: |
548 | case S_IFSOCK: | 548 | case S_IFSOCK: |
549 | if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) { | 549 | if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) { |
550 | XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW, | 550 | XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW, |
551 | ip->i_mount, dip); | 551 | ip->i_mount, dip); |
552 | return XFS_ERROR(EFSCORRUPTED); | 552 | return XFS_ERROR(EFSCORRUPTED); |
553 | } | 553 | } |
554 | ip->i_d.di_size = 0; | 554 | ip->i_d.di_size = 0; |
555 | ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip); | 555 | ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip); |
556 | break; | 556 | break; |
557 | 557 | ||
558 | case S_IFREG: | 558 | case S_IFREG: |
559 | case S_IFLNK: | 559 | case S_IFLNK: |
560 | case S_IFDIR: | 560 | case S_IFDIR: |
561 | switch (dip->di_format) { | 561 | switch (dip->di_format) { |
562 | case XFS_DINODE_FMT_LOCAL: | 562 | case XFS_DINODE_FMT_LOCAL: |
563 | /* | 563 | /* |
564 | * no local regular files yet | 564 | * no local regular files yet |
565 | */ | 565 | */ |
566 | if (unlikely(S_ISREG(be16_to_cpu(dip->di_mode)))) { | 566 | if (unlikely(S_ISREG(be16_to_cpu(dip->di_mode)))) { |
567 | xfs_warn(ip->i_mount, | 567 | xfs_warn(ip->i_mount, |
568 | "corrupt inode %Lu (local format for regular file).", | 568 | "corrupt inode %Lu (local format for regular file).", |
569 | (unsigned long long) ip->i_ino); | 569 | (unsigned long long) ip->i_ino); |
570 | XFS_CORRUPTION_ERROR("xfs_iformat(4)", | 570 | XFS_CORRUPTION_ERROR("xfs_iformat(4)", |
571 | XFS_ERRLEVEL_LOW, | 571 | XFS_ERRLEVEL_LOW, |
572 | ip->i_mount, dip); | 572 | ip->i_mount, dip); |
573 | return XFS_ERROR(EFSCORRUPTED); | 573 | return XFS_ERROR(EFSCORRUPTED); |
574 | } | 574 | } |
575 | 575 | ||
576 | di_size = be64_to_cpu(dip->di_size); | 576 | di_size = be64_to_cpu(dip->di_size); |
577 | if (unlikely(di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) { | 577 | if (unlikely(di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) { |
578 | xfs_warn(ip->i_mount, | 578 | xfs_warn(ip->i_mount, |
579 | "corrupt inode %Lu (bad size %Ld for local inode).", | 579 | "corrupt inode %Lu (bad size %Ld for local inode).", |
580 | (unsigned long long) ip->i_ino, | 580 | (unsigned long long) ip->i_ino, |
581 | (long long) di_size); | 581 | (long long) di_size); |
582 | XFS_CORRUPTION_ERROR("xfs_iformat(5)", | 582 | XFS_CORRUPTION_ERROR("xfs_iformat(5)", |
583 | XFS_ERRLEVEL_LOW, | 583 | XFS_ERRLEVEL_LOW, |
584 | ip->i_mount, dip); | 584 | ip->i_mount, dip); |
585 | return XFS_ERROR(EFSCORRUPTED); | 585 | return XFS_ERROR(EFSCORRUPTED); |
586 | } | 586 | } |
587 | 587 | ||
588 | size = (int)di_size; | 588 | size = (int)di_size; |
589 | error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size); | 589 | error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size); |
590 | break; | 590 | break; |
591 | case XFS_DINODE_FMT_EXTENTS: | 591 | case XFS_DINODE_FMT_EXTENTS: |
592 | error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK); | 592 | error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK); |
593 | break; | 593 | break; |
594 | case XFS_DINODE_FMT_BTREE: | 594 | case XFS_DINODE_FMT_BTREE: |
595 | error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK); | 595 | error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK); |
596 | break; | 596 | break; |
597 | default: | 597 | default: |
598 | XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW, | 598 | XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW, |
599 | ip->i_mount); | 599 | ip->i_mount); |
600 | return XFS_ERROR(EFSCORRUPTED); | 600 | return XFS_ERROR(EFSCORRUPTED); |
601 | } | 601 | } |
602 | break; | 602 | break; |
603 | 603 | ||
604 | default: | 604 | default: |
605 | XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount); | 605 | XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount); |
606 | return XFS_ERROR(EFSCORRUPTED); | 606 | return XFS_ERROR(EFSCORRUPTED); |
607 | } | 607 | } |
608 | if (error) { | 608 | if (error) { |
609 | return error; | 609 | return error; |
610 | } | 610 | } |
611 | if (!XFS_DFORK_Q(dip)) | 611 | if (!XFS_DFORK_Q(dip)) |
612 | return 0; | 612 | return 0; |
613 | 613 | ||
614 | ASSERT(ip->i_afp == NULL); | 614 | ASSERT(ip->i_afp == NULL); |
615 | ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS); | 615 | ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS); |
616 | 616 | ||
617 | switch (dip->di_aformat) { | 617 | switch (dip->di_aformat) { |
618 | case XFS_DINODE_FMT_LOCAL: | 618 | case XFS_DINODE_FMT_LOCAL: |
619 | atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); | 619 | atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); |
620 | size = be16_to_cpu(atp->hdr.totsize); | 620 | size = be16_to_cpu(atp->hdr.totsize); |
621 | 621 | ||
622 | if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) { | 622 | if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) { |
623 | xfs_warn(ip->i_mount, | 623 | xfs_warn(ip->i_mount, |
624 | "corrupt inode %Lu (bad attr fork size %Ld).", | 624 | "corrupt inode %Lu (bad attr fork size %Ld).", |
625 | (unsigned long long) ip->i_ino, | 625 | (unsigned long long) ip->i_ino, |
626 | (long long) size); | 626 | (long long) size); |
627 | XFS_CORRUPTION_ERROR("xfs_iformat(8)", | 627 | XFS_CORRUPTION_ERROR("xfs_iformat(8)", |
628 | XFS_ERRLEVEL_LOW, | 628 | XFS_ERRLEVEL_LOW, |
629 | ip->i_mount, dip); | 629 | ip->i_mount, dip); |
630 | return XFS_ERROR(EFSCORRUPTED); | 630 | return XFS_ERROR(EFSCORRUPTED); |
631 | } | 631 | } |
632 | 632 | ||
633 | error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size); | 633 | error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size); |
634 | break; | 634 | break; |
635 | case XFS_DINODE_FMT_EXTENTS: | 635 | case XFS_DINODE_FMT_EXTENTS: |
636 | error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK); | 636 | error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK); |
637 | break; | 637 | break; |
638 | case XFS_DINODE_FMT_BTREE: | 638 | case XFS_DINODE_FMT_BTREE: |
639 | error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK); | 639 | error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK); |
640 | break; | 640 | break; |
641 | default: | 641 | default: |
642 | error = XFS_ERROR(EFSCORRUPTED); | 642 | error = XFS_ERROR(EFSCORRUPTED); |
643 | break; | 643 | break; |
644 | } | 644 | } |
645 | if (error) { | 645 | if (error) { |
646 | kmem_zone_free(xfs_ifork_zone, ip->i_afp); | 646 | kmem_zone_free(xfs_ifork_zone, ip->i_afp); |
647 | ip->i_afp = NULL; | 647 | ip->i_afp = NULL; |
648 | xfs_idestroy_fork(ip, XFS_DATA_FORK); | 648 | xfs_idestroy_fork(ip, XFS_DATA_FORK); |
649 | } | 649 | } |
650 | return error; | 650 | return error; |
651 | } | 651 | } |
652 | 652 | ||
653 | /* | 653 | /* |
654 | * The file is in-lined in the on-disk inode. | 654 | * The file is in-lined in the on-disk inode. |
655 | * If it fits into if_inline_data, then copy | 655 | * If it fits into if_inline_data, then copy |
656 | * it there, otherwise allocate a buffer for it | 656 | * it there, otherwise allocate a buffer for it |
657 | * and copy the data there. Either way, set | 657 | * and copy the data there. Either way, set |
658 | * if_data to point at the data. | 658 | * if_data to point at the data. |
659 | * If we allocate a buffer for the data, make | 659 | * If we allocate a buffer for the data, make |
660 | * sure that its size is a multiple of 4 and | 660 | * sure that its size is a multiple of 4 and |
661 | * record the real size in i_real_bytes. | 661 | * record the real size in i_real_bytes. |
662 | */ | 662 | */ |
663 | STATIC int | 663 | STATIC int |
664 | xfs_iformat_local( | 664 | xfs_iformat_local( |
665 | xfs_inode_t *ip, | 665 | xfs_inode_t *ip, |
666 | xfs_dinode_t *dip, | 666 | xfs_dinode_t *dip, |
667 | int whichfork, | 667 | int whichfork, |
668 | int size) | 668 | int size) |
669 | { | 669 | { |
670 | xfs_ifork_t *ifp; | 670 | xfs_ifork_t *ifp; |
671 | int real_size; | 671 | int real_size; |
672 | 672 | ||
673 | /* | 673 | /* |
674 | * If the size is unreasonable, then something | 674 | * If the size is unreasonable, then something |
675 | * is wrong and we just bail out rather than crash in | 675 | * is wrong and we just bail out rather than crash in |
676 | * kmem_alloc() or memcpy() below. | 676 | * kmem_alloc() or memcpy() below. |
677 | */ | 677 | */ |
678 | if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { | 678 | if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { |
679 | xfs_warn(ip->i_mount, | 679 | xfs_warn(ip->i_mount, |
680 | "corrupt inode %Lu (bad size %d for local fork, size = %d).", | 680 | "corrupt inode %Lu (bad size %d for local fork, size = %d).", |
681 | (unsigned long long) ip->i_ino, size, | 681 | (unsigned long long) ip->i_ino, size, |
682 | XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)); | 682 | XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)); |
683 | XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW, | 683 | XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW, |
684 | ip->i_mount, dip); | 684 | ip->i_mount, dip); |
685 | return XFS_ERROR(EFSCORRUPTED); | 685 | return XFS_ERROR(EFSCORRUPTED); |
686 | } | 686 | } |
687 | ifp = XFS_IFORK_PTR(ip, whichfork); | 687 | ifp = XFS_IFORK_PTR(ip, whichfork); |
688 | real_size = 0; | 688 | real_size = 0; |
689 | if (size == 0) | 689 | if (size == 0) |
690 | ifp->if_u1.if_data = NULL; | 690 | ifp->if_u1.if_data = NULL; |
691 | else if (size <= sizeof(ifp->if_u2.if_inline_data)) | 691 | else if (size <= sizeof(ifp->if_u2.if_inline_data)) |
692 | ifp->if_u1.if_data = ifp->if_u2.if_inline_data; | 692 | ifp->if_u1.if_data = ifp->if_u2.if_inline_data; |
693 | else { | 693 | else { |
694 | real_size = roundup(size, 4); | 694 | real_size = roundup(size, 4); |
695 | ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS); | 695 | ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS); |
696 | } | 696 | } |
697 | ifp->if_bytes = size; | 697 | ifp->if_bytes = size; |
698 | ifp->if_real_bytes = real_size; | 698 | ifp->if_real_bytes = real_size; |
699 | if (size) | 699 | if (size) |
700 | memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size); | 700 | memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size); |
701 | ifp->if_flags &= ~XFS_IFEXTENTS; | 701 | ifp->if_flags &= ~XFS_IFEXTENTS; |
702 | ifp->if_flags |= XFS_IFINLINE; | 702 | ifp->if_flags |= XFS_IFINLINE; |
703 | return 0; | 703 | return 0; |
704 | } | 704 | } |
705 | 705 | ||
706 | /* | 706 | /* |
707 | * The file consists of a set of extents all | 707 | * The file consists of a set of extents all |
708 | * of which fit into the on-disk inode. | 708 | * of which fit into the on-disk inode. |
709 | * If there are few enough extents to fit into | 709 | * If there are few enough extents to fit into |
710 | * the if_inline_ext, then copy them there. | 710 | * the if_inline_ext, then copy them there. |
711 | * Otherwise allocate a buffer for them and copy | 711 | * Otherwise allocate a buffer for them and copy |
712 | * them into it. Either way, set if_extents | 712 | * them into it. Either way, set if_extents |
713 | * to point at the extents. | 713 | * to point at the extents. |
714 | */ | 714 | */ |
715 | STATIC int | 715 | STATIC int |
716 | xfs_iformat_extents( | 716 | xfs_iformat_extents( |
717 | xfs_inode_t *ip, | 717 | xfs_inode_t *ip, |
718 | xfs_dinode_t *dip, | 718 | xfs_dinode_t *dip, |
719 | int whichfork) | 719 | int whichfork) |
720 | { | 720 | { |
721 | xfs_bmbt_rec_t *dp; | 721 | xfs_bmbt_rec_t *dp; |
722 | xfs_ifork_t *ifp; | 722 | xfs_ifork_t *ifp; |
723 | int nex; | 723 | int nex; |
724 | int size; | 724 | int size; |
725 | int i; | 725 | int i; |
726 | 726 | ||
727 | ifp = XFS_IFORK_PTR(ip, whichfork); | 727 | ifp = XFS_IFORK_PTR(ip, whichfork); |
728 | nex = XFS_DFORK_NEXTENTS(dip, whichfork); | 728 | nex = XFS_DFORK_NEXTENTS(dip, whichfork); |
729 | size = nex * (uint)sizeof(xfs_bmbt_rec_t); | 729 | size = nex * (uint)sizeof(xfs_bmbt_rec_t); |
730 | 730 | ||
731 | /* | 731 | /* |
732 | * If the number of extents is unreasonable, then something | 732 | * If the number of extents is unreasonable, then something |
733 | * is wrong and we just bail out rather than crash in | 733 | * is wrong and we just bail out rather than crash in |
734 | * kmem_alloc() or memcpy() below. | 734 | * kmem_alloc() or memcpy() below. |
735 | */ | 735 | */ |
736 | if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { | 736 | if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { |
737 | xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).", | 737 | xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).", |
738 | (unsigned long long) ip->i_ino, nex); | 738 | (unsigned long long) ip->i_ino, nex); |
739 | XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW, | 739 | XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW, |
740 | ip->i_mount, dip); | 740 | ip->i_mount, dip); |
741 | return XFS_ERROR(EFSCORRUPTED); | 741 | return XFS_ERROR(EFSCORRUPTED); |
742 | } | 742 | } |
743 | 743 | ||
744 | ifp->if_real_bytes = 0; | 744 | ifp->if_real_bytes = 0; |
745 | if (nex == 0) | 745 | if (nex == 0) |
746 | ifp->if_u1.if_extents = NULL; | 746 | ifp->if_u1.if_extents = NULL; |
747 | else if (nex <= XFS_INLINE_EXTS) | 747 | else if (nex <= XFS_INLINE_EXTS) |
748 | ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; | 748 | ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; |
749 | else | 749 | else |
750 | xfs_iext_add(ifp, 0, nex); | 750 | xfs_iext_add(ifp, 0, nex); |
751 | 751 | ||
752 | ifp->if_bytes = size; | 752 | ifp->if_bytes = size; |
753 | if (size) { | 753 | if (size) { |
754 | dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork); | 754 | dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork); |
755 | xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip)); | 755 | xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip)); |
756 | for (i = 0; i < nex; i++, dp++) { | 756 | for (i = 0; i < nex; i++, dp++) { |
757 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); | 757 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); |
758 | ep->l0 = get_unaligned_be64(&dp->l0); | 758 | ep->l0 = get_unaligned_be64(&dp->l0); |
759 | ep->l1 = get_unaligned_be64(&dp->l1); | 759 | ep->l1 = get_unaligned_be64(&dp->l1); |
760 | } | 760 | } |
761 | XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork); | 761 | XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork); |
762 | if (whichfork != XFS_DATA_FORK || | 762 | if (whichfork != XFS_DATA_FORK || |
763 | XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE) | 763 | XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE) |
764 | if (unlikely(xfs_check_nostate_extents( | 764 | if (unlikely(xfs_check_nostate_extents( |
765 | ifp, 0, nex))) { | 765 | ifp, 0, nex))) { |
766 | XFS_ERROR_REPORT("xfs_iformat_extents(2)", | 766 | XFS_ERROR_REPORT("xfs_iformat_extents(2)", |
767 | XFS_ERRLEVEL_LOW, | 767 | XFS_ERRLEVEL_LOW, |
768 | ip->i_mount); | 768 | ip->i_mount); |
769 | return XFS_ERROR(EFSCORRUPTED); | 769 | return XFS_ERROR(EFSCORRUPTED); |
770 | } | 770 | } |
771 | } | 771 | } |
772 | ifp->if_flags |= XFS_IFEXTENTS; | 772 | ifp->if_flags |= XFS_IFEXTENTS; |
773 | return 0; | 773 | return 0; |
774 | } | 774 | } |
775 | 775 | ||
776 | /* | 776 | /* |
777 | * The file has too many extents to fit into | 777 | * The file has too many extents to fit into |
778 | * the inode, so they are in B-tree format. | 778 | * the inode, so they are in B-tree format. |
779 | * Allocate a buffer for the root of the B-tree | 779 | * Allocate a buffer for the root of the B-tree |
780 | * and copy the root into it. The i_extents | 780 | * and copy the root into it. The i_extents |
781 | * field will remain NULL until all of the | 781 | * field will remain NULL until all of the |
782 | * extents are read in (when they are needed). | 782 | * extents are read in (when they are needed). |
783 | */ | 783 | */ |
784 | STATIC int | 784 | STATIC int |
785 | xfs_iformat_btree( | 785 | xfs_iformat_btree( |
786 | xfs_inode_t *ip, | 786 | xfs_inode_t *ip, |
787 | xfs_dinode_t *dip, | 787 | xfs_dinode_t *dip, |
788 | int whichfork) | 788 | int whichfork) |
789 | { | 789 | { |
790 | struct xfs_mount *mp = ip->i_mount; | 790 | struct xfs_mount *mp = ip->i_mount; |
791 | xfs_bmdr_block_t *dfp; | 791 | xfs_bmdr_block_t *dfp; |
792 | xfs_ifork_t *ifp; | 792 | xfs_ifork_t *ifp; |
793 | /* REFERENCED */ | 793 | /* REFERENCED */ |
794 | int nrecs; | 794 | int nrecs; |
795 | int size; | 795 | int size; |
796 | 796 | ||
797 | ifp = XFS_IFORK_PTR(ip, whichfork); | 797 | ifp = XFS_IFORK_PTR(ip, whichfork); |
798 | dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); | 798 | dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); |
799 | size = XFS_BMAP_BROOT_SPACE(mp, dfp); | 799 | size = XFS_BMAP_BROOT_SPACE(mp, dfp); |
800 | nrecs = be16_to_cpu(dfp->bb_numrecs); | 800 | nrecs = be16_to_cpu(dfp->bb_numrecs); |
801 | 801 | ||
802 | /* | 802 | /* |
803 | * blow out if -- fork has less extents than can fit in | 803 | * blow out if -- fork has less extents than can fit in |
804 | * fork (fork shouldn't be a btree format), root btree | 804 | * fork (fork shouldn't be a btree format), root btree |
805 | * block has more records than can fit into the fork, | 805 | * block has more records than can fit into the fork, |
806 | * or the number of extents is greater than the number of | 806 | * or the number of extents is greater than the number of |
807 | * blocks. | 807 | * blocks. |
808 | */ | 808 | */ |
809 | if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= | 809 | if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= |
810 | XFS_IFORK_MAXEXT(ip, whichfork) || | 810 | XFS_IFORK_MAXEXT(ip, whichfork) || |
811 | XFS_BMDR_SPACE_CALC(nrecs) > | 811 | XFS_BMDR_SPACE_CALC(nrecs) > |
812 | XFS_DFORK_SIZE(dip, mp, whichfork) || | 812 | XFS_DFORK_SIZE(dip, mp, whichfork) || |
813 | XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) { | 813 | XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) { |
814 | xfs_warn(mp, "corrupt inode %Lu (btree).", | 814 | xfs_warn(mp, "corrupt inode %Lu (btree).", |
815 | (unsigned long long) ip->i_ino); | 815 | (unsigned long long) ip->i_ino); |
816 | XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW, | 816 | XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW, |
817 | mp, dip); | 817 | mp, dip); |
818 | return XFS_ERROR(EFSCORRUPTED); | 818 | return XFS_ERROR(EFSCORRUPTED); |
819 | } | 819 | } |
820 | 820 | ||
821 | ifp->if_broot_bytes = size; | 821 | ifp->if_broot_bytes = size; |
822 | ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS); | 822 | ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS); |
823 | ASSERT(ifp->if_broot != NULL); | 823 | ASSERT(ifp->if_broot != NULL); |
824 | /* | 824 | /* |
825 | * Copy and convert from the on-disk structure | 825 | * Copy and convert from the on-disk structure |
826 | * to the in-memory structure. | 826 | * to the in-memory structure. |
827 | */ | 827 | */ |
828 | xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork), | 828 | xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork), |
829 | ifp->if_broot, size); | 829 | ifp->if_broot, size); |
830 | ifp->if_flags &= ~XFS_IFEXTENTS; | 830 | ifp->if_flags &= ~XFS_IFEXTENTS; |
831 | ifp->if_flags |= XFS_IFBROOT; | 831 | ifp->if_flags |= XFS_IFBROOT; |
832 | 832 | ||
833 | return 0; | 833 | return 0; |
834 | } | 834 | } |
835 | 835 | ||
836 | STATIC void | 836 | STATIC void |
837 | xfs_dinode_from_disk( | 837 | xfs_dinode_from_disk( |
838 | xfs_icdinode_t *to, | 838 | xfs_icdinode_t *to, |
839 | xfs_dinode_t *from) | 839 | xfs_dinode_t *from) |
840 | { | 840 | { |
841 | to->di_magic = be16_to_cpu(from->di_magic); | 841 | to->di_magic = be16_to_cpu(from->di_magic); |
842 | to->di_mode = be16_to_cpu(from->di_mode); | 842 | to->di_mode = be16_to_cpu(from->di_mode); |
843 | to->di_version = from ->di_version; | 843 | to->di_version = from ->di_version; |
844 | to->di_format = from->di_format; | 844 | to->di_format = from->di_format; |
845 | to->di_onlink = be16_to_cpu(from->di_onlink); | 845 | to->di_onlink = be16_to_cpu(from->di_onlink); |
846 | to->di_uid = be32_to_cpu(from->di_uid); | 846 | to->di_uid = be32_to_cpu(from->di_uid); |
847 | to->di_gid = be32_to_cpu(from->di_gid); | 847 | to->di_gid = be32_to_cpu(from->di_gid); |
848 | to->di_nlink = be32_to_cpu(from->di_nlink); | 848 | to->di_nlink = be32_to_cpu(from->di_nlink); |
849 | to->di_projid_lo = be16_to_cpu(from->di_projid_lo); | 849 | to->di_projid_lo = be16_to_cpu(from->di_projid_lo); |
850 | to->di_projid_hi = be16_to_cpu(from->di_projid_hi); | 850 | to->di_projid_hi = be16_to_cpu(from->di_projid_hi); |
851 | memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); | 851 | memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); |
852 | to->di_flushiter = be16_to_cpu(from->di_flushiter); | 852 | to->di_flushiter = be16_to_cpu(from->di_flushiter); |
853 | to->di_atime.t_sec = be32_to_cpu(from->di_atime.t_sec); | 853 | to->di_atime.t_sec = be32_to_cpu(from->di_atime.t_sec); |
854 | to->di_atime.t_nsec = be32_to_cpu(from->di_atime.t_nsec); | 854 | to->di_atime.t_nsec = be32_to_cpu(from->di_atime.t_nsec); |
855 | to->di_mtime.t_sec = be32_to_cpu(from->di_mtime.t_sec); | 855 | to->di_mtime.t_sec = be32_to_cpu(from->di_mtime.t_sec); |
856 | to->di_mtime.t_nsec = be32_to_cpu(from->di_mtime.t_nsec); | 856 | to->di_mtime.t_nsec = be32_to_cpu(from->di_mtime.t_nsec); |
857 | to->di_ctime.t_sec = be32_to_cpu(from->di_ctime.t_sec); | 857 | to->di_ctime.t_sec = be32_to_cpu(from->di_ctime.t_sec); |
858 | to->di_ctime.t_nsec = be32_to_cpu(from->di_ctime.t_nsec); | 858 | to->di_ctime.t_nsec = be32_to_cpu(from->di_ctime.t_nsec); |
859 | to->di_size = be64_to_cpu(from->di_size); | 859 | to->di_size = be64_to_cpu(from->di_size); |
860 | to->di_nblocks = be64_to_cpu(from->di_nblocks); | 860 | to->di_nblocks = be64_to_cpu(from->di_nblocks); |
861 | to->di_extsize = be32_to_cpu(from->di_extsize); | 861 | to->di_extsize = be32_to_cpu(from->di_extsize); |
862 | to->di_nextents = be32_to_cpu(from->di_nextents); | 862 | to->di_nextents = be32_to_cpu(from->di_nextents); |
863 | to->di_anextents = be16_to_cpu(from->di_anextents); | 863 | to->di_anextents = be16_to_cpu(from->di_anextents); |
864 | to->di_forkoff = from->di_forkoff; | 864 | to->di_forkoff = from->di_forkoff; |
865 | to->di_aformat = from->di_aformat; | 865 | to->di_aformat = from->di_aformat; |
866 | to->di_dmevmask = be32_to_cpu(from->di_dmevmask); | 866 | to->di_dmevmask = be32_to_cpu(from->di_dmevmask); |
867 | to->di_dmstate = be16_to_cpu(from->di_dmstate); | 867 | to->di_dmstate = be16_to_cpu(from->di_dmstate); |
868 | to->di_flags = be16_to_cpu(from->di_flags); | 868 | to->di_flags = be16_to_cpu(from->di_flags); |
869 | to->di_gen = be32_to_cpu(from->di_gen); | 869 | to->di_gen = be32_to_cpu(from->di_gen); |
870 | 870 | ||
871 | if (to->di_version == 3) { | 871 | if (to->di_version == 3) { |
872 | to->di_changecount = be64_to_cpu(from->di_changecount); | 872 | to->di_changecount = be64_to_cpu(from->di_changecount); |
873 | to->di_crtime.t_sec = be32_to_cpu(from->di_crtime.t_sec); | 873 | to->di_crtime.t_sec = be32_to_cpu(from->di_crtime.t_sec); |
874 | to->di_crtime.t_nsec = be32_to_cpu(from->di_crtime.t_nsec); | 874 | to->di_crtime.t_nsec = be32_to_cpu(from->di_crtime.t_nsec); |
875 | to->di_flags2 = be64_to_cpu(from->di_flags2); | 875 | to->di_flags2 = be64_to_cpu(from->di_flags2); |
876 | to->di_ino = be64_to_cpu(from->di_ino); | 876 | to->di_ino = be64_to_cpu(from->di_ino); |
877 | to->di_lsn = be64_to_cpu(from->di_lsn); | 877 | to->di_lsn = be64_to_cpu(from->di_lsn); |
878 | memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2)); | 878 | memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2)); |
879 | uuid_copy(&to->di_uuid, &from->di_uuid); | 879 | uuid_copy(&to->di_uuid, &from->di_uuid); |
880 | } | 880 | } |
881 | } | 881 | } |
882 | 882 | ||
883 | void | 883 | void |
884 | xfs_dinode_to_disk( | 884 | xfs_dinode_to_disk( |
885 | xfs_dinode_t *to, | 885 | xfs_dinode_t *to, |
886 | xfs_icdinode_t *from) | 886 | xfs_icdinode_t *from) |
887 | { | 887 | { |
888 | to->di_magic = cpu_to_be16(from->di_magic); | 888 | to->di_magic = cpu_to_be16(from->di_magic); |
889 | to->di_mode = cpu_to_be16(from->di_mode); | 889 | to->di_mode = cpu_to_be16(from->di_mode); |
890 | to->di_version = from ->di_version; | 890 | to->di_version = from ->di_version; |
891 | to->di_format = from->di_format; | 891 | to->di_format = from->di_format; |
892 | to->di_onlink = cpu_to_be16(from->di_onlink); | 892 | to->di_onlink = cpu_to_be16(from->di_onlink); |
893 | to->di_uid = cpu_to_be32(from->di_uid); | 893 | to->di_uid = cpu_to_be32(from->di_uid); |
894 | to->di_gid = cpu_to_be32(from->di_gid); | 894 | to->di_gid = cpu_to_be32(from->di_gid); |
895 | to->di_nlink = cpu_to_be32(from->di_nlink); | 895 | to->di_nlink = cpu_to_be32(from->di_nlink); |
896 | to->di_projid_lo = cpu_to_be16(from->di_projid_lo); | 896 | to->di_projid_lo = cpu_to_be16(from->di_projid_lo); |
897 | to->di_projid_hi = cpu_to_be16(from->di_projid_hi); | 897 | to->di_projid_hi = cpu_to_be16(from->di_projid_hi); |
898 | memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); | 898 | memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); |
899 | to->di_flushiter = cpu_to_be16(from->di_flushiter); | 899 | to->di_flushiter = cpu_to_be16(from->di_flushiter); |
900 | to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec); | 900 | to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec); |
901 | to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec); | 901 | to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec); |
902 | to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec); | 902 | to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec); |
903 | to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec); | 903 | to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec); |
904 | to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec); | 904 | to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec); |
905 | to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec); | 905 | to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec); |
906 | to->di_size = cpu_to_be64(from->di_size); | 906 | to->di_size = cpu_to_be64(from->di_size); |
907 | to->di_nblocks = cpu_to_be64(from->di_nblocks); | 907 | to->di_nblocks = cpu_to_be64(from->di_nblocks); |
908 | to->di_extsize = cpu_to_be32(from->di_extsize); | 908 | to->di_extsize = cpu_to_be32(from->di_extsize); |
909 | to->di_nextents = cpu_to_be32(from->di_nextents); | 909 | to->di_nextents = cpu_to_be32(from->di_nextents); |
910 | to->di_anextents = cpu_to_be16(from->di_anextents); | 910 | to->di_anextents = cpu_to_be16(from->di_anextents); |
911 | to->di_forkoff = from->di_forkoff; | 911 | to->di_forkoff = from->di_forkoff; |
912 | to->di_aformat = from->di_aformat; | 912 | to->di_aformat = from->di_aformat; |
913 | to->di_dmevmask = cpu_to_be32(from->di_dmevmask); | 913 | to->di_dmevmask = cpu_to_be32(from->di_dmevmask); |
914 | to->di_dmstate = cpu_to_be16(from->di_dmstate); | 914 | to->di_dmstate = cpu_to_be16(from->di_dmstate); |
915 | to->di_flags = cpu_to_be16(from->di_flags); | 915 | to->di_flags = cpu_to_be16(from->di_flags); |
916 | to->di_gen = cpu_to_be32(from->di_gen); | 916 | to->di_gen = cpu_to_be32(from->di_gen); |
917 | 917 | ||
918 | if (from->di_version == 3) { | 918 | if (from->di_version == 3) { |
919 | to->di_changecount = cpu_to_be64(from->di_changecount); | 919 | to->di_changecount = cpu_to_be64(from->di_changecount); |
920 | to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec); | 920 | to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec); |
921 | to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec); | 921 | to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec); |
922 | to->di_flags2 = cpu_to_be64(from->di_flags2); | 922 | to->di_flags2 = cpu_to_be64(from->di_flags2); |
923 | to->di_ino = cpu_to_be64(from->di_ino); | 923 | to->di_ino = cpu_to_be64(from->di_ino); |
924 | to->di_lsn = cpu_to_be64(from->di_lsn); | 924 | to->di_lsn = cpu_to_be64(from->di_lsn); |
925 | memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2)); | 925 | memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2)); |
926 | uuid_copy(&to->di_uuid, &from->di_uuid); | 926 | uuid_copy(&to->di_uuid, &from->di_uuid); |
927 | } | 927 | } |
928 | } | 928 | } |
929 | 929 | ||
930 | STATIC uint | 930 | STATIC uint |
931 | _xfs_dic2xflags( | 931 | _xfs_dic2xflags( |
932 | __uint16_t di_flags) | 932 | __uint16_t di_flags) |
933 | { | 933 | { |
934 | uint flags = 0; | 934 | uint flags = 0; |
935 | 935 | ||
936 | if (di_flags & XFS_DIFLAG_ANY) { | 936 | if (di_flags & XFS_DIFLAG_ANY) { |
937 | if (di_flags & XFS_DIFLAG_REALTIME) | 937 | if (di_flags & XFS_DIFLAG_REALTIME) |
938 | flags |= XFS_XFLAG_REALTIME; | 938 | flags |= XFS_XFLAG_REALTIME; |
939 | if (di_flags & XFS_DIFLAG_PREALLOC) | 939 | if (di_flags & XFS_DIFLAG_PREALLOC) |
940 | flags |= XFS_XFLAG_PREALLOC; | 940 | flags |= XFS_XFLAG_PREALLOC; |
941 | if (di_flags & XFS_DIFLAG_IMMUTABLE) | 941 | if (di_flags & XFS_DIFLAG_IMMUTABLE) |
942 | flags |= XFS_XFLAG_IMMUTABLE; | 942 | flags |= XFS_XFLAG_IMMUTABLE; |
943 | if (di_flags & XFS_DIFLAG_APPEND) | 943 | if (di_flags & XFS_DIFLAG_APPEND) |
944 | flags |= XFS_XFLAG_APPEND; | 944 | flags |= XFS_XFLAG_APPEND; |
945 | if (di_flags & XFS_DIFLAG_SYNC) | 945 | if (di_flags & XFS_DIFLAG_SYNC) |
946 | flags |= XFS_XFLAG_SYNC; | 946 | flags |= XFS_XFLAG_SYNC; |
947 | if (di_flags & XFS_DIFLAG_NOATIME) | 947 | if (di_flags & XFS_DIFLAG_NOATIME) |
948 | flags |= XFS_XFLAG_NOATIME; | 948 | flags |= XFS_XFLAG_NOATIME; |
949 | if (di_flags & XFS_DIFLAG_NODUMP) | 949 | if (di_flags & XFS_DIFLAG_NODUMP) |
950 | flags |= XFS_XFLAG_NODUMP; | 950 | flags |= XFS_XFLAG_NODUMP; |
951 | if (di_flags & XFS_DIFLAG_RTINHERIT) | 951 | if (di_flags & XFS_DIFLAG_RTINHERIT) |
952 | flags |= XFS_XFLAG_RTINHERIT; | 952 | flags |= XFS_XFLAG_RTINHERIT; |
953 | if (di_flags & XFS_DIFLAG_PROJINHERIT) | 953 | if (di_flags & XFS_DIFLAG_PROJINHERIT) |
954 | flags |= XFS_XFLAG_PROJINHERIT; | 954 | flags |= XFS_XFLAG_PROJINHERIT; |
955 | if (di_flags & XFS_DIFLAG_NOSYMLINKS) | 955 | if (di_flags & XFS_DIFLAG_NOSYMLINKS) |
956 | flags |= XFS_XFLAG_NOSYMLINKS; | 956 | flags |= XFS_XFLAG_NOSYMLINKS; |
957 | if (di_flags & XFS_DIFLAG_EXTSIZE) | 957 | if (di_flags & XFS_DIFLAG_EXTSIZE) |
958 | flags |= XFS_XFLAG_EXTSIZE; | 958 | flags |= XFS_XFLAG_EXTSIZE; |
959 | if (di_flags & XFS_DIFLAG_EXTSZINHERIT) | 959 | if (di_flags & XFS_DIFLAG_EXTSZINHERIT) |
960 | flags |= XFS_XFLAG_EXTSZINHERIT; | 960 | flags |= XFS_XFLAG_EXTSZINHERIT; |
961 | if (di_flags & XFS_DIFLAG_NODEFRAG) | 961 | if (di_flags & XFS_DIFLAG_NODEFRAG) |
962 | flags |= XFS_XFLAG_NODEFRAG; | 962 | flags |= XFS_XFLAG_NODEFRAG; |
963 | if (di_flags & XFS_DIFLAG_FILESTREAM) | 963 | if (di_flags & XFS_DIFLAG_FILESTREAM) |
964 | flags |= XFS_XFLAG_FILESTREAM; | 964 | flags |= XFS_XFLAG_FILESTREAM; |
965 | } | 965 | } |
966 | 966 | ||
967 | return flags; | 967 | return flags; |
968 | } | 968 | } |
969 | 969 | ||
970 | uint | 970 | uint |
971 | xfs_ip2xflags( | 971 | xfs_ip2xflags( |
972 | xfs_inode_t *ip) | 972 | xfs_inode_t *ip) |
973 | { | 973 | { |
974 | xfs_icdinode_t *dic = &ip->i_d; | 974 | xfs_icdinode_t *dic = &ip->i_d; |
975 | 975 | ||
976 | return _xfs_dic2xflags(dic->di_flags) | | 976 | return _xfs_dic2xflags(dic->di_flags) | |
977 | (XFS_IFORK_Q(ip) ? XFS_XFLAG_HASATTR : 0); | 977 | (XFS_IFORK_Q(ip) ? XFS_XFLAG_HASATTR : 0); |
978 | } | 978 | } |
979 | 979 | ||
980 | uint | 980 | uint |
981 | xfs_dic2xflags( | 981 | xfs_dic2xflags( |
982 | xfs_dinode_t *dip) | 982 | xfs_dinode_t *dip) |
983 | { | 983 | { |
984 | return _xfs_dic2xflags(be16_to_cpu(dip->di_flags)) | | 984 | return _xfs_dic2xflags(be16_to_cpu(dip->di_flags)) | |
985 | (XFS_DFORK_Q(dip) ? XFS_XFLAG_HASATTR : 0); | 985 | (XFS_DFORK_Q(dip) ? XFS_XFLAG_HASATTR : 0); |
986 | } | 986 | } |
987 | 987 | ||
988 | static bool | 988 | static bool |
989 | xfs_dinode_verify( | 989 | xfs_dinode_verify( |
990 | struct xfs_mount *mp, | 990 | struct xfs_mount *mp, |
991 | struct xfs_inode *ip, | 991 | struct xfs_inode *ip, |
992 | struct xfs_dinode *dip) | 992 | struct xfs_dinode *dip) |
993 | { | 993 | { |
994 | if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) | 994 | if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) |
995 | return false; | 995 | return false; |
996 | 996 | ||
997 | /* only version 3 or greater inodes are extensively verified here */ | 997 | /* only version 3 or greater inodes are extensively verified here */ |
998 | if (dip->di_version < 3) | 998 | if (dip->di_version < 3) |
999 | return true; | 999 | return true; |
1000 | 1000 | ||
1001 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | 1001 | if (!xfs_sb_version_hascrc(&mp->m_sb)) |
1002 | return false; | 1002 | return false; |
1003 | if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize, | 1003 | if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize, |
1004 | offsetof(struct xfs_dinode, di_crc))) | 1004 | offsetof(struct xfs_dinode, di_crc))) |
1005 | return false; | 1005 | return false; |
1006 | if (be64_to_cpu(dip->di_ino) != ip->i_ino) | 1006 | if (be64_to_cpu(dip->di_ino) != ip->i_ino) |
1007 | return false; | 1007 | return false; |
1008 | if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid)) | 1008 | if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid)) |
1009 | return false; | 1009 | return false; |
1010 | return true; | 1010 | return true; |
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | void | 1013 | void |
1014 | xfs_dinode_calc_crc( | 1014 | xfs_dinode_calc_crc( |
1015 | struct xfs_mount *mp, | 1015 | struct xfs_mount *mp, |
1016 | struct xfs_dinode *dip) | 1016 | struct xfs_dinode *dip) |
1017 | { | 1017 | { |
1018 | __uint32_t crc; | 1018 | __uint32_t crc; |
1019 | 1019 | ||
1020 | if (dip->di_version < 3) | 1020 | if (dip->di_version < 3) |
1021 | return; | 1021 | return; |
1022 | 1022 | ||
1023 | ASSERT(xfs_sb_version_hascrc(&mp->m_sb)); | 1023 | ASSERT(xfs_sb_version_hascrc(&mp->m_sb)); |
1024 | crc = xfs_start_cksum((char *)dip, mp->m_sb.sb_inodesize, | 1024 | crc = xfs_start_cksum((char *)dip, mp->m_sb.sb_inodesize, |
1025 | offsetof(struct xfs_dinode, di_crc)); | 1025 | offsetof(struct xfs_dinode, di_crc)); |
1026 | dip->di_crc = xfs_end_cksum(crc); | 1026 | dip->di_crc = xfs_end_cksum(crc); |
1027 | } | 1027 | } |
1028 | 1028 | ||
1029 | /* | 1029 | /* |
1030 | * Read the disk inode attributes into the in-core inode structure. | 1030 | * Read the disk inode attributes into the in-core inode structure. |
1031 | */ | 1031 | */ |
1032 | int | 1032 | int |
1033 | xfs_iread( | 1033 | xfs_iread( |
1034 | xfs_mount_t *mp, | 1034 | xfs_mount_t *mp, |
1035 | xfs_trans_t *tp, | 1035 | xfs_trans_t *tp, |
1036 | xfs_inode_t *ip, | 1036 | xfs_inode_t *ip, |
1037 | uint iget_flags) | 1037 | uint iget_flags) |
1038 | { | 1038 | { |
1039 | xfs_buf_t *bp; | 1039 | xfs_buf_t *bp; |
1040 | xfs_dinode_t *dip; | 1040 | xfs_dinode_t *dip; |
1041 | int error; | 1041 | int error; |
1042 | 1042 | ||
1043 | /* | 1043 | /* |
1044 | * Fill in the location information in the in-core inode. | 1044 | * Fill in the location information in the in-core inode. |
1045 | */ | 1045 | */ |
1046 | error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags); | 1046 | error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags); |
1047 | if (error) | 1047 | if (error) |
1048 | return error; | 1048 | return error; |
1049 | 1049 | ||
1050 | /* | 1050 | /* |
1051 | * Get pointers to the on-disk inode and the buffer containing it. | 1051 | * Get pointers to the on-disk inode and the buffer containing it. |
1052 | */ | 1052 | */ |
1053 | error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &bp, 0, iget_flags); | 1053 | error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &bp, 0, iget_flags); |
1054 | if (error) | 1054 | if (error) |
1055 | return error; | 1055 | return error; |
1056 | 1056 | ||
1057 | /* even unallocated inodes are verified */ | 1057 | /* even unallocated inodes are verified */ |
1058 | if (!xfs_dinode_verify(mp, ip, dip)) { | 1058 | if (!xfs_dinode_verify(mp, ip, dip)) { |
1059 | xfs_alert(mp, "%s: validation failed for inode %lld failed", | 1059 | xfs_alert(mp, "%s: validation failed for inode %lld failed", |
1060 | __func__, ip->i_ino); | 1060 | __func__, ip->i_ino); |
1061 | 1061 | ||
1062 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, dip); | 1062 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, dip); |
1063 | error = XFS_ERROR(EFSCORRUPTED); | 1063 | error = XFS_ERROR(EFSCORRUPTED); |
1064 | goto out_brelse; | 1064 | goto out_brelse; |
1065 | } | 1065 | } |
1066 | 1066 | ||
1067 | /* | 1067 | /* |
1068 | * If the on-disk inode is already linked to a directory | 1068 | * If the on-disk inode is already linked to a directory |
1069 | * entry, copy all of the inode into the in-core inode. | 1069 | * entry, copy all of the inode into the in-core inode. |
1070 | * xfs_iformat() handles copying in the inode format | 1070 | * xfs_iformat() handles copying in the inode format |
1071 | * specific information. | 1071 | * specific information. |
1072 | * Otherwise, just get the truly permanent information. | 1072 | * Otherwise, just get the truly permanent information. |
1073 | */ | 1073 | */ |
1074 | if (dip->di_mode) { | 1074 | if (dip->di_mode) { |
1075 | xfs_dinode_from_disk(&ip->i_d, dip); | 1075 | xfs_dinode_from_disk(&ip->i_d, dip); |
1076 | error = xfs_iformat(ip, dip); | 1076 | error = xfs_iformat(ip, dip); |
1077 | if (error) { | 1077 | if (error) { |
1078 | #ifdef DEBUG | 1078 | #ifdef DEBUG |
1079 | xfs_alert(mp, "%s: xfs_iformat() returned error %d", | 1079 | xfs_alert(mp, "%s: xfs_iformat() returned error %d", |
1080 | __func__, error); | 1080 | __func__, error); |
1081 | #endif /* DEBUG */ | 1081 | #endif /* DEBUG */ |
1082 | goto out_brelse; | 1082 | goto out_brelse; |
1083 | } | 1083 | } |
1084 | } else { | 1084 | } else { |
1085 | /* | 1085 | /* |
1086 | * Partial initialisation of the in-core inode. Just the bits | 1086 | * Partial initialisation of the in-core inode. Just the bits |
1087 | * that xfs_ialloc won't overwrite or relies on being correct. | 1087 | * that xfs_ialloc won't overwrite or relies on being correct. |
1088 | */ | 1088 | */ |
1089 | ip->i_d.di_magic = be16_to_cpu(dip->di_magic); | 1089 | ip->i_d.di_magic = be16_to_cpu(dip->di_magic); |
1090 | ip->i_d.di_version = dip->di_version; | 1090 | ip->i_d.di_version = dip->di_version; |
1091 | ip->i_d.di_gen = be32_to_cpu(dip->di_gen); | 1091 | ip->i_d.di_gen = be32_to_cpu(dip->di_gen); |
1092 | ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter); | 1092 | ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter); |
1093 | 1093 | ||
1094 | if (dip->di_version == 3) { | 1094 | if (dip->di_version == 3) { |
1095 | ip->i_d.di_ino = be64_to_cpu(dip->di_ino); | 1095 | ip->i_d.di_ino = be64_to_cpu(dip->di_ino); |
1096 | uuid_copy(&ip->i_d.di_uuid, &dip->di_uuid); | 1096 | uuid_copy(&ip->i_d.di_uuid, &dip->di_uuid); |
1097 | } | 1097 | } |
1098 | 1098 | ||
1099 | /* | 1099 | /* |
1100 | * Make sure to pull in the mode here as well in | 1100 | * Make sure to pull in the mode here as well in |
1101 | * case the inode is released without being used. | 1101 | * case the inode is released without being used. |
1102 | * This ensures that xfs_inactive() will see that | 1102 | * This ensures that xfs_inactive() will see that |
1103 | * the inode is already free and not try to mess | 1103 | * the inode is already free and not try to mess |
1104 | * with the uninitialized part of it. | 1104 | * with the uninitialized part of it. |
1105 | */ | 1105 | */ |
1106 | ip->i_d.di_mode = 0; | 1106 | ip->i_d.di_mode = 0; |
1107 | } | 1107 | } |
1108 | 1108 | ||
1109 | /* | 1109 | /* |
1110 | * The inode format changed when we moved the link count and | 1110 | * The inode format changed when we moved the link count and |
1111 | * made it 32 bits long. If this is an old format inode, | 1111 | * made it 32 bits long. If this is an old format inode, |
1112 | * convert it in memory to look like a new one. If it gets | 1112 | * convert it in memory to look like a new one. If it gets |
1113 | * flushed to disk we will convert back before flushing or | 1113 | * flushed to disk we will convert back before flushing or |
1114 | * logging it. We zero out the new projid field and the old link | 1114 | * logging it. We zero out the new projid field and the old link |
1115 | * count field. We'll handle clearing the pad field (the remains | 1115 | * count field. We'll handle clearing the pad field (the remains |
1116 | * of the old uuid field) when we actually convert the inode to | 1116 | * of the old uuid field) when we actually convert the inode to |
1117 | * the new format. We don't change the version number so that we | 1117 | * the new format. We don't change the version number so that we |
1118 | * can distinguish this from a real new format inode. | 1118 | * can distinguish this from a real new format inode. |
1119 | */ | 1119 | */ |
1120 | if (ip->i_d.di_version == 1) { | 1120 | if (ip->i_d.di_version == 1) { |
1121 | ip->i_d.di_nlink = ip->i_d.di_onlink; | 1121 | ip->i_d.di_nlink = ip->i_d.di_onlink; |
1122 | ip->i_d.di_onlink = 0; | 1122 | ip->i_d.di_onlink = 0; |
1123 | xfs_set_projid(ip, 0); | 1123 | xfs_set_projid(ip, 0); |
1124 | } | 1124 | } |
1125 | 1125 | ||
1126 | ip->i_delayed_blks = 0; | 1126 | ip->i_delayed_blks = 0; |
1127 | 1127 | ||
1128 | /* | 1128 | /* |
1129 | * Mark the buffer containing the inode as something to keep | 1129 | * Mark the buffer containing the inode as something to keep |
1130 | * around for a while. This helps to keep recently accessed | 1130 | * around for a while. This helps to keep recently accessed |
1131 | * meta-data in-core longer. | 1131 | * meta-data in-core longer. |
1132 | */ | 1132 | */ |
1133 | xfs_buf_set_ref(bp, XFS_INO_REF); | 1133 | xfs_buf_set_ref(bp, XFS_INO_REF); |
1134 | 1134 | ||
1135 | /* | 1135 | /* |
1136 | * Use xfs_trans_brelse() to release the buffer containing the | 1136 | * Use xfs_trans_brelse() to release the buffer containing the |
1137 | * on-disk inode, because it was acquired with xfs_trans_read_buf() | 1137 | * on-disk inode, because it was acquired with xfs_trans_read_buf() |
1138 | * in xfs_imap_to_bp() above. If tp is NULL, this is just a normal | 1138 | * in xfs_imap_to_bp() above. If tp is NULL, this is just a normal |
1139 | * brelse(). If we're within a transaction, then xfs_trans_brelse() | 1139 | * brelse(). If we're within a transaction, then xfs_trans_brelse() |
1140 | * will only release the buffer if it is not dirty within the | 1140 | * will only release the buffer if it is not dirty within the |
1141 | * transaction. It will be OK to release the buffer in this case, | 1141 | * transaction. It will be OK to release the buffer in this case, |
1142 | * because inodes on disk are never destroyed and we will be | 1142 | * because inodes on disk are never destroyed and we will be |
1143 | * locking the new in-core inode before putting it in the hash | 1143 | * locking the new in-core inode before putting it in the hash |
1144 | * table where other processes can find it. Thus we don't have | 1144 | * table where other processes can find it. Thus we don't have |
1145 | * to worry about the inode being changed just because we released | 1145 | * to worry about the inode being changed just because we released |
1146 | * the buffer. | 1146 | * the buffer. |
1147 | */ | 1147 | */ |
1148 | out_brelse: | 1148 | out_brelse: |
1149 | xfs_trans_brelse(tp, bp); | 1149 | xfs_trans_brelse(tp, bp); |
1150 | return error; | 1150 | return error; |
1151 | } | 1151 | } |
1152 | 1152 | ||
1153 | /* | 1153 | /* |
1154 | * Read in extents from a btree-format inode. | 1154 | * Read in extents from a btree-format inode. |
1155 | * Allocate and fill in if_extents. Real work is done in xfs_bmap.c. | 1155 | * Allocate and fill in if_extents. Real work is done in xfs_bmap.c. |
1156 | */ | 1156 | */ |
1157 | int | 1157 | int |
1158 | xfs_iread_extents( | 1158 | xfs_iread_extents( |
1159 | xfs_trans_t *tp, | 1159 | xfs_trans_t *tp, |
1160 | xfs_inode_t *ip, | 1160 | xfs_inode_t *ip, |
1161 | int whichfork) | 1161 | int whichfork) |
1162 | { | 1162 | { |
1163 | int error; | 1163 | int error; |
1164 | xfs_ifork_t *ifp; | 1164 | xfs_ifork_t *ifp; |
1165 | xfs_extnum_t nextents; | 1165 | xfs_extnum_t nextents; |
1166 | 1166 | ||
1167 | if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) { | 1167 | if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) { |
1168 | XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW, | 1168 | XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW, |
1169 | ip->i_mount); | 1169 | ip->i_mount); |
1170 | return XFS_ERROR(EFSCORRUPTED); | 1170 | return XFS_ERROR(EFSCORRUPTED); |
1171 | } | 1171 | } |
1172 | nextents = XFS_IFORK_NEXTENTS(ip, whichfork); | 1172 | nextents = XFS_IFORK_NEXTENTS(ip, whichfork); |
1173 | ifp = XFS_IFORK_PTR(ip, whichfork); | 1173 | ifp = XFS_IFORK_PTR(ip, whichfork); |
1174 | 1174 | ||
1175 | /* | 1175 | /* |
1176 | * We know that the size is valid (it's checked in iformat_btree) | 1176 | * We know that the size is valid (it's checked in iformat_btree) |
1177 | */ | 1177 | */ |
1178 | ifp->if_bytes = ifp->if_real_bytes = 0; | 1178 | ifp->if_bytes = ifp->if_real_bytes = 0; |
1179 | ifp->if_flags |= XFS_IFEXTENTS; | 1179 | ifp->if_flags |= XFS_IFEXTENTS; |
1180 | xfs_iext_add(ifp, 0, nextents); | 1180 | xfs_iext_add(ifp, 0, nextents); |
1181 | error = xfs_bmap_read_extents(tp, ip, whichfork); | 1181 | error = xfs_bmap_read_extents(tp, ip, whichfork); |
1182 | if (error) { | 1182 | if (error) { |
1183 | xfs_iext_destroy(ifp); | 1183 | xfs_iext_destroy(ifp); |
1184 | ifp->if_flags &= ~XFS_IFEXTENTS; | 1184 | ifp->if_flags &= ~XFS_IFEXTENTS; |
1185 | return error; | 1185 | return error; |
1186 | } | 1186 | } |
1187 | xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip)); | 1187 | xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip)); |
1188 | return 0; | 1188 | return 0; |
1189 | } | 1189 | } |
1190 | 1190 | ||
1191 | /* | 1191 | /* |
1192 | * Allocate an inode on disk and return a copy of its in-core version. | 1192 | * Allocate an inode on disk and return a copy of its in-core version. |
1193 | * The in-core inode is locked exclusively. Set mode, nlink, and rdev | 1193 | * The in-core inode is locked exclusively. Set mode, nlink, and rdev |
1194 | * appropriately within the inode. The uid and gid for the inode are | 1194 | * appropriately within the inode. The uid and gid for the inode are |
1195 | * set according to the contents of the given cred structure. | 1195 | * set according to the contents of the given cred structure. |
1196 | * | 1196 | * |
1197 | * Use xfs_dialloc() to allocate the on-disk inode. If xfs_dialloc() | 1197 | * Use xfs_dialloc() to allocate the on-disk inode. If xfs_dialloc() |
1198 | * has a free inode available, call xfs_iget() to obtain the in-core | 1198 | * has a free inode available, call xfs_iget() to obtain the in-core |
1199 | * version of the allocated inode. Finally, fill in the inode and | 1199 | * version of the allocated inode. Finally, fill in the inode and |
1200 | * log its initial contents. In this case, ialloc_context would be | 1200 | * log its initial contents. In this case, ialloc_context would be |
1201 | * set to NULL. | 1201 | * set to NULL. |
1202 | * | 1202 | * |
1203 | * If xfs_dialloc() does not have an available inode, it will replenish | 1203 | * If xfs_dialloc() does not have an available inode, it will replenish |
1204 | * its supply by doing an allocation. Since we can only do one | 1204 | * its supply by doing an allocation. Since we can only do one |
1205 | * allocation within a transaction without deadlocks, we must commit | 1205 | * allocation within a transaction without deadlocks, we must commit |
1206 | * the current transaction before returning the inode itself. | 1206 | * the current transaction before returning the inode itself. |
1207 | * In this case, therefore, we will set ialloc_context and return. | 1207 | * In this case, therefore, we will set ialloc_context and return. |
1208 | * The caller should then commit the current transaction, start a new | 1208 | * The caller should then commit the current transaction, start a new |
1209 | * transaction, and call xfs_ialloc() again to actually get the inode. | 1209 | * transaction, and call xfs_ialloc() again to actually get the inode. |
1210 | * | 1210 | * |
1211 | * To ensure that some other process does not grab the inode that | 1211 | * To ensure that some other process does not grab the inode that |
1212 | * was allocated during the first call to xfs_ialloc(), this routine | 1212 | * was allocated during the first call to xfs_ialloc(), this routine |
1213 | * also returns the [locked] bp pointing to the head of the freelist | 1213 | * also returns the [locked] bp pointing to the head of the freelist |
1214 | * as ialloc_context. The caller should hold this buffer across | 1214 | * as ialloc_context. The caller should hold this buffer across |
1215 | * the commit and pass it back into this routine on the second call. | 1215 | * the commit and pass it back into this routine on the second call. |
1216 | * | 1216 | * |
1217 | * If we are allocating quota inodes, we do not have a parent inode | 1217 | * If we are allocating quota inodes, we do not have a parent inode |
1218 | * to attach to or associate with (i.e. pip == NULL) because they | 1218 | * to attach to or associate with (i.e. pip == NULL) because they |
1219 | * are not linked into the directory structure - they are attached | 1219 | * are not linked into the directory structure - they are attached |
1220 | * directly to the superblock - and so have no parent. | 1220 | * directly to the superblock - and so have no parent. |
1221 | */ | 1221 | */ |
1222 | int | 1222 | int |
1223 | xfs_ialloc( | 1223 | xfs_ialloc( |
1224 | xfs_trans_t *tp, | 1224 | xfs_trans_t *tp, |
1225 | xfs_inode_t *pip, | 1225 | xfs_inode_t *pip, |
1226 | umode_t mode, | 1226 | umode_t mode, |
1227 | xfs_nlink_t nlink, | 1227 | xfs_nlink_t nlink, |
1228 | xfs_dev_t rdev, | 1228 | xfs_dev_t rdev, |
1229 | prid_t prid, | 1229 | prid_t prid, |
1230 | int okalloc, | 1230 | int okalloc, |
1231 | xfs_buf_t **ialloc_context, | 1231 | xfs_buf_t **ialloc_context, |
1232 | xfs_inode_t **ipp) | 1232 | xfs_inode_t **ipp) |
1233 | { | 1233 | { |
1234 | struct xfs_mount *mp = tp->t_mountp; | 1234 | struct xfs_mount *mp = tp->t_mountp; |
1235 | xfs_ino_t ino; | 1235 | xfs_ino_t ino; |
1236 | xfs_inode_t *ip; | 1236 | xfs_inode_t *ip; |
1237 | uint flags; | 1237 | uint flags; |
1238 | int error; | 1238 | int error; |
1239 | timespec_t tv; | 1239 | timespec_t tv; |
1240 | int filestreams = 0; | 1240 | int filestreams = 0; |
1241 | 1241 | ||
1242 | /* | 1242 | /* |
1243 | * Call the space management code to pick | 1243 | * Call the space management code to pick |
1244 | * the on-disk inode to be allocated. | 1244 | * the on-disk inode to be allocated. |
1245 | */ | 1245 | */ |
1246 | error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc, | 1246 | error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc, |
1247 | ialloc_context, &ino); | 1247 | ialloc_context, &ino); |
1248 | if (error) | 1248 | if (error) |
1249 | return error; | 1249 | return error; |
1250 | if (*ialloc_context || ino == NULLFSINO) { | 1250 | if (*ialloc_context || ino == NULLFSINO) { |
1251 | *ipp = NULL; | 1251 | *ipp = NULL; |
1252 | return 0; | 1252 | return 0; |
1253 | } | 1253 | } |
1254 | ASSERT(*ialloc_context == NULL); | 1254 | ASSERT(*ialloc_context == NULL); |
1255 | 1255 | ||
1256 | /* | 1256 | /* |
1257 | * Get the in-core inode with the lock held exclusively. | 1257 | * Get the in-core inode with the lock held exclusively. |
1258 | * This is because we're setting fields here we need | 1258 | * This is because we're setting fields here we need |
1259 | * to prevent others from looking at until we're done. | 1259 | * to prevent others from looking at until we're done. |
1260 | */ | 1260 | */ |
1261 | error = xfs_iget(mp, tp, ino, XFS_IGET_CREATE, | 1261 | error = xfs_iget(mp, tp, ino, XFS_IGET_CREATE, |
1262 | XFS_ILOCK_EXCL, &ip); | 1262 | XFS_ILOCK_EXCL, &ip); |
1263 | if (error) | 1263 | if (error) |
1264 | return error; | 1264 | return error; |
1265 | ASSERT(ip != NULL); | 1265 | ASSERT(ip != NULL); |
1266 | 1266 | ||
1267 | ip->i_d.di_mode = mode; | 1267 | ip->i_d.di_mode = mode; |
1268 | ip->i_d.di_onlink = 0; | 1268 | ip->i_d.di_onlink = 0; |
1269 | ip->i_d.di_nlink = nlink; | 1269 | ip->i_d.di_nlink = nlink; |
1270 | ASSERT(ip->i_d.di_nlink == nlink); | 1270 | ASSERT(ip->i_d.di_nlink == nlink); |
1271 | ip->i_d.di_uid = current_fsuid(); | 1271 | ip->i_d.di_uid = current_fsuid(); |
1272 | ip->i_d.di_gid = current_fsgid(); | 1272 | ip->i_d.di_gid = current_fsgid(); |
1273 | xfs_set_projid(ip, prid); | 1273 | xfs_set_projid(ip, prid); |
1274 | memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); | 1274 | memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); |
1275 | 1275 | ||
1276 | /* | 1276 | /* |
1277 | * If the superblock version is up to where we support new format | 1277 | * If the superblock version is up to where we support new format |
1278 | * inodes and this is currently an old format inode, then change | 1278 | * inodes and this is currently an old format inode, then change |
1279 | * the inode version number now. This way we only do the conversion | 1279 | * the inode version number now. This way we only do the conversion |
1280 | * here rather than here and in the flush/logging code. | 1280 | * here rather than here and in the flush/logging code. |
1281 | */ | 1281 | */ |
1282 | if (xfs_sb_version_hasnlink(&mp->m_sb) && | 1282 | if (xfs_sb_version_hasnlink(&mp->m_sb) && |
1283 | ip->i_d.di_version == 1) { | 1283 | ip->i_d.di_version == 1) { |
1284 | ip->i_d.di_version = 2; | 1284 | ip->i_d.di_version = 2; |
1285 | /* | 1285 | /* |
1286 | * We've already zeroed the old link count, the projid field, | 1286 | * We've already zeroed the old link count, the projid field, |
1287 | * and the pad field. | 1287 | * and the pad field. |
1288 | */ | 1288 | */ |
1289 | } | 1289 | } |
1290 | 1290 | ||
1291 | /* | 1291 | /* |
1292 | * Project ids won't be stored on disk if we are using a version 1 inode. | 1292 | * Project ids won't be stored on disk if we are using a version 1 inode. |
1293 | */ | 1293 | */ |
1294 | if ((prid != 0) && (ip->i_d.di_version == 1)) | 1294 | if ((prid != 0) && (ip->i_d.di_version == 1)) |
1295 | xfs_bump_ino_vers2(tp, ip); | 1295 | xfs_bump_ino_vers2(tp, ip); |
1296 | 1296 | ||
1297 | if (pip && XFS_INHERIT_GID(pip)) { | 1297 | if (pip && XFS_INHERIT_GID(pip)) { |
1298 | ip->i_d.di_gid = pip->i_d.di_gid; | 1298 | ip->i_d.di_gid = pip->i_d.di_gid; |
1299 | if ((pip->i_d.di_mode & S_ISGID) && S_ISDIR(mode)) { | 1299 | if ((pip->i_d.di_mode & S_ISGID) && S_ISDIR(mode)) { |
1300 | ip->i_d.di_mode |= S_ISGID; | 1300 | ip->i_d.di_mode |= S_ISGID; |
1301 | } | 1301 | } |
1302 | } | 1302 | } |
1303 | 1303 | ||
1304 | /* | 1304 | /* |
1305 | * If the group ID of the new file does not match the effective group | 1305 | * If the group ID of the new file does not match the effective group |
1306 | * ID or one of the supplementary group IDs, the S_ISGID bit is cleared | 1306 | * ID or one of the supplementary group IDs, the S_ISGID bit is cleared |
1307 | * (and only if the irix_sgid_inherit compatibility variable is set). | 1307 | * (and only if the irix_sgid_inherit compatibility variable is set). |
1308 | */ | 1308 | */ |
1309 | if ((irix_sgid_inherit) && | 1309 | if ((irix_sgid_inherit) && |
1310 | (ip->i_d.di_mode & S_ISGID) && | 1310 | (ip->i_d.di_mode & S_ISGID) && |
1311 | (!in_group_p((gid_t)ip->i_d.di_gid))) { | 1311 | (!in_group_p((gid_t)ip->i_d.di_gid))) { |
1312 | ip->i_d.di_mode &= ~S_ISGID; | 1312 | ip->i_d.di_mode &= ~S_ISGID; |
1313 | } | 1313 | } |
1314 | 1314 | ||
1315 | ip->i_d.di_size = 0; | 1315 | ip->i_d.di_size = 0; |
1316 | ip->i_d.di_nextents = 0; | 1316 | ip->i_d.di_nextents = 0; |
1317 | ASSERT(ip->i_d.di_nblocks == 0); | 1317 | ASSERT(ip->i_d.di_nblocks == 0); |
1318 | 1318 | ||
1319 | nanotime(&tv); | 1319 | nanotime(&tv); |
1320 | ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec; | 1320 | ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec; |
1321 | ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec; | 1321 | ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec; |
1322 | ip->i_d.di_atime = ip->i_d.di_mtime; | 1322 | ip->i_d.di_atime = ip->i_d.di_mtime; |
1323 | ip->i_d.di_ctime = ip->i_d.di_mtime; | 1323 | ip->i_d.di_ctime = ip->i_d.di_mtime; |
1324 | 1324 | ||
1325 | /* | 1325 | /* |
1326 | * di_gen will have been taken care of in xfs_iread. | 1326 | * di_gen will have been taken care of in xfs_iread. |
1327 | */ | 1327 | */ |
1328 | ip->i_d.di_extsize = 0; | 1328 | ip->i_d.di_extsize = 0; |
1329 | ip->i_d.di_dmevmask = 0; | 1329 | ip->i_d.di_dmevmask = 0; |
1330 | ip->i_d.di_dmstate = 0; | 1330 | ip->i_d.di_dmstate = 0; |
1331 | ip->i_d.di_flags = 0; | 1331 | ip->i_d.di_flags = 0; |
1332 | 1332 | ||
1333 | if (ip->i_d.di_version == 3) { | 1333 | if (ip->i_d.di_version == 3) { |
1334 | ASSERT(ip->i_d.di_ino == ino); | 1334 | ASSERT(ip->i_d.di_ino == ino); |
1335 | ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid)); | 1335 | ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid)); |
1336 | ip->i_d.di_crc = 0; | 1336 | ip->i_d.di_crc = 0; |
1337 | ip->i_d.di_changecount = 1; | 1337 | ip->i_d.di_changecount = 1; |
1338 | ip->i_d.di_lsn = 0; | 1338 | ip->i_d.di_lsn = 0; |
1339 | ip->i_d.di_flags2 = 0; | 1339 | ip->i_d.di_flags2 = 0; |
1340 | memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2)); | 1340 | memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2)); |
1341 | ip->i_d.di_crtime = ip->i_d.di_mtime; | 1341 | ip->i_d.di_crtime = ip->i_d.di_mtime; |
1342 | } | 1342 | } |
1343 | 1343 | ||
1344 | 1344 | ||
1345 | flags = XFS_ILOG_CORE; | 1345 | flags = XFS_ILOG_CORE; |
1346 | switch (mode & S_IFMT) { | 1346 | switch (mode & S_IFMT) { |
1347 | case S_IFIFO: | 1347 | case S_IFIFO: |
1348 | case S_IFCHR: | 1348 | case S_IFCHR: |
1349 | case S_IFBLK: | 1349 | case S_IFBLK: |
1350 | case S_IFSOCK: | 1350 | case S_IFSOCK: |
1351 | ip->i_d.di_format = XFS_DINODE_FMT_DEV; | 1351 | ip->i_d.di_format = XFS_DINODE_FMT_DEV; |
1352 | ip->i_df.if_u2.if_rdev = rdev; | 1352 | ip->i_df.if_u2.if_rdev = rdev; |
1353 | ip->i_df.if_flags = 0; | 1353 | ip->i_df.if_flags = 0; |
1354 | flags |= XFS_ILOG_DEV; | 1354 | flags |= XFS_ILOG_DEV; |
1355 | break; | 1355 | break; |
1356 | case S_IFREG: | 1356 | case S_IFREG: |
1357 | /* | 1357 | /* |
1358 | * we can't set up filestreams until after the VFS inode | 1358 | * we can't set up filestreams until after the VFS inode |
1359 | * is set up properly. | 1359 | * is set up properly. |
1360 | */ | 1360 | */ |
1361 | if (pip && xfs_inode_is_filestream(pip)) | 1361 | if (pip && xfs_inode_is_filestream(pip)) |
1362 | filestreams = 1; | 1362 | filestreams = 1; |
1363 | /* fall through */ | 1363 | /* fall through */ |
1364 | case S_IFDIR: | 1364 | case S_IFDIR: |
1365 | if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) { | 1365 | if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) { |
1366 | uint di_flags = 0; | 1366 | uint di_flags = 0; |
1367 | 1367 | ||
1368 | if (S_ISDIR(mode)) { | 1368 | if (S_ISDIR(mode)) { |
1369 | if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) | 1369 | if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) |
1370 | di_flags |= XFS_DIFLAG_RTINHERIT; | 1370 | di_flags |= XFS_DIFLAG_RTINHERIT; |
1371 | if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { | 1371 | if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { |
1372 | di_flags |= XFS_DIFLAG_EXTSZINHERIT; | 1372 | di_flags |= XFS_DIFLAG_EXTSZINHERIT; |
1373 | ip->i_d.di_extsize = pip->i_d.di_extsize; | 1373 | ip->i_d.di_extsize = pip->i_d.di_extsize; |
1374 | } | 1374 | } |
1375 | } else if (S_ISREG(mode)) { | 1375 | } else if (S_ISREG(mode)) { |
1376 | if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) | 1376 | if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) |
1377 | di_flags |= XFS_DIFLAG_REALTIME; | 1377 | di_flags |= XFS_DIFLAG_REALTIME; |
1378 | if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { | 1378 | if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { |
1379 | di_flags |= XFS_DIFLAG_EXTSIZE; | 1379 | di_flags |= XFS_DIFLAG_EXTSIZE; |
1380 | ip->i_d.di_extsize = pip->i_d.di_extsize; | 1380 | ip->i_d.di_extsize = pip->i_d.di_extsize; |
1381 | } | 1381 | } |
1382 | } | 1382 | } |
1383 | if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) && | 1383 | if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) && |
1384 | xfs_inherit_noatime) | 1384 | xfs_inherit_noatime) |
1385 | di_flags |= XFS_DIFLAG_NOATIME; | 1385 | di_flags |= XFS_DIFLAG_NOATIME; |
1386 | if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) && | 1386 | if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) && |
1387 | xfs_inherit_nodump) | 1387 | xfs_inherit_nodump) |
1388 | di_flags |= XFS_DIFLAG_NODUMP; | 1388 | di_flags |= XFS_DIFLAG_NODUMP; |
1389 | if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) && | 1389 | if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) && |
1390 | xfs_inherit_sync) | 1390 | xfs_inherit_sync) |
1391 | di_flags |= XFS_DIFLAG_SYNC; | 1391 | di_flags |= XFS_DIFLAG_SYNC; |
1392 | if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) && | 1392 | if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) && |
1393 | xfs_inherit_nosymlinks) | 1393 | xfs_inherit_nosymlinks) |
1394 | di_flags |= XFS_DIFLAG_NOSYMLINKS; | 1394 | di_flags |= XFS_DIFLAG_NOSYMLINKS; |
1395 | if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) | 1395 | if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) |
1396 | di_flags |= XFS_DIFLAG_PROJINHERIT; | 1396 | di_flags |= XFS_DIFLAG_PROJINHERIT; |
1397 | if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) && | 1397 | if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) && |
1398 | xfs_inherit_nodefrag) | 1398 | xfs_inherit_nodefrag) |
1399 | di_flags |= XFS_DIFLAG_NODEFRAG; | 1399 | di_flags |= XFS_DIFLAG_NODEFRAG; |
1400 | if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM) | 1400 | if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM) |
1401 | di_flags |= XFS_DIFLAG_FILESTREAM; | 1401 | di_flags |= XFS_DIFLAG_FILESTREAM; |
1402 | ip->i_d.di_flags |= di_flags; | 1402 | ip->i_d.di_flags |= di_flags; |
1403 | } | 1403 | } |
1404 | /* FALLTHROUGH */ | 1404 | /* FALLTHROUGH */ |
1405 | case S_IFLNK: | 1405 | case S_IFLNK: |
1406 | ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; | 1406 | ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; |
1407 | ip->i_df.if_flags = XFS_IFEXTENTS; | 1407 | ip->i_df.if_flags = XFS_IFEXTENTS; |
1408 | ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; | 1408 | ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; |
1409 | ip->i_df.if_u1.if_extents = NULL; | 1409 | ip->i_df.if_u1.if_extents = NULL; |
1410 | break; | 1410 | break; |
1411 | default: | 1411 | default: |
1412 | ASSERT(0); | 1412 | ASSERT(0); |
1413 | } | 1413 | } |
1414 | /* | 1414 | /* |
1415 | * Attribute fork settings for new inode. | 1415 | * Attribute fork settings for new inode. |
1416 | */ | 1416 | */ |
1417 | ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; | 1417 | ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; |
1418 | ip->i_d.di_anextents = 0; | 1418 | ip->i_d.di_anextents = 0; |
1419 | 1419 | ||
1420 | /* | 1420 | /* |
1421 | * Log the new values stuffed into the inode. | 1421 | * Log the new values stuffed into the inode. |
1422 | */ | 1422 | */ |
1423 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 1423 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
1424 | xfs_trans_log_inode(tp, ip, flags); | 1424 | xfs_trans_log_inode(tp, ip, flags); |
1425 | 1425 | ||
1426 | /* now that we have an i_mode we can setup inode ops and unlock */ | 1426 | /* now that we have an i_mode we can setup inode ops and unlock */ |
1427 | xfs_setup_inode(ip); | 1427 | xfs_setup_inode(ip); |
1428 | 1428 | ||
1429 | /* now we have set up the vfs inode we can associate the filestream */ | 1429 | /* now we have set up the vfs inode we can associate the filestream */ |
1430 | if (filestreams) { | 1430 | if (filestreams) { |
1431 | error = xfs_filestream_associate(pip, ip); | 1431 | error = xfs_filestream_associate(pip, ip); |
1432 | if (error < 0) | 1432 | if (error < 0) |
1433 | return -error; | 1433 | return -error; |
1434 | if (!error) | 1434 | if (!error) |
1435 | xfs_iflags_set(ip, XFS_IFILESTREAM); | 1435 | xfs_iflags_set(ip, XFS_IFILESTREAM); |
1436 | } | 1436 | } |
1437 | 1437 | ||
1438 | *ipp = ip; | 1438 | *ipp = ip; |
1439 | return 0; | 1439 | return 0; |
1440 | } | 1440 | } |
1441 | 1441 | ||
1442 | /* | 1442 | /* |
1443 | * Free up the underlying blocks past new_size. The new size must be smaller | 1443 | * Free up the underlying blocks past new_size. The new size must be smaller |
1444 | * than the current size. This routine can be used both for the attribute and | 1444 | * than the current size. This routine can be used both for the attribute and |
1445 | * data fork, and does not modify the inode size, which is left to the caller. | 1445 | * data fork, and does not modify the inode size, which is left to the caller. |
1446 | * | 1446 | * |
1447 | * The transaction passed to this routine must have made a permanent log | 1447 | * The transaction passed to this routine must have made a permanent log |
1448 | * reservation of at least XFS_ITRUNCATE_LOG_RES. This routine may commit the | 1448 | * reservation of at least XFS_ITRUNCATE_LOG_RES. This routine may commit the |
1449 | * given transaction and start new ones, so make sure everything involved in | 1449 | * given transaction and start new ones, so make sure everything involved in |
1450 | * the transaction is tidy before calling here. Some transaction will be | 1450 | * the transaction is tidy before calling here. Some transaction will be |
1451 | * returned to the caller to be committed. The incoming transaction must | 1451 | * returned to the caller to be committed. The incoming transaction must |
1452 | * already include the inode, and both inode locks must be held exclusively. | 1452 | * already include the inode, and both inode locks must be held exclusively. |
1453 | * The inode must also be "held" within the transaction. On return the inode | 1453 | * The inode must also be "held" within the transaction. On return the inode |
1454 | * will be "held" within the returned transaction. This routine does NOT | 1454 | * will be "held" within the returned transaction. This routine does NOT |
1455 | * require any disk space to be reserved for it within the transaction. | 1455 | * require any disk space to be reserved for it within the transaction. |
1456 | * | 1456 | * |
1457 | * If we get an error, we must return with the inode locked and linked into the | 1457 | * If we get an error, we must return with the inode locked and linked into the |
1458 | * current transaction. This keeps things simple for the higher level code, | 1458 | * current transaction. This keeps things simple for the higher level code, |
1459 | * because it always knows that the inode is locked and held in the transaction | 1459 | * because it always knows that the inode is locked and held in the transaction |
1460 | * that returns to it whether errors occur or not. We don't mark the inode | 1460 | * that returns to it whether errors occur or not. We don't mark the inode |
1461 | * dirty on error so that transactions can be easily aborted if possible. | 1461 | * dirty on error so that transactions can be easily aborted if possible. |
1462 | */ | 1462 | */ |
1463 | int | 1463 | int |
1464 | xfs_itruncate_extents( | 1464 | xfs_itruncate_extents( |
1465 | struct xfs_trans **tpp, | 1465 | struct xfs_trans **tpp, |
1466 | struct xfs_inode *ip, | 1466 | struct xfs_inode *ip, |
1467 | int whichfork, | 1467 | int whichfork, |
1468 | xfs_fsize_t new_size) | 1468 | xfs_fsize_t new_size) |
1469 | { | 1469 | { |
1470 | struct xfs_mount *mp = ip->i_mount; | 1470 | struct xfs_mount *mp = ip->i_mount; |
1471 | struct xfs_trans *tp = *tpp; | 1471 | struct xfs_trans *tp = *tpp; |
1472 | struct xfs_trans *ntp; | 1472 | struct xfs_trans *ntp; |
1473 | xfs_bmap_free_t free_list; | 1473 | xfs_bmap_free_t free_list; |
1474 | xfs_fsblock_t first_block; | 1474 | xfs_fsblock_t first_block; |
1475 | xfs_fileoff_t first_unmap_block; | 1475 | xfs_fileoff_t first_unmap_block; |
1476 | xfs_fileoff_t last_block; | 1476 | xfs_fileoff_t last_block; |
1477 | xfs_filblks_t unmap_len; | 1477 | xfs_filblks_t unmap_len; |
1478 | int committed; | 1478 | int committed; |
1479 | int error = 0; | 1479 | int error = 0; |
1480 | int done = 0; | 1480 | int done = 0; |
1481 | 1481 | ||
1482 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | 1482 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); |
1483 | ASSERT(!atomic_read(&VFS_I(ip)->i_count) || | 1483 | ASSERT(!atomic_read(&VFS_I(ip)->i_count) || |
1484 | xfs_isilocked(ip, XFS_IOLOCK_EXCL)); | 1484 | xfs_isilocked(ip, XFS_IOLOCK_EXCL)); |
1485 | ASSERT(new_size <= XFS_ISIZE(ip)); | 1485 | ASSERT(new_size <= XFS_ISIZE(ip)); |
1486 | ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); | 1486 | ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); |
1487 | ASSERT(ip->i_itemp != NULL); | 1487 | ASSERT(ip->i_itemp != NULL); |
1488 | ASSERT(ip->i_itemp->ili_lock_flags == 0); | 1488 | ASSERT(ip->i_itemp->ili_lock_flags == 0); |
1489 | ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); | 1489 | ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); |
1490 | 1490 | ||
1491 | trace_xfs_itruncate_extents_start(ip, new_size); | 1491 | trace_xfs_itruncate_extents_start(ip, new_size); |
1492 | 1492 | ||
1493 | /* | 1493 | /* |
1494 | * Since it is possible for space to become allocated beyond | 1494 | * Since it is possible for space to become allocated beyond |
1495 | * the end of the file (in a crash where the space is allocated | 1495 | * the end of the file (in a crash where the space is allocated |
1496 | * but the inode size is not yet updated), simply remove any | 1496 | * but the inode size is not yet updated), simply remove any |
1497 | * blocks which show up between the new EOF and the maximum | 1497 | * blocks which show up between the new EOF and the maximum |
1498 | * possible file size. If the first block to be removed is | 1498 | * possible file size. If the first block to be removed is |
1499 | * beyond the maximum file size (ie it is the same as last_block), | 1499 | * beyond the maximum file size (ie it is the same as last_block), |
1500 | * then there is nothing to do. | 1500 | * then there is nothing to do. |
1501 | */ | 1501 | */ |
1502 | first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); | 1502 | first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); |
1503 | last_block = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes); | 1503 | last_block = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes); |
1504 | if (first_unmap_block == last_block) | 1504 | if (first_unmap_block == last_block) |
1505 | return 0; | 1505 | return 0; |
1506 | 1506 | ||
1507 | ASSERT(first_unmap_block < last_block); | 1507 | ASSERT(first_unmap_block < last_block); |
1508 | unmap_len = last_block - first_unmap_block + 1; | 1508 | unmap_len = last_block - first_unmap_block + 1; |
1509 | while (!done) { | 1509 | while (!done) { |
1510 | xfs_bmap_init(&free_list, &first_block); | 1510 | xfs_bmap_init(&free_list, &first_block); |
1511 | error = xfs_bunmapi(tp, ip, | 1511 | error = xfs_bunmapi(tp, ip, |
1512 | first_unmap_block, unmap_len, | 1512 | first_unmap_block, unmap_len, |
1513 | xfs_bmapi_aflag(whichfork), | 1513 | xfs_bmapi_aflag(whichfork), |
1514 | XFS_ITRUNC_MAX_EXTENTS, | 1514 | XFS_ITRUNC_MAX_EXTENTS, |
1515 | &first_block, &free_list, | 1515 | &first_block, &free_list, |
1516 | &done); | 1516 | &done); |
1517 | if (error) | 1517 | if (error) |
1518 | goto out_bmap_cancel; | 1518 | goto out_bmap_cancel; |
1519 | 1519 | ||
1520 | /* | 1520 | /* |
1521 | * Duplicate the transaction that has the permanent | 1521 | * Duplicate the transaction that has the permanent |
1522 | * reservation and commit the old transaction. | 1522 | * reservation and commit the old transaction. |
1523 | */ | 1523 | */ |
1524 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 1524 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
1525 | if (committed) | 1525 | if (committed) |
1526 | xfs_trans_ijoin(tp, ip, 0); | 1526 | xfs_trans_ijoin(tp, ip, 0); |
1527 | if (error) | 1527 | if (error) |
1528 | goto out_bmap_cancel; | 1528 | goto out_bmap_cancel; |
1529 | 1529 | ||
1530 | if (committed) { | 1530 | if (committed) { |
1531 | /* | 1531 | /* |
1532 | * Mark the inode dirty so it will be logged and | 1532 | * Mark the inode dirty so it will be logged and |
1533 | * moved forward in the log as part of every commit. | 1533 | * moved forward in the log as part of every commit. |
1534 | */ | 1534 | */ |
1535 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 1535 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
1536 | } | 1536 | } |
1537 | 1537 | ||
1538 | ntp = xfs_trans_dup(tp); | 1538 | ntp = xfs_trans_dup(tp); |
1539 | error = xfs_trans_commit(tp, 0); | 1539 | error = xfs_trans_commit(tp, 0); |
1540 | tp = ntp; | 1540 | tp = ntp; |
1541 | 1541 | ||
1542 | xfs_trans_ijoin(tp, ip, 0); | 1542 | xfs_trans_ijoin(tp, ip, 0); |
1543 | 1543 | ||
1544 | if (error) | 1544 | if (error) |
1545 | goto out; | 1545 | goto out; |
1546 | 1546 | ||
1547 | /* | 1547 | /* |
1548 | * Transaction commit worked ok so we can drop the extra ticket | 1548 | * Transaction commit worked ok so we can drop the extra ticket |
1549 | * reference that we gained in xfs_trans_dup() | 1549 | * reference that we gained in xfs_trans_dup() |
1550 | */ | 1550 | */ |
1551 | xfs_log_ticket_put(tp->t_ticket); | 1551 | xfs_log_ticket_put(tp->t_ticket); |
1552 | error = xfs_trans_reserve(tp, 0, | 1552 | error = xfs_trans_reserve(tp, 0, |
1553 | XFS_ITRUNCATE_LOG_RES(mp), 0, | 1553 | XFS_ITRUNCATE_LOG_RES(mp), 0, |
1554 | XFS_TRANS_PERM_LOG_RES, | 1554 | XFS_TRANS_PERM_LOG_RES, |
1555 | XFS_ITRUNCATE_LOG_COUNT); | 1555 | XFS_ITRUNCATE_LOG_COUNT); |
1556 | if (error) | 1556 | if (error) |
1557 | goto out; | 1557 | goto out; |
1558 | } | 1558 | } |
1559 | 1559 | ||
1560 | /* | 1560 | /* |
1561 | * Always re-log the inode so that our permanent transaction can keep | 1561 | * Always re-log the inode so that our permanent transaction can keep |
1562 | * on rolling it forward in the log. | 1562 | * on rolling it forward in the log. |
1563 | */ | 1563 | */ |
1564 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 1564 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
1565 | 1565 | ||
1566 | trace_xfs_itruncate_extents_end(ip, new_size); | 1566 | trace_xfs_itruncate_extents_end(ip, new_size); |
1567 | 1567 | ||
1568 | out: | 1568 | out: |
1569 | *tpp = tp; | 1569 | *tpp = tp; |
1570 | return error; | 1570 | return error; |
1571 | out_bmap_cancel: | 1571 | out_bmap_cancel: |
1572 | /* | 1572 | /* |
1573 | * If the bunmapi call encounters an error, return to the caller where | 1573 | * If the bunmapi call encounters an error, return to the caller where |
1574 | * the transaction can be properly aborted. We just need to make sure | 1574 | * the transaction can be properly aborted. We just need to make sure |
1575 | * we're not holding any resources that we were not when we came in. | 1575 | * we're not holding any resources that we were not when we came in. |
1576 | */ | 1576 | */ |
1577 | xfs_bmap_cancel(&free_list); | 1577 | xfs_bmap_cancel(&free_list); |
1578 | goto out; | 1578 | goto out; |
1579 | } | 1579 | } |
1580 | 1580 | ||
1581 | /* | 1581 | /* |
1582 | * This is called when the inode's link count goes to 0. | 1582 | * This is called when the inode's link count goes to 0. |
1583 | * We place the on-disk inode on a list in the AGI. It | 1583 | * We place the on-disk inode on a list in the AGI. It |
1584 | * will be pulled from this list when the inode is freed. | 1584 | * will be pulled from this list when the inode is freed. |
1585 | */ | 1585 | */ |
1586 | int | 1586 | int |
1587 | xfs_iunlink( | 1587 | xfs_iunlink( |
1588 | xfs_trans_t *tp, | 1588 | xfs_trans_t *tp, |
1589 | xfs_inode_t *ip) | 1589 | xfs_inode_t *ip) |
1590 | { | 1590 | { |
1591 | xfs_mount_t *mp; | 1591 | xfs_mount_t *mp; |
1592 | xfs_agi_t *agi; | 1592 | xfs_agi_t *agi; |
1593 | xfs_dinode_t *dip; | 1593 | xfs_dinode_t *dip; |
1594 | xfs_buf_t *agibp; | 1594 | xfs_buf_t *agibp; |
1595 | xfs_buf_t *ibp; | 1595 | xfs_buf_t *ibp; |
1596 | xfs_agino_t agino; | 1596 | xfs_agino_t agino; |
1597 | short bucket_index; | 1597 | short bucket_index; |
1598 | int offset; | 1598 | int offset; |
1599 | int error; | 1599 | int error; |
1600 | 1600 | ||
1601 | ASSERT(ip->i_d.di_nlink == 0); | 1601 | ASSERT(ip->i_d.di_nlink == 0); |
1602 | ASSERT(ip->i_d.di_mode != 0); | 1602 | ASSERT(ip->i_d.di_mode != 0); |
1603 | 1603 | ||
1604 | mp = tp->t_mountp; | 1604 | mp = tp->t_mountp; |
1605 | 1605 | ||
1606 | /* | 1606 | /* |
1607 | * Get the agi buffer first. It ensures lock ordering | 1607 | * Get the agi buffer first. It ensures lock ordering |
1608 | * on the list. | 1608 | * on the list. |
1609 | */ | 1609 | */ |
1610 | error = xfs_read_agi(mp, tp, XFS_INO_TO_AGNO(mp, ip->i_ino), &agibp); | 1610 | error = xfs_read_agi(mp, tp, XFS_INO_TO_AGNO(mp, ip->i_ino), &agibp); |
1611 | if (error) | 1611 | if (error) |
1612 | return error; | 1612 | return error; |
1613 | agi = XFS_BUF_TO_AGI(agibp); | 1613 | agi = XFS_BUF_TO_AGI(agibp); |
1614 | 1614 | ||
1615 | /* | 1615 | /* |
1616 | * Get the index into the agi hash table for the | 1616 | * Get the index into the agi hash table for the |
1617 | * list this inode will go on. | 1617 | * list this inode will go on. |
1618 | */ | 1618 | */ |
1619 | agino = XFS_INO_TO_AGINO(mp, ip->i_ino); | 1619 | agino = XFS_INO_TO_AGINO(mp, ip->i_ino); |
1620 | ASSERT(agino != 0); | 1620 | ASSERT(agino != 0); |
1621 | bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; | 1621 | bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; |
1622 | ASSERT(agi->agi_unlinked[bucket_index]); | 1622 | ASSERT(agi->agi_unlinked[bucket_index]); |
1623 | ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != agino); | 1623 | ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != agino); |
1624 | 1624 | ||
1625 | if (agi->agi_unlinked[bucket_index] != cpu_to_be32(NULLAGINO)) { | 1625 | if (agi->agi_unlinked[bucket_index] != cpu_to_be32(NULLAGINO)) { |
1626 | /* | 1626 | /* |
1627 | * There is already another inode in the bucket we need | 1627 | * There is already another inode in the bucket we need |
1628 | * to add ourselves to. Add us at the front of the list. | 1628 | * to add ourselves to. Add us at the front of the list. |
1629 | * Here we put the head pointer into our next pointer, | 1629 | * Here we put the head pointer into our next pointer, |
1630 | * and then we fall through to point the head at us. | 1630 | * and then we fall through to point the head at us. |
1631 | */ | 1631 | */ |
1632 | error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp, | 1632 | error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp, |
1633 | 0, 0); | 1633 | 0, 0); |
1634 | if (error) | 1634 | if (error) |
1635 | return error; | 1635 | return error; |
1636 | 1636 | ||
1637 | ASSERT(dip->di_next_unlinked == cpu_to_be32(NULLAGINO)); | 1637 | ASSERT(dip->di_next_unlinked == cpu_to_be32(NULLAGINO)); |
1638 | dip->di_next_unlinked = agi->agi_unlinked[bucket_index]; | 1638 | dip->di_next_unlinked = agi->agi_unlinked[bucket_index]; |
1639 | offset = ip->i_imap.im_boffset + | 1639 | offset = ip->i_imap.im_boffset + |
1640 | offsetof(xfs_dinode_t, di_next_unlinked); | 1640 | offsetof(xfs_dinode_t, di_next_unlinked); |
1641 | xfs_trans_inode_buf(tp, ibp); | 1641 | xfs_trans_inode_buf(tp, ibp); |
1642 | xfs_trans_log_buf(tp, ibp, offset, | 1642 | xfs_trans_log_buf(tp, ibp, offset, |
1643 | (offset + sizeof(xfs_agino_t) - 1)); | 1643 | (offset + sizeof(xfs_agino_t) - 1)); |
1644 | xfs_inobp_check(mp, ibp); | 1644 | xfs_inobp_check(mp, ibp); |
1645 | } | 1645 | } |
1646 | 1646 | ||
1647 | /* | 1647 | /* |
1648 | * Point the bucket head pointer at the inode being inserted. | 1648 | * Point the bucket head pointer at the inode being inserted. |
1649 | */ | 1649 | */ |
1650 | ASSERT(agino != 0); | 1650 | ASSERT(agino != 0); |
1651 | agi->agi_unlinked[bucket_index] = cpu_to_be32(agino); | 1651 | agi->agi_unlinked[bucket_index] = cpu_to_be32(agino); |
1652 | offset = offsetof(xfs_agi_t, agi_unlinked) + | 1652 | offset = offsetof(xfs_agi_t, agi_unlinked) + |
1653 | (sizeof(xfs_agino_t) * bucket_index); | 1653 | (sizeof(xfs_agino_t) * bucket_index); |
1654 | xfs_trans_log_buf(tp, agibp, offset, | 1654 | xfs_trans_log_buf(tp, agibp, offset, |
1655 | (offset + sizeof(xfs_agino_t) - 1)); | 1655 | (offset + sizeof(xfs_agino_t) - 1)); |
1656 | return 0; | 1656 | return 0; |
1657 | } | 1657 | } |
1658 | 1658 | ||
1659 | /* | 1659 | /* |
1660 | * Pull the on-disk inode from the AGI unlinked list. | 1660 | * Pull the on-disk inode from the AGI unlinked list. |
1661 | */ | 1661 | */ |
1662 | STATIC int | 1662 | STATIC int |
1663 | xfs_iunlink_remove( | 1663 | xfs_iunlink_remove( |
1664 | xfs_trans_t *tp, | 1664 | xfs_trans_t *tp, |
1665 | xfs_inode_t *ip) | 1665 | xfs_inode_t *ip) |
1666 | { | 1666 | { |
1667 | xfs_ino_t next_ino; | 1667 | xfs_ino_t next_ino; |
1668 | xfs_mount_t *mp; | 1668 | xfs_mount_t *mp; |
1669 | xfs_agi_t *agi; | 1669 | xfs_agi_t *agi; |
1670 | xfs_dinode_t *dip; | 1670 | xfs_dinode_t *dip; |
1671 | xfs_buf_t *agibp; | 1671 | xfs_buf_t *agibp; |
1672 | xfs_buf_t *ibp; | 1672 | xfs_buf_t *ibp; |
1673 | xfs_agnumber_t agno; | 1673 | xfs_agnumber_t agno; |
1674 | xfs_agino_t agino; | 1674 | xfs_agino_t agino; |
1675 | xfs_agino_t next_agino; | 1675 | xfs_agino_t next_agino; |
1676 | xfs_buf_t *last_ibp; | 1676 | xfs_buf_t *last_ibp; |
1677 | xfs_dinode_t *last_dip = NULL; | 1677 | xfs_dinode_t *last_dip = NULL; |
1678 | short bucket_index; | 1678 | short bucket_index; |
1679 | int offset, last_offset = 0; | 1679 | int offset, last_offset = 0; |
1680 | int error; | 1680 | int error; |
1681 | 1681 | ||
1682 | mp = tp->t_mountp; | 1682 | mp = tp->t_mountp; |
1683 | agno = XFS_INO_TO_AGNO(mp, ip->i_ino); | 1683 | agno = XFS_INO_TO_AGNO(mp, ip->i_ino); |
1684 | 1684 | ||
1685 | /* | 1685 | /* |
1686 | * Get the agi buffer first. It ensures lock ordering | 1686 | * Get the agi buffer first. It ensures lock ordering |
1687 | * on the list. | 1687 | * on the list. |
1688 | */ | 1688 | */ |
1689 | error = xfs_read_agi(mp, tp, agno, &agibp); | 1689 | error = xfs_read_agi(mp, tp, agno, &agibp); |
1690 | if (error) | 1690 | if (error) |
1691 | return error; | 1691 | return error; |
1692 | 1692 | ||
1693 | agi = XFS_BUF_TO_AGI(agibp); | 1693 | agi = XFS_BUF_TO_AGI(agibp); |
1694 | 1694 | ||
1695 | /* | 1695 | /* |
1696 | * Get the index into the agi hash table for the | 1696 | * Get the index into the agi hash table for the |
1697 | * list this inode will go on. | 1697 | * list this inode will go on. |
1698 | */ | 1698 | */ |
1699 | agino = XFS_INO_TO_AGINO(mp, ip->i_ino); | 1699 | agino = XFS_INO_TO_AGINO(mp, ip->i_ino); |
1700 | ASSERT(agino != 0); | 1700 | ASSERT(agino != 0); |
1701 | bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; | 1701 | bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; |
1702 | ASSERT(agi->agi_unlinked[bucket_index] != cpu_to_be32(NULLAGINO)); | 1702 | ASSERT(agi->agi_unlinked[bucket_index] != cpu_to_be32(NULLAGINO)); |
1703 | ASSERT(agi->agi_unlinked[bucket_index]); | 1703 | ASSERT(agi->agi_unlinked[bucket_index]); |
1704 | 1704 | ||
1705 | if (be32_to_cpu(agi->agi_unlinked[bucket_index]) == agino) { | 1705 | if (be32_to_cpu(agi->agi_unlinked[bucket_index]) == agino) { |
1706 | /* | 1706 | /* |
1707 | * We're at the head of the list. Get the inode's on-disk | 1707 | * We're at the head of the list. Get the inode's on-disk |
1708 | * buffer to see if there is anyone after us on the list. | 1708 | * buffer to see if there is anyone after us on the list. |
1709 | * Only modify our next pointer if it is not already NULLAGINO. | 1709 | * Only modify our next pointer if it is not already NULLAGINO. |
1710 | * This saves us the overhead of dealing with the buffer when | 1710 | * This saves us the overhead of dealing with the buffer when |
1711 | * there is no need to change it. | 1711 | * there is no need to change it. |
1712 | */ | 1712 | */ |
1713 | error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp, | 1713 | error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp, |
1714 | 0, 0); | 1714 | 0, 0); |
1715 | if (error) { | 1715 | if (error) { |
1716 | xfs_warn(mp, "%s: xfs_imap_to_bp returned error %d.", | 1716 | xfs_warn(mp, "%s: xfs_imap_to_bp returned error %d.", |
1717 | __func__, error); | 1717 | __func__, error); |
1718 | return error; | 1718 | return error; |
1719 | } | 1719 | } |
1720 | next_agino = be32_to_cpu(dip->di_next_unlinked); | 1720 | next_agino = be32_to_cpu(dip->di_next_unlinked); |
1721 | ASSERT(next_agino != 0); | 1721 | ASSERT(next_agino != 0); |
1722 | if (next_agino != NULLAGINO) { | 1722 | if (next_agino != NULLAGINO) { |
1723 | dip->di_next_unlinked = cpu_to_be32(NULLAGINO); | 1723 | dip->di_next_unlinked = cpu_to_be32(NULLAGINO); |
1724 | offset = ip->i_imap.im_boffset + | 1724 | offset = ip->i_imap.im_boffset + |
1725 | offsetof(xfs_dinode_t, di_next_unlinked); | 1725 | offsetof(xfs_dinode_t, di_next_unlinked); |
1726 | xfs_trans_inode_buf(tp, ibp); | 1726 | xfs_trans_inode_buf(tp, ibp); |
1727 | xfs_trans_log_buf(tp, ibp, offset, | 1727 | xfs_trans_log_buf(tp, ibp, offset, |
1728 | (offset + sizeof(xfs_agino_t) - 1)); | 1728 | (offset + sizeof(xfs_agino_t) - 1)); |
1729 | xfs_inobp_check(mp, ibp); | 1729 | xfs_inobp_check(mp, ibp); |
1730 | } else { | 1730 | } else { |
1731 | xfs_trans_brelse(tp, ibp); | 1731 | xfs_trans_brelse(tp, ibp); |
1732 | } | 1732 | } |
1733 | /* | 1733 | /* |
1734 | * Point the bucket head pointer at the next inode. | 1734 | * Point the bucket head pointer at the next inode. |
1735 | */ | 1735 | */ |
1736 | ASSERT(next_agino != 0); | 1736 | ASSERT(next_agino != 0); |
1737 | ASSERT(next_agino != agino); | 1737 | ASSERT(next_agino != agino); |
1738 | agi->agi_unlinked[bucket_index] = cpu_to_be32(next_agino); | 1738 | agi->agi_unlinked[bucket_index] = cpu_to_be32(next_agino); |
1739 | offset = offsetof(xfs_agi_t, agi_unlinked) + | 1739 | offset = offsetof(xfs_agi_t, agi_unlinked) + |
1740 | (sizeof(xfs_agino_t) * bucket_index); | 1740 | (sizeof(xfs_agino_t) * bucket_index); |
1741 | xfs_trans_log_buf(tp, agibp, offset, | 1741 | xfs_trans_log_buf(tp, agibp, offset, |
1742 | (offset + sizeof(xfs_agino_t) - 1)); | 1742 | (offset + sizeof(xfs_agino_t) - 1)); |
1743 | } else { | 1743 | } else { |
1744 | /* | 1744 | /* |
1745 | * We need to search the list for the inode being freed. | 1745 | * We need to search the list for the inode being freed. |
1746 | */ | 1746 | */ |
1747 | next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]); | 1747 | next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]); |
1748 | last_ibp = NULL; | 1748 | last_ibp = NULL; |
1749 | while (next_agino != agino) { | 1749 | while (next_agino != agino) { |
1750 | struct xfs_imap imap; | 1750 | struct xfs_imap imap; |
1751 | 1751 | ||
1752 | if (last_ibp) | 1752 | if (last_ibp) |
1753 | xfs_trans_brelse(tp, last_ibp); | 1753 | xfs_trans_brelse(tp, last_ibp); |
1754 | 1754 | ||
1755 | imap.im_blkno = 0; | 1755 | imap.im_blkno = 0; |
1756 | next_ino = XFS_AGINO_TO_INO(mp, agno, next_agino); | 1756 | next_ino = XFS_AGINO_TO_INO(mp, agno, next_agino); |
1757 | 1757 | ||
1758 | error = xfs_imap(mp, tp, next_ino, &imap, 0); | 1758 | error = xfs_imap(mp, tp, next_ino, &imap, 0); |
1759 | if (error) { | 1759 | if (error) { |
1760 | xfs_warn(mp, | 1760 | xfs_warn(mp, |
1761 | "%s: xfs_imap returned error %d.", | 1761 | "%s: xfs_imap returned error %d.", |
1762 | __func__, error); | 1762 | __func__, error); |
1763 | return error; | 1763 | return error; |
1764 | } | 1764 | } |
1765 | 1765 | ||
1766 | error = xfs_imap_to_bp(mp, tp, &imap, &last_dip, | 1766 | error = xfs_imap_to_bp(mp, tp, &imap, &last_dip, |
1767 | &last_ibp, 0, 0); | 1767 | &last_ibp, 0, 0); |
1768 | if (error) { | 1768 | if (error) { |
1769 | xfs_warn(mp, | 1769 | xfs_warn(mp, |
1770 | "%s: xfs_imap_to_bp returned error %d.", | 1770 | "%s: xfs_imap_to_bp returned error %d.", |
1771 | __func__, error); | 1771 | __func__, error); |
1772 | return error; | 1772 | return error; |
1773 | } | 1773 | } |
1774 | 1774 | ||
1775 | last_offset = imap.im_boffset; | 1775 | last_offset = imap.im_boffset; |
1776 | next_agino = be32_to_cpu(last_dip->di_next_unlinked); | 1776 | next_agino = be32_to_cpu(last_dip->di_next_unlinked); |
1777 | ASSERT(next_agino != NULLAGINO); | 1777 | ASSERT(next_agino != NULLAGINO); |
1778 | ASSERT(next_agino != 0); | 1778 | ASSERT(next_agino != 0); |
1779 | } | 1779 | } |
1780 | 1780 | ||
1781 | /* | 1781 | /* |
1782 | * Now last_ibp points to the buffer previous to us on the | 1782 | * Now last_ibp points to the buffer previous to us on the |
1783 | * unlinked list. Pull us from the list. | 1783 | * unlinked list. Pull us from the list. |
1784 | */ | 1784 | */ |
1785 | error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp, | 1785 | error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp, |
1786 | 0, 0); | 1786 | 0, 0); |
1787 | if (error) { | 1787 | if (error) { |
1788 | xfs_warn(mp, "%s: xfs_imap_to_bp(2) returned error %d.", | 1788 | xfs_warn(mp, "%s: xfs_imap_to_bp(2) returned error %d.", |
1789 | __func__, error); | 1789 | __func__, error); |
1790 | return error; | 1790 | return error; |
1791 | } | 1791 | } |
1792 | next_agino = be32_to_cpu(dip->di_next_unlinked); | 1792 | next_agino = be32_to_cpu(dip->di_next_unlinked); |
1793 | ASSERT(next_agino != 0); | 1793 | ASSERT(next_agino != 0); |
1794 | ASSERT(next_agino != agino); | 1794 | ASSERT(next_agino != agino); |
1795 | if (next_agino != NULLAGINO) { | 1795 | if (next_agino != NULLAGINO) { |
1796 | dip->di_next_unlinked = cpu_to_be32(NULLAGINO); | 1796 | dip->di_next_unlinked = cpu_to_be32(NULLAGINO); |
1797 | offset = ip->i_imap.im_boffset + | 1797 | offset = ip->i_imap.im_boffset + |
1798 | offsetof(xfs_dinode_t, di_next_unlinked); | 1798 | offsetof(xfs_dinode_t, di_next_unlinked); |
1799 | xfs_trans_inode_buf(tp, ibp); | 1799 | xfs_trans_inode_buf(tp, ibp); |
1800 | xfs_trans_log_buf(tp, ibp, offset, | 1800 | xfs_trans_log_buf(tp, ibp, offset, |
1801 | (offset + sizeof(xfs_agino_t) - 1)); | 1801 | (offset + sizeof(xfs_agino_t) - 1)); |
1802 | xfs_inobp_check(mp, ibp); | 1802 | xfs_inobp_check(mp, ibp); |
1803 | } else { | 1803 | } else { |
1804 | xfs_trans_brelse(tp, ibp); | 1804 | xfs_trans_brelse(tp, ibp); |
1805 | } | 1805 | } |
1806 | /* | 1806 | /* |
1807 | * Point the previous inode on the list to the next inode. | 1807 | * Point the previous inode on the list to the next inode. |
1808 | */ | 1808 | */ |
1809 | last_dip->di_next_unlinked = cpu_to_be32(next_agino); | 1809 | last_dip->di_next_unlinked = cpu_to_be32(next_agino); |
1810 | ASSERT(next_agino != 0); | 1810 | ASSERT(next_agino != 0); |
1811 | offset = last_offset + offsetof(xfs_dinode_t, di_next_unlinked); | 1811 | offset = last_offset + offsetof(xfs_dinode_t, di_next_unlinked); |
1812 | xfs_trans_inode_buf(tp, last_ibp); | 1812 | xfs_trans_inode_buf(tp, last_ibp); |
1813 | xfs_trans_log_buf(tp, last_ibp, offset, | 1813 | xfs_trans_log_buf(tp, last_ibp, offset, |
1814 | (offset + sizeof(xfs_agino_t) - 1)); | 1814 | (offset + sizeof(xfs_agino_t) - 1)); |
1815 | xfs_inobp_check(mp, last_ibp); | 1815 | xfs_inobp_check(mp, last_ibp); |
1816 | } | 1816 | } |
1817 | return 0; | 1817 | return 0; |
1818 | } | 1818 | } |
1819 | 1819 | ||
1820 | /* | 1820 | /* |
1821 | * A big issue when freeing the inode cluster is is that we _cannot_ skip any | 1821 | * A big issue when freeing the inode cluster is is that we _cannot_ skip any |
1822 | * inodes that are in memory - they all must be marked stale and attached to | 1822 | * inodes that are in memory - they all must be marked stale and attached to |
1823 | * the cluster buffer. | 1823 | * the cluster buffer. |
1824 | */ | 1824 | */ |
1825 | STATIC int | 1825 | STATIC int |
1826 | xfs_ifree_cluster( | 1826 | xfs_ifree_cluster( |
1827 | xfs_inode_t *free_ip, | 1827 | xfs_inode_t *free_ip, |
1828 | xfs_trans_t *tp, | 1828 | xfs_trans_t *tp, |
1829 | xfs_ino_t inum) | 1829 | xfs_ino_t inum) |
1830 | { | 1830 | { |
1831 | xfs_mount_t *mp = free_ip->i_mount; | 1831 | xfs_mount_t *mp = free_ip->i_mount; |
1832 | int blks_per_cluster; | 1832 | int blks_per_cluster; |
1833 | int nbufs; | 1833 | int nbufs; |
1834 | int ninodes; | 1834 | int ninodes; |
1835 | int i, j; | 1835 | int i, j; |
1836 | xfs_daddr_t blkno; | 1836 | xfs_daddr_t blkno; |
1837 | xfs_buf_t *bp; | 1837 | xfs_buf_t *bp; |
1838 | xfs_inode_t *ip; | 1838 | xfs_inode_t *ip; |
1839 | xfs_inode_log_item_t *iip; | 1839 | xfs_inode_log_item_t *iip; |
1840 | xfs_log_item_t *lip; | 1840 | xfs_log_item_t *lip; |
1841 | struct xfs_perag *pag; | 1841 | struct xfs_perag *pag; |
1842 | 1842 | ||
1843 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, inum)); | 1843 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, inum)); |
1844 | if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) { | 1844 | if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) { |
1845 | blks_per_cluster = 1; | 1845 | blks_per_cluster = 1; |
1846 | ninodes = mp->m_sb.sb_inopblock; | 1846 | ninodes = mp->m_sb.sb_inopblock; |
1847 | nbufs = XFS_IALLOC_BLOCKS(mp); | 1847 | nbufs = XFS_IALLOC_BLOCKS(mp); |
1848 | } else { | 1848 | } else { |
1849 | blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) / | 1849 | blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) / |
1850 | mp->m_sb.sb_blocksize; | 1850 | mp->m_sb.sb_blocksize; |
1851 | ninodes = blks_per_cluster * mp->m_sb.sb_inopblock; | 1851 | ninodes = blks_per_cluster * mp->m_sb.sb_inopblock; |
1852 | nbufs = XFS_IALLOC_BLOCKS(mp) / blks_per_cluster; | 1852 | nbufs = XFS_IALLOC_BLOCKS(mp) / blks_per_cluster; |
1853 | } | 1853 | } |
1854 | 1854 | ||
1855 | for (j = 0; j < nbufs; j++, inum += ninodes) { | 1855 | for (j = 0; j < nbufs; j++, inum += ninodes) { |
1856 | blkno = XFS_AGB_TO_DADDR(mp, XFS_INO_TO_AGNO(mp, inum), | 1856 | blkno = XFS_AGB_TO_DADDR(mp, XFS_INO_TO_AGNO(mp, inum), |
1857 | XFS_INO_TO_AGBNO(mp, inum)); | 1857 | XFS_INO_TO_AGBNO(mp, inum)); |
1858 | 1858 | ||
1859 | /* | 1859 | /* |
1860 | * We obtain and lock the backing buffer first in the process | 1860 | * We obtain and lock the backing buffer first in the process |
1861 | * here, as we have to ensure that any dirty inode that we | 1861 | * here, as we have to ensure that any dirty inode that we |
1862 | * can't get the flush lock on is attached to the buffer. | 1862 | * can't get the flush lock on is attached to the buffer. |
1863 | * If we scan the in-memory inodes first, then buffer IO can | 1863 | * If we scan the in-memory inodes first, then buffer IO can |
1864 | * complete before we get a lock on it, and hence we may fail | 1864 | * complete before we get a lock on it, and hence we may fail |
1865 | * to mark all the active inodes on the buffer stale. | 1865 | * to mark all the active inodes on the buffer stale. |
1866 | */ | 1866 | */ |
1867 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, | 1867 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, |
1868 | mp->m_bsize * blks_per_cluster, | 1868 | mp->m_bsize * blks_per_cluster, |
1869 | XBF_UNMAPPED); | 1869 | XBF_UNMAPPED); |
1870 | 1870 | ||
1871 | if (!bp) | 1871 | if (!bp) |
1872 | return ENOMEM; | 1872 | return ENOMEM; |
1873 | 1873 | ||
1874 | /* | 1874 | /* |
1875 | * This buffer may not have been correctly initialised as we | 1875 | * This buffer may not have been correctly initialised as we |
1876 | * didn't read it from disk. That's not important because we are | 1876 | * didn't read it from disk. That's not important because we are |
1877 | * only using to mark the buffer as stale in the log, and to | 1877 | * only using to mark the buffer as stale in the log, and to |
1878 | * attach stale cached inodes on it. That means it will never be | 1878 | * attach stale cached inodes on it. That means it will never be |
1879 | * dispatched for IO. If it is, we want to know about it, and we | 1879 | * dispatched for IO. If it is, we want to know about it, and we |
1880 | * want it to fail. We can acheive this by adding a write | 1880 | * want it to fail. We can acheive this by adding a write |
1881 | * verifier to the buffer. | 1881 | * verifier to the buffer. |
1882 | */ | 1882 | */ |
1883 | bp->b_ops = &xfs_inode_buf_ops; | 1883 | bp->b_ops = &xfs_inode_buf_ops; |
1884 | 1884 | ||
1885 | /* | 1885 | /* |
1886 | * Walk the inodes already attached to the buffer and mark them | 1886 | * Walk the inodes already attached to the buffer and mark them |
1887 | * stale. These will all have the flush locks held, so an | 1887 | * stale. These will all have the flush locks held, so an |
1888 | * in-memory inode walk can't lock them. By marking them all | 1888 | * in-memory inode walk can't lock them. By marking them all |
1889 | * stale first, we will not attempt to lock them in the loop | 1889 | * stale first, we will not attempt to lock them in the loop |
1890 | * below as the XFS_ISTALE flag will be set. | 1890 | * below as the XFS_ISTALE flag will be set. |
1891 | */ | 1891 | */ |
1892 | lip = bp->b_fspriv; | 1892 | lip = bp->b_fspriv; |
1893 | while (lip) { | 1893 | while (lip) { |
1894 | if (lip->li_type == XFS_LI_INODE) { | 1894 | if (lip->li_type == XFS_LI_INODE) { |
1895 | iip = (xfs_inode_log_item_t *)lip; | 1895 | iip = (xfs_inode_log_item_t *)lip; |
1896 | ASSERT(iip->ili_logged == 1); | 1896 | ASSERT(iip->ili_logged == 1); |
1897 | lip->li_cb = xfs_istale_done; | 1897 | lip->li_cb = xfs_istale_done; |
1898 | xfs_trans_ail_copy_lsn(mp->m_ail, | 1898 | xfs_trans_ail_copy_lsn(mp->m_ail, |
1899 | &iip->ili_flush_lsn, | 1899 | &iip->ili_flush_lsn, |
1900 | &iip->ili_item.li_lsn); | 1900 | &iip->ili_item.li_lsn); |
1901 | xfs_iflags_set(iip->ili_inode, XFS_ISTALE); | 1901 | xfs_iflags_set(iip->ili_inode, XFS_ISTALE); |
1902 | } | 1902 | } |
1903 | lip = lip->li_bio_list; | 1903 | lip = lip->li_bio_list; |
1904 | } | 1904 | } |
1905 | 1905 | ||
1906 | 1906 | ||
1907 | /* | 1907 | /* |
1908 | * For each inode in memory attempt to add it to the inode | 1908 | * For each inode in memory attempt to add it to the inode |
1909 | * buffer and set it up for being staled on buffer IO | 1909 | * buffer and set it up for being staled on buffer IO |
1910 | * completion. This is safe as we've locked out tail pushing | 1910 | * completion. This is safe as we've locked out tail pushing |
1911 | * and flushing by locking the buffer. | 1911 | * and flushing by locking the buffer. |
1912 | * | 1912 | * |
1913 | * We have already marked every inode that was part of a | 1913 | * We have already marked every inode that was part of a |
1914 | * transaction stale above, which means there is no point in | 1914 | * transaction stale above, which means there is no point in |
1915 | * even trying to lock them. | 1915 | * even trying to lock them. |
1916 | */ | 1916 | */ |
1917 | for (i = 0; i < ninodes; i++) { | 1917 | for (i = 0; i < ninodes; i++) { |
1918 | retry: | 1918 | retry: |
1919 | rcu_read_lock(); | 1919 | rcu_read_lock(); |
1920 | ip = radix_tree_lookup(&pag->pag_ici_root, | 1920 | ip = radix_tree_lookup(&pag->pag_ici_root, |
1921 | XFS_INO_TO_AGINO(mp, (inum + i))); | 1921 | XFS_INO_TO_AGINO(mp, (inum + i))); |
1922 | 1922 | ||
1923 | /* Inode not in memory, nothing to do */ | 1923 | /* Inode not in memory, nothing to do */ |
1924 | if (!ip) { | 1924 | if (!ip) { |
1925 | rcu_read_unlock(); | 1925 | rcu_read_unlock(); |
1926 | continue; | 1926 | continue; |
1927 | } | 1927 | } |
1928 | 1928 | ||
1929 | /* | 1929 | /* |
1930 | * because this is an RCU protected lookup, we could | 1930 | * because this is an RCU protected lookup, we could |
1931 | * find a recently freed or even reallocated inode | 1931 | * find a recently freed or even reallocated inode |
1932 | * during the lookup. We need to check under the | 1932 | * during the lookup. We need to check under the |
1933 | * i_flags_lock for a valid inode here. Skip it if it | 1933 | * i_flags_lock for a valid inode here. Skip it if it |
1934 | * is not valid, the wrong inode or stale. | 1934 | * is not valid, the wrong inode or stale. |
1935 | */ | 1935 | */ |
1936 | spin_lock(&ip->i_flags_lock); | 1936 | spin_lock(&ip->i_flags_lock); |
1937 | if (ip->i_ino != inum + i || | 1937 | if (ip->i_ino != inum + i || |
1938 | __xfs_iflags_test(ip, XFS_ISTALE)) { | 1938 | __xfs_iflags_test(ip, XFS_ISTALE)) { |
1939 | spin_unlock(&ip->i_flags_lock); | 1939 | spin_unlock(&ip->i_flags_lock); |
1940 | rcu_read_unlock(); | 1940 | rcu_read_unlock(); |
1941 | continue; | 1941 | continue; |
1942 | } | 1942 | } |
1943 | spin_unlock(&ip->i_flags_lock); | 1943 | spin_unlock(&ip->i_flags_lock); |
1944 | 1944 | ||
1945 | /* | 1945 | /* |
1946 | * Don't try to lock/unlock the current inode, but we | 1946 | * Don't try to lock/unlock the current inode, but we |
1947 | * _cannot_ skip the other inodes that we did not find | 1947 | * _cannot_ skip the other inodes that we did not find |
1948 | * in the list attached to the buffer and are not | 1948 | * in the list attached to the buffer and are not |
1949 | * already marked stale. If we can't lock it, back off | 1949 | * already marked stale. If we can't lock it, back off |
1950 | * and retry. | 1950 | * and retry. |
1951 | */ | 1951 | */ |
1952 | if (ip != free_ip && | 1952 | if (ip != free_ip && |
1953 | !xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { | 1953 | !xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { |
1954 | rcu_read_unlock(); | 1954 | rcu_read_unlock(); |
1955 | delay(1); | 1955 | delay(1); |
1956 | goto retry; | 1956 | goto retry; |
1957 | } | 1957 | } |
1958 | rcu_read_unlock(); | 1958 | rcu_read_unlock(); |
1959 | 1959 | ||
1960 | xfs_iflock(ip); | 1960 | xfs_iflock(ip); |
1961 | xfs_iflags_set(ip, XFS_ISTALE); | 1961 | xfs_iflags_set(ip, XFS_ISTALE); |
1962 | 1962 | ||
1963 | /* | 1963 | /* |
1964 | * we don't need to attach clean inodes or those only | 1964 | * we don't need to attach clean inodes or those only |
1965 | * with unlogged changes (which we throw away, anyway). | 1965 | * with unlogged changes (which we throw away, anyway). |
1966 | */ | 1966 | */ |
1967 | iip = ip->i_itemp; | 1967 | iip = ip->i_itemp; |
1968 | if (!iip || xfs_inode_clean(ip)) { | 1968 | if (!iip || xfs_inode_clean(ip)) { |
1969 | ASSERT(ip != free_ip); | 1969 | ASSERT(ip != free_ip); |
1970 | xfs_ifunlock(ip); | 1970 | xfs_ifunlock(ip); |
1971 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 1971 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
1972 | continue; | 1972 | continue; |
1973 | } | 1973 | } |
1974 | 1974 | ||
1975 | iip->ili_last_fields = iip->ili_fields; | 1975 | iip->ili_last_fields = iip->ili_fields; |
1976 | iip->ili_fields = 0; | 1976 | iip->ili_fields = 0; |
1977 | iip->ili_logged = 1; | 1977 | iip->ili_logged = 1; |
1978 | xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, | 1978 | xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, |
1979 | &iip->ili_item.li_lsn); | 1979 | &iip->ili_item.li_lsn); |
1980 | 1980 | ||
1981 | xfs_buf_attach_iodone(bp, xfs_istale_done, | 1981 | xfs_buf_attach_iodone(bp, xfs_istale_done, |
1982 | &iip->ili_item); | 1982 | &iip->ili_item); |
1983 | 1983 | ||
1984 | if (ip != free_ip) | 1984 | if (ip != free_ip) |
1985 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 1985 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
1986 | } | 1986 | } |
1987 | 1987 | ||
1988 | xfs_trans_stale_inode_buf(tp, bp); | 1988 | xfs_trans_stale_inode_buf(tp, bp); |
1989 | xfs_trans_binval(tp, bp); | 1989 | xfs_trans_binval(tp, bp); |
1990 | } | 1990 | } |
1991 | 1991 | ||
1992 | xfs_perag_put(pag); | 1992 | xfs_perag_put(pag); |
1993 | return 0; | 1993 | return 0; |
1994 | } | 1994 | } |
1995 | 1995 | ||
1996 | /* | 1996 | /* |
1997 | * This is called to return an inode to the inode free list. | 1997 | * This is called to return an inode to the inode free list. |
1998 | * The inode should already be truncated to 0 length and have | 1998 | * The inode should already be truncated to 0 length and have |
1999 | * no pages associated with it. This routine also assumes that | 1999 | * no pages associated with it. This routine also assumes that |
2000 | * the inode is already a part of the transaction. | 2000 | * the inode is already a part of the transaction. |
2001 | * | 2001 | * |
2002 | * The on-disk copy of the inode will have been added to the list | 2002 | * The on-disk copy of the inode will have been added to the list |
2003 | * of unlinked inodes in the AGI. We need to remove the inode from | 2003 | * of unlinked inodes in the AGI. We need to remove the inode from |
2004 | * that list atomically with respect to freeing it here. | 2004 | * that list atomically with respect to freeing it here. |
2005 | */ | 2005 | */ |
2006 | int | 2006 | int |
2007 | xfs_ifree( | 2007 | xfs_ifree( |
2008 | xfs_trans_t *tp, | 2008 | xfs_trans_t *tp, |
2009 | xfs_inode_t *ip, | 2009 | xfs_inode_t *ip, |
2010 | xfs_bmap_free_t *flist) | 2010 | xfs_bmap_free_t *flist) |
2011 | { | 2011 | { |
2012 | int error; | 2012 | int error; |
2013 | int delete; | 2013 | int delete; |
2014 | xfs_ino_t first_ino; | 2014 | xfs_ino_t first_ino; |
2015 | xfs_dinode_t *dip; | 2015 | xfs_dinode_t *dip; |
2016 | xfs_buf_t *ibp; | 2016 | xfs_buf_t *ibp; |
2017 | 2017 | ||
2018 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | 2018 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); |
2019 | ASSERT(ip->i_d.di_nlink == 0); | 2019 | ASSERT(ip->i_d.di_nlink == 0); |
2020 | ASSERT(ip->i_d.di_nextents == 0); | 2020 | ASSERT(ip->i_d.di_nextents == 0); |
2021 | ASSERT(ip->i_d.di_anextents == 0); | 2021 | ASSERT(ip->i_d.di_anextents == 0); |
2022 | ASSERT(ip->i_d.di_size == 0 || !S_ISREG(ip->i_d.di_mode)); | 2022 | ASSERT(ip->i_d.di_size == 0 || !S_ISREG(ip->i_d.di_mode)); |
2023 | ASSERT(ip->i_d.di_nblocks == 0); | 2023 | ASSERT(ip->i_d.di_nblocks == 0); |
2024 | 2024 | ||
2025 | /* | 2025 | /* |
2026 | * Pull the on-disk inode from the AGI unlinked list. | 2026 | * Pull the on-disk inode from the AGI unlinked list. |
2027 | */ | 2027 | */ |
2028 | error = xfs_iunlink_remove(tp, ip); | 2028 | error = xfs_iunlink_remove(tp, ip); |
2029 | if (error != 0) { | 2029 | if (error != 0) { |
2030 | return error; | 2030 | return error; |
2031 | } | 2031 | } |
2032 | 2032 | ||
2033 | error = xfs_difree(tp, ip->i_ino, flist, &delete, &first_ino); | 2033 | error = xfs_difree(tp, ip->i_ino, flist, &delete, &first_ino); |
2034 | if (error != 0) { | 2034 | if (error != 0) { |
2035 | return error; | 2035 | return error; |
2036 | } | 2036 | } |
2037 | ip->i_d.di_mode = 0; /* mark incore inode as free */ | 2037 | ip->i_d.di_mode = 0; /* mark incore inode as free */ |
2038 | ip->i_d.di_flags = 0; | 2038 | ip->i_d.di_flags = 0; |
2039 | ip->i_d.di_dmevmask = 0; | 2039 | ip->i_d.di_dmevmask = 0; |
2040 | ip->i_d.di_forkoff = 0; /* mark the attr fork not in use */ | 2040 | ip->i_d.di_forkoff = 0; /* mark the attr fork not in use */ |
2041 | ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; | 2041 | ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; |
2042 | ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; | 2042 | ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; |
2043 | /* | 2043 | /* |
2044 | * Bump the generation count so no one will be confused | 2044 | * Bump the generation count so no one will be confused |
2045 | * by reincarnations of this inode. | 2045 | * by reincarnations of this inode. |
2046 | */ | 2046 | */ |
2047 | ip->i_d.di_gen++; | 2047 | ip->i_d.di_gen++; |
2048 | 2048 | ||
2049 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 2049 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
2050 | 2050 | ||
2051 | error = xfs_imap_to_bp(ip->i_mount, tp, &ip->i_imap, &dip, &ibp, | 2051 | error = xfs_imap_to_bp(ip->i_mount, tp, &ip->i_imap, &dip, &ibp, |
2052 | 0, 0); | 2052 | 0, 0); |
2053 | if (error) | 2053 | if (error) |
2054 | return error; | 2054 | return error; |
2055 | 2055 | ||
2056 | /* | 2056 | /* |
2057 | * Clear the on-disk di_mode. This is to prevent xfs_bulkstat | 2057 | * Clear the on-disk di_mode. This is to prevent xfs_bulkstat |
2058 | * from picking up this inode when it is reclaimed (its incore state | 2058 | * from picking up this inode when it is reclaimed (its incore state |
2059 | * initialzed but not flushed to disk yet). The in-core di_mode is | 2059 | * initialzed but not flushed to disk yet). The in-core di_mode is |
2060 | * already cleared and a corresponding transaction logged. | 2060 | * already cleared and a corresponding transaction logged. |
2061 | * The hack here just synchronizes the in-core to on-disk | 2061 | * The hack here just synchronizes the in-core to on-disk |
2062 | * di_mode value in advance before the actual inode sync to disk. | 2062 | * di_mode value in advance before the actual inode sync to disk. |
2063 | * This is OK because the inode is already unlinked and would never | 2063 | * This is OK because the inode is already unlinked and would never |
2064 | * change its di_mode again for this inode generation. | 2064 | * change its di_mode again for this inode generation. |
2065 | * This is a temporary hack that would require a proper fix | 2065 | * This is a temporary hack that would require a proper fix |
2066 | * in the future. | 2066 | * in the future. |
2067 | */ | 2067 | */ |
2068 | dip->di_mode = 0; | 2068 | dip->di_mode = 0; |
2069 | 2069 | ||
2070 | if (delete) { | 2070 | if (delete) { |
2071 | error = xfs_ifree_cluster(ip, tp, first_ino); | 2071 | error = xfs_ifree_cluster(ip, tp, first_ino); |
2072 | } | 2072 | } |
2073 | 2073 | ||
2074 | return error; | 2074 | return error; |
2075 | } | 2075 | } |
2076 | 2076 | ||
2077 | /* | 2077 | /* |
2078 | * Reallocate the space for if_broot based on the number of records | 2078 | * Reallocate the space for if_broot based on the number of records |
2079 | * being added or deleted as indicated in rec_diff. Move the records | 2079 | * being added or deleted as indicated in rec_diff. Move the records |
2080 | * and pointers in if_broot to fit the new size. When shrinking this | 2080 | * and pointers in if_broot to fit the new size. When shrinking this |
2081 | * will eliminate holes between the records and pointers created by | 2081 | * will eliminate holes between the records and pointers created by |
2082 | * the caller. When growing this will create holes to be filled in | 2082 | * the caller. When growing this will create holes to be filled in |
2083 | * by the caller. | 2083 | * by the caller. |
2084 | * | 2084 | * |
2085 | * The caller must not request to add more records than would fit in | 2085 | * The caller must not request to add more records than would fit in |
2086 | * the on-disk inode root. If the if_broot is currently NULL, then | 2086 | * the on-disk inode root. If the if_broot is currently NULL, then |
2087 | * if we adding records one will be allocated. The caller must also | 2087 | * if we adding records one will be allocated. The caller must also |
2088 | * not request that the number of records go below zero, although | 2088 | * not request that the number of records go below zero, although |
2089 | * it can go to zero. | 2089 | * it can go to zero. |
2090 | * | 2090 | * |
2091 | * ip -- the inode whose if_broot area is changing | 2091 | * ip -- the inode whose if_broot area is changing |
2092 | * ext_diff -- the change in the number of records, positive or negative, | 2092 | * ext_diff -- the change in the number of records, positive or negative, |
2093 | * requested for the if_broot array. | 2093 | * requested for the if_broot array. |
2094 | */ | 2094 | */ |
2095 | void | 2095 | void |
2096 | xfs_iroot_realloc( | 2096 | xfs_iroot_realloc( |
2097 | xfs_inode_t *ip, | 2097 | xfs_inode_t *ip, |
2098 | int rec_diff, | 2098 | int rec_diff, |
2099 | int whichfork) | 2099 | int whichfork) |
2100 | { | 2100 | { |
2101 | struct xfs_mount *mp = ip->i_mount; | 2101 | struct xfs_mount *mp = ip->i_mount; |
2102 | int cur_max; | 2102 | int cur_max; |
2103 | xfs_ifork_t *ifp; | 2103 | xfs_ifork_t *ifp; |
2104 | struct xfs_btree_block *new_broot; | 2104 | struct xfs_btree_block *new_broot; |
2105 | int new_max; | 2105 | int new_max; |
2106 | size_t new_size; | 2106 | size_t new_size; |
2107 | char *np; | 2107 | char *np; |
2108 | char *op; | 2108 | char *op; |
2109 | 2109 | ||
2110 | /* | 2110 | /* |
2111 | * Handle the degenerate case quietly. | 2111 | * Handle the degenerate case quietly. |
2112 | */ | 2112 | */ |
2113 | if (rec_diff == 0) { | 2113 | if (rec_diff == 0) { |
2114 | return; | 2114 | return; |
2115 | } | 2115 | } |
2116 | 2116 | ||
2117 | ifp = XFS_IFORK_PTR(ip, whichfork); | 2117 | ifp = XFS_IFORK_PTR(ip, whichfork); |
2118 | if (rec_diff > 0) { | 2118 | if (rec_diff > 0) { |
2119 | /* | 2119 | /* |
2120 | * If there wasn't any memory allocated before, just | 2120 | * If there wasn't any memory allocated before, just |
2121 | * allocate it now and get out. | 2121 | * allocate it now and get out. |
2122 | */ | 2122 | */ |
2123 | if (ifp->if_broot_bytes == 0) { | 2123 | if (ifp->if_broot_bytes == 0) { |
2124 | new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff); | 2124 | new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff); |
2125 | ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); | 2125 | ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); |
2126 | ifp->if_broot_bytes = (int)new_size; | 2126 | ifp->if_broot_bytes = (int)new_size; |
2127 | return; | 2127 | return; |
2128 | } | 2128 | } |
2129 | 2129 | ||
2130 | /* | 2130 | /* |
2131 | * If there is already an existing if_broot, then we need | 2131 | * If there is already an existing if_broot, then we need |
2132 | * to realloc() it and shift the pointers to their new | 2132 | * to realloc() it and shift the pointers to their new |
2133 | * location. The records don't change location because | 2133 | * location. The records don't change location because |
2134 | * they are kept butted up against the btree block header. | 2134 | * they are kept butted up against the btree block header. |
2135 | */ | 2135 | */ |
2136 | cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); | 2136 | cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); |
2137 | new_max = cur_max + rec_diff; | 2137 | new_max = cur_max + rec_diff; |
2138 | new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max); | 2138 | new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max); |
2139 | ifp->if_broot = kmem_realloc(ifp->if_broot, new_size, | 2139 | ifp->if_broot = kmem_realloc(ifp->if_broot, new_size, |
2140 | XFS_BMAP_BROOT_SPACE_CALC(mp, cur_max), | 2140 | XFS_BMAP_BROOT_SPACE_CALC(mp, cur_max), |
2141 | KM_SLEEP | KM_NOFS); | 2141 | KM_SLEEP | KM_NOFS); |
2142 | op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, | 2142 | op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, |
2143 | ifp->if_broot_bytes); | 2143 | ifp->if_broot_bytes); |
2144 | np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, | 2144 | np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, |
2145 | (int)new_size); | 2145 | (int)new_size); |
2146 | ifp->if_broot_bytes = (int)new_size; | 2146 | ifp->if_broot_bytes = (int)new_size; |
2147 | ASSERT(ifp->if_broot_bytes <= | 2147 | ASSERT(ifp->if_broot_bytes <= |
2148 | XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ(ip)); | 2148 | XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ(ip)); |
2149 | memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t)); | 2149 | memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t)); |
2150 | return; | 2150 | return; |
2151 | } | 2151 | } |
2152 | 2152 | ||
2153 | /* | 2153 | /* |
2154 | * rec_diff is less than 0. In this case, we are shrinking the | 2154 | * rec_diff is less than 0. In this case, we are shrinking the |
2155 | * if_broot buffer. It must already exist. If we go to zero | 2155 | * if_broot buffer. It must already exist. If we go to zero |
2156 | * records, just get rid of the root and clear the status bit. | 2156 | * records, just get rid of the root and clear the status bit. |
2157 | */ | 2157 | */ |
2158 | ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0)); | 2158 | ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0)); |
2159 | cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); | 2159 | cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); |
2160 | new_max = cur_max + rec_diff; | 2160 | new_max = cur_max + rec_diff; |
2161 | ASSERT(new_max >= 0); | 2161 | ASSERT(new_max >= 0); |
2162 | if (new_max > 0) | 2162 | if (new_max > 0) |
2163 | new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max); | 2163 | new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max); |
2164 | else | 2164 | else |
2165 | new_size = 0; | 2165 | new_size = 0; |
2166 | if (new_size > 0) { | 2166 | if (new_size > 0) { |
2167 | new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); | 2167 | new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); |
2168 | /* | 2168 | /* |
2169 | * First copy over the btree block header. | 2169 | * First copy over the btree block header. |
2170 | */ | 2170 | */ |
2171 | memcpy(new_broot, ifp->if_broot, | 2171 | memcpy(new_broot, ifp->if_broot, |
2172 | XFS_BMBT_BLOCK_LEN(ip->i_mount)); | 2172 | XFS_BMBT_BLOCK_LEN(ip->i_mount)); |
2173 | } else { | 2173 | } else { |
2174 | new_broot = NULL; | 2174 | new_broot = NULL; |
2175 | ifp->if_flags &= ~XFS_IFBROOT; | 2175 | ifp->if_flags &= ~XFS_IFBROOT; |
2176 | } | 2176 | } |
2177 | 2177 | ||
2178 | /* | 2178 | /* |
2179 | * Only copy the records and pointers if there are any. | 2179 | * Only copy the records and pointers if there are any. |
2180 | */ | 2180 | */ |
2181 | if (new_max > 0) { | 2181 | if (new_max > 0) { |
2182 | /* | 2182 | /* |
2183 | * First copy the records. | 2183 | * First copy the records. |
2184 | */ | 2184 | */ |
2185 | op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1); | 2185 | op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1); |
2186 | np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1); | 2186 | np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1); |
2187 | memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t)); | 2187 | memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t)); |
2188 | 2188 | ||
2189 | /* | 2189 | /* |
2190 | * Then copy the pointers. | 2190 | * Then copy the pointers. |
2191 | */ | 2191 | */ |
2192 | op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, | 2192 | op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, |
2193 | ifp->if_broot_bytes); | 2193 | ifp->if_broot_bytes); |
2194 | np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1, | 2194 | np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1, |
2195 | (int)new_size); | 2195 | (int)new_size); |
2196 | memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t)); | 2196 | memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t)); |
2197 | } | 2197 | } |
2198 | kmem_free(ifp->if_broot); | 2198 | kmem_free(ifp->if_broot); |
2199 | ifp->if_broot = new_broot; | 2199 | ifp->if_broot = new_broot; |
2200 | ifp->if_broot_bytes = (int)new_size; | 2200 | ifp->if_broot_bytes = (int)new_size; |
2201 | ASSERT(ifp->if_broot_bytes <= | 2201 | ASSERT(ifp->if_broot_bytes <= |
2202 | XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ(ip)); | 2202 | XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ(ip)); |
2203 | return; | 2203 | return; |
2204 | } | 2204 | } |
2205 | 2205 | ||
2206 | 2206 | ||
2207 | /* | 2207 | /* |
2208 | * This is called when the amount of space needed for if_data | 2208 | * This is called when the amount of space needed for if_data |
2209 | * is increased or decreased. The change in size is indicated by | 2209 | * is increased or decreased. The change in size is indicated by |
2210 | * the number of bytes that need to be added or deleted in the | 2210 | * the number of bytes that need to be added or deleted in the |
2211 | * byte_diff parameter. | 2211 | * byte_diff parameter. |
2212 | * | 2212 | * |
2213 | * If the amount of space needed has decreased below the size of the | 2213 | * If the amount of space needed has decreased below the size of the |
2214 | * inline buffer, then switch to using the inline buffer. Otherwise, | 2214 | * inline buffer, then switch to using the inline buffer. Otherwise, |
2215 | * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer | 2215 | * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer |
2216 | * to what is needed. | 2216 | * to what is needed. |
2217 | * | 2217 | * |
2218 | * ip -- the inode whose if_data area is changing | 2218 | * ip -- the inode whose if_data area is changing |
2219 | * byte_diff -- the change in the number of bytes, positive or negative, | 2219 | * byte_diff -- the change in the number of bytes, positive or negative, |
2220 | * requested for the if_data array. | 2220 | * requested for the if_data array. |
2221 | */ | 2221 | */ |
2222 | void | 2222 | void |
2223 | xfs_idata_realloc( | 2223 | xfs_idata_realloc( |
2224 | xfs_inode_t *ip, | 2224 | xfs_inode_t *ip, |
2225 | int byte_diff, | 2225 | int byte_diff, |
2226 | int whichfork) | 2226 | int whichfork) |
2227 | { | 2227 | { |
2228 | xfs_ifork_t *ifp; | 2228 | xfs_ifork_t *ifp; |
2229 | int new_size; | 2229 | int new_size; |
2230 | int real_size; | 2230 | int real_size; |
2231 | 2231 | ||
2232 | if (byte_diff == 0) { | 2232 | if (byte_diff == 0) { |
2233 | return; | 2233 | return; |
2234 | } | 2234 | } |
2235 | 2235 | ||
2236 | ifp = XFS_IFORK_PTR(ip, whichfork); | 2236 | ifp = XFS_IFORK_PTR(ip, whichfork); |
2237 | new_size = (int)ifp->if_bytes + byte_diff; | 2237 | new_size = (int)ifp->if_bytes + byte_diff; |
2238 | ASSERT(new_size >= 0); | 2238 | ASSERT(new_size >= 0); |
2239 | 2239 | ||
2240 | if (new_size == 0) { | 2240 | if (new_size == 0) { |
2241 | if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { | 2241 | if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { |
2242 | kmem_free(ifp->if_u1.if_data); | 2242 | kmem_free(ifp->if_u1.if_data); |
2243 | } | 2243 | } |
2244 | ifp->if_u1.if_data = NULL; | 2244 | ifp->if_u1.if_data = NULL; |
2245 | real_size = 0; | 2245 | real_size = 0; |
2246 | } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) { | 2246 | } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) { |
2247 | /* | 2247 | /* |
2248 | * If the valid extents/data can fit in if_inline_ext/data, | 2248 | * If the valid extents/data can fit in if_inline_ext/data, |
2249 | * copy them from the malloc'd vector and free it. | 2249 | * copy them from the malloc'd vector and free it. |
2250 | */ | 2250 | */ |
2251 | if (ifp->if_u1.if_data == NULL) { | 2251 | if (ifp->if_u1.if_data == NULL) { |
2252 | ifp->if_u1.if_data = ifp->if_u2.if_inline_data; | 2252 | ifp->if_u1.if_data = ifp->if_u2.if_inline_data; |
2253 | } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { | 2253 | } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { |
2254 | ASSERT(ifp->if_real_bytes != 0); | 2254 | ASSERT(ifp->if_real_bytes != 0); |
2255 | memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data, | 2255 | memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data, |
2256 | new_size); | 2256 | new_size); |
2257 | kmem_free(ifp->if_u1.if_data); | 2257 | kmem_free(ifp->if_u1.if_data); |
2258 | ifp->if_u1.if_data = ifp->if_u2.if_inline_data; | 2258 | ifp->if_u1.if_data = ifp->if_u2.if_inline_data; |
2259 | } | 2259 | } |
2260 | real_size = 0; | 2260 | real_size = 0; |
2261 | } else { | 2261 | } else { |
2262 | /* | 2262 | /* |
2263 | * Stuck with malloc/realloc. | 2263 | * Stuck with malloc/realloc. |
2264 | * For inline data, the underlying buffer must be | 2264 | * For inline data, the underlying buffer must be |
2265 | * a multiple of 4 bytes in size so that it can be | 2265 | * a multiple of 4 bytes in size so that it can be |
2266 | * logged and stay on word boundaries. We enforce | 2266 | * logged and stay on word boundaries. We enforce |
2267 | * that here. | 2267 | * that here. |
2268 | */ | 2268 | */ |
2269 | real_size = roundup(new_size, 4); | 2269 | real_size = roundup(new_size, 4); |
2270 | if (ifp->if_u1.if_data == NULL) { | 2270 | if (ifp->if_u1.if_data == NULL) { |
2271 | ASSERT(ifp->if_real_bytes == 0); | 2271 | ASSERT(ifp->if_real_bytes == 0); |
2272 | ifp->if_u1.if_data = kmem_alloc(real_size, | 2272 | ifp->if_u1.if_data = kmem_alloc(real_size, |
2273 | KM_SLEEP | KM_NOFS); | 2273 | KM_SLEEP | KM_NOFS); |
2274 | } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { | 2274 | } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { |
2275 | /* | 2275 | /* |
2276 | * Only do the realloc if the underlying size | 2276 | * Only do the realloc if the underlying size |
2277 | * is really changing. | 2277 | * is really changing. |
2278 | */ | 2278 | */ |
2279 | if (ifp->if_real_bytes != real_size) { | 2279 | if (ifp->if_real_bytes != real_size) { |
2280 | ifp->if_u1.if_data = | 2280 | ifp->if_u1.if_data = |
2281 | kmem_realloc(ifp->if_u1.if_data, | 2281 | kmem_realloc(ifp->if_u1.if_data, |
2282 | real_size, | 2282 | real_size, |
2283 | ifp->if_real_bytes, | 2283 | ifp->if_real_bytes, |
2284 | KM_SLEEP | KM_NOFS); | 2284 | KM_SLEEP | KM_NOFS); |
2285 | } | 2285 | } |
2286 | } else { | 2286 | } else { |
2287 | ASSERT(ifp->if_real_bytes == 0); | 2287 | ASSERT(ifp->if_real_bytes == 0); |
2288 | ifp->if_u1.if_data = kmem_alloc(real_size, | 2288 | ifp->if_u1.if_data = kmem_alloc(real_size, |
2289 | KM_SLEEP | KM_NOFS); | 2289 | KM_SLEEP | KM_NOFS); |
2290 | memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data, | 2290 | memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data, |
2291 | ifp->if_bytes); | 2291 | ifp->if_bytes); |
2292 | } | 2292 | } |
2293 | } | 2293 | } |
2294 | ifp->if_real_bytes = real_size; | 2294 | ifp->if_real_bytes = real_size; |
2295 | ifp->if_bytes = new_size; | 2295 | ifp->if_bytes = new_size; |
2296 | ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); | 2296 | ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); |
2297 | } | 2297 | } |
2298 | 2298 | ||
2299 | void | 2299 | void |
2300 | xfs_idestroy_fork( | 2300 | xfs_idestroy_fork( |
2301 | xfs_inode_t *ip, | 2301 | xfs_inode_t *ip, |
2302 | int whichfork) | 2302 | int whichfork) |
2303 | { | 2303 | { |
2304 | xfs_ifork_t *ifp; | 2304 | xfs_ifork_t *ifp; |
2305 | 2305 | ||
2306 | ifp = XFS_IFORK_PTR(ip, whichfork); | 2306 | ifp = XFS_IFORK_PTR(ip, whichfork); |
2307 | if (ifp->if_broot != NULL) { | 2307 | if (ifp->if_broot != NULL) { |
2308 | kmem_free(ifp->if_broot); | 2308 | kmem_free(ifp->if_broot); |
2309 | ifp->if_broot = NULL; | 2309 | ifp->if_broot = NULL; |
2310 | } | 2310 | } |
2311 | 2311 | ||
2312 | /* | 2312 | /* |
2313 | * If the format is local, then we can't have an extents | 2313 | * If the format is local, then we can't have an extents |
2314 | * array so just look for an inline data array. If we're | 2314 | * array so just look for an inline data array. If we're |
2315 | * not local then we may or may not have an extents list, | 2315 | * not local then we may or may not have an extents list, |
2316 | * so check and free it up if we do. | 2316 | * so check and free it up if we do. |
2317 | */ | 2317 | */ |
2318 | if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { | 2318 | if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { |
2319 | if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) && | 2319 | if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) && |
2320 | (ifp->if_u1.if_data != NULL)) { | 2320 | (ifp->if_u1.if_data != NULL)) { |
2321 | ASSERT(ifp->if_real_bytes != 0); | 2321 | ASSERT(ifp->if_real_bytes != 0); |
2322 | kmem_free(ifp->if_u1.if_data); | 2322 | kmem_free(ifp->if_u1.if_data); |
2323 | ifp->if_u1.if_data = NULL; | 2323 | ifp->if_u1.if_data = NULL; |
2324 | ifp->if_real_bytes = 0; | 2324 | ifp->if_real_bytes = 0; |
2325 | } | 2325 | } |
2326 | } else if ((ifp->if_flags & XFS_IFEXTENTS) && | 2326 | } else if ((ifp->if_flags & XFS_IFEXTENTS) && |
2327 | ((ifp->if_flags & XFS_IFEXTIREC) || | 2327 | ((ifp->if_flags & XFS_IFEXTIREC) || |
2328 | ((ifp->if_u1.if_extents != NULL) && | 2328 | ((ifp->if_u1.if_extents != NULL) && |
2329 | (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)))) { | 2329 | (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)))) { |
2330 | ASSERT(ifp->if_real_bytes != 0); | 2330 | ASSERT(ifp->if_real_bytes != 0); |
2331 | xfs_iext_destroy(ifp); | 2331 | xfs_iext_destroy(ifp); |
2332 | } | 2332 | } |
2333 | ASSERT(ifp->if_u1.if_extents == NULL || | 2333 | ASSERT(ifp->if_u1.if_extents == NULL || |
2334 | ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext); | 2334 | ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext); |
2335 | ASSERT(ifp->if_real_bytes == 0); | 2335 | ASSERT(ifp->if_real_bytes == 0); |
2336 | if (whichfork == XFS_ATTR_FORK) { | 2336 | if (whichfork == XFS_ATTR_FORK) { |
2337 | kmem_zone_free(xfs_ifork_zone, ip->i_afp); | 2337 | kmem_zone_free(xfs_ifork_zone, ip->i_afp); |
2338 | ip->i_afp = NULL; | 2338 | ip->i_afp = NULL; |
2339 | } | 2339 | } |
2340 | } | 2340 | } |
2341 | 2341 | ||
2342 | /* | 2342 | /* |
2343 | * This is called to unpin an inode. The caller must have the inode locked | 2343 | * This is called to unpin an inode. The caller must have the inode locked |
2344 | * in at least shared mode so that the buffer cannot be subsequently pinned | 2344 | * in at least shared mode so that the buffer cannot be subsequently pinned |
2345 | * once someone is waiting for it to be unpinned. | 2345 | * once someone is waiting for it to be unpinned. |
2346 | */ | 2346 | */ |
2347 | static void | 2347 | static void |
2348 | xfs_iunpin( | 2348 | xfs_iunpin( |
2349 | struct xfs_inode *ip) | 2349 | struct xfs_inode *ip) |
2350 | { | 2350 | { |
2351 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); | 2351 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); |
2352 | 2352 | ||
2353 | trace_xfs_inode_unpin_nowait(ip, _RET_IP_); | 2353 | trace_xfs_inode_unpin_nowait(ip, _RET_IP_); |
2354 | 2354 | ||
2355 | /* Give the log a push to start the unpinning I/O */ | 2355 | /* Give the log a push to start the unpinning I/O */ |
2356 | xfs_log_force_lsn(ip->i_mount, ip->i_itemp->ili_last_lsn, 0); | 2356 | xfs_log_force_lsn(ip->i_mount, ip->i_itemp->ili_last_lsn, 0); |
2357 | 2357 | ||
2358 | } | 2358 | } |
2359 | 2359 | ||
2360 | static void | 2360 | static void |
2361 | __xfs_iunpin_wait( | 2361 | __xfs_iunpin_wait( |
2362 | struct xfs_inode *ip) | 2362 | struct xfs_inode *ip) |
2363 | { | 2363 | { |
2364 | wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IPINNED_BIT); | 2364 | wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IPINNED_BIT); |
2365 | DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IPINNED_BIT); | 2365 | DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IPINNED_BIT); |
2366 | 2366 | ||
2367 | xfs_iunpin(ip); | 2367 | xfs_iunpin(ip); |
2368 | 2368 | ||
2369 | do { | 2369 | do { |
2370 | prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); | 2370 | prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); |
2371 | if (xfs_ipincount(ip)) | 2371 | if (xfs_ipincount(ip)) |
2372 | io_schedule(); | 2372 | io_schedule(); |
2373 | } while (xfs_ipincount(ip)); | 2373 | } while (xfs_ipincount(ip)); |
2374 | finish_wait(wq, &wait.wait); | 2374 | finish_wait(wq, &wait.wait); |
2375 | } | 2375 | } |
2376 | 2376 | ||
2377 | void | 2377 | void |
2378 | xfs_iunpin_wait( | 2378 | xfs_iunpin_wait( |
2379 | struct xfs_inode *ip) | 2379 | struct xfs_inode *ip) |
2380 | { | 2380 | { |
2381 | if (xfs_ipincount(ip)) | 2381 | if (xfs_ipincount(ip)) |
2382 | __xfs_iunpin_wait(ip); | 2382 | __xfs_iunpin_wait(ip); |
2383 | } | 2383 | } |
2384 | 2384 | ||
2385 | /* | 2385 | /* |
2386 | * xfs_iextents_copy() | 2386 | * xfs_iextents_copy() |
2387 | * | 2387 | * |
2388 | * This is called to copy the REAL extents (as opposed to the delayed | 2388 | * This is called to copy the REAL extents (as opposed to the delayed |
2389 | * allocation extents) from the inode into the given buffer. It | 2389 | * allocation extents) from the inode into the given buffer. It |
2390 | * returns the number of bytes copied into the buffer. | 2390 | * returns the number of bytes copied into the buffer. |
2391 | * | 2391 | * |
2392 | * If there are no delayed allocation extents, then we can just | 2392 | * If there are no delayed allocation extents, then we can just |
2393 | * memcpy() the extents into the buffer. Otherwise, we need to | 2393 | * memcpy() the extents into the buffer. Otherwise, we need to |
2394 | * examine each extent in turn and skip those which are delayed. | 2394 | * examine each extent in turn and skip those which are delayed. |
2395 | */ | 2395 | */ |
2396 | int | 2396 | int |
2397 | xfs_iextents_copy( | 2397 | xfs_iextents_copy( |
2398 | xfs_inode_t *ip, | 2398 | xfs_inode_t *ip, |
2399 | xfs_bmbt_rec_t *dp, | 2399 | xfs_bmbt_rec_t *dp, |
2400 | int whichfork) | 2400 | int whichfork) |
2401 | { | 2401 | { |
2402 | int copied; | 2402 | int copied; |
2403 | int i; | 2403 | int i; |
2404 | xfs_ifork_t *ifp; | 2404 | xfs_ifork_t *ifp; |
2405 | int nrecs; | 2405 | int nrecs; |
2406 | xfs_fsblock_t start_block; | 2406 | xfs_fsblock_t start_block; |
2407 | 2407 | ||
2408 | ifp = XFS_IFORK_PTR(ip, whichfork); | 2408 | ifp = XFS_IFORK_PTR(ip, whichfork); |
2409 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); | 2409 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); |
2410 | ASSERT(ifp->if_bytes > 0); | 2410 | ASSERT(ifp->if_bytes > 0); |
2411 | 2411 | ||
2412 | nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | 2412 | nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); |
2413 | XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork); | 2413 | XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork); |
2414 | ASSERT(nrecs > 0); | 2414 | ASSERT(nrecs > 0); |
2415 | 2415 | ||
2416 | /* | 2416 | /* |
2417 | * There are some delayed allocation extents in the | 2417 | * There are some delayed allocation extents in the |
2418 | * inode, so copy the extents one at a time and skip | 2418 | * inode, so copy the extents one at a time and skip |
2419 | * the delayed ones. There must be at least one | 2419 | * the delayed ones. There must be at least one |
2420 | * non-delayed extent. | 2420 | * non-delayed extent. |
2421 | */ | 2421 | */ |
2422 | copied = 0; | 2422 | copied = 0; |
2423 | for (i = 0; i < nrecs; i++) { | 2423 | for (i = 0; i < nrecs; i++) { |
2424 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); | 2424 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); |
2425 | start_block = xfs_bmbt_get_startblock(ep); | 2425 | start_block = xfs_bmbt_get_startblock(ep); |
2426 | if (isnullstartblock(start_block)) { | 2426 | if (isnullstartblock(start_block)) { |
2427 | /* | 2427 | /* |
2428 | * It's a delayed allocation extent, so skip it. | 2428 | * It's a delayed allocation extent, so skip it. |
2429 | */ | 2429 | */ |
2430 | continue; | 2430 | continue; |
2431 | } | 2431 | } |
2432 | 2432 | ||
2433 | /* Translate to on disk format */ | 2433 | /* Translate to on disk format */ |
2434 | put_unaligned(cpu_to_be64(ep->l0), &dp->l0); | 2434 | put_unaligned(cpu_to_be64(ep->l0), &dp->l0); |
2435 | put_unaligned(cpu_to_be64(ep->l1), &dp->l1); | 2435 | put_unaligned(cpu_to_be64(ep->l1), &dp->l1); |
2436 | dp++; | 2436 | dp++; |
2437 | copied++; | 2437 | copied++; |
2438 | } | 2438 | } |
2439 | ASSERT(copied != 0); | 2439 | ASSERT(copied != 0); |
2440 | xfs_validate_extents(ifp, copied, XFS_EXTFMT_INODE(ip)); | 2440 | xfs_validate_extents(ifp, copied, XFS_EXTFMT_INODE(ip)); |
2441 | 2441 | ||
2442 | return (copied * (uint)sizeof(xfs_bmbt_rec_t)); | 2442 | return (copied * (uint)sizeof(xfs_bmbt_rec_t)); |
2443 | } | 2443 | } |
2444 | 2444 | ||
2445 | /* | 2445 | /* |
2446 | * Each of the following cases stores data into the same region | 2446 | * Each of the following cases stores data into the same region |
2447 | * of the on-disk inode, so only one of them can be valid at | 2447 | * of the on-disk inode, so only one of them can be valid at |
2448 | * any given time. While it is possible to have conflicting formats | 2448 | * any given time. While it is possible to have conflicting formats |
2449 | * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is | 2449 | * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is |
2450 | * in EXTENTS format, this can only happen when the fork has | 2450 | * in EXTENTS format, this can only happen when the fork has |
2451 | * changed formats after being modified but before being flushed. | 2451 | * changed formats after being modified but before being flushed. |
2452 | * In these cases, the format always takes precedence, because the | 2452 | * In these cases, the format always takes precedence, because the |
2453 | * format indicates the current state of the fork. | 2453 | * format indicates the current state of the fork. |
2454 | */ | 2454 | */ |
2455 | /*ARGSUSED*/ | 2455 | /*ARGSUSED*/ |
2456 | STATIC void | 2456 | STATIC void |
2457 | xfs_iflush_fork( | 2457 | xfs_iflush_fork( |
2458 | xfs_inode_t *ip, | 2458 | xfs_inode_t *ip, |
2459 | xfs_dinode_t *dip, | 2459 | xfs_dinode_t *dip, |
2460 | xfs_inode_log_item_t *iip, | 2460 | xfs_inode_log_item_t *iip, |
2461 | int whichfork, | 2461 | int whichfork, |
2462 | xfs_buf_t *bp) | 2462 | xfs_buf_t *bp) |
2463 | { | 2463 | { |
2464 | char *cp; | 2464 | char *cp; |
2465 | xfs_ifork_t *ifp; | 2465 | xfs_ifork_t *ifp; |
2466 | xfs_mount_t *mp; | 2466 | xfs_mount_t *mp; |
2467 | static const short brootflag[2] = | 2467 | static const short brootflag[2] = |
2468 | { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT }; | 2468 | { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT }; |
2469 | static const short dataflag[2] = | 2469 | static const short dataflag[2] = |
2470 | { XFS_ILOG_DDATA, XFS_ILOG_ADATA }; | 2470 | { XFS_ILOG_DDATA, XFS_ILOG_ADATA }; |
2471 | static const short extflag[2] = | 2471 | static const short extflag[2] = |
2472 | { XFS_ILOG_DEXT, XFS_ILOG_AEXT }; | 2472 | { XFS_ILOG_DEXT, XFS_ILOG_AEXT }; |
2473 | 2473 | ||
2474 | if (!iip) | 2474 | if (!iip) |
2475 | return; | 2475 | return; |
2476 | ifp = XFS_IFORK_PTR(ip, whichfork); | 2476 | ifp = XFS_IFORK_PTR(ip, whichfork); |
2477 | /* | 2477 | /* |
2478 | * This can happen if we gave up in iformat in an error path, | 2478 | * This can happen if we gave up in iformat in an error path, |
2479 | * for the attribute fork. | 2479 | * for the attribute fork. |
2480 | */ | 2480 | */ |
2481 | if (!ifp) { | 2481 | if (!ifp) { |
2482 | ASSERT(whichfork == XFS_ATTR_FORK); | 2482 | ASSERT(whichfork == XFS_ATTR_FORK); |
2483 | return; | 2483 | return; |
2484 | } | 2484 | } |
2485 | cp = XFS_DFORK_PTR(dip, whichfork); | 2485 | cp = XFS_DFORK_PTR(dip, whichfork); |
2486 | mp = ip->i_mount; | 2486 | mp = ip->i_mount; |
2487 | switch (XFS_IFORK_FORMAT(ip, whichfork)) { | 2487 | switch (XFS_IFORK_FORMAT(ip, whichfork)) { |
2488 | case XFS_DINODE_FMT_LOCAL: | 2488 | case XFS_DINODE_FMT_LOCAL: |
2489 | if ((iip->ili_fields & dataflag[whichfork]) && | 2489 | if ((iip->ili_fields & dataflag[whichfork]) && |
2490 | (ifp->if_bytes > 0)) { | 2490 | (ifp->if_bytes > 0)) { |
2491 | ASSERT(ifp->if_u1.if_data != NULL); | 2491 | ASSERT(ifp->if_u1.if_data != NULL); |
2492 | ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); | 2492 | ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); |
2493 | memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes); | 2493 | memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes); |
2494 | } | 2494 | } |
2495 | break; | 2495 | break; |
2496 | 2496 | ||
2497 | case XFS_DINODE_FMT_EXTENTS: | 2497 | case XFS_DINODE_FMT_EXTENTS: |
2498 | ASSERT((ifp->if_flags & XFS_IFEXTENTS) || | 2498 | ASSERT((ifp->if_flags & XFS_IFEXTENTS) || |
2499 | !(iip->ili_fields & extflag[whichfork])); | 2499 | !(iip->ili_fields & extflag[whichfork])); |
2500 | if ((iip->ili_fields & extflag[whichfork]) && | 2500 | if ((iip->ili_fields & extflag[whichfork]) && |
2501 | (ifp->if_bytes > 0)) { | 2501 | (ifp->if_bytes > 0)) { |
2502 | ASSERT(xfs_iext_get_ext(ifp, 0)); | 2502 | ASSERT(xfs_iext_get_ext(ifp, 0)); |
2503 | ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); | 2503 | ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); |
2504 | (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp, | 2504 | (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp, |
2505 | whichfork); | 2505 | whichfork); |
2506 | } | 2506 | } |
2507 | break; | 2507 | break; |
2508 | 2508 | ||
2509 | case XFS_DINODE_FMT_BTREE: | 2509 | case XFS_DINODE_FMT_BTREE: |
2510 | if ((iip->ili_fields & brootflag[whichfork]) && | 2510 | if ((iip->ili_fields & brootflag[whichfork]) && |
2511 | (ifp->if_broot_bytes > 0)) { | 2511 | (ifp->if_broot_bytes > 0)) { |
2512 | ASSERT(ifp->if_broot != NULL); | 2512 | ASSERT(ifp->if_broot != NULL); |
2513 | ASSERT(ifp->if_broot_bytes <= | 2513 | ASSERT(ifp->if_broot_bytes <= |
2514 | (XFS_IFORK_SIZE(ip, whichfork) + | 2514 | (XFS_IFORK_SIZE(ip, whichfork) + |
2515 | XFS_BROOT_SIZE_ADJ(ip))); | 2515 | XFS_BROOT_SIZE_ADJ(ip))); |
2516 | xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes, | 2516 | xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes, |
2517 | (xfs_bmdr_block_t *)cp, | 2517 | (xfs_bmdr_block_t *)cp, |
2518 | XFS_DFORK_SIZE(dip, mp, whichfork)); | 2518 | XFS_DFORK_SIZE(dip, mp, whichfork)); |
2519 | } | 2519 | } |
2520 | break; | 2520 | break; |
2521 | 2521 | ||
2522 | case XFS_DINODE_FMT_DEV: | 2522 | case XFS_DINODE_FMT_DEV: |
2523 | if (iip->ili_fields & XFS_ILOG_DEV) { | 2523 | if (iip->ili_fields & XFS_ILOG_DEV) { |
2524 | ASSERT(whichfork == XFS_DATA_FORK); | 2524 | ASSERT(whichfork == XFS_DATA_FORK); |
2525 | xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev); | 2525 | xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev); |
2526 | } | 2526 | } |
2527 | break; | 2527 | break; |
2528 | 2528 | ||
2529 | case XFS_DINODE_FMT_UUID: | 2529 | case XFS_DINODE_FMT_UUID: |
2530 | if (iip->ili_fields & XFS_ILOG_UUID) { | 2530 | if (iip->ili_fields & XFS_ILOG_UUID) { |
2531 | ASSERT(whichfork == XFS_DATA_FORK); | 2531 | ASSERT(whichfork == XFS_DATA_FORK); |
2532 | memcpy(XFS_DFORK_DPTR(dip), | 2532 | memcpy(XFS_DFORK_DPTR(dip), |
2533 | &ip->i_df.if_u2.if_uuid, | 2533 | &ip->i_df.if_u2.if_uuid, |
2534 | sizeof(uuid_t)); | 2534 | sizeof(uuid_t)); |
2535 | } | 2535 | } |
2536 | break; | 2536 | break; |
2537 | 2537 | ||
2538 | default: | 2538 | default: |
2539 | ASSERT(0); | 2539 | ASSERT(0); |
2540 | break; | 2540 | break; |
2541 | } | 2541 | } |
2542 | } | 2542 | } |
2543 | 2543 | ||
2544 | STATIC int | 2544 | STATIC int |
2545 | xfs_iflush_cluster( | 2545 | xfs_iflush_cluster( |
2546 | xfs_inode_t *ip, | 2546 | xfs_inode_t *ip, |
2547 | xfs_buf_t *bp) | 2547 | xfs_buf_t *bp) |
2548 | { | 2548 | { |
2549 | xfs_mount_t *mp = ip->i_mount; | 2549 | xfs_mount_t *mp = ip->i_mount; |
2550 | struct xfs_perag *pag; | 2550 | struct xfs_perag *pag; |
2551 | unsigned long first_index, mask; | 2551 | unsigned long first_index, mask; |
2552 | unsigned long inodes_per_cluster; | 2552 | unsigned long inodes_per_cluster; |
2553 | int ilist_size; | 2553 | int ilist_size; |
2554 | xfs_inode_t **ilist; | 2554 | xfs_inode_t **ilist; |
2555 | xfs_inode_t *iq; | 2555 | xfs_inode_t *iq; |
2556 | int nr_found; | 2556 | int nr_found; |
2557 | int clcount = 0; | 2557 | int clcount = 0; |
2558 | int bufwasdelwri; | 2558 | int bufwasdelwri; |
2559 | int i; | 2559 | int i; |
2560 | 2560 | ||
2561 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); | 2561 | pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); |
2562 | 2562 | ||
2563 | inodes_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog; | 2563 | inodes_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog; |
2564 | ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *); | 2564 | ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *); |
2565 | ilist = kmem_alloc(ilist_size, KM_MAYFAIL|KM_NOFS); | 2565 | ilist = kmem_alloc(ilist_size, KM_MAYFAIL|KM_NOFS); |
2566 | if (!ilist) | 2566 | if (!ilist) |
2567 | goto out_put; | 2567 | goto out_put; |
2568 | 2568 | ||
2569 | mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1); | 2569 | mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1); |
2570 | first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask; | 2570 | first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask; |
2571 | rcu_read_lock(); | 2571 | rcu_read_lock(); |
2572 | /* really need a gang lookup range call here */ | 2572 | /* really need a gang lookup range call here */ |
2573 | nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, (void**)ilist, | 2573 | nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, (void**)ilist, |
2574 | first_index, inodes_per_cluster); | 2574 | first_index, inodes_per_cluster); |
2575 | if (nr_found == 0) | 2575 | if (nr_found == 0) |
2576 | goto out_free; | 2576 | goto out_free; |
2577 | 2577 | ||
2578 | for (i = 0; i < nr_found; i++) { | 2578 | for (i = 0; i < nr_found; i++) { |
2579 | iq = ilist[i]; | 2579 | iq = ilist[i]; |
2580 | if (iq == ip) | 2580 | if (iq == ip) |
2581 | continue; | 2581 | continue; |
2582 | 2582 | ||
2583 | /* | 2583 | /* |
2584 | * because this is an RCU protected lookup, we could find a | 2584 | * because this is an RCU protected lookup, we could find a |
2585 | * recently freed or even reallocated inode during the lookup. | 2585 | * recently freed or even reallocated inode during the lookup. |
2586 | * We need to check under the i_flags_lock for a valid inode | 2586 | * We need to check under the i_flags_lock for a valid inode |
2587 | * here. Skip it if it is not valid or the wrong inode. | 2587 | * here. Skip it if it is not valid or the wrong inode. |
2588 | */ | 2588 | */ |
2589 | spin_lock(&ip->i_flags_lock); | 2589 | spin_lock(&ip->i_flags_lock); |
2590 | if (!ip->i_ino || | 2590 | if (!ip->i_ino || |
2591 | (XFS_INO_TO_AGINO(mp, iq->i_ino) & mask) != first_index) { | 2591 | (XFS_INO_TO_AGINO(mp, iq->i_ino) & mask) != first_index) { |
2592 | spin_unlock(&ip->i_flags_lock); | 2592 | spin_unlock(&ip->i_flags_lock); |
2593 | continue; | 2593 | continue; |
2594 | } | 2594 | } |
2595 | spin_unlock(&ip->i_flags_lock); | 2595 | spin_unlock(&ip->i_flags_lock); |
2596 | 2596 | ||
2597 | /* | 2597 | /* |
2598 | * Do an un-protected check to see if the inode is dirty and | 2598 | * Do an un-protected check to see if the inode is dirty and |
2599 | * is a candidate for flushing. These checks will be repeated | 2599 | * is a candidate for flushing. These checks will be repeated |
2600 | * later after the appropriate locks are acquired. | 2600 | * later after the appropriate locks are acquired. |
2601 | */ | 2601 | */ |
2602 | if (xfs_inode_clean(iq) && xfs_ipincount(iq) == 0) | 2602 | if (xfs_inode_clean(iq) && xfs_ipincount(iq) == 0) |
2603 | continue; | 2603 | continue; |
2604 | 2604 | ||
2605 | /* | 2605 | /* |
2606 | * Try to get locks. If any are unavailable or it is pinned, | 2606 | * Try to get locks. If any are unavailable or it is pinned, |
2607 | * then this inode cannot be flushed and is skipped. | 2607 | * then this inode cannot be flushed and is skipped. |
2608 | */ | 2608 | */ |
2609 | 2609 | ||
2610 | if (!xfs_ilock_nowait(iq, XFS_ILOCK_SHARED)) | 2610 | if (!xfs_ilock_nowait(iq, XFS_ILOCK_SHARED)) |
2611 | continue; | 2611 | continue; |
2612 | if (!xfs_iflock_nowait(iq)) { | 2612 | if (!xfs_iflock_nowait(iq)) { |
2613 | xfs_iunlock(iq, XFS_ILOCK_SHARED); | 2613 | xfs_iunlock(iq, XFS_ILOCK_SHARED); |
2614 | continue; | 2614 | continue; |
2615 | } | 2615 | } |
2616 | if (xfs_ipincount(iq)) { | 2616 | if (xfs_ipincount(iq)) { |
2617 | xfs_ifunlock(iq); | 2617 | xfs_ifunlock(iq); |
2618 | xfs_iunlock(iq, XFS_ILOCK_SHARED); | 2618 | xfs_iunlock(iq, XFS_ILOCK_SHARED); |
2619 | continue; | 2619 | continue; |
2620 | } | 2620 | } |
2621 | 2621 | ||
2622 | /* | 2622 | /* |
2623 | * arriving here means that this inode can be flushed. First | 2623 | * arriving here means that this inode can be flushed. First |
2624 | * re-check that it's dirty before flushing. | 2624 | * re-check that it's dirty before flushing. |
2625 | */ | 2625 | */ |
2626 | if (!xfs_inode_clean(iq)) { | 2626 | if (!xfs_inode_clean(iq)) { |
2627 | int error; | 2627 | int error; |
2628 | error = xfs_iflush_int(iq, bp); | 2628 | error = xfs_iflush_int(iq, bp); |
2629 | if (error) { | 2629 | if (error) { |
2630 | xfs_iunlock(iq, XFS_ILOCK_SHARED); | 2630 | xfs_iunlock(iq, XFS_ILOCK_SHARED); |
2631 | goto cluster_corrupt_out; | 2631 | goto cluster_corrupt_out; |
2632 | } | 2632 | } |
2633 | clcount++; | 2633 | clcount++; |
2634 | } else { | 2634 | } else { |
2635 | xfs_ifunlock(iq); | 2635 | xfs_ifunlock(iq); |
2636 | } | 2636 | } |
2637 | xfs_iunlock(iq, XFS_ILOCK_SHARED); | 2637 | xfs_iunlock(iq, XFS_ILOCK_SHARED); |
2638 | } | 2638 | } |
2639 | 2639 | ||
2640 | if (clcount) { | 2640 | if (clcount) { |
2641 | XFS_STATS_INC(xs_icluster_flushcnt); | 2641 | XFS_STATS_INC(xs_icluster_flushcnt); |
2642 | XFS_STATS_ADD(xs_icluster_flushinode, clcount); | 2642 | XFS_STATS_ADD(xs_icluster_flushinode, clcount); |
2643 | } | 2643 | } |
2644 | 2644 | ||
2645 | out_free: | 2645 | out_free: |
2646 | rcu_read_unlock(); | 2646 | rcu_read_unlock(); |
2647 | kmem_free(ilist); | 2647 | kmem_free(ilist); |
2648 | out_put: | 2648 | out_put: |
2649 | xfs_perag_put(pag); | 2649 | xfs_perag_put(pag); |
2650 | return 0; | 2650 | return 0; |
2651 | 2651 | ||
2652 | 2652 | ||
2653 | cluster_corrupt_out: | 2653 | cluster_corrupt_out: |
2654 | /* | 2654 | /* |
2655 | * Corruption detected in the clustering loop. Invalidate the | 2655 | * Corruption detected in the clustering loop. Invalidate the |
2656 | * inode buffer and shut down the filesystem. | 2656 | * inode buffer and shut down the filesystem. |
2657 | */ | 2657 | */ |
2658 | rcu_read_unlock(); | 2658 | rcu_read_unlock(); |
2659 | /* | 2659 | /* |
2660 | * Clean up the buffer. If it was delwri, just release it -- | 2660 | * Clean up the buffer. If it was delwri, just release it -- |
2661 | * brelse can handle it with no problems. If not, shut down the | 2661 | * brelse can handle it with no problems. If not, shut down the |
2662 | * filesystem before releasing the buffer. | 2662 | * filesystem before releasing the buffer. |
2663 | */ | 2663 | */ |
2664 | bufwasdelwri = (bp->b_flags & _XBF_DELWRI_Q); | 2664 | bufwasdelwri = (bp->b_flags & _XBF_DELWRI_Q); |
2665 | if (bufwasdelwri) | 2665 | if (bufwasdelwri) |
2666 | xfs_buf_relse(bp); | 2666 | xfs_buf_relse(bp); |
2667 | 2667 | ||
2668 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); | 2668 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); |
2669 | 2669 | ||
2670 | if (!bufwasdelwri) { | 2670 | if (!bufwasdelwri) { |
2671 | /* | 2671 | /* |
2672 | * Just like incore_relse: if we have b_iodone functions, | 2672 | * Just like incore_relse: if we have b_iodone functions, |
2673 | * mark the buffer as an error and call them. Otherwise | 2673 | * mark the buffer as an error and call them. Otherwise |
2674 | * mark it as stale and brelse. | 2674 | * mark it as stale and brelse. |
2675 | */ | 2675 | */ |
2676 | if (bp->b_iodone) { | 2676 | if (bp->b_iodone) { |
2677 | XFS_BUF_UNDONE(bp); | 2677 | XFS_BUF_UNDONE(bp); |
2678 | xfs_buf_stale(bp); | 2678 | xfs_buf_stale(bp); |
2679 | xfs_buf_ioerror(bp, EIO); | 2679 | xfs_buf_ioerror(bp, EIO); |
2680 | xfs_buf_ioend(bp, 0); | 2680 | xfs_buf_ioend(bp, 0); |
2681 | } else { | 2681 | } else { |
2682 | xfs_buf_stale(bp); | 2682 | xfs_buf_stale(bp); |
2683 | xfs_buf_relse(bp); | 2683 | xfs_buf_relse(bp); |
2684 | } | 2684 | } |
2685 | } | 2685 | } |
2686 | 2686 | ||
2687 | /* | 2687 | /* |
2688 | * Unlocks the flush lock | 2688 | * Unlocks the flush lock |
2689 | */ | 2689 | */ |
2690 | xfs_iflush_abort(iq, false); | 2690 | xfs_iflush_abort(iq, false); |
2691 | kmem_free(ilist); | 2691 | kmem_free(ilist); |
2692 | xfs_perag_put(pag); | 2692 | xfs_perag_put(pag); |
2693 | return XFS_ERROR(EFSCORRUPTED); | 2693 | return XFS_ERROR(EFSCORRUPTED); |
2694 | } | 2694 | } |
2695 | 2695 | ||
2696 | /* | 2696 | /* |
2697 | * Flush dirty inode metadata into the backing buffer. | 2697 | * Flush dirty inode metadata into the backing buffer. |
2698 | * | 2698 | * |
2699 | * The caller must have the inode lock and the inode flush lock held. The | 2699 | * The caller must have the inode lock and the inode flush lock held. The |
2700 | * inode lock will still be held upon return to the caller, and the inode | 2700 | * inode lock will still be held upon return to the caller, and the inode |
2701 | * flush lock will be released after the inode has reached the disk. | 2701 | * flush lock will be released after the inode has reached the disk. |
2702 | * | 2702 | * |
2703 | * The caller must write out the buffer returned in *bpp and release it. | 2703 | * The caller must write out the buffer returned in *bpp and release it. |
2704 | */ | 2704 | */ |
2705 | int | 2705 | int |
2706 | xfs_iflush( | 2706 | xfs_iflush( |
2707 | struct xfs_inode *ip, | 2707 | struct xfs_inode *ip, |
2708 | struct xfs_buf **bpp) | 2708 | struct xfs_buf **bpp) |
2709 | { | 2709 | { |
2710 | struct xfs_mount *mp = ip->i_mount; | 2710 | struct xfs_mount *mp = ip->i_mount; |
2711 | struct xfs_buf *bp; | 2711 | struct xfs_buf *bp; |
2712 | struct xfs_dinode *dip; | 2712 | struct xfs_dinode *dip; |
2713 | int error; | 2713 | int error; |
2714 | 2714 | ||
2715 | XFS_STATS_INC(xs_iflush_count); | 2715 | XFS_STATS_INC(xs_iflush_count); |
2716 | 2716 | ||
2717 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); | 2717 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); |
2718 | ASSERT(xfs_isiflocked(ip)); | 2718 | ASSERT(xfs_isiflocked(ip)); |
2719 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || | 2719 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || |
2720 | ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)); | 2720 | ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)); |
2721 | 2721 | ||
2722 | *bpp = NULL; | 2722 | *bpp = NULL; |
2723 | 2723 | ||
2724 | xfs_iunpin_wait(ip); | 2724 | xfs_iunpin_wait(ip); |
2725 | 2725 | ||
2726 | /* | 2726 | /* |
2727 | * For stale inodes we cannot rely on the backing buffer remaining | 2727 | * For stale inodes we cannot rely on the backing buffer remaining |
2728 | * stale in cache for the remaining life of the stale inode and so | 2728 | * stale in cache for the remaining life of the stale inode and so |
2729 | * xfs_imap_to_bp() below may give us a buffer that no longer contains | 2729 | * xfs_imap_to_bp() below may give us a buffer that no longer contains |
2730 | * inodes below. We have to check this after ensuring the inode is | 2730 | * inodes below. We have to check this after ensuring the inode is |
2731 | * unpinned so that it is safe to reclaim the stale inode after the | 2731 | * unpinned so that it is safe to reclaim the stale inode after the |
2732 | * flush call. | 2732 | * flush call. |
2733 | */ | 2733 | */ |
2734 | if (xfs_iflags_test(ip, XFS_ISTALE)) { | 2734 | if (xfs_iflags_test(ip, XFS_ISTALE)) { |
2735 | xfs_ifunlock(ip); | 2735 | xfs_ifunlock(ip); |
2736 | return 0; | 2736 | return 0; |
2737 | } | 2737 | } |
2738 | 2738 | ||
2739 | /* | 2739 | /* |
2740 | * This may have been unpinned because the filesystem is shutting | 2740 | * This may have been unpinned because the filesystem is shutting |
2741 | * down forcibly. If that's the case we must not write this inode | 2741 | * down forcibly. If that's the case we must not write this inode |
2742 | * to disk, because the log record didn't make it to disk. | 2742 | * to disk, because the log record didn't make it to disk. |
2743 | * | 2743 | * |
2744 | * We also have to remove the log item from the AIL in this case, | 2744 | * We also have to remove the log item from the AIL in this case, |
2745 | * as we wait for an empty AIL as part of the unmount process. | 2745 | * as we wait for an empty AIL as part of the unmount process. |
2746 | */ | 2746 | */ |
2747 | if (XFS_FORCED_SHUTDOWN(mp)) { | 2747 | if (XFS_FORCED_SHUTDOWN(mp)) { |
2748 | error = XFS_ERROR(EIO); | 2748 | error = XFS_ERROR(EIO); |
2749 | goto abort_out; | 2749 | goto abort_out; |
2750 | } | 2750 | } |
2751 | 2751 | ||
2752 | /* | 2752 | /* |
2753 | * Get the buffer containing the on-disk inode. | 2753 | * Get the buffer containing the on-disk inode. |
2754 | */ | 2754 | */ |
2755 | error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, XBF_TRYLOCK, | 2755 | error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, XBF_TRYLOCK, |
2756 | 0); | 2756 | 0); |
2757 | if (error || !bp) { | 2757 | if (error || !bp) { |
2758 | xfs_ifunlock(ip); | 2758 | xfs_ifunlock(ip); |
2759 | return error; | 2759 | return error; |
2760 | } | 2760 | } |
2761 | 2761 | ||
2762 | /* | 2762 | /* |
2763 | * First flush out the inode that xfs_iflush was called with. | 2763 | * First flush out the inode that xfs_iflush was called with. |
2764 | */ | 2764 | */ |
2765 | error = xfs_iflush_int(ip, bp); | 2765 | error = xfs_iflush_int(ip, bp); |
2766 | if (error) | 2766 | if (error) |
2767 | goto corrupt_out; | 2767 | goto corrupt_out; |
2768 | 2768 | ||
2769 | /* | 2769 | /* |
2770 | * If the buffer is pinned then push on the log now so we won't | 2770 | * If the buffer is pinned then push on the log now so we won't |
2771 | * get stuck waiting in the write for too long. | 2771 | * get stuck waiting in the write for too long. |
2772 | */ | 2772 | */ |
2773 | if (xfs_buf_ispinned(bp)) | 2773 | if (xfs_buf_ispinned(bp)) |
2774 | xfs_log_force(mp, 0); | 2774 | xfs_log_force(mp, 0); |
2775 | 2775 | ||
2776 | /* | 2776 | /* |
2777 | * inode clustering: | 2777 | * inode clustering: |
2778 | * see if other inodes can be gathered into this write | 2778 | * see if other inodes can be gathered into this write |
2779 | */ | 2779 | */ |
2780 | error = xfs_iflush_cluster(ip, bp); | 2780 | error = xfs_iflush_cluster(ip, bp); |
2781 | if (error) | 2781 | if (error) |
2782 | goto cluster_corrupt_out; | 2782 | goto cluster_corrupt_out; |
2783 | 2783 | ||
2784 | *bpp = bp; | 2784 | *bpp = bp; |
2785 | return 0; | 2785 | return 0; |
2786 | 2786 | ||
2787 | corrupt_out: | 2787 | corrupt_out: |
2788 | xfs_buf_relse(bp); | 2788 | xfs_buf_relse(bp); |
2789 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); | 2789 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); |
2790 | cluster_corrupt_out: | 2790 | cluster_corrupt_out: |
2791 | error = XFS_ERROR(EFSCORRUPTED); | 2791 | error = XFS_ERROR(EFSCORRUPTED); |
2792 | abort_out: | 2792 | abort_out: |
2793 | /* | 2793 | /* |
2794 | * Unlocks the flush lock | 2794 | * Unlocks the flush lock |
2795 | */ | 2795 | */ |
2796 | xfs_iflush_abort(ip, false); | 2796 | xfs_iflush_abort(ip, false); |
2797 | return error; | 2797 | return error; |
2798 | } | 2798 | } |
2799 | 2799 | ||
2800 | 2800 | ||
2801 | STATIC int | 2801 | STATIC int |
2802 | xfs_iflush_int( | 2802 | xfs_iflush_int( |
2803 | struct xfs_inode *ip, | 2803 | struct xfs_inode *ip, |
2804 | struct xfs_buf *bp) | 2804 | struct xfs_buf *bp) |
2805 | { | 2805 | { |
2806 | struct xfs_inode_log_item *iip = ip->i_itemp; | 2806 | struct xfs_inode_log_item *iip = ip->i_itemp; |
2807 | struct xfs_dinode *dip; | 2807 | struct xfs_dinode *dip; |
2808 | struct xfs_mount *mp = ip->i_mount; | 2808 | struct xfs_mount *mp = ip->i_mount; |
2809 | 2809 | ||
2810 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); | 2810 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); |
2811 | ASSERT(xfs_isiflocked(ip)); | 2811 | ASSERT(xfs_isiflocked(ip)); |
2812 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || | 2812 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || |
2813 | ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)); | 2813 | ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)); |
2814 | ASSERT(iip != NULL && iip->ili_fields != 0); | 2814 | ASSERT(iip != NULL && iip->ili_fields != 0); |
2815 | 2815 | ||
2816 | /* set *dip = inode's place in the buffer */ | 2816 | /* set *dip = inode's place in the buffer */ |
2817 | dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset); | 2817 | dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset); |
2818 | 2818 | ||
2819 | if (XFS_TEST_ERROR(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC), | 2819 | if (XFS_TEST_ERROR(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC), |
2820 | mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) { | 2820 | mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) { |
2821 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, | 2821 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, |
2822 | "%s: Bad inode %Lu magic number 0x%x, ptr 0x%p", | 2822 | "%s: Bad inode %Lu magic number 0x%x, ptr 0x%p", |
2823 | __func__, ip->i_ino, be16_to_cpu(dip->di_magic), dip); | 2823 | __func__, ip->i_ino, be16_to_cpu(dip->di_magic), dip); |
2824 | goto corrupt_out; | 2824 | goto corrupt_out; |
2825 | } | 2825 | } |
2826 | if (XFS_TEST_ERROR(ip->i_d.di_magic != XFS_DINODE_MAGIC, | 2826 | if (XFS_TEST_ERROR(ip->i_d.di_magic != XFS_DINODE_MAGIC, |
2827 | mp, XFS_ERRTAG_IFLUSH_2, XFS_RANDOM_IFLUSH_2)) { | 2827 | mp, XFS_ERRTAG_IFLUSH_2, XFS_RANDOM_IFLUSH_2)) { |
2828 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, | 2828 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, |
2829 | "%s: Bad inode %Lu, ptr 0x%p, magic number 0x%x", | 2829 | "%s: Bad inode %Lu, ptr 0x%p, magic number 0x%x", |
2830 | __func__, ip->i_ino, ip, ip->i_d.di_magic); | 2830 | __func__, ip->i_ino, ip, ip->i_d.di_magic); |
2831 | goto corrupt_out; | 2831 | goto corrupt_out; |
2832 | } | 2832 | } |
2833 | if (S_ISREG(ip->i_d.di_mode)) { | 2833 | if (S_ISREG(ip->i_d.di_mode)) { |
2834 | if (XFS_TEST_ERROR( | 2834 | if (XFS_TEST_ERROR( |
2835 | (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && | 2835 | (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && |
2836 | (ip->i_d.di_format != XFS_DINODE_FMT_BTREE), | 2836 | (ip->i_d.di_format != XFS_DINODE_FMT_BTREE), |
2837 | mp, XFS_ERRTAG_IFLUSH_3, XFS_RANDOM_IFLUSH_3)) { | 2837 | mp, XFS_ERRTAG_IFLUSH_3, XFS_RANDOM_IFLUSH_3)) { |
2838 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, | 2838 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, |
2839 | "%s: Bad regular inode %Lu, ptr 0x%p", | 2839 | "%s: Bad regular inode %Lu, ptr 0x%p", |
2840 | __func__, ip->i_ino, ip); | 2840 | __func__, ip->i_ino, ip); |
2841 | goto corrupt_out; | 2841 | goto corrupt_out; |
2842 | } | 2842 | } |
2843 | } else if (S_ISDIR(ip->i_d.di_mode)) { | 2843 | } else if (S_ISDIR(ip->i_d.di_mode)) { |
2844 | if (XFS_TEST_ERROR( | 2844 | if (XFS_TEST_ERROR( |
2845 | (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && | 2845 | (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && |
2846 | (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) && | 2846 | (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) && |
2847 | (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL), | 2847 | (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL), |
2848 | mp, XFS_ERRTAG_IFLUSH_4, XFS_RANDOM_IFLUSH_4)) { | 2848 | mp, XFS_ERRTAG_IFLUSH_4, XFS_RANDOM_IFLUSH_4)) { |
2849 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, | 2849 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, |
2850 | "%s: Bad directory inode %Lu, ptr 0x%p", | 2850 | "%s: Bad directory inode %Lu, ptr 0x%p", |
2851 | __func__, ip->i_ino, ip); | 2851 | __func__, ip->i_ino, ip); |
2852 | goto corrupt_out; | 2852 | goto corrupt_out; |
2853 | } | 2853 | } |
2854 | } | 2854 | } |
2855 | if (XFS_TEST_ERROR(ip->i_d.di_nextents + ip->i_d.di_anextents > | 2855 | if (XFS_TEST_ERROR(ip->i_d.di_nextents + ip->i_d.di_anextents > |
2856 | ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5, | 2856 | ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5, |
2857 | XFS_RANDOM_IFLUSH_5)) { | 2857 | XFS_RANDOM_IFLUSH_5)) { |
2858 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, | 2858 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, |
2859 | "%s: detected corrupt incore inode %Lu, " | 2859 | "%s: detected corrupt incore inode %Lu, " |
2860 | "total extents = %d, nblocks = %Ld, ptr 0x%p", | 2860 | "total extents = %d, nblocks = %Ld, ptr 0x%p", |
2861 | __func__, ip->i_ino, | 2861 | __func__, ip->i_ino, |
2862 | ip->i_d.di_nextents + ip->i_d.di_anextents, | 2862 | ip->i_d.di_nextents + ip->i_d.di_anextents, |
2863 | ip->i_d.di_nblocks, ip); | 2863 | ip->i_d.di_nblocks, ip); |
2864 | goto corrupt_out; | 2864 | goto corrupt_out; |
2865 | } | 2865 | } |
2866 | if (XFS_TEST_ERROR(ip->i_d.di_forkoff > mp->m_sb.sb_inodesize, | 2866 | if (XFS_TEST_ERROR(ip->i_d.di_forkoff > mp->m_sb.sb_inodesize, |
2867 | mp, XFS_ERRTAG_IFLUSH_6, XFS_RANDOM_IFLUSH_6)) { | 2867 | mp, XFS_ERRTAG_IFLUSH_6, XFS_RANDOM_IFLUSH_6)) { |
2868 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, | 2868 | xfs_alert_tag(mp, XFS_PTAG_IFLUSH, |
2869 | "%s: bad inode %Lu, forkoff 0x%x, ptr 0x%p", | 2869 | "%s: bad inode %Lu, forkoff 0x%x, ptr 0x%p", |
2870 | __func__, ip->i_ino, ip->i_d.di_forkoff, ip); | 2870 | __func__, ip->i_ino, ip->i_d.di_forkoff, ip); |
2871 | goto corrupt_out; | 2871 | goto corrupt_out; |
2872 | } | 2872 | } |
2873 | /* | 2873 | /* |
2874 | * bump the flush iteration count, used to detect flushes which | 2874 | * bump the flush iteration count, used to detect flushes which |
2875 | * postdate a log record during recovery. This is redundant as we now | 2875 | * postdate a log record during recovery. This is redundant as we now |
2876 | * log every change and hence this can't happen. Still, it doesn't hurt. | 2876 | * log every change and hence this can't happen. Still, it doesn't hurt. |
2877 | */ | 2877 | */ |
2878 | ip->i_d.di_flushiter++; | 2878 | ip->i_d.di_flushiter++; |
2879 | 2879 | ||
2880 | /* | 2880 | /* |
2881 | * Copy the dirty parts of the inode into the on-disk | 2881 | * Copy the dirty parts of the inode into the on-disk |
2882 | * inode. We always copy out the core of the inode, | 2882 | * inode. We always copy out the core of the inode, |
2883 | * because if the inode is dirty at all the core must | 2883 | * because if the inode is dirty at all the core must |
2884 | * be. | 2884 | * be. |
2885 | */ | 2885 | */ |
2886 | xfs_dinode_to_disk(dip, &ip->i_d); | 2886 | xfs_dinode_to_disk(dip, &ip->i_d); |
2887 | 2887 | ||
2888 | /* Wrap, we never let the log put out DI_MAX_FLUSH */ | 2888 | /* Wrap, we never let the log put out DI_MAX_FLUSH */ |
2889 | if (ip->i_d.di_flushiter == DI_MAX_FLUSH) | 2889 | if (ip->i_d.di_flushiter == DI_MAX_FLUSH) |
2890 | ip->i_d.di_flushiter = 0; | 2890 | ip->i_d.di_flushiter = 0; |
2891 | 2891 | ||
2892 | /* | 2892 | /* |
2893 | * If this is really an old format inode and the superblock version | 2893 | * If this is really an old format inode and the superblock version |
2894 | * has not been updated to support only new format inodes, then | 2894 | * has not been updated to support only new format inodes, then |
2895 | * convert back to the old inode format. If the superblock version | 2895 | * convert back to the old inode format. If the superblock version |
2896 | * has been updated, then make the conversion permanent. | 2896 | * has been updated, then make the conversion permanent. |
2897 | */ | 2897 | */ |
2898 | ASSERT(ip->i_d.di_version == 1 || xfs_sb_version_hasnlink(&mp->m_sb)); | 2898 | ASSERT(ip->i_d.di_version == 1 || xfs_sb_version_hasnlink(&mp->m_sb)); |
2899 | if (ip->i_d.di_version == 1) { | 2899 | if (ip->i_d.di_version == 1) { |
2900 | if (!xfs_sb_version_hasnlink(&mp->m_sb)) { | 2900 | if (!xfs_sb_version_hasnlink(&mp->m_sb)) { |
2901 | /* | 2901 | /* |
2902 | * Convert it back. | 2902 | * Convert it back. |
2903 | */ | 2903 | */ |
2904 | ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1); | 2904 | ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1); |
2905 | dip->di_onlink = cpu_to_be16(ip->i_d.di_nlink); | 2905 | dip->di_onlink = cpu_to_be16(ip->i_d.di_nlink); |
2906 | } else { | 2906 | } else { |
2907 | /* | 2907 | /* |
2908 | * The superblock version has already been bumped, | 2908 | * The superblock version has already been bumped, |
2909 | * so just make the conversion to the new inode | 2909 | * so just make the conversion to the new inode |
2910 | * format permanent. | 2910 | * format permanent. |
2911 | */ | 2911 | */ |
2912 | ip->i_d.di_version = 2; | 2912 | ip->i_d.di_version = 2; |
2913 | dip->di_version = 2; | 2913 | dip->di_version = 2; |
2914 | ip->i_d.di_onlink = 0; | 2914 | ip->i_d.di_onlink = 0; |
2915 | dip->di_onlink = 0; | 2915 | dip->di_onlink = 0; |
2916 | memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); | 2916 | memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); |
2917 | memset(&(dip->di_pad[0]), 0, | 2917 | memset(&(dip->di_pad[0]), 0, |
2918 | sizeof(dip->di_pad)); | 2918 | sizeof(dip->di_pad)); |
2919 | ASSERT(xfs_get_projid(ip) == 0); | 2919 | ASSERT(xfs_get_projid(ip) == 0); |
2920 | } | 2920 | } |
2921 | } | 2921 | } |
2922 | 2922 | ||
2923 | xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp); | 2923 | xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp); |
2924 | if (XFS_IFORK_Q(ip)) | 2924 | if (XFS_IFORK_Q(ip)) |
2925 | xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp); | 2925 | xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp); |
2926 | xfs_inobp_check(mp, bp); | 2926 | xfs_inobp_check(mp, bp); |
2927 | 2927 | ||
2928 | /* | 2928 | /* |
2929 | * We've recorded everything logged in the inode, so we'd like to clear | 2929 | * We've recorded everything logged in the inode, so we'd like to clear |
2930 | * the ili_fields bits so we don't log and flush things unnecessarily. | 2930 | * the ili_fields bits so we don't log and flush things unnecessarily. |
2931 | * However, we can't stop logging all this information until the data | 2931 | * However, we can't stop logging all this information until the data |
2932 | * we've copied into the disk buffer is written to disk. If we did we | 2932 | * we've copied into the disk buffer is written to disk. If we did we |
2933 | * might overwrite the copy of the inode in the log with all the data | 2933 | * might overwrite the copy of the inode in the log with all the data |
2934 | * after re-logging only part of it, and in the face of a crash we | 2934 | * after re-logging only part of it, and in the face of a crash we |
2935 | * wouldn't have all the data we need to recover. | 2935 | * wouldn't have all the data we need to recover. |
2936 | * | 2936 | * |
2937 | * What we do is move the bits to the ili_last_fields field. When | 2937 | * What we do is move the bits to the ili_last_fields field. When |
2938 | * logging the inode, these bits are moved back to the ili_fields field. | 2938 | * logging the inode, these bits are moved back to the ili_fields field. |
2939 | * In the xfs_iflush_done() routine we clear ili_last_fields, since we | 2939 | * In the xfs_iflush_done() routine we clear ili_last_fields, since we |
2940 | * know that the information those bits represent is permanently on | 2940 | * know that the information those bits represent is permanently on |
2941 | * disk. As long as the flush completes before the inode is logged | 2941 | * disk. As long as the flush completes before the inode is logged |
2942 | * again, then both ili_fields and ili_last_fields will be cleared. | 2942 | * again, then both ili_fields and ili_last_fields will be cleared. |
2943 | * | 2943 | * |
2944 | * We can play with the ili_fields bits here, because the inode lock | 2944 | * We can play with the ili_fields bits here, because the inode lock |
2945 | * must be held exclusively in order to set bits there and the flush | 2945 | * must be held exclusively in order to set bits there and the flush |
2946 | * lock protects the ili_last_fields bits. Set ili_logged so the flush | 2946 | * lock protects the ili_last_fields bits. Set ili_logged so the flush |
2947 | * done routine can tell whether or not to look in the AIL. Also, store | 2947 | * done routine can tell whether or not to look in the AIL. Also, store |
2948 | * the current LSN of the inode so that we can tell whether the item has | 2948 | * the current LSN of the inode so that we can tell whether the item has |
2949 | * moved in the AIL from xfs_iflush_done(). In order to read the lsn we | 2949 | * moved in the AIL from xfs_iflush_done(). In order to read the lsn we |
2950 | * need the AIL lock, because it is a 64 bit value that cannot be read | 2950 | * need the AIL lock, because it is a 64 bit value that cannot be read |
2951 | * atomically. | 2951 | * atomically. |
2952 | */ | 2952 | */ |
2953 | iip->ili_last_fields = iip->ili_fields; | 2953 | iip->ili_last_fields = iip->ili_fields; |
2954 | iip->ili_fields = 0; | 2954 | iip->ili_fields = 0; |
2955 | iip->ili_logged = 1; | 2955 | iip->ili_logged = 1; |
2956 | 2956 | ||
2957 | xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, | 2957 | xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, |
2958 | &iip->ili_item.li_lsn); | 2958 | &iip->ili_item.li_lsn); |
2959 | 2959 | ||
2960 | /* | 2960 | /* |
2961 | * Attach the function xfs_iflush_done to the inode's | 2961 | * Attach the function xfs_iflush_done to the inode's |
2962 | * buffer. This will remove the inode from the AIL | 2962 | * buffer. This will remove the inode from the AIL |
2963 | * and unlock the inode's flush lock when the inode is | 2963 | * and unlock the inode's flush lock when the inode is |
2964 | * completely written to disk. | 2964 | * completely written to disk. |
2965 | */ | 2965 | */ |
2966 | xfs_buf_attach_iodone(bp, xfs_iflush_done, &iip->ili_item); | 2966 | xfs_buf_attach_iodone(bp, xfs_iflush_done, &iip->ili_item); |
2967 | 2967 | ||
2968 | /* update the lsn in the on disk inode if required */ | 2968 | /* update the lsn in the on disk inode if required */ |
2969 | if (ip->i_d.di_version == 3) | 2969 | if (ip->i_d.di_version == 3) |
2970 | dip->di_lsn = cpu_to_be64(iip->ili_item.li_lsn); | 2970 | dip->di_lsn = cpu_to_be64(iip->ili_item.li_lsn); |
2971 | 2971 | ||
2972 | /* generate the checksum. */ | 2972 | /* generate the checksum. */ |
2973 | xfs_dinode_calc_crc(mp, dip); | 2973 | xfs_dinode_calc_crc(mp, dip); |
2974 | 2974 | ||
2975 | ASSERT(bp->b_fspriv != NULL); | 2975 | ASSERT(bp->b_fspriv != NULL); |
2976 | ASSERT(bp->b_iodone != NULL); | 2976 | ASSERT(bp->b_iodone != NULL); |
2977 | return 0; | 2977 | return 0; |
2978 | 2978 | ||
2979 | corrupt_out: | 2979 | corrupt_out: |
2980 | return XFS_ERROR(EFSCORRUPTED); | 2980 | return XFS_ERROR(EFSCORRUPTED); |
2981 | } | 2981 | } |
2982 | 2982 | ||
2983 | /* | 2983 | /* |
2984 | * Return a pointer to the extent record at file index idx. | 2984 | * Return a pointer to the extent record at file index idx. |
2985 | */ | 2985 | */ |
2986 | xfs_bmbt_rec_host_t * | 2986 | xfs_bmbt_rec_host_t * |
2987 | xfs_iext_get_ext( | 2987 | xfs_iext_get_ext( |
2988 | xfs_ifork_t *ifp, /* inode fork pointer */ | 2988 | xfs_ifork_t *ifp, /* inode fork pointer */ |
2989 | xfs_extnum_t idx) /* index of target extent */ | 2989 | xfs_extnum_t idx) /* index of target extent */ |
2990 | { | 2990 | { |
2991 | ASSERT(idx >= 0); | 2991 | ASSERT(idx >= 0); |
2992 | ASSERT(idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)); | 2992 | ASSERT(idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)); |
2993 | 2993 | ||
2994 | if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) { | 2994 | if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) { |
2995 | return ifp->if_u1.if_ext_irec->er_extbuf; | 2995 | return ifp->if_u1.if_ext_irec->er_extbuf; |
2996 | } else if (ifp->if_flags & XFS_IFEXTIREC) { | 2996 | } else if (ifp->if_flags & XFS_IFEXTIREC) { |
2997 | xfs_ext_irec_t *erp; /* irec pointer */ | 2997 | xfs_ext_irec_t *erp; /* irec pointer */ |
2998 | int erp_idx = 0; /* irec index */ | 2998 | int erp_idx = 0; /* irec index */ |
2999 | xfs_extnum_t page_idx = idx; /* ext index in target list */ | 2999 | xfs_extnum_t page_idx = idx; /* ext index in target list */ |
3000 | 3000 | ||
3001 | erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0); | 3001 | erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0); |
3002 | return &erp->er_extbuf[page_idx]; | 3002 | return &erp->er_extbuf[page_idx]; |
3003 | } else if (ifp->if_bytes) { | 3003 | } else if (ifp->if_bytes) { |
3004 | return &ifp->if_u1.if_extents[idx]; | 3004 | return &ifp->if_u1.if_extents[idx]; |
3005 | } else { | 3005 | } else { |
3006 | return NULL; | 3006 | return NULL; |
3007 | } | 3007 | } |
3008 | } | 3008 | } |
3009 | 3009 | ||
3010 | /* | 3010 | /* |
3011 | * Insert new item(s) into the extent records for incore inode | 3011 | * Insert new item(s) into the extent records for incore inode |
3012 | * fork 'ifp'. 'count' new items are inserted at index 'idx'. | 3012 | * fork 'ifp'. 'count' new items are inserted at index 'idx'. |
3013 | */ | 3013 | */ |
3014 | void | 3014 | void |
3015 | xfs_iext_insert( | 3015 | xfs_iext_insert( |
3016 | xfs_inode_t *ip, /* incore inode pointer */ | 3016 | xfs_inode_t *ip, /* incore inode pointer */ |
3017 | xfs_extnum_t idx, /* starting index of new items */ | 3017 | xfs_extnum_t idx, /* starting index of new items */ |
3018 | xfs_extnum_t count, /* number of inserted items */ | 3018 | xfs_extnum_t count, /* number of inserted items */ |
3019 | xfs_bmbt_irec_t *new, /* items to insert */ | 3019 | xfs_bmbt_irec_t *new, /* items to insert */ |
3020 | int state) /* type of extent conversion */ | 3020 | int state) /* type of extent conversion */ |
3021 | { | 3021 | { |
3022 | xfs_ifork_t *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df; | 3022 | xfs_ifork_t *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df; |
3023 | xfs_extnum_t i; /* extent record index */ | 3023 | xfs_extnum_t i; /* extent record index */ |
3024 | 3024 | ||
3025 | trace_xfs_iext_insert(ip, idx, new, state, _RET_IP_); | 3025 | trace_xfs_iext_insert(ip, idx, new, state, _RET_IP_); |
3026 | 3026 | ||
3027 | ASSERT(ifp->if_flags & XFS_IFEXTENTS); | 3027 | ASSERT(ifp->if_flags & XFS_IFEXTENTS); |
3028 | xfs_iext_add(ifp, idx, count); | 3028 | xfs_iext_add(ifp, idx, count); |
3029 | for (i = idx; i < idx + count; i++, new++) | 3029 | for (i = idx; i < idx + count; i++, new++) |
3030 | xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new); | 3030 | xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new); |
3031 | } | 3031 | } |
3032 | 3032 | ||
3033 | /* | 3033 | /* |
3034 | * This is called when the amount of space required for incore file | 3034 | * This is called when the amount of space required for incore file |
3035 | * extents needs to be increased. The ext_diff parameter stores the | 3035 | * extents needs to be increased. The ext_diff parameter stores the |
3036 | * number of new extents being added and the idx parameter contains | 3036 | * number of new extents being added and the idx parameter contains |
3037 | * the extent index where the new extents will be added. If the new | 3037 | * the extent index where the new extents will be added. If the new |
3038 | * extents are being appended, then we just need to (re)allocate and | 3038 | * extents are being appended, then we just need to (re)allocate and |
3039 | * initialize the space. Otherwise, if the new extents are being | 3039 | * initialize the space. Otherwise, if the new extents are being |
3040 | * inserted into the middle of the existing entries, a bit more work | 3040 | * inserted into the middle of the existing entries, a bit more work |
3041 | * is required to make room for the new extents to be inserted. The | 3041 | * is required to make room for the new extents to be inserted. The |
3042 | * caller is responsible for filling in the new extent entries upon | 3042 | * caller is responsible for filling in the new extent entries upon |
3043 | * return. | 3043 | * return. |
3044 | */ | 3044 | */ |
3045 | void | 3045 | void |
3046 | xfs_iext_add( | 3046 | xfs_iext_add( |
3047 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3047 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3048 | xfs_extnum_t idx, /* index to begin adding exts */ | 3048 | xfs_extnum_t idx, /* index to begin adding exts */ |
3049 | int ext_diff) /* number of extents to add */ | 3049 | int ext_diff) /* number of extents to add */ |
3050 | { | 3050 | { |
3051 | int byte_diff; /* new bytes being added */ | 3051 | int byte_diff; /* new bytes being added */ |
3052 | int new_size; /* size of extents after adding */ | 3052 | int new_size; /* size of extents after adding */ |
3053 | xfs_extnum_t nextents; /* number of extents in file */ | 3053 | xfs_extnum_t nextents; /* number of extents in file */ |
3054 | 3054 | ||
3055 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | 3055 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); |
3056 | ASSERT((idx >= 0) && (idx <= nextents)); | 3056 | ASSERT((idx >= 0) && (idx <= nextents)); |
3057 | byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t); | 3057 | byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t); |
3058 | new_size = ifp->if_bytes + byte_diff; | 3058 | new_size = ifp->if_bytes + byte_diff; |
3059 | /* | 3059 | /* |
3060 | * If the new number of extents (nextents + ext_diff) | 3060 | * If the new number of extents (nextents + ext_diff) |
3061 | * fits inside the inode, then continue to use the inline | 3061 | * fits inside the inode, then continue to use the inline |
3062 | * extent buffer. | 3062 | * extent buffer. |
3063 | */ | 3063 | */ |
3064 | if (nextents + ext_diff <= XFS_INLINE_EXTS) { | 3064 | if (nextents + ext_diff <= XFS_INLINE_EXTS) { |
3065 | if (idx < nextents) { | 3065 | if (idx < nextents) { |
3066 | memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff], | 3066 | memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff], |
3067 | &ifp->if_u2.if_inline_ext[idx], | 3067 | &ifp->if_u2.if_inline_ext[idx], |
3068 | (nextents - idx) * sizeof(xfs_bmbt_rec_t)); | 3068 | (nextents - idx) * sizeof(xfs_bmbt_rec_t)); |
3069 | memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff); | 3069 | memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff); |
3070 | } | 3070 | } |
3071 | ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; | 3071 | ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; |
3072 | ifp->if_real_bytes = 0; | 3072 | ifp->if_real_bytes = 0; |
3073 | } | 3073 | } |
3074 | /* | 3074 | /* |
3075 | * Otherwise use a linear (direct) extent list. | 3075 | * Otherwise use a linear (direct) extent list. |
3076 | * If the extents are currently inside the inode, | 3076 | * If the extents are currently inside the inode, |
3077 | * xfs_iext_realloc_direct will switch us from | 3077 | * xfs_iext_realloc_direct will switch us from |
3078 | * inline to direct extent allocation mode. | 3078 | * inline to direct extent allocation mode. |
3079 | */ | 3079 | */ |
3080 | else if (nextents + ext_diff <= XFS_LINEAR_EXTS) { | 3080 | else if (nextents + ext_diff <= XFS_LINEAR_EXTS) { |
3081 | xfs_iext_realloc_direct(ifp, new_size); | 3081 | xfs_iext_realloc_direct(ifp, new_size); |
3082 | if (idx < nextents) { | 3082 | if (idx < nextents) { |
3083 | memmove(&ifp->if_u1.if_extents[idx + ext_diff], | 3083 | memmove(&ifp->if_u1.if_extents[idx + ext_diff], |
3084 | &ifp->if_u1.if_extents[idx], | 3084 | &ifp->if_u1.if_extents[idx], |
3085 | (nextents - idx) * sizeof(xfs_bmbt_rec_t)); | 3085 | (nextents - idx) * sizeof(xfs_bmbt_rec_t)); |
3086 | memset(&ifp->if_u1.if_extents[idx], 0, byte_diff); | 3086 | memset(&ifp->if_u1.if_extents[idx], 0, byte_diff); |
3087 | } | 3087 | } |
3088 | } | 3088 | } |
3089 | /* Indirection array */ | 3089 | /* Indirection array */ |
3090 | else { | 3090 | else { |
3091 | xfs_ext_irec_t *erp; | 3091 | xfs_ext_irec_t *erp; |
3092 | int erp_idx = 0; | 3092 | int erp_idx = 0; |
3093 | int page_idx = idx; | 3093 | int page_idx = idx; |
3094 | 3094 | ||
3095 | ASSERT(nextents + ext_diff > XFS_LINEAR_EXTS); | 3095 | ASSERT(nextents + ext_diff > XFS_LINEAR_EXTS); |
3096 | if (ifp->if_flags & XFS_IFEXTIREC) { | 3096 | if (ifp->if_flags & XFS_IFEXTIREC) { |
3097 | erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 1); | 3097 | erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 1); |
3098 | } else { | 3098 | } else { |
3099 | xfs_iext_irec_init(ifp); | 3099 | xfs_iext_irec_init(ifp); |
3100 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3100 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3101 | erp = ifp->if_u1.if_ext_irec; | 3101 | erp = ifp->if_u1.if_ext_irec; |
3102 | } | 3102 | } |
3103 | /* Extents fit in target extent page */ | 3103 | /* Extents fit in target extent page */ |
3104 | if (erp && erp->er_extcount + ext_diff <= XFS_LINEAR_EXTS) { | 3104 | if (erp && erp->er_extcount + ext_diff <= XFS_LINEAR_EXTS) { |
3105 | if (page_idx < erp->er_extcount) { | 3105 | if (page_idx < erp->er_extcount) { |
3106 | memmove(&erp->er_extbuf[page_idx + ext_diff], | 3106 | memmove(&erp->er_extbuf[page_idx + ext_diff], |
3107 | &erp->er_extbuf[page_idx], | 3107 | &erp->er_extbuf[page_idx], |
3108 | (erp->er_extcount - page_idx) * | 3108 | (erp->er_extcount - page_idx) * |
3109 | sizeof(xfs_bmbt_rec_t)); | 3109 | sizeof(xfs_bmbt_rec_t)); |
3110 | memset(&erp->er_extbuf[page_idx], 0, byte_diff); | 3110 | memset(&erp->er_extbuf[page_idx], 0, byte_diff); |
3111 | } | 3111 | } |
3112 | erp->er_extcount += ext_diff; | 3112 | erp->er_extcount += ext_diff; |
3113 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); | 3113 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); |
3114 | } | 3114 | } |
3115 | /* Insert a new extent page */ | 3115 | /* Insert a new extent page */ |
3116 | else if (erp) { | 3116 | else if (erp) { |
3117 | xfs_iext_add_indirect_multi(ifp, | 3117 | xfs_iext_add_indirect_multi(ifp, |
3118 | erp_idx, page_idx, ext_diff); | 3118 | erp_idx, page_idx, ext_diff); |
3119 | } | 3119 | } |
3120 | /* | 3120 | /* |
3121 | * If extent(s) are being appended to the last page in | 3121 | * If extent(s) are being appended to the last page in |
3122 | * the indirection array and the new extent(s) don't fit | 3122 | * the indirection array and the new extent(s) don't fit |
3123 | * in the page, then erp is NULL and erp_idx is set to | 3123 | * in the page, then erp is NULL and erp_idx is set to |
3124 | * the next index needed in the indirection array. | 3124 | * the next index needed in the indirection array. |
3125 | */ | 3125 | */ |
3126 | else { | 3126 | else { |
3127 | int count = ext_diff; | 3127 | int count = ext_diff; |
3128 | 3128 | ||
3129 | while (count) { | 3129 | while (count) { |
3130 | erp = xfs_iext_irec_new(ifp, erp_idx); | 3130 | erp = xfs_iext_irec_new(ifp, erp_idx); |
3131 | erp->er_extcount = count; | 3131 | erp->er_extcount = count; |
3132 | count -= MIN(count, (int)XFS_LINEAR_EXTS); | 3132 | count -= MIN(count, (int)XFS_LINEAR_EXTS); |
3133 | if (count) { | 3133 | if (count) { |
3134 | erp_idx++; | 3134 | erp_idx++; |
3135 | } | 3135 | } |
3136 | } | 3136 | } |
3137 | } | 3137 | } |
3138 | } | 3138 | } |
3139 | ifp->if_bytes = new_size; | 3139 | ifp->if_bytes = new_size; |
3140 | } | 3140 | } |
3141 | 3141 | ||
3142 | /* | 3142 | /* |
3143 | * This is called when incore extents are being added to the indirection | 3143 | * This is called when incore extents are being added to the indirection |
3144 | * array and the new extents do not fit in the target extent list. The | 3144 | * array and the new extents do not fit in the target extent list. The |
3145 | * erp_idx parameter contains the irec index for the target extent list | 3145 | * erp_idx parameter contains the irec index for the target extent list |
3146 | * in the indirection array, and the idx parameter contains the extent | 3146 | * in the indirection array, and the idx parameter contains the extent |
3147 | * index within the list. The number of extents being added is stored | 3147 | * index within the list. The number of extents being added is stored |
3148 | * in the count parameter. | 3148 | * in the count parameter. |
3149 | * | 3149 | * |
3150 | * |-------| |-------| | 3150 | * |-------| |-------| |
3151 | * | | | | idx - number of extents before idx | 3151 | * | | | | idx - number of extents before idx |
3152 | * | idx | | count | | 3152 | * | idx | | count | |
3153 | * | | | | count - number of extents being inserted at idx | 3153 | * | | | | count - number of extents being inserted at idx |
3154 | * |-------| |-------| | 3154 | * |-------| |-------| |
3155 | * | count | | nex2 | nex2 - number of extents after idx + count | 3155 | * | count | | nex2 | nex2 - number of extents after idx + count |
3156 | * |-------| |-------| | 3156 | * |-------| |-------| |
3157 | */ | 3157 | */ |
3158 | void | 3158 | void |
3159 | xfs_iext_add_indirect_multi( | 3159 | xfs_iext_add_indirect_multi( |
3160 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3160 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3161 | int erp_idx, /* target extent irec index */ | 3161 | int erp_idx, /* target extent irec index */ |
3162 | xfs_extnum_t idx, /* index within target list */ | 3162 | xfs_extnum_t idx, /* index within target list */ |
3163 | int count) /* new extents being added */ | 3163 | int count) /* new extents being added */ |
3164 | { | 3164 | { |
3165 | int byte_diff; /* new bytes being added */ | 3165 | int byte_diff; /* new bytes being added */ |
3166 | xfs_ext_irec_t *erp; /* pointer to irec entry */ | 3166 | xfs_ext_irec_t *erp; /* pointer to irec entry */ |
3167 | xfs_extnum_t ext_diff; /* number of extents to add */ | 3167 | xfs_extnum_t ext_diff; /* number of extents to add */ |
3168 | xfs_extnum_t ext_cnt; /* new extents still needed */ | 3168 | xfs_extnum_t ext_cnt; /* new extents still needed */ |
3169 | xfs_extnum_t nex2; /* extents after idx + count */ | 3169 | xfs_extnum_t nex2; /* extents after idx + count */ |
3170 | xfs_bmbt_rec_t *nex2_ep = NULL; /* temp list for nex2 extents */ | 3170 | xfs_bmbt_rec_t *nex2_ep = NULL; /* temp list for nex2 extents */ |
3171 | int nlists; /* number of irec's (lists) */ | 3171 | int nlists; /* number of irec's (lists) */ |
3172 | 3172 | ||
3173 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3173 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3174 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; | 3174 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; |
3175 | nex2 = erp->er_extcount - idx; | 3175 | nex2 = erp->er_extcount - idx; |
3176 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 3176 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
3177 | 3177 | ||
3178 | /* | 3178 | /* |
3179 | * Save second part of target extent list | 3179 | * Save second part of target extent list |
3180 | * (all extents past */ | 3180 | * (all extents past */ |
3181 | if (nex2) { | 3181 | if (nex2) { |
3182 | byte_diff = nex2 * sizeof(xfs_bmbt_rec_t); | 3182 | byte_diff = nex2 * sizeof(xfs_bmbt_rec_t); |
3183 | nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_NOFS); | 3183 | nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_NOFS); |
3184 | memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff); | 3184 | memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff); |
3185 | erp->er_extcount -= nex2; | 3185 | erp->er_extcount -= nex2; |
3186 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2); | 3186 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2); |
3187 | memset(&erp->er_extbuf[idx], 0, byte_diff); | 3187 | memset(&erp->er_extbuf[idx], 0, byte_diff); |
3188 | } | 3188 | } |
3189 | 3189 | ||
3190 | /* | 3190 | /* |
3191 | * Add the new extents to the end of the target | 3191 | * Add the new extents to the end of the target |
3192 | * list, then allocate new irec record(s) and | 3192 | * list, then allocate new irec record(s) and |
3193 | * extent buffer(s) as needed to store the rest | 3193 | * extent buffer(s) as needed to store the rest |
3194 | * of the new extents. | 3194 | * of the new extents. |
3195 | */ | 3195 | */ |
3196 | ext_cnt = count; | 3196 | ext_cnt = count; |
3197 | ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS - erp->er_extcount); | 3197 | ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS - erp->er_extcount); |
3198 | if (ext_diff) { | 3198 | if (ext_diff) { |
3199 | erp->er_extcount += ext_diff; | 3199 | erp->er_extcount += ext_diff; |
3200 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); | 3200 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); |
3201 | ext_cnt -= ext_diff; | 3201 | ext_cnt -= ext_diff; |
3202 | } | 3202 | } |
3203 | while (ext_cnt) { | 3203 | while (ext_cnt) { |
3204 | erp_idx++; | 3204 | erp_idx++; |
3205 | erp = xfs_iext_irec_new(ifp, erp_idx); | 3205 | erp = xfs_iext_irec_new(ifp, erp_idx); |
3206 | ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS); | 3206 | ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS); |
3207 | erp->er_extcount = ext_diff; | 3207 | erp->er_extcount = ext_diff; |
3208 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); | 3208 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); |
3209 | ext_cnt -= ext_diff; | 3209 | ext_cnt -= ext_diff; |
3210 | } | 3210 | } |
3211 | 3211 | ||
3212 | /* Add nex2 extents back to indirection array */ | 3212 | /* Add nex2 extents back to indirection array */ |
3213 | if (nex2) { | 3213 | if (nex2) { |
3214 | xfs_extnum_t ext_avail; | 3214 | xfs_extnum_t ext_avail; |
3215 | int i; | 3215 | int i; |
3216 | 3216 | ||
3217 | byte_diff = nex2 * sizeof(xfs_bmbt_rec_t); | 3217 | byte_diff = nex2 * sizeof(xfs_bmbt_rec_t); |
3218 | ext_avail = XFS_LINEAR_EXTS - erp->er_extcount; | 3218 | ext_avail = XFS_LINEAR_EXTS - erp->er_extcount; |
3219 | i = 0; | 3219 | i = 0; |
3220 | /* | 3220 | /* |
3221 | * If nex2 extents fit in the current page, append | 3221 | * If nex2 extents fit in the current page, append |
3222 | * nex2_ep after the new extents. | 3222 | * nex2_ep after the new extents. |
3223 | */ | 3223 | */ |
3224 | if (nex2 <= ext_avail) { | 3224 | if (nex2 <= ext_avail) { |
3225 | i = erp->er_extcount; | 3225 | i = erp->er_extcount; |
3226 | } | 3226 | } |
3227 | /* | 3227 | /* |
3228 | * Otherwise, check if space is available in the | 3228 | * Otherwise, check if space is available in the |
3229 | * next page. | 3229 | * next page. |
3230 | */ | 3230 | */ |
3231 | else if ((erp_idx < nlists - 1) && | 3231 | else if ((erp_idx < nlists - 1) && |
3232 | (nex2 <= (ext_avail = XFS_LINEAR_EXTS - | 3232 | (nex2 <= (ext_avail = XFS_LINEAR_EXTS - |
3233 | ifp->if_u1.if_ext_irec[erp_idx+1].er_extcount))) { | 3233 | ifp->if_u1.if_ext_irec[erp_idx+1].er_extcount))) { |
3234 | erp_idx++; | 3234 | erp_idx++; |
3235 | erp++; | 3235 | erp++; |
3236 | /* Create a hole for nex2 extents */ | 3236 | /* Create a hole for nex2 extents */ |
3237 | memmove(&erp->er_extbuf[nex2], erp->er_extbuf, | 3237 | memmove(&erp->er_extbuf[nex2], erp->er_extbuf, |
3238 | erp->er_extcount * sizeof(xfs_bmbt_rec_t)); | 3238 | erp->er_extcount * sizeof(xfs_bmbt_rec_t)); |
3239 | } | 3239 | } |
3240 | /* | 3240 | /* |
3241 | * Final choice, create a new extent page for | 3241 | * Final choice, create a new extent page for |
3242 | * nex2 extents. | 3242 | * nex2 extents. |
3243 | */ | 3243 | */ |
3244 | else { | 3244 | else { |
3245 | erp_idx++; | 3245 | erp_idx++; |
3246 | erp = xfs_iext_irec_new(ifp, erp_idx); | 3246 | erp = xfs_iext_irec_new(ifp, erp_idx); |
3247 | } | 3247 | } |
3248 | memmove(&erp->er_extbuf[i], nex2_ep, byte_diff); | 3248 | memmove(&erp->er_extbuf[i], nex2_ep, byte_diff); |
3249 | kmem_free(nex2_ep); | 3249 | kmem_free(nex2_ep); |
3250 | erp->er_extcount += nex2; | 3250 | erp->er_extcount += nex2; |
3251 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2); | 3251 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2); |
3252 | } | 3252 | } |
3253 | } | 3253 | } |
3254 | 3254 | ||
3255 | /* | 3255 | /* |
3256 | * This is called when the amount of space required for incore file | 3256 | * This is called when the amount of space required for incore file |
3257 | * extents needs to be decreased. The ext_diff parameter stores the | 3257 | * extents needs to be decreased. The ext_diff parameter stores the |
3258 | * number of extents to be removed and the idx parameter contains | 3258 | * number of extents to be removed and the idx parameter contains |
3259 | * the extent index where the extents will be removed from. | 3259 | * the extent index where the extents will be removed from. |
3260 | * | 3260 | * |
3261 | * If the amount of space needed has decreased below the linear | 3261 | * If the amount of space needed has decreased below the linear |
3262 | * limit, XFS_IEXT_BUFSZ, then switch to using the contiguous | 3262 | * limit, XFS_IEXT_BUFSZ, then switch to using the contiguous |
3263 | * extent array. Otherwise, use kmem_realloc() to adjust the | 3263 | * extent array. Otherwise, use kmem_realloc() to adjust the |
3264 | * size to what is needed. | 3264 | * size to what is needed. |
3265 | */ | 3265 | */ |
3266 | void | 3266 | void |
3267 | xfs_iext_remove( | 3267 | xfs_iext_remove( |
3268 | xfs_inode_t *ip, /* incore inode pointer */ | 3268 | xfs_inode_t *ip, /* incore inode pointer */ |
3269 | xfs_extnum_t idx, /* index to begin removing exts */ | 3269 | xfs_extnum_t idx, /* index to begin removing exts */ |
3270 | int ext_diff, /* number of extents to remove */ | 3270 | int ext_diff, /* number of extents to remove */ |
3271 | int state) /* type of extent conversion */ | 3271 | int state) /* type of extent conversion */ |
3272 | { | 3272 | { |
3273 | xfs_ifork_t *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df; | 3273 | xfs_ifork_t *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df; |
3274 | xfs_extnum_t nextents; /* number of extents in file */ | 3274 | xfs_extnum_t nextents; /* number of extents in file */ |
3275 | int new_size; /* size of extents after removal */ | 3275 | int new_size; /* size of extents after removal */ |
3276 | 3276 | ||
3277 | trace_xfs_iext_remove(ip, idx, state, _RET_IP_); | 3277 | trace_xfs_iext_remove(ip, idx, state, _RET_IP_); |
3278 | 3278 | ||
3279 | ASSERT(ext_diff > 0); | 3279 | ASSERT(ext_diff > 0); |
3280 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | 3280 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); |
3281 | new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t); | 3281 | new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t); |
3282 | 3282 | ||
3283 | if (new_size == 0) { | 3283 | if (new_size == 0) { |
3284 | xfs_iext_destroy(ifp); | 3284 | xfs_iext_destroy(ifp); |
3285 | } else if (ifp->if_flags & XFS_IFEXTIREC) { | 3285 | } else if (ifp->if_flags & XFS_IFEXTIREC) { |
3286 | xfs_iext_remove_indirect(ifp, idx, ext_diff); | 3286 | xfs_iext_remove_indirect(ifp, idx, ext_diff); |
3287 | } else if (ifp->if_real_bytes) { | 3287 | } else if (ifp->if_real_bytes) { |
3288 | xfs_iext_remove_direct(ifp, idx, ext_diff); | 3288 | xfs_iext_remove_direct(ifp, idx, ext_diff); |
3289 | } else { | 3289 | } else { |
3290 | xfs_iext_remove_inline(ifp, idx, ext_diff); | 3290 | xfs_iext_remove_inline(ifp, idx, ext_diff); |
3291 | } | 3291 | } |
3292 | ifp->if_bytes = new_size; | 3292 | ifp->if_bytes = new_size; |
3293 | } | 3293 | } |
3294 | 3294 | ||
3295 | /* | 3295 | /* |
3296 | * This removes ext_diff extents from the inline buffer, beginning | 3296 | * This removes ext_diff extents from the inline buffer, beginning |
3297 | * at extent index idx. | 3297 | * at extent index idx. |
3298 | */ | 3298 | */ |
3299 | void | 3299 | void |
3300 | xfs_iext_remove_inline( | 3300 | xfs_iext_remove_inline( |
3301 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3301 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3302 | xfs_extnum_t idx, /* index to begin removing exts */ | 3302 | xfs_extnum_t idx, /* index to begin removing exts */ |
3303 | int ext_diff) /* number of extents to remove */ | 3303 | int ext_diff) /* number of extents to remove */ |
3304 | { | 3304 | { |
3305 | int nextents; /* number of extents in file */ | 3305 | int nextents; /* number of extents in file */ |
3306 | 3306 | ||
3307 | ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); | 3307 | ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); |
3308 | ASSERT(idx < XFS_INLINE_EXTS); | 3308 | ASSERT(idx < XFS_INLINE_EXTS); |
3309 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | 3309 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); |
3310 | ASSERT(((nextents - ext_diff) > 0) && | 3310 | ASSERT(((nextents - ext_diff) > 0) && |
3311 | (nextents - ext_diff) < XFS_INLINE_EXTS); | 3311 | (nextents - ext_diff) < XFS_INLINE_EXTS); |
3312 | 3312 | ||
3313 | if (idx + ext_diff < nextents) { | 3313 | if (idx + ext_diff < nextents) { |
3314 | memmove(&ifp->if_u2.if_inline_ext[idx], | 3314 | memmove(&ifp->if_u2.if_inline_ext[idx], |
3315 | &ifp->if_u2.if_inline_ext[idx + ext_diff], | 3315 | &ifp->if_u2.if_inline_ext[idx + ext_diff], |
3316 | (nextents - (idx + ext_diff)) * | 3316 | (nextents - (idx + ext_diff)) * |
3317 | sizeof(xfs_bmbt_rec_t)); | 3317 | sizeof(xfs_bmbt_rec_t)); |
3318 | memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff], | 3318 | memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff], |
3319 | 0, ext_diff * sizeof(xfs_bmbt_rec_t)); | 3319 | 0, ext_diff * sizeof(xfs_bmbt_rec_t)); |
3320 | } else { | 3320 | } else { |
3321 | memset(&ifp->if_u2.if_inline_ext[idx], 0, | 3321 | memset(&ifp->if_u2.if_inline_ext[idx], 0, |
3322 | ext_diff * sizeof(xfs_bmbt_rec_t)); | 3322 | ext_diff * sizeof(xfs_bmbt_rec_t)); |
3323 | } | 3323 | } |
3324 | } | 3324 | } |
3325 | 3325 | ||
3326 | /* | 3326 | /* |
3327 | * This removes ext_diff extents from a linear (direct) extent list, | 3327 | * This removes ext_diff extents from a linear (direct) extent list, |
3328 | * beginning at extent index idx. If the extents are being removed | 3328 | * beginning at extent index idx. If the extents are being removed |
3329 | * from the end of the list (ie. truncate) then we just need to re- | 3329 | * from the end of the list (ie. truncate) then we just need to re- |
3330 | * allocate the list to remove the extra space. Otherwise, if the | 3330 | * allocate the list to remove the extra space. Otherwise, if the |
3331 | * extents are being removed from the middle of the existing extent | 3331 | * extents are being removed from the middle of the existing extent |
3332 | * entries, then we first need to move the extent records beginning | 3332 | * entries, then we first need to move the extent records beginning |
3333 | * at idx + ext_diff up in the list to overwrite the records being | 3333 | * at idx + ext_diff up in the list to overwrite the records being |
3334 | * removed, then remove the extra space via kmem_realloc. | 3334 | * removed, then remove the extra space via kmem_realloc. |
3335 | */ | 3335 | */ |
3336 | void | 3336 | void |
3337 | xfs_iext_remove_direct( | 3337 | xfs_iext_remove_direct( |
3338 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3338 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3339 | xfs_extnum_t idx, /* index to begin removing exts */ | 3339 | xfs_extnum_t idx, /* index to begin removing exts */ |
3340 | int ext_diff) /* number of extents to remove */ | 3340 | int ext_diff) /* number of extents to remove */ |
3341 | { | 3341 | { |
3342 | xfs_extnum_t nextents; /* number of extents in file */ | 3342 | xfs_extnum_t nextents; /* number of extents in file */ |
3343 | int new_size; /* size of extents after removal */ | 3343 | int new_size; /* size of extents after removal */ |
3344 | 3344 | ||
3345 | ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); | 3345 | ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); |
3346 | new_size = ifp->if_bytes - | 3346 | new_size = ifp->if_bytes - |
3347 | (ext_diff * sizeof(xfs_bmbt_rec_t)); | 3347 | (ext_diff * sizeof(xfs_bmbt_rec_t)); |
3348 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | 3348 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); |
3349 | 3349 | ||
3350 | if (new_size == 0) { | 3350 | if (new_size == 0) { |
3351 | xfs_iext_destroy(ifp); | 3351 | xfs_iext_destroy(ifp); |
3352 | return; | 3352 | return; |
3353 | } | 3353 | } |
3354 | /* Move extents up in the list (if needed) */ | 3354 | /* Move extents up in the list (if needed) */ |
3355 | if (idx + ext_diff < nextents) { | 3355 | if (idx + ext_diff < nextents) { |
3356 | memmove(&ifp->if_u1.if_extents[idx], | 3356 | memmove(&ifp->if_u1.if_extents[idx], |
3357 | &ifp->if_u1.if_extents[idx + ext_diff], | 3357 | &ifp->if_u1.if_extents[idx + ext_diff], |
3358 | (nextents - (idx + ext_diff)) * | 3358 | (nextents - (idx + ext_diff)) * |
3359 | sizeof(xfs_bmbt_rec_t)); | 3359 | sizeof(xfs_bmbt_rec_t)); |
3360 | } | 3360 | } |
3361 | memset(&ifp->if_u1.if_extents[nextents - ext_diff], | 3361 | memset(&ifp->if_u1.if_extents[nextents - ext_diff], |
3362 | 0, ext_diff * sizeof(xfs_bmbt_rec_t)); | 3362 | 0, ext_diff * sizeof(xfs_bmbt_rec_t)); |
3363 | /* | 3363 | /* |
3364 | * Reallocate the direct extent list. If the extents | 3364 | * Reallocate the direct extent list. If the extents |
3365 | * will fit inside the inode then xfs_iext_realloc_direct | 3365 | * will fit inside the inode then xfs_iext_realloc_direct |
3366 | * will switch from direct to inline extent allocation | 3366 | * will switch from direct to inline extent allocation |
3367 | * mode for us. | 3367 | * mode for us. |
3368 | */ | 3368 | */ |
3369 | xfs_iext_realloc_direct(ifp, new_size); | 3369 | xfs_iext_realloc_direct(ifp, new_size); |
3370 | ifp->if_bytes = new_size; | 3370 | ifp->if_bytes = new_size; |
3371 | } | 3371 | } |
3372 | 3372 | ||
3373 | /* | 3373 | /* |
3374 | * This is called when incore extents are being removed from the | 3374 | * This is called when incore extents are being removed from the |
3375 | * indirection array and the extents being removed span multiple extent | 3375 | * indirection array and the extents being removed span multiple extent |
3376 | * buffers. The idx parameter contains the file extent index where we | 3376 | * buffers. The idx parameter contains the file extent index where we |
3377 | * want to begin removing extents, and the count parameter contains | 3377 | * want to begin removing extents, and the count parameter contains |
3378 | * how many extents need to be removed. | 3378 | * how many extents need to be removed. |
3379 | * | 3379 | * |
3380 | * |-------| |-------| | 3380 | * |-------| |-------| |
3381 | * | nex1 | | | nex1 - number of extents before idx | 3381 | * | nex1 | | | nex1 - number of extents before idx |
3382 | * |-------| | count | | 3382 | * |-------| | count | |
3383 | * | | | | count - number of extents being removed at idx | 3383 | * | | | | count - number of extents being removed at idx |
3384 | * | count | |-------| | 3384 | * | count | |-------| |
3385 | * | | | nex2 | nex2 - number of extents after idx + count | 3385 | * | | | nex2 | nex2 - number of extents after idx + count |
3386 | * |-------| |-------| | 3386 | * |-------| |-------| |
3387 | */ | 3387 | */ |
3388 | void | 3388 | void |
3389 | xfs_iext_remove_indirect( | 3389 | xfs_iext_remove_indirect( |
3390 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3390 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3391 | xfs_extnum_t idx, /* index to begin removing extents */ | 3391 | xfs_extnum_t idx, /* index to begin removing extents */ |
3392 | int count) /* number of extents to remove */ | 3392 | int count) /* number of extents to remove */ |
3393 | { | 3393 | { |
3394 | xfs_ext_irec_t *erp; /* indirection array pointer */ | 3394 | xfs_ext_irec_t *erp; /* indirection array pointer */ |
3395 | int erp_idx = 0; /* indirection array index */ | 3395 | int erp_idx = 0; /* indirection array index */ |
3396 | xfs_extnum_t ext_cnt; /* extents left to remove */ | 3396 | xfs_extnum_t ext_cnt; /* extents left to remove */ |
3397 | xfs_extnum_t ext_diff; /* extents to remove in current list */ | 3397 | xfs_extnum_t ext_diff; /* extents to remove in current list */ |
3398 | xfs_extnum_t nex1; /* number of extents before idx */ | 3398 | xfs_extnum_t nex1; /* number of extents before idx */ |
3399 | xfs_extnum_t nex2; /* extents after idx + count */ | 3399 | xfs_extnum_t nex2; /* extents after idx + count */ |
3400 | int page_idx = idx; /* index in target extent list */ | 3400 | int page_idx = idx; /* index in target extent list */ |
3401 | 3401 | ||
3402 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3402 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3403 | erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0); | 3403 | erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0); |
3404 | ASSERT(erp != NULL); | 3404 | ASSERT(erp != NULL); |
3405 | nex1 = page_idx; | 3405 | nex1 = page_idx; |
3406 | ext_cnt = count; | 3406 | ext_cnt = count; |
3407 | while (ext_cnt) { | 3407 | while (ext_cnt) { |
3408 | nex2 = MAX((erp->er_extcount - (nex1 + ext_cnt)), 0); | 3408 | nex2 = MAX((erp->er_extcount - (nex1 + ext_cnt)), 0); |
3409 | ext_diff = MIN(ext_cnt, (erp->er_extcount - nex1)); | 3409 | ext_diff = MIN(ext_cnt, (erp->er_extcount - nex1)); |
3410 | /* | 3410 | /* |
3411 | * Check for deletion of entire list; | 3411 | * Check for deletion of entire list; |
3412 | * xfs_iext_irec_remove() updates extent offsets. | 3412 | * xfs_iext_irec_remove() updates extent offsets. |
3413 | */ | 3413 | */ |
3414 | if (ext_diff == erp->er_extcount) { | 3414 | if (ext_diff == erp->er_extcount) { |
3415 | xfs_iext_irec_remove(ifp, erp_idx); | 3415 | xfs_iext_irec_remove(ifp, erp_idx); |
3416 | ext_cnt -= ext_diff; | 3416 | ext_cnt -= ext_diff; |
3417 | nex1 = 0; | 3417 | nex1 = 0; |
3418 | if (ext_cnt) { | 3418 | if (ext_cnt) { |
3419 | ASSERT(erp_idx < ifp->if_real_bytes / | 3419 | ASSERT(erp_idx < ifp->if_real_bytes / |
3420 | XFS_IEXT_BUFSZ); | 3420 | XFS_IEXT_BUFSZ); |
3421 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; | 3421 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; |
3422 | nex1 = 0; | 3422 | nex1 = 0; |
3423 | continue; | 3423 | continue; |
3424 | } else { | 3424 | } else { |
3425 | break; | 3425 | break; |
3426 | } | 3426 | } |
3427 | } | 3427 | } |
3428 | /* Move extents up (if needed) */ | 3428 | /* Move extents up (if needed) */ |
3429 | if (nex2) { | 3429 | if (nex2) { |
3430 | memmove(&erp->er_extbuf[nex1], | 3430 | memmove(&erp->er_extbuf[nex1], |
3431 | &erp->er_extbuf[nex1 + ext_diff], | 3431 | &erp->er_extbuf[nex1 + ext_diff], |
3432 | nex2 * sizeof(xfs_bmbt_rec_t)); | 3432 | nex2 * sizeof(xfs_bmbt_rec_t)); |
3433 | } | 3433 | } |
3434 | /* Zero out rest of page */ | 3434 | /* Zero out rest of page */ |
3435 | memset(&erp->er_extbuf[nex1 + nex2], 0, (XFS_IEXT_BUFSZ - | 3435 | memset(&erp->er_extbuf[nex1 + nex2], 0, (XFS_IEXT_BUFSZ - |
3436 | ((nex1 + nex2) * sizeof(xfs_bmbt_rec_t)))); | 3436 | ((nex1 + nex2) * sizeof(xfs_bmbt_rec_t)))); |
3437 | /* Update remaining counters */ | 3437 | /* Update remaining counters */ |
3438 | erp->er_extcount -= ext_diff; | 3438 | erp->er_extcount -= ext_diff; |
3439 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -ext_diff); | 3439 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -ext_diff); |
3440 | ext_cnt -= ext_diff; | 3440 | ext_cnt -= ext_diff; |
3441 | nex1 = 0; | 3441 | nex1 = 0; |
3442 | erp_idx++; | 3442 | erp_idx++; |
3443 | erp++; | 3443 | erp++; |
3444 | } | 3444 | } |
3445 | ifp->if_bytes -= count * sizeof(xfs_bmbt_rec_t); | 3445 | ifp->if_bytes -= count * sizeof(xfs_bmbt_rec_t); |
3446 | xfs_iext_irec_compact(ifp); | 3446 | xfs_iext_irec_compact(ifp); |
3447 | } | 3447 | } |
3448 | 3448 | ||
3449 | /* | 3449 | /* |
3450 | * Create, destroy, or resize a linear (direct) block of extents. | 3450 | * Create, destroy, or resize a linear (direct) block of extents. |
3451 | */ | 3451 | */ |
3452 | void | 3452 | void |
3453 | xfs_iext_realloc_direct( | 3453 | xfs_iext_realloc_direct( |
3454 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3454 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3455 | int new_size) /* new size of extents */ | 3455 | int new_size) /* new size of extents */ |
3456 | { | 3456 | { |
3457 | int rnew_size; /* real new size of extents */ | 3457 | int rnew_size; /* real new size of extents */ |
3458 | 3458 | ||
3459 | rnew_size = new_size; | 3459 | rnew_size = new_size; |
3460 | 3460 | ||
3461 | ASSERT(!(ifp->if_flags & XFS_IFEXTIREC) || | 3461 | ASSERT(!(ifp->if_flags & XFS_IFEXTIREC) || |
3462 | ((new_size >= 0) && (new_size <= XFS_IEXT_BUFSZ) && | 3462 | ((new_size >= 0) && (new_size <= XFS_IEXT_BUFSZ) && |
3463 | (new_size != ifp->if_real_bytes))); | 3463 | (new_size != ifp->if_real_bytes))); |
3464 | 3464 | ||
3465 | /* Free extent records */ | 3465 | /* Free extent records */ |
3466 | if (new_size == 0) { | 3466 | if (new_size == 0) { |
3467 | xfs_iext_destroy(ifp); | 3467 | xfs_iext_destroy(ifp); |
3468 | } | 3468 | } |
3469 | /* Resize direct extent list and zero any new bytes */ | 3469 | /* Resize direct extent list and zero any new bytes */ |
3470 | else if (ifp->if_real_bytes) { | 3470 | else if (ifp->if_real_bytes) { |
3471 | /* Check if extents will fit inside the inode */ | 3471 | /* Check if extents will fit inside the inode */ |
3472 | if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) { | 3472 | if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) { |
3473 | xfs_iext_direct_to_inline(ifp, new_size / | 3473 | xfs_iext_direct_to_inline(ifp, new_size / |
3474 | (uint)sizeof(xfs_bmbt_rec_t)); | 3474 | (uint)sizeof(xfs_bmbt_rec_t)); |
3475 | ifp->if_bytes = new_size; | 3475 | ifp->if_bytes = new_size; |
3476 | return; | 3476 | return; |
3477 | } | 3477 | } |
3478 | if (!is_power_of_2(new_size)){ | 3478 | if (!is_power_of_2(new_size)){ |
3479 | rnew_size = roundup_pow_of_two(new_size); | 3479 | rnew_size = roundup_pow_of_two(new_size); |
3480 | } | 3480 | } |
3481 | if (rnew_size != ifp->if_real_bytes) { | 3481 | if (rnew_size != ifp->if_real_bytes) { |
3482 | ifp->if_u1.if_extents = | 3482 | ifp->if_u1.if_extents = |
3483 | kmem_realloc(ifp->if_u1.if_extents, | 3483 | kmem_realloc(ifp->if_u1.if_extents, |
3484 | rnew_size, | 3484 | rnew_size, |
3485 | ifp->if_real_bytes, KM_NOFS); | 3485 | ifp->if_real_bytes, KM_NOFS); |
3486 | } | 3486 | } |
3487 | if (rnew_size > ifp->if_real_bytes) { | 3487 | if (rnew_size > ifp->if_real_bytes) { |
3488 | memset(&ifp->if_u1.if_extents[ifp->if_bytes / | 3488 | memset(&ifp->if_u1.if_extents[ifp->if_bytes / |
3489 | (uint)sizeof(xfs_bmbt_rec_t)], 0, | 3489 | (uint)sizeof(xfs_bmbt_rec_t)], 0, |
3490 | rnew_size - ifp->if_real_bytes); | 3490 | rnew_size - ifp->if_real_bytes); |
3491 | } | 3491 | } |
3492 | } | 3492 | } |
3493 | /* | 3493 | /* |
3494 | * Switch from the inline extent buffer to a direct | 3494 | * Switch from the inline extent buffer to a direct |
3495 | * extent list. Be sure to include the inline extent | 3495 | * extent list. Be sure to include the inline extent |
3496 | * bytes in new_size. | 3496 | * bytes in new_size. |
3497 | */ | 3497 | */ |
3498 | else { | 3498 | else { |
3499 | new_size += ifp->if_bytes; | 3499 | new_size += ifp->if_bytes; |
3500 | if (!is_power_of_2(new_size)) { | 3500 | if (!is_power_of_2(new_size)) { |
3501 | rnew_size = roundup_pow_of_two(new_size); | 3501 | rnew_size = roundup_pow_of_two(new_size); |
3502 | } | 3502 | } |
3503 | xfs_iext_inline_to_direct(ifp, rnew_size); | 3503 | xfs_iext_inline_to_direct(ifp, rnew_size); |
3504 | } | 3504 | } |
3505 | ifp->if_real_bytes = rnew_size; | 3505 | ifp->if_real_bytes = rnew_size; |
3506 | ifp->if_bytes = new_size; | 3506 | ifp->if_bytes = new_size; |
3507 | } | 3507 | } |
3508 | 3508 | ||
3509 | /* | 3509 | /* |
3510 | * Switch from linear (direct) extent records to inline buffer. | 3510 | * Switch from linear (direct) extent records to inline buffer. |
3511 | */ | 3511 | */ |
3512 | void | 3512 | void |
3513 | xfs_iext_direct_to_inline( | 3513 | xfs_iext_direct_to_inline( |
3514 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3514 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3515 | xfs_extnum_t nextents) /* number of extents in file */ | 3515 | xfs_extnum_t nextents) /* number of extents in file */ |
3516 | { | 3516 | { |
3517 | ASSERT(ifp->if_flags & XFS_IFEXTENTS); | 3517 | ASSERT(ifp->if_flags & XFS_IFEXTENTS); |
3518 | ASSERT(nextents <= XFS_INLINE_EXTS); | 3518 | ASSERT(nextents <= XFS_INLINE_EXTS); |
3519 | /* | 3519 | /* |
3520 | * The inline buffer was zeroed when we switched | 3520 | * The inline buffer was zeroed when we switched |
3521 | * from inline to direct extent allocation mode, | 3521 | * from inline to direct extent allocation mode, |
3522 | * so we don't need to clear it here. | 3522 | * so we don't need to clear it here. |
3523 | */ | 3523 | */ |
3524 | memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, | 3524 | memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, |
3525 | nextents * sizeof(xfs_bmbt_rec_t)); | 3525 | nextents * sizeof(xfs_bmbt_rec_t)); |
3526 | kmem_free(ifp->if_u1.if_extents); | 3526 | kmem_free(ifp->if_u1.if_extents); |
3527 | ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; | 3527 | ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; |
3528 | ifp->if_real_bytes = 0; | 3528 | ifp->if_real_bytes = 0; |
3529 | } | 3529 | } |
3530 | 3530 | ||
3531 | /* | 3531 | /* |
3532 | * Switch from inline buffer to linear (direct) extent records. | 3532 | * Switch from inline buffer to linear (direct) extent records. |
3533 | * new_size should already be rounded up to the next power of 2 | 3533 | * new_size should already be rounded up to the next power of 2 |
3534 | * by the caller (when appropriate), so use new_size as it is. | 3534 | * by the caller (when appropriate), so use new_size as it is. |
3535 | * However, since new_size may be rounded up, we can't update | 3535 | * However, since new_size may be rounded up, we can't update |
3536 | * if_bytes here. It is the caller's responsibility to update | 3536 | * if_bytes here. It is the caller's responsibility to update |
3537 | * if_bytes upon return. | 3537 | * if_bytes upon return. |
3538 | */ | 3538 | */ |
3539 | void | 3539 | void |
3540 | xfs_iext_inline_to_direct( | 3540 | xfs_iext_inline_to_direct( |
3541 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3541 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3542 | int new_size) /* number of extents in file */ | 3542 | int new_size) /* number of extents in file */ |
3543 | { | 3543 | { |
3544 | ifp->if_u1.if_extents = kmem_alloc(new_size, KM_NOFS); | 3544 | ifp->if_u1.if_extents = kmem_alloc(new_size, KM_NOFS); |
3545 | memset(ifp->if_u1.if_extents, 0, new_size); | 3545 | memset(ifp->if_u1.if_extents, 0, new_size); |
3546 | if (ifp->if_bytes) { | 3546 | if (ifp->if_bytes) { |
3547 | memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext, | 3547 | memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext, |
3548 | ifp->if_bytes); | 3548 | ifp->if_bytes); |
3549 | memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * | 3549 | memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * |
3550 | sizeof(xfs_bmbt_rec_t)); | 3550 | sizeof(xfs_bmbt_rec_t)); |
3551 | } | 3551 | } |
3552 | ifp->if_real_bytes = new_size; | 3552 | ifp->if_real_bytes = new_size; |
3553 | } | 3553 | } |
3554 | 3554 | ||
3555 | /* | 3555 | /* |
3556 | * Resize an extent indirection array to new_size bytes. | 3556 | * Resize an extent indirection array to new_size bytes. |
3557 | */ | 3557 | */ |
3558 | STATIC void | 3558 | STATIC void |
3559 | xfs_iext_realloc_indirect( | 3559 | xfs_iext_realloc_indirect( |
3560 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3560 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3561 | int new_size) /* new indirection array size */ | 3561 | int new_size) /* new indirection array size */ |
3562 | { | 3562 | { |
3563 | int nlists; /* number of irec's (ex lists) */ | 3563 | int nlists; /* number of irec's (ex lists) */ |
3564 | int size; /* current indirection array size */ | 3564 | int size; /* current indirection array size */ |
3565 | 3565 | ||
3566 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3566 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3567 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 3567 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
3568 | size = nlists * sizeof(xfs_ext_irec_t); | 3568 | size = nlists * sizeof(xfs_ext_irec_t); |
3569 | ASSERT(ifp->if_real_bytes); | 3569 | ASSERT(ifp->if_real_bytes); |
3570 | ASSERT((new_size >= 0) && (new_size != size)); | 3570 | ASSERT((new_size >= 0) && (new_size != size)); |
3571 | if (new_size == 0) { | 3571 | if (new_size == 0) { |
3572 | xfs_iext_destroy(ifp); | 3572 | xfs_iext_destroy(ifp); |
3573 | } else { | 3573 | } else { |
3574 | ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *) | 3574 | ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *) |
3575 | kmem_realloc(ifp->if_u1.if_ext_irec, | 3575 | kmem_realloc(ifp->if_u1.if_ext_irec, |
3576 | new_size, size, KM_NOFS); | 3576 | new_size, size, KM_NOFS); |
3577 | } | 3577 | } |
3578 | } | 3578 | } |
3579 | 3579 | ||
3580 | /* | 3580 | /* |
3581 | * Switch from indirection array to linear (direct) extent allocations. | 3581 | * Switch from indirection array to linear (direct) extent allocations. |
3582 | */ | 3582 | */ |
3583 | STATIC void | 3583 | STATIC void |
3584 | xfs_iext_indirect_to_direct( | 3584 | xfs_iext_indirect_to_direct( |
3585 | xfs_ifork_t *ifp) /* inode fork pointer */ | 3585 | xfs_ifork_t *ifp) /* inode fork pointer */ |
3586 | { | 3586 | { |
3587 | xfs_bmbt_rec_host_t *ep; /* extent record pointer */ | 3587 | xfs_bmbt_rec_host_t *ep; /* extent record pointer */ |
3588 | xfs_extnum_t nextents; /* number of extents in file */ | 3588 | xfs_extnum_t nextents; /* number of extents in file */ |
3589 | int size; /* size of file extents */ | 3589 | int size; /* size of file extents */ |
3590 | 3590 | ||
3591 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3591 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3592 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | 3592 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); |
3593 | ASSERT(nextents <= XFS_LINEAR_EXTS); | 3593 | ASSERT(nextents <= XFS_LINEAR_EXTS); |
3594 | size = nextents * sizeof(xfs_bmbt_rec_t); | 3594 | size = nextents * sizeof(xfs_bmbt_rec_t); |
3595 | 3595 | ||
3596 | xfs_iext_irec_compact_pages(ifp); | 3596 | xfs_iext_irec_compact_pages(ifp); |
3597 | ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ); | 3597 | ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ); |
3598 | 3598 | ||
3599 | ep = ifp->if_u1.if_ext_irec->er_extbuf; | 3599 | ep = ifp->if_u1.if_ext_irec->er_extbuf; |
3600 | kmem_free(ifp->if_u1.if_ext_irec); | 3600 | kmem_free(ifp->if_u1.if_ext_irec); |
3601 | ifp->if_flags &= ~XFS_IFEXTIREC; | 3601 | ifp->if_flags &= ~XFS_IFEXTIREC; |
3602 | ifp->if_u1.if_extents = ep; | 3602 | ifp->if_u1.if_extents = ep; |
3603 | ifp->if_bytes = size; | 3603 | ifp->if_bytes = size; |
3604 | if (nextents < XFS_LINEAR_EXTS) { | 3604 | if (nextents < XFS_LINEAR_EXTS) { |
3605 | xfs_iext_realloc_direct(ifp, size); | 3605 | xfs_iext_realloc_direct(ifp, size); |
3606 | } | 3606 | } |
3607 | } | 3607 | } |
3608 | 3608 | ||
3609 | /* | 3609 | /* |
3610 | * Free incore file extents. | 3610 | * Free incore file extents. |
3611 | */ | 3611 | */ |
3612 | void | 3612 | void |
3613 | xfs_iext_destroy( | 3613 | xfs_iext_destroy( |
3614 | xfs_ifork_t *ifp) /* inode fork pointer */ | 3614 | xfs_ifork_t *ifp) /* inode fork pointer */ |
3615 | { | 3615 | { |
3616 | if (ifp->if_flags & XFS_IFEXTIREC) { | 3616 | if (ifp->if_flags & XFS_IFEXTIREC) { |
3617 | int erp_idx; | 3617 | int erp_idx; |
3618 | int nlists; | 3618 | int nlists; |
3619 | 3619 | ||
3620 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 3620 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
3621 | for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) { | 3621 | for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) { |
3622 | xfs_iext_irec_remove(ifp, erp_idx); | 3622 | xfs_iext_irec_remove(ifp, erp_idx); |
3623 | } | 3623 | } |
3624 | ifp->if_flags &= ~XFS_IFEXTIREC; | 3624 | ifp->if_flags &= ~XFS_IFEXTIREC; |
3625 | } else if (ifp->if_real_bytes) { | 3625 | } else if (ifp->if_real_bytes) { |
3626 | kmem_free(ifp->if_u1.if_extents); | 3626 | kmem_free(ifp->if_u1.if_extents); |
3627 | } else if (ifp->if_bytes) { | 3627 | } else if (ifp->if_bytes) { |
3628 | memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * | 3628 | memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * |
3629 | sizeof(xfs_bmbt_rec_t)); | 3629 | sizeof(xfs_bmbt_rec_t)); |
3630 | } | 3630 | } |
3631 | ifp->if_u1.if_extents = NULL; | 3631 | ifp->if_u1.if_extents = NULL; |
3632 | ifp->if_real_bytes = 0; | 3632 | ifp->if_real_bytes = 0; |
3633 | ifp->if_bytes = 0; | 3633 | ifp->if_bytes = 0; |
3634 | } | 3634 | } |
3635 | 3635 | ||
3636 | /* | 3636 | /* |
3637 | * Return a pointer to the extent record for file system block bno. | 3637 | * Return a pointer to the extent record for file system block bno. |
3638 | */ | 3638 | */ |
3639 | xfs_bmbt_rec_host_t * /* pointer to found extent record */ | 3639 | xfs_bmbt_rec_host_t * /* pointer to found extent record */ |
3640 | xfs_iext_bno_to_ext( | 3640 | xfs_iext_bno_to_ext( |
3641 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3641 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3642 | xfs_fileoff_t bno, /* block number to search for */ | 3642 | xfs_fileoff_t bno, /* block number to search for */ |
3643 | xfs_extnum_t *idxp) /* index of target extent */ | 3643 | xfs_extnum_t *idxp) /* index of target extent */ |
3644 | { | 3644 | { |
3645 | xfs_bmbt_rec_host_t *base; /* pointer to first extent */ | 3645 | xfs_bmbt_rec_host_t *base; /* pointer to first extent */ |
3646 | xfs_filblks_t blockcount = 0; /* number of blocks in extent */ | 3646 | xfs_filblks_t blockcount = 0; /* number of blocks in extent */ |
3647 | xfs_bmbt_rec_host_t *ep = NULL; /* pointer to target extent */ | 3647 | xfs_bmbt_rec_host_t *ep = NULL; /* pointer to target extent */ |
3648 | xfs_ext_irec_t *erp = NULL; /* indirection array pointer */ | 3648 | xfs_ext_irec_t *erp = NULL; /* indirection array pointer */ |
3649 | int high; /* upper boundary in search */ | 3649 | int high; /* upper boundary in search */ |
3650 | xfs_extnum_t idx = 0; /* index of target extent */ | 3650 | xfs_extnum_t idx = 0; /* index of target extent */ |
3651 | int low; /* lower boundary in search */ | 3651 | int low; /* lower boundary in search */ |
3652 | xfs_extnum_t nextents; /* number of file extents */ | 3652 | xfs_extnum_t nextents; /* number of file extents */ |
3653 | xfs_fileoff_t startoff = 0; /* start offset of extent */ | 3653 | xfs_fileoff_t startoff = 0; /* start offset of extent */ |
3654 | 3654 | ||
3655 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | 3655 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); |
3656 | if (nextents == 0) { | 3656 | if (nextents == 0) { |
3657 | *idxp = 0; | 3657 | *idxp = 0; |
3658 | return NULL; | 3658 | return NULL; |
3659 | } | 3659 | } |
3660 | low = 0; | 3660 | low = 0; |
3661 | if (ifp->if_flags & XFS_IFEXTIREC) { | 3661 | if (ifp->if_flags & XFS_IFEXTIREC) { |
3662 | /* Find target extent list */ | 3662 | /* Find target extent list */ |
3663 | int erp_idx = 0; | 3663 | int erp_idx = 0; |
3664 | erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx); | 3664 | erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx); |
3665 | base = erp->er_extbuf; | 3665 | base = erp->er_extbuf; |
3666 | high = erp->er_extcount - 1; | 3666 | high = erp->er_extcount - 1; |
3667 | } else { | 3667 | } else { |
3668 | base = ifp->if_u1.if_extents; | 3668 | base = ifp->if_u1.if_extents; |
3669 | high = nextents - 1; | 3669 | high = nextents - 1; |
3670 | } | 3670 | } |
3671 | /* Binary search extent records */ | 3671 | /* Binary search extent records */ |
3672 | while (low <= high) { | 3672 | while (low <= high) { |
3673 | idx = (low + high) >> 1; | 3673 | idx = (low + high) >> 1; |
3674 | ep = base + idx; | 3674 | ep = base + idx; |
3675 | startoff = xfs_bmbt_get_startoff(ep); | 3675 | startoff = xfs_bmbt_get_startoff(ep); |
3676 | blockcount = xfs_bmbt_get_blockcount(ep); | 3676 | blockcount = xfs_bmbt_get_blockcount(ep); |
3677 | if (bno < startoff) { | 3677 | if (bno < startoff) { |
3678 | high = idx - 1; | 3678 | high = idx - 1; |
3679 | } else if (bno >= startoff + blockcount) { | 3679 | } else if (bno >= startoff + blockcount) { |
3680 | low = idx + 1; | 3680 | low = idx + 1; |
3681 | } else { | 3681 | } else { |
3682 | /* Convert back to file-based extent index */ | 3682 | /* Convert back to file-based extent index */ |
3683 | if (ifp->if_flags & XFS_IFEXTIREC) { | 3683 | if (ifp->if_flags & XFS_IFEXTIREC) { |
3684 | idx += erp->er_extoff; | 3684 | idx += erp->er_extoff; |
3685 | } | 3685 | } |
3686 | *idxp = idx; | 3686 | *idxp = idx; |
3687 | return ep; | 3687 | return ep; |
3688 | } | 3688 | } |
3689 | } | 3689 | } |
3690 | /* Convert back to file-based extent index */ | 3690 | /* Convert back to file-based extent index */ |
3691 | if (ifp->if_flags & XFS_IFEXTIREC) { | 3691 | if (ifp->if_flags & XFS_IFEXTIREC) { |
3692 | idx += erp->er_extoff; | 3692 | idx += erp->er_extoff; |
3693 | } | 3693 | } |
3694 | if (bno >= startoff + blockcount) { | 3694 | if (bno >= startoff + blockcount) { |
3695 | if (++idx == nextents) { | 3695 | if (++idx == nextents) { |
3696 | ep = NULL; | 3696 | ep = NULL; |
3697 | } else { | 3697 | } else { |
3698 | ep = xfs_iext_get_ext(ifp, idx); | 3698 | ep = xfs_iext_get_ext(ifp, idx); |
3699 | } | 3699 | } |
3700 | } | 3700 | } |
3701 | *idxp = idx; | 3701 | *idxp = idx; |
3702 | return ep; | 3702 | return ep; |
3703 | } | 3703 | } |
3704 | 3704 | ||
3705 | /* | 3705 | /* |
3706 | * Return a pointer to the indirection array entry containing the | 3706 | * Return a pointer to the indirection array entry containing the |
3707 | * extent record for filesystem block bno. Store the index of the | 3707 | * extent record for filesystem block bno. Store the index of the |
3708 | * target irec in *erp_idxp. | 3708 | * target irec in *erp_idxp. |
3709 | */ | 3709 | */ |
3710 | xfs_ext_irec_t * /* pointer to found extent record */ | 3710 | xfs_ext_irec_t * /* pointer to found extent record */ |
3711 | xfs_iext_bno_to_irec( | 3711 | xfs_iext_bno_to_irec( |
3712 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3712 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3713 | xfs_fileoff_t bno, /* block number to search for */ | 3713 | xfs_fileoff_t bno, /* block number to search for */ |
3714 | int *erp_idxp) /* irec index of target ext list */ | 3714 | int *erp_idxp) /* irec index of target ext list */ |
3715 | { | 3715 | { |
3716 | xfs_ext_irec_t *erp = NULL; /* indirection array pointer */ | 3716 | xfs_ext_irec_t *erp = NULL; /* indirection array pointer */ |
3717 | xfs_ext_irec_t *erp_next; /* next indirection array entry */ | 3717 | xfs_ext_irec_t *erp_next; /* next indirection array entry */ |
3718 | int erp_idx; /* indirection array index */ | 3718 | int erp_idx; /* indirection array index */ |
3719 | int nlists; /* number of extent irec's (lists) */ | 3719 | int nlists; /* number of extent irec's (lists) */ |
3720 | int high; /* binary search upper limit */ | 3720 | int high; /* binary search upper limit */ |
3721 | int low; /* binary search lower limit */ | 3721 | int low; /* binary search lower limit */ |
3722 | 3722 | ||
3723 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3723 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3724 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 3724 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
3725 | erp_idx = 0; | 3725 | erp_idx = 0; |
3726 | low = 0; | 3726 | low = 0; |
3727 | high = nlists - 1; | 3727 | high = nlists - 1; |
3728 | while (low <= high) { | 3728 | while (low <= high) { |
3729 | erp_idx = (low + high) >> 1; | 3729 | erp_idx = (low + high) >> 1; |
3730 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; | 3730 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; |
3731 | erp_next = erp_idx < nlists - 1 ? erp + 1 : NULL; | 3731 | erp_next = erp_idx < nlists - 1 ? erp + 1 : NULL; |
3732 | if (bno < xfs_bmbt_get_startoff(erp->er_extbuf)) { | 3732 | if (bno < xfs_bmbt_get_startoff(erp->er_extbuf)) { |
3733 | high = erp_idx - 1; | 3733 | high = erp_idx - 1; |
3734 | } else if (erp_next && bno >= | 3734 | } else if (erp_next && bno >= |
3735 | xfs_bmbt_get_startoff(erp_next->er_extbuf)) { | 3735 | xfs_bmbt_get_startoff(erp_next->er_extbuf)) { |
3736 | low = erp_idx + 1; | 3736 | low = erp_idx + 1; |
3737 | } else { | 3737 | } else { |
3738 | break; | 3738 | break; |
3739 | } | 3739 | } |
3740 | } | 3740 | } |
3741 | *erp_idxp = erp_idx; | 3741 | *erp_idxp = erp_idx; |
3742 | return erp; | 3742 | return erp; |
3743 | } | 3743 | } |
3744 | 3744 | ||
3745 | /* | 3745 | /* |
3746 | * Return a pointer to the indirection array entry containing the | 3746 | * Return a pointer to the indirection array entry containing the |
3747 | * extent record at file extent index *idxp. Store the index of the | 3747 | * extent record at file extent index *idxp. Store the index of the |
3748 | * target irec in *erp_idxp and store the page index of the target | 3748 | * target irec in *erp_idxp and store the page index of the target |
3749 | * extent record in *idxp. | 3749 | * extent record in *idxp. |
3750 | */ | 3750 | */ |
3751 | xfs_ext_irec_t * | 3751 | xfs_ext_irec_t * |
3752 | xfs_iext_idx_to_irec( | 3752 | xfs_iext_idx_to_irec( |
3753 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3753 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3754 | xfs_extnum_t *idxp, /* extent index (file -> page) */ | 3754 | xfs_extnum_t *idxp, /* extent index (file -> page) */ |
3755 | int *erp_idxp, /* pointer to target irec */ | 3755 | int *erp_idxp, /* pointer to target irec */ |
3756 | int realloc) /* new bytes were just added */ | 3756 | int realloc) /* new bytes were just added */ |
3757 | { | 3757 | { |
3758 | xfs_ext_irec_t *prev; /* pointer to previous irec */ | 3758 | xfs_ext_irec_t *prev; /* pointer to previous irec */ |
3759 | xfs_ext_irec_t *erp = NULL; /* pointer to current irec */ | 3759 | xfs_ext_irec_t *erp = NULL; /* pointer to current irec */ |
3760 | int erp_idx; /* indirection array index */ | 3760 | int erp_idx; /* indirection array index */ |
3761 | int nlists; /* number of irec's (ex lists) */ | 3761 | int nlists; /* number of irec's (ex lists) */ |
3762 | int high; /* binary search upper limit */ | 3762 | int high; /* binary search upper limit */ |
3763 | int low; /* binary search lower limit */ | 3763 | int low; /* binary search lower limit */ |
3764 | xfs_extnum_t page_idx = *idxp; /* extent index in target list */ | 3764 | xfs_extnum_t page_idx = *idxp; /* extent index in target list */ |
3765 | 3765 | ||
3766 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3766 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3767 | ASSERT(page_idx >= 0); | 3767 | ASSERT(page_idx >= 0); |
3768 | ASSERT(page_idx <= ifp->if_bytes / sizeof(xfs_bmbt_rec_t)); | 3768 | ASSERT(page_idx <= ifp->if_bytes / sizeof(xfs_bmbt_rec_t)); |
3769 | ASSERT(page_idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t) || realloc); | 3769 | ASSERT(page_idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t) || realloc); |
3770 | 3770 | ||
3771 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 3771 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
3772 | erp_idx = 0; | 3772 | erp_idx = 0; |
3773 | low = 0; | 3773 | low = 0; |
3774 | high = nlists - 1; | 3774 | high = nlists - 1; |
3775 | 3775 | ||
3776 | /* Binary search extent irec's */ | 3776 | /* Binary search extent irec's */ |
3777 | while (low <= high) { | 3777 | while (low <= high) { |
3778 | erp_idx = (low + high) >> 1; | 3778 | erp_idx = (low + high) >> 1; |
3779 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; | 3779 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; |
3780 | prev = erp_idx > 0 ? erp - 1 : NULL; | 3780 | prev = erp_idx > 0 ? erp - 1 : NULL; |
3781 | if (page_idx < erp->er_extoff || (page_idx == erp->er_extoff && | 3781 | if (page_idx < erp->er_extoff || (page_idx == erp->er_extoff && |
3782 | realloc && prev && prev->er_extcount < XFS_LINEAR_EXTS)) { | 3782 | realloc && prev && prev->er_extcount < XFS_LINEAR_EXTS)) { |
3783 | high = erp_idx - 1; | 3783 | high = erp_idx - 1; |
3784 | } else if (page_idx > erp->er_extoff + erp->er_extcount || | 3784 | } else if (page_idx > erp->er_extoff + erp->er_extcount || |
3785 | (page_idx == erp->er_extoff + erp->er_extcount && | 3785 | (page_idx == erp->er_extoff + erp->er_extcount && |
3786 | !realloc)) { | 3786 | !realloc)) { |
3787 | low = erp_idx + 1; | 3787 | low = erp_idx + 1; |
3788 | } else if (page_idx == erp->er_extoff + erp->er_extcount && | 3788 | } else if (page_idx == erp->er_extoff + erp->er_extcount && |
3789 | erp->er_extcount == XFS_LINEAR_EXTS) { | 3789 | erp->er_extcount == XFS_LINEAR_EXTS) { |
3790 | ASSERT(realloc); | 3790 | ASSERT(realloc); |
3791 | page_idx = 0; | 3791 | page_idx = 0; |
3792 | erp_idx++; | 3792 | erp_idx++; |
3793 | erp = erp_idx < nlists ? erp + 1 : NULL; | 3793 | erp = erp_idx < nlists ? erp + 1 : NULL; |
3794 | break; | 3794 | break; |
3795 | } else { | 3795 | } else { |
3796 | page_idx -= erp->er_extoff; | 3796 | page_idx -= erp->er_extoff; |
3797 | break; | 3797 | break; |
3798 | } | 3798 | } |
3799 | } | 3799 | } |
3800 | *idxp = page_idx; | 3800 | *idxp = page_idx; |
3801 | *erp_idxp = erp_idx; | 3801 | *erp_idxp = erp_idx; |
3802 | return(erp); | 3802 | return(erp); |
3803 | } | 3803 | } |
3804 | 3804 | ||
3805 | /* | 3805 | /* |
3806 | * Allocate and initialize an indirection array once the space needed | 3806 | * Allocate and initialize an indirection array once the space needed |
3807 | * for incore extents increases above XFS_IEXT_BUFSZ. | 3807 | * for incore extents increases above XFS_IEXT_BUFSZ. |
3808 | */ | 3808 | */ |
3809 | void | 3809 | void |
3810 | xfs_iext_irec_init( | 3810 | xfs_iext_irec_init( |
3811 | xfs_ifork_t *ifp) /* inode fork pointer */ | 3811 | xfs_ifork_t *ifp) /* inode fork pointer */ |
3812 | { | 3812 | { |
3813 | xfs_ext_irec_t *erp; /* indirection array pointer */ | 3813 | xfs_ext_irec_t *erp; /* indirection array pointer */ |
3814 | xfs_extnum_t nextents; /* number of extents in file */ | 3814 | xfs_extnum_t nextents; /* number of extents in file */ |
3815 | 3815 | ||
3816 | ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); | 3816 | ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); |
3817 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | 3817 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); |
3818 | ASSERT(nextents <= XFS_LINEAR_EXTS); | 3818 | ASSERT(nextents <= XFS_LINEAR_EXTS); |
3819 | 3819 | ||
3820 | erp = kmem_alloc(sizeof(xfs_ext_irec_t), KM_NOFS); | 3820 | erp = kmem_alloc(sizeof(xfs_ext_irec_t), KM_NOFS); |
3821 | 3821 | ||
3822 | if (nextents == 0) { | 3822 | if (nextents == 0) { |
3823 | ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS); | 3823 | ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS); |
3824 | } else if (!ifp->if_real_bytes) { | 3824 | } else if (!ifp->if_real_bytes) { |
3825 | xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ); | 3825 | xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ); |
3826 | } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) { | 3826 | } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) { |
3827 | xfs_iext_realloc_direct(ifp, XFS_IEXT_BUFSZ); | 3827 | xfs_iext_realloc_direct(ifp, XFS_IEXT_BUFSZ); |
3828 | } | 3828 | } |
3829 | erp->er_extbuf = ifp->if_u1.if_extents; | 3829 | erp->er_extbuf = ifp->if_u1.if_extents; |
3830 | erp->er_extcount = nextents; | 3830 | erp->er_extcount = nextents; |
3831 | erp->er_extoff = 0; | 3831 | erp->er_extoff = 0; |
3832 | 3832 | ||
3833 | ifp->if_flags |= XFS_IFEXTIREC; | 3833 | ifp->if_flags |= XFS_IFEXTIREC; |
3834 | ifp->if_real_bytes = XFS_IEXT_BUFSZ; | 3834 | ifp->if_real_bytes = XFS_IEXT_BUFSZ; |
3835 | ifp->if_bytes = nextents * sizeof(xfs_bmbt_rec_t); | 3835 | ifp->if_bytes = nextents * sizeof(xfs_bmbt_rec_t); |
3836 | ifp->if_u1.if_ext_irec = erp; | 3836 | ifp->if_u1.if_ext_irec = erp; |
3837 | 3837 | ||
3838 | return; | 3838 | return; |
3839 | } | 3839 | } |
3840 | 3840 | ||
3841 | /* | 3841 | /* |
3842 | * Allocate and initialize a new entry in the indirection array. | 3842 | * Allocate and initialize a new entry in the indirection array. |
3843 | */ | 3843 | */ |
3844 | xfs_ext_irec_t * | 3844 | xfs_ext_irec_t * |
3845 | xfs_iext_irec_new( | 3845 | xfs_iext_irec_new( |
3846 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3846 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3847 | int erp_idx) /* index for new irec */ | 3847 | int erp_idx) /* index for new irec */ |
3848 | { | 3848 | { |
3849 | xfs_ext_irec_t *erp; /* indirection array pointer */ | 3849 | xfs_ext_irec_t *erp; /* indirection array pointer */ |
3850 | int i; /* loop counter */ | 3850 | int i; /* loop counter */ |
3851 | int nlists; /* number of irec's (ex lists) */ | 3851 | int nlists; /* number of irec's (ex lists) */ |
3852 | 3852 | ||
3853 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3853 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3854 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 3854 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
3855 | 3855 | ||
3856 | /* Resize indirection array */ | 3856 | /* Resize indirection array */ |
3857 | xfs_iext_realloc_indirect(ifp, ++nlists * | 3857 | xfs_iext_realloc_indirect(ifp, ++nlists * |
3858 | sizeof(xfs_ext_irec_t)); | 3858 | sizeof(xfs_ext_irec_t)); |
3859 | /* | 3859 | /* |
3860 | * Move records down in the array so the | 3860 | * Move records down in the array so the |
3861 | * new page can use erp_idx. | 3861 | * new page can use erp_idx. |
3862 | */ | 3862 | */ |
3863 | erp = ifp->if_u1.if_ext_irec; | 3863 | erp = ifp->if_u1.if_ext_irec; |
3864 | for (i = nlists - 1; i > erp_idx; i--) { | 3864 | for (i = nlists - 1; i > erp_idx; i--) { |
3865 | memmove(&erp[i], &erp[i-1], sizeof(xfs_ext_irec_t)); | 3865 | memmove(&erp[i], &erp[i-1], sizeof(xfs_ext_irec_t)); |
3866 | } | 3866 | } |
3867 | ASSERT(i == erp_idx); | 3867 | ASSERT(i == erp_idx); |
3868 | 3868 | ||
3869 | /* Initialize new extent record */ | 3869 | /* Initialize new extent record */ |
3870 | erp = ifp->if_u1.if_ext_irec; | 3870 | erp = ifp->if_u1.if_ext_irec; |
3871 | erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS); | 3871 | erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS); |
3872 | ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; | 3872 | ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; |
3873 | memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ); | 3873 | memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ); |
3874 | erp[erp_idx].er_extcount = 0; | 3874 | erp[erp_idx].er_extcount = 0; |
3875 | erp[erp_idx].er_extoff = erp_idx > 0 ? | 3875 | erp[erp_idx].er_extoff = erp_idx > 0 ? |
3876 | erp[erp_idx-1].er_extoff + erp[erp_idx-1].er_extcount : 0; | 3876 | erp[erp_idx-1].er_extoff + erp[erp_idx-1].er_extcount : 0; |
3877 | return (&erp[erp_idx]); | 3877 | return (&erp[erp_idx]); |
3878 | } | 3878 | } |
3879 | 3879 | ||
3880 | /* | 3880 | /* |
3881 | * Remove a record from the indirection array. | 3881 | * Remove a record from the indirection array. |
3882 | */ | 3882 | */ |
3883 | void | 3883 | void |
3884 | xfs_iext_irec_remove( | 3884 | xfs_iext_irec_remove( |
3885 | xfs_ifork_t *ifp, /* inode fork pointer */ | 3885 | xfs_ifork_t *ifp, /* inode fork pointer */ |
3886 | int erp_idx) /* irec index to remove */ | 3886 | int erp_idx) /* irec index to remove */ |
3887 | { | 3887 | { |
3888 | xfs_ext_irec_t *erp; /* indirection array pointer */ | 3888 | xfs_ext_irec_t *erp; /* indirection array pointer */ |
3889 | int i; /* loop counter */ | 3889 | int i; /* loop counter */ |
3890 | int nlists; /* number of irec's (ex lists) */ | 3890 | int nlists; /* number of irec's (ex lists) */ |
3891 | 3891 | ||
3892 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3892 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3893 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 3893 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
3894 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; | 3894 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; |
3895 | if (erp->er_extbuf) { | 3895 | if (erp->er_extbuf) { |
3896 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, | 3896 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, |
3897 | -erp->er_extcount); | 3897 | -erp->er_extcount); |
3898 | kmem_free(erp->er_extbuf); | 3898 | kmem_free(erp->er_extbuf); |
3899 | } | 3899 | } |
3900 | /* Compact extent records */ | 3900 | /* Compact extent records */ |
3901 | erp = ifp->if_u1.if_ext_irec; | 3901 | erp = ifp->if_u1.if_ext_irec; |
3902 | for (i = erp_idx; i < nlists - 1; i++) { | 3902 | for (i = erp_idx; i < nlists - 1; i++) { |
3903 | memmove(&erp[i], &erp[i+1], sizeof(xfs_ext_irec_t)); | 3903 | memmove(&erp[i], &erp[i+1], sizeof(xfs_ext_irec_t)); |
3904 | } | 3904 | } |
3905 | /* | 3905 | /* |
3906 | * Manually free the last extent record from the indirection | 3906 | * Manually free the last extent record from the indirection |
3907 | * array. A call to xfs_iext_realloc_indirect() with a size | 3907 | * array. A call to xfs_iext_realloc_indirect() with a size |
3908 | * of zero would result in a call to xfs_iext_destroy() which | 3908 | * of zero would result in a call to xfs_iext_destroy() which |
3909 | * would in turn call this function again, creating a nasty | 3909 | * would in turn call this function again, creating a nasty |
3910 | * infinite loop. | 3910 | * infinite loop. |
3911 | */ | 3911 | */ |
3912 | if (--nlists) { | 3912 | if (--nlists) { |
3913 | xfs_iext_realloc_indirect(ifp, | 3913 | xfs_iext_realloc_indirect(ifp, |
3914 | nlists * sizeof(xfs_ext_irec_t)); | 3914 | nlists * sizeof(xfs_ext_irec_t)); |
3915 | } else { | 3915 | } else { |
3916 | kmem_free(ifp->if_u1.if_ext_irec); | 3916 | kmem_free(ifp->if_u1.if_ext_irec); |
3917 | } | 3917 | } |
3918 | ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; | 3918 | ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; |
3919 | } | 3919 | } |
3920 | 3920 | ||
3921 | /* | 3921 | /* |
3922 | * This is called to clean up large amounts of unused memory allocated | 3922 | * This is called to clean up large amounts of unused memory allocated |
3923 | * by the indirection array. Before compacting anything though, verify | 3923 | * by the indirection array. Before compacting anything though, verify |
3924 | * that the indirection array is still needed and switch back to the | 3924 | * that the indirection array is still needed and switch back to the |
3925 | * linear extent list (or even the inline buffer) if possible. The | 3925 | * linear extent list (or even the inline buffer) if possible. The |
3926 | * compaction policy is as follows: | 3926 | * compaction policy is as follows: |
3927 | * | 3927 | * |
3928 | * Full Compaction: Extents fit into a single page (or inline buffer) | 3928 | * Full Compaction: Extents fit into a single page (or inline buffer) |
3929 | * Partial Compaction: Extents occupy less than 50% of allocated space | 3929 | * Partial Compaction: Extents occupy less than 50% of allocated space |
3930 | * No Compaction: Extents occupy at least 50% of allocated space | 3930 | * No Compaction: Extents occupy at least 50% of allocated space |
3931 | */ | 3931 | */ |
3932 | void | 3932 | void |
3933 | xfs_iext_irec_compact( | 3933 | xfs_iext_irec_compact( |
3934 | xfs_ifork_t *ifp) /* inode fork pointer */ | 3934 | xfs_ifork_t *ifp) /* inode fork pointer */ |
3935 | { | 3935 | { |
3936 | xfs_extnum_t nextents; /* number of extents in file */ | 3936 | xfs_extnum_t nextents; /* number of extents in file */ |
3937 | int nlists; /* number of irec's (ex lists) */ | 3937 | int nlists; /* number of irec's (ex lists) */ |
3938 | 3938 | ||
3939 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3939 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3940 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 3940 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
3941 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | 3941 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); |
3942 | 3942 | ||
3943 | if (nextents == 0) { | 3943 | if (nextents == 0) { |
3944 | xfs_iext_destroy(ifp); | 3944 | xfs_iext_destroy(ifp); |
3945 | } else if (nextents <= XFS_INLINE_EXTS) { | 3945 | } else if (nextents <= XFS_INLINE_EXTS) { |
3946 | xfs_iext_indirect_to_direct(ifp); | 3946 | xfs_iext_indirect_to_direct(ifp); |
3947 | xfs_iext_direct_to_inline(ifp, nextents); | 3947 | xfs_iext_direct_to_inline(ifp, nextents); |
3948 | } else if (nextents <= XFS_LINEAR_EXTS) { | 3948 | } else if (nextents <= XFS_LINEAR_EXTS) { |
3949 | xfs_iext_indirect_to_direct(ifp); | 3949 | xfs_iext_indirect_to_direct(ifp); |
3950 | } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) { | 3950 | } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) { |
3951 | xfs_iext_irec_compact_pages(ifp); | 3951 | xfs_iext_irec_compact_pages(ifp); |
3952 | } | 3952 | } |
3953 | } | 3953 | } |
3954 | 3954 | ||
3955 | /* | 3955 | /* |
3956 | * Combine extents from neighboring extent pages. | 3956 | * Combine extents from neighboring extent pages. |
3957 | */ | 3957 | */ |
3958 | void | 3958 | void |
3959 | xfs_iext_irec_compact_pages( | 3959 | xfs_iext_irec_compact_pages( |
3960 | xfs_ifork_t *ifp) /* inode fork pointer */ | 3960 | xfs_ifork_t *ifp) /* inode fork pointer */ |
3961 | { | 3961 | { |
3962 | xfs_ext_irec_t *erp, *erp_next;/* pointers to irec entries */ | 3962 | xfs_ext_irec_t *erp, *erp_next;/* pointers to irec entries */ |
3963 | int erp_idx = 0; /* indirection array index */ | 3963 | int erp_idx = 0; /* indirection array index */ |
3964 | int nlists; /* number of irec's (ex lists) */ | 3964 | int nlists; /* number of irec's (ex lists) */ |
3965 | 3965 | ||
3966 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 3966 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
3967 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 3967 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
3968 | while (erp_idx < nlists - 1) { | 3968 | while (erp_idx < nlists - 1) { |
3969 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; | 3969 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; |
3970 | erp_next = erp + 1; | 3970 | erp_next = erp + 1; |
3971 | if (erp_next->er_extcount <= | 3971 | if (erp_next->er_extcount <= |
3972 | (XFS_LINEAR_EXTS - erp->er_extcount)) { | 3972 | (XFS_LINEAR_EXTS - erp->er_extcount)) { |
3973 | memcpy(&erp->er_extbuf[erp->er_extcount], | 3973 | memcpy(&erp->er_extbuf[erp->er_extcount], |
3974 | erp_next->er_extbuf, erp_next->er_extcount * | 3974 | erp_next->er_extbuf, erp_next->er_extcount * |
3975 | sizeof(xfs_bmbt_rec_t)); | 3975 | sizeof(xfs_bmbt_rec_t)); |
3976 | erp->er_extcount += erp_next->er_extcount; | 3976 | erp->er_extcount += erp_next->er_extcount; |
3977 | /* | 3977 | /* |
3978 | * Free page before removing extent record | 3978 | * Free page before removing extent record |
3979 | * so er_extoffs don't get modified in | 3979 | * so er_extoffs don't get modified in |
3980 | * xfs_iext_irec_remove. | 3980 | * xfs_iext_irec_remove. |
3981 | */ | 3981 | */ |
3982 | kmem_free(erp_next->er_extbuf); | 3982 | kmem_free(erp_next->er_extbuf); |
3983 | erp_next->er_extbuf = NULL; | 3983 | erp_next->er_extbuf = NULL; |
3984 | xfs_iext_irec_remove(ifp, erp_idx + 1); | 3984 | xfs_iext_irec_remove(ifp, erp_idx + 1); |
3985 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 3985 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
3986 | } else { | 3986 | } else { |
3987 | erp_idx++; | 3987 | erp_idx++; |
3988 | } | 3988 | } |
3989 | } | 3989 | } |
3990 | } | 3990 | } |
3991 | 3991 | ||
3992 | /* | 3992 | /* |
3993 | * This is called to update the er_extoff field in the indirection | 3993 | * This is called to update the er_extoff field in the indirection |
3994 | * array when extents have been added or removed from one of the | 3994 | * array when extents have been added or removed from one of the |
3995 | * extent lists. erp_idx contains the irec index to begin updating | 3995 | * extent lists. erp_idx contains the irec index to begin updating |
3996 | * at and ext_diff contains the number of extents that were added | 3996 | * at and ext_diff contains the number of extents that were added |
3997 | * or removed. | 3997 | * or removed. |
3998 | */ | 3998 | */ |
3999 | void | 3999 | void |
4000 | xfs_iext_irec_update_extoffs( | 4000 | xfs_iext_irec_update_extoffs( |
4001 | xfs_ifork_t *ifp, /* inode fork pointer */ | 4001 | xfs_ifork_t *ifp, /* inode fork pointer */ |
4002 | int erp_idx, /* irec index to update */ | 4002 | int erp_idx, /* irec index to update */ |
4003 | int ext_diff) /* number of new extents */ | 4003 | int ext_diff) /* number of new extents */ |
4004 | { | 4004 | { |
4005 | int i; /* loop counter */ | 4005 | int i; /* loop counter */ |
4006 | int nlists; /* number of irec's (ex lists */ | 4006 | int nlists; /* number of irec's (ex lists */ |
4007 | 4007 | ||
4008 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 4008 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
4009 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 4009 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
4010 | for (i = erp_idx; i < nlists; i++) { | 4010 | for (i = erp_idx; i < nlists; i++) { |
4011 | ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff; | 4011 | ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff; |
4012 | } | 4012 | } |
4013 | } | 4013 | } |
4014 | 4014 | ||
4015 | /* | 4015 | /* |
4016 | * Test whether it is appropriate to check an inode for and free post EOF | 4016 | * Test whether it is appropriate to check an inode for and free post EOF |
4017 | * blocks. The 'force' parameter determines whether we should also consider | 4017 | * blocks. The 'force' parameter determines whether we should also consider |
4018 | * regular files that are marked preallocated or append-only. | 4018 | * regular files that are marked preallocated or append-only. |
4019 | */ | 4019 | */ |
4020 | bool | 4020 | bool |
4021 | xfs_can_free_eofblocks(struct xfs_inode *ip, bool force) | 4021 | xfs_can_free_eofblocks(struct xfs_inode *ip, bool force) |
4022 | { | 4022 | { |
4023 | /* prealloc/delalloc exists only on regular files */ | 4023 | /* prealloc/delalloc exists only on regular files */ |
4024 | if (!S_ISREG(ip->i_d.di_mode)) | 4024 | if (!S_ISREG(ip->i_d.di_mode)) |
4025 | return false; | 4025 | return false; |
4026 | 4026 | ||
4027 | /* | 4027 | /* |
4028 | * Zero sized files with no cached pages and delalloc blocks will not | 4028 | * Zero sized files with no cached pages and delalloc blocks will not |
4029 | * have speculative prealloc/delalloc blocks to remove. | 4029 | * have speculative prealloc/delalloc blocks to remove. |
4030 | */ | 4030 | */ |
4031 | if (VFS_I(ip)->i_size == 0 && | 4031 | if (VFS_I(ip)->i_size == 0 && |
4032 | VN_CACHED(VFS_I(ip)) == 0 && | 4032 | VN_CACHED(VFS_I(ip)) == 0 && |
4033 | ip->i_delayed_blks == 0) | 4033 | ip->i_delayed_blks == 0) |
4034 | return false; | 4034 | return false; |
4035 | 4035 | ||
4036 | /* If we haven't read in the extent list, then don't do it now. */ | 4036 | /* If we haven't read in the extent list, then don't do it now. */ |
4037 | if (!(ip->i_df.if_flags & XFS_IFEXTENTS)) | 4037 | if (!(ip->i_df.if_flags & XFS_IFEXTENTS)) |
4038 | return false; | 4038 | return false; |
4039 | 4039 | ||
4040 | /* | 4040 | /* |
4041 | * Do not free real preallocated or append-only files unless the file | 4041 | * Do not free real preallocated or append-only files unless the file |
4042 | * has delalloc blocks and we are forced to remove them. | 4042 | * has delalloc blocks and we are forced to remove them. |
4043 | */ | 4043 | */ |
4044 | if (ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) | 4044 | if (ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) |
4045 | if (!force || ip->i_delayed_blks == 0) | 4045 | if (!force || ip->i_delayed_blks == 0) |
4046 | return false; | 4046 | return false; |
4047 | 4047 | ||
4048 | return true; | 4048 | return true; |
4049 | } | 4049 | } |
4050 | 4050 | ||
4051 | 4051 |
fs/xfs/xfs_linux.h
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | 6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | * | 8 | * |
9 | * This program is distributed in the hope that it would be useful, | 9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | #ifndef __XFS_LINUX__ | 18 | #ifndef __XFS_LINUX__ |
19 | #define __XFS_LINUX__ | 19 | #define __XFS_LINUX__ |
20 | 20 | ||
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits. | 24 | * XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits. |
25 | * XFS_BIG_INUMS requires XFS_BIG_BLKNOS to be set. | 25 | * XFS_BIG_INUMS requires XFS_BIG_BLKNOS to be set. |
26 | */ | 26 | */ |
27 | #if defined(CONFIG_LBDAF) || (BITS_PER_LONG == 64) | 27 | #if defined(CONFIG_LBDAF) || (BITS_PER_LONG == 64) |
28 | # define XFS_BIG_BLKNOS 1 | 28 | # define XFS_BIG_BLKNOS 1 |
29 | # define XFS_BIG_INUMS 1 | 29 | # define XFS_BIG_INUMS 1 |
30 | #else | 30 | #else |
31 | # define XFS_BIG_BLKNOS 0 | 31 | # define XFS_BIG_BLKNOS 0 |
32 | # define XFS_BIG_INUMS 0 | 32 | # define XFS_BIG_INUMS 0 |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | #include "xfs_types.h" | 35 | #include "xfs_types.h" |
36 | 36 | ||
37 | #include "kmem.h" | 37 | #include "kmem.h" |
38 | #include "mrlock.h" | 38 | #include "mrlock.h" |
39 | #include "time.h" | 39 | #include "time.h" |
40 | #include "uuid.h" | 40 | #include "uuid.h" |
41 | 41 | ||
42 | #include <linux/semaphore.h> | 42 | #include <linux/semaphore.h> |
43 | #include <linux/mm.h> | 43 | #include <linux/mm.h> |
44 | #include <linux/kernel.h> | 44 | #include <linux/kernel.h> |
45 | #include <linux/blkdev.h> | 45 | #include <linux/blkdev.h> |
46 | #include <linux/slab.h> | 46 | #include <linux/slab.h> |
47 | #include <linux/crc32c.h> | 47 | #include <linux/crc32c.h> |
48 | #include <linux/module.h> | 48 | #include <linux/module.h> |
49 | #include <linux/mutex.h> | 49 | #include <linux/mutex.h> |
50 | #include <linux/file.h> | 50 | #include <linux/file.h> |
51 | #include <linux/swap.h> | 51 | #include <linux/swap.h> |
52 | #include <linux/errno.h> | 52 | #include <linux/errno.h> |
53 | #include <linux/sched.h> | 53 | #include <linux/sched.h> |
54 | #include <linux/bitops.h> | 54 | #include <linux/bitops.h> |
55 | #include <linux/major.h> | 55 | #include <linux/major.h> |
56 | #include <linux/pagemap.h> | 56 | #include <linux/pagemap.h> |
57 | #include <linux/vfs.h> | 57 | #include <linux/vfs.h> |
58 | #include <linux/seq_file.h> | 58 | #include <linux/seq_file.h> |
59 | #include <linux/init.h> | 59 | #include <linux/init.h> |
60 | #include <linux/list.h> | 60 | #include <linux/list.h> |
61 | #include <linux/proc_fs.h> | 61 | #include <linux/proc_fs.h> |
62 | #include <linux/sort.h> | 62 | #include <linux/sort.h> |
63 | #include <linux/cpu.h> | 63 | #include <linux/cpu.h> |
64 | #include <linux/notifier.h> | 64 | #include <linux/notifier.h> |
65 | #include <linux/delay.h> | 65 | #include <linux/delay.h> |
66 | #include <linux/log2.h> | 66 | #include <linux/log2.h> |
67 | #include <linux/spinlock.h> | 67 | #include <linux/spinlock.h> |
68 | #include <linux/random.h> | 68 | #include <linux/random.h> |
69 | #include <linux/ctype.h> | 69 | #include <linux/ctype.h> |
70 | #include <linux/writeback.h> | 70 | #include <linux/writeback.h> |
71 | #include <linux/capability.h> | 71 | #include <linux/capability.h> |
72 | #include <linux/kthread.h> | 72 | #include <linux/kthread.h> |
73 | #include <linux/freezer.h> | 73 | #include <linux/freezer.h> |
74 | #include <linux/list_sort.h> | 74 | #include <linux/list_sort.h> |
75 | #include <linux/ratelimit.h> | 75 | #include <linux/ratelimit.h> |
76 | 76 | ||
77 | #include <asm/page.h> | 77 | #include <asm/page.h> |
78 | #include <asm/div64.h> | 78 | #include <asm/div64.h> |
79 | #include <asm/param.h> | 79 | #include <asm/param.h> |
80 | #include <asm/uaccess.h> | 80 | #include <asm/uaccess.h> |
81 | #include <asm/byteorder.h> | 81 | #include <asm/byteorder.h> |
82 | #include <asm/unaligned.h> | 82 | #include <asm/unaligned.h> |
83 | 83 | ||
84 | #include "xfs_vnode.h" | 84 | #include "xfs_vnode.h" |
85 | #include "xfs_stats.h" | 85 | #include "xfs_stats.h" |
86 | #include "xfs_sysctl.h" | 86 | #include "xfs_sysctl.h" |
87 | #include "xfs_iops.h" | 87 | #include "xfs_iops.h" |
88 | #include "xfs_aops.h" | 88 | #include "xfs_aops.h" |
89 | #include "xfs_super.h" | 89 | #include "xfs_super.h" |
90 | #include "xfs_buf.h" | 90 | #include "xfs_buf.h" |
91 | #include "xfs_message.h" | 91 | #include "xfs_message.h" |
92 | 92 | ||
93 | #ifdef __BIG_ENDIAN | 93 | #ifdef __BIG_ENDIAN |
94 | #define XFS_NATIVE_HOST 1 | 94 | #define XFS_NATIVE_HOST 1 |
95 | #else | 95 | #else |
96 | #undef XFS_NATIVE_HOST | 96 | #undef XFS_NATIVE_HOST |
97 | #endif | 97 | #endif |
98 | 98 | ||
99 | /* | 99 | /* |
100 | * Feature macros (disable/enable) | 100 | * Feature macros (disable/enable) |
101 | */ | 101 | */ |
102 | #ifdef CONFIG_SMP | 102 | #ifdef CONFIG_SMP |
103 | #define HAVE_PERCPU_SB /* per cpu superblock counters are a 2.6 feature */ | 103 | #define HAVE_PERCPU_SB /* per cpu superblock counters are a 2.6 feature */ |
104 | #else | 104 | #else |
105 | #undef HAVE_PERCPU_SB /* per cpu superblock counters are a 2.6 feature */ | 105 | #undef HAVE_PERCPU_SB /* per cpu superblock counters are a 2.6 feature */ |
106 | #endif | 106 | #endif |
107 | 107 | ||
108 | #define irix_sgid_inherit xfs_params.sgid_inherit.val | 108 | #define irix_sgid_inherit xfs_params.sgid_inherit.val |
109 | #define irix_symlink_mode xfs_params.symlink_mode.val | 109 | #define irix_symlink_mode xfs_params.symlink_mode.val |
110 | #define xfs_panic_mask xfs_params.panic_mask.val | 110 | #define xfs_panic_mask xfs_params.panic_mask.val |
111 | #define xfs_error_level xfs_params.error_level.val | 111 | #define xfs_error_level xfs_params.error_level.val |
112 | #define xfs_syncd_centisecs xfs_params.syncd_timer.val | 112 | #define xfs_syncd_centisecs xfs_params.syncd_timer.val |
113 | #define xfs_stats_clear xfs_params.stats_clear.val | 113 | #define xfs_stats_clear xfs_params.stats_clear.val |
114 | #define xfs_inherit_sync xfs_params.inherit_sync.val | 114 | #define xfs_inherit_sync xfs_params.inherit_sync.val |
115 | #define xfs_inherit_nodump xfs_params.inherit_nodump.val | 115 | #define xfs_inherit_nodump xfs_params.inherit_nodump.val |
116 | #define xfs_inherit_noatime xfs_params.inherit_noatim.val | 116 | #define xfs_inherit_noatime xfs_params.inherit_noatim.val |
117 | #define xfs_buf_timer_centisecs xfs_params.xfs_buf_timer.val | 117 | #define xfs_buf_timer_centisecs xfs_params.xfs_buf_timer.val |
118 | #define xfs_buf_age_centisecs xfs_params.xfs_buf_age.val | 118 | #define xfs_buf_age_centisecs xfs_params.xfs_buf_age.val |
119 | #define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val | 119 | #define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val |
120 | #define xfs_rotorstep xfs_params.rotorstep.val | 120 | #define xfs_rotorstep xfs_params.rotorstep.val |
121 | #define xfs_inherit_nodefrag xfs_params.inherit_nodfrg.val | 121 | #define xfs_inherit_nodefrag xfs_params.inherit_nodfrg.val |
122 | #define xfs_fstrm_centisecs xfs_params.fstrm_timer.val | 122 | #define xfs_fstrm_centisecs xfs_params.fstrm_timer.val |
123 | #define xfs_eofb_secs xfs_params.eofb_timer.val | 123 | #define xfs_eofb_secs xfs_params.eofb_timer.val |
124 | 124 | ||
125 | #define current_cpu() (raw_smp_processor_id()) | 125 | #define current_cpu() (raw_smp_processor_id()) |
126 | #define current_pid() (current->pid) | 126 | #define current_pid() (current->pid) |
127 | #define current_test_flags(f) (current->flags & (f)) | 127 | #define current_test_flags(f) (current->flags & (f)) |
128 | #define current_set_flags_nested(sp, f) \ | 128 | #define current_set_flags_nested(sp, f) \ |
129 | (*(sp) = current->flags, current->flags |= (f)) | 129 | (*(sp) = current->flags, current->flags |= (f)) |
130 | #define current_clear_flags_nested(sp, f) \ | 130 | #define current_clear_flags_nested(sp, f) \ |
131 | (*(sp) = current->flags, current->flags &= ~(f)) | 131 | (*(sp) = current->flags, current->flags &= ~(f)) |
132 | #define current_restore_flags_nested(sp, f) \ | 132 | #define current_restore_flags_nested(sp, f) \ |
133 | (current->flags = ((current->flags & ~(f)) | (*(sp) & (f)))) | 133 | (current->flags = ((current->flags & ~(f)) | (*(sp) & (f)))) |
134 | 134 | ||
135 | #define spinlock_destroy(lock) | 135 | #define spinlock_destroy(lock) |
136 | 136 | ||
137 | #define NBBY 8 /* number of bits per byte */ | 137 | #define NBBY 8 /* number of bits per byte */ |
138 | 138 | ||
139 | /* | 139 | /* |
140 | * Size of block device i/o is parameterized here. | 140 | * Size of block device i/o is parameterized here. |
141 | * Currently the system supports page-sized i/o. | 141 | * Currently the system supports page-sized i/o. |
142 | */ | 142 | */ |
143 | #define BLKDEV_IOSHIFT PAGE_CACHE_SHIFT | 143 | #define BLKDEV_IOSHIFT PAGE_CACHE_SHIFT |
144 | #define BLKDEV_IOSIZE (1<<BLKDEV_IOSHIFT) | 144 | #define BLKDEV_IOSIZE (1<<BLKDEV_IOSHIFT) |
145 | /* number of BB's per block device block */ | 145 | /* number of BB's per block device block */ |
146 | #define BLKDEV_BB BTOBB(BLKDEV_IOSIZE) | 146 | #define BLKDEV_BB BTOBB(BLKDEV_IOSIZE) |
147 | 147 | ||
148 | #define ENOATTR ENODATA /* Attribute not found */ | 148 | #define ENOATTR ENODATA /* Attribute not found */ |
149 | #define EWRONGFS EINVAL /* Mount with wrong filesystem type */ | 149 | #define EWRONGFS EINVAL /* Mount with wrong filesystem type */ |
150 | #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ | 150 | #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ |
151 | 151 | ||
152 | #define SYNCHRONIZE() barrier() | 152 | #define SYNCHRONIZE() barrier() |
153 | #define __return_address __builtin_return_address(0) | 153 | #define __return_address __builtin_return_address(0) |
154 | 154 | ||
155 | #define XFS_PROJID_DEFAULT 0 | 155 | #define XFS_PROJID_DEFAULT 0 |
156 | #define MAXPATHLEN 1024 | 156 | #define MAXPATHLEN 1024 |
157 | 157 | ||
158 | #define MIN(a,b) (min(a,b)) | 158 | #define MIN(a,b) (min(a,b)) |
159 | #define MAX(a,b) (max(a,b)) | 159 | #define MAX(a,b) (max(a,b)) |
160 | #define howmany(x, y) (((x)+((y)-1))/(y)) | 160 | #define howmany(x, y) (((x)+((y)-1))/(y)) |
161 | 161 | ||
162 | /* | 162 | /* |
163 | * Various platform dependent calls that don't fit anywhere else | 163 | * Various platform dependent calls that don't fit anywhere else |
164 | */ | 164 | */ |
165 | #define xfs_sort(a,n,s,fn) sort(a,n,s,fn,NULL) | 165 | #define xfs_sort(a,n,s,fn) sort(a,n,s,fn,NULL) |
166 | #define xfs_stack_trace() dump_stack() | 166 | #define xfs_stack_trace() dump_stack() |
167 | 167 | ||
168 | 168 | ||
169 | /* Move the kernel do_div definition off to one side */ | 169 | /* Move the kernel do_div definition off to one side */ |
170 | 170 | ||
171 | #if defined __i386__ | 171 | #if defined __i386__ |
172 | /* For ia32 we need to pull some tricks to get past various versions | 172 | /* For ia32 we need to pull some tricks to get past various versions |
173 | * of the compiler which do not like us using do_div in the middle | 173 | * of the compiler which do not like us using do_div in the middle |
174 | * of large functions. | 174 | * of large functions. |
175 | */ | 175 | */ |
176 | static inline __u32 xfs_do_div(void *a, __u32 b, int n) | 176 | static inline __u32 xfs_do_div(void *a, __u32 b, int n) |
177 | { | 177 | { |
178 | __u32 mod; | 178 | __u32 mod; |
179 | 179 | ||
180 | switch (n) { | 180 | switch (n) { |
181 | case 4: | 181 | case 4: |
182 | mod = *(__u32 *)a % b; | 182 | mod = *(__u32 *)a % b; |
183 | *(__u32 *)a = *(__u32 *)a / b; | 183 | *(__u32 *)a = *(__u32 *)a / b; |
184 | return mod; | 184 | return mod; |
185 | case 8: | 185 | case 8: |
186 | { | 186 | { |
187 | unsigned long __upper, __low, __high, __mod; | 187 | unsigned long __upper, __low, __high, __mod; |
188 | __u64 c = *(__u64 *)a; | 188 | __u64 c = *(__u64 *)a; |
189 | __upper = __high = c >> 32; | 189 | __upper = __high = c >> 32; |
190 | __low = c; | 190 | __low = c; |
191 | if (__high) { | 191 | if (__high) { |
192 | __upper = __high % (b); | 192 | __upper = __high % (b); |
193 | __high = __high / (b); | 193 | __high = __high / (b); |
194 | } | 194 | } |
195 | asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); | 195 | asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); |
196 | asm("":"=A" (c):"a" (__low),"d" (__high)); | 196 | asm("":"=A" (c):"a" (__low),"d" (__high)); |
197 | *(__u64 *)a = c; | 197 | *(__u64 *)a = c; |
198 | return __mod; | 198 | return __mod; |
199 | } | 199 | } |
200 | } | 200 | } |
201 | 201 | ||
202 | /* NOTREACHED */ | 202 | /* NOTREACHED */ |
203 | return 0; | 203 | return 0; |
204 | } | 204 | } |
205 | 205 | ||
206 | /* Side effect free 64 bit mod operation */ | 206 | /* Side effect free 64 bit mod operation */ |
207 | static inline __u32 xfs_do_mod(void *a, __u32 b, int n) | 207 | static inline __u32 xfs_do_mod(void *a, __u32 b, int n) |
208 | { | 208 | { |
209 | switch (n) { | 209 | switch (n) { |
210 | case 4: | 210 | case 4: |
211 | return *(__u32 *)a % b; | 211 | return *(__u32 *)a % b; |
212 | case 8: | 212 | case 8: |
213 | { | 213 | { |
214 | unsigned long __upper, __low, __high, __mod; | 214 | unsigned long __upper, __low, __high, __mod; |
215 | __u64 c = *(__u64 *)a; | 215 | __u64 c = *(__u64 *)a; |
216 | __upper = __high = c >> 32; | 216 | __upper = __high = c >> 32; |
217 | __low = c; | 217 | __low = c; |
218 | if (__high) { | 218 | if (__high) { |
219 | __upper = __high % (b); | 219 | __upper = __high % (b); |
220 | __high = __high / (b); | 220 | __high = __high / (b); |
221 | } | 221 | } |
222 | asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); | 222 | asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); |
223 | asm("":"=A" (c):"a" (__low),"d" (__high)); | 223 | asm("":"=A" (c):"a" (__low),"d" (__high)); |
224 | return __mod; | 224 | return __mod; |
225 | } | 225 | } |
226 | } | 226 | } |
227 | 227 | ||
228 | /* NOTREACHED */ | 228 | /* NOTREACHED */ |
229 | return 0; | 229 | return 0; |
230 | } | 230 | } |
231 | #else | 231 | #else |
232 | static inline __u32 xfs_do_div(void *a, __u32 b, int n) | 232 | static inline __u32 xfs_do_div(void *a, __u32 b, int n) |
233 | { | 233 | { |
234 | __u32 mod; | 234 | __u32 mod; |
235 | 235 | ||
236 | switch (n) { | 236 | switch (n) { |
237 | case 4: | 237 | case 4: |
238 | mod = *(__u32 *)a % b; | 238 | mod = *(__u32 *)a % b; |
239 | *(__u32 *)a = *(__u32 *)a / b; | 239 | *(__u32 *)a = *(__u32 *)a / b; |
240 | return mod; | 240 | return mod; |
241 | case 8: | 241 | case 8: |
242 | mod = do_div(*(__u64 *)a, b); | 242 | mod = do_div(*(__u64 *)a, b); |
243 | return mod; | 243 | return mod; |
244 | } | 244 | } |
245 | 245 | ||
246 | /* NOTREACHED */ | 246 | /* NOTREACHED */ |
247 | return 0; | 247 | return 0; |
248 | } | 248 | } |
249 | 249 | ||
250 | /* Side effect free 64 bit mod operation */ | 250 | /* Side effect free 64 bit mod operation */ |
251 | static inline __u32 xfs_do_mod(void *a, __u32 b, int n) | 251 | static inline __u32 xfs_do_mod(void *a, __u32 b, int n) |
252 | { | 252 | { |
253 | switch (n) { | 253 | switch (n) { |
254 | case 4: | 254 | case 4: |
255 | return *(__u32 *)a % b; | 255 | return *(__u32 *)a % b; |
256 | case 8: | 256 | case 8: |
257 | { | 257 | { |
258 | __u64 c = *(__u64 *)a; | 258 | __u64 c = *(__u64 *)a; |
259 | return do_div(c, b); | 259 | return do_div(c, b); |
260 | } | 260 | } |
261 | } | 261 | } |
262 | 262 | ||
263 | /* NOTREACHED */ | 263 | /* NOTREACHED */ |
264 | return 0; | 264 | return 0; |
265 | } | 265 | } |
266 | #endif | 266 | #endif |
267 | 267 | ||
268 | #undef do_div | 268 | #undef do_div |
269 | #define do_div(a, b) xfs_do_div(&(a), (b), sizeof(a)) | 269 | #define do_div(a, b) xfs_do_div(&(a), (b), sizeof(a)) |
270 | #define do_mod(a, b) xfs_do_mod(&(a), (b), sizeof(a)) | 270 | #define do_mod(a, b) xfs_do_mod(&(a), (b), sizeof(a)) |
271 | 271 | ||
272 | static inline __uint64_t roundup_64(__uint64_t x, __uint32_t y) | 272 | static inline __uint64_t roundup_64(__uint64_t x, __uint32_t y) |
273 | { | 273 | { |
274 | x += y - 1; | 274 | x += y - 1; |
275 | do_div(x, y); | 275 | do_div(x, y); |
276 | return(x * y); | 276 | return(x * y); |
277 | } | 277 | } |
278 | 278 | ||
279 | static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y) | 279 | static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y) |
280 | { | 280 | { |
281 | x += y - 1; | 281 | x += y - 1; |
282 | do_div(x, y); | 282 | do_div(x, y); |
283 | return x; | 283 | return x; |
284 | } | 284 | } |
285 | 285 | ||
286 | /* ARM old ABI has some weird alignment/padding */ | 286 | /* ARM old ABI has some weird alignment/padding */ |
287 | #if defined(__arm__) && !defined(__ARM_EABI__) | 287 | #if defined(__arm__) && !defined(__ARM_EABI__) |
288 | #define __arch_pack __attribute__((packed)) | 288 | #define __arch_pack __attribute__((packed)) |
289 | #else | 289 | #else |
290 | #define __arch_pack | 290 | #define __arch_pack |
291 | #endif | 291 | #endif |
292 | 292 | ||
293 | #define ASSERT_ALWAYS(expr) \ | 293 | #define ASSERT_ALWAYS(expr) \ |
294 | (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) | 294 | (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) |
295 | 295 | ||
296 | #ifndef DEBUG | 296 | #ifdef DEBUG |
297 | #define ASSERT(expr) ((void)0) | 297 | #define ASSERT(expr) \ |
298 | (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) | ||
298 | 299 | ||
299 | #ifndef STATIC | 300 | #ifndef STATIC |
300 | # define STATIC static noinline | 301 | # define STATIC noinline |
301 | #endif | 302 | #endif |
302 | 303 | ||
303 | #else /* DEBUG */ | 304 | #else /* !DEBUG */ |
304 | 305 | ||
306 | #ifdef XFS_WARN | ||
307 | |||
305 | #define ASSERT(expr) \ | 308 | #define ASSERT(expr) \ |
306 | (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) | 309 | (unlikely(expr) ? (void)0 : asswarn(#expr, __FILE__, __LINE__)) |
307 | 310 | ||
308 | #ifndef STATIC | 311 | #ifndef STATIC |
309 | # define STATIC noinline | 312 | # define STATIC static noinline |
310 | #endif | 313 | #endif |
311 | 314 | ||
315 | #else /* !DEBUG && !XFS_WARN */ | ||
316 | |||
317 | #define ASSERT(expr) ((void)0) | ||
318 | |||
319 | #ifndef STATIC | ||
320 | # define STATIC static noinline | ||
321 | #endif | ||
322 | |||
323 | #endif /* XFS_WARN */ | ||
312 | #endif /* DEBUG */ | 324 | #endif /* DEBUG */ |
313 | 325 | ||
314 | #endif /* __XFS_LINUX__ */ | 326 | #endif /* __XFS_LINUX__ */ |
315 | 327 |
fs/xfs/xfs_message.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2011 Red Hat, Inc. All Rights Reserved. | 2 | * Copyright (c) 2011 Red Hat, Inc. All Rights Reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License as | 5 | * modify it under the terms of the GNU General Public License as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | * | 7 | * |
8 | * This program is distributed in the hope that it would be useful, | 8 | * This program is distributed in the hope that it would be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License | 13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program; if not, write the Free Software Foundation, | 14 | * along with this program; if not, write the Free Software Foundation, |
15 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 15 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include "xfs.h" | 18 | #include "xfs.h" |
19 | #include "xfs_fs.h" | 19 | #include "xfs_fs.h" |
20 | #include "xfs_types.h" | 20 | #include "xfs_types.h" |
21 | #include "xfs_log.h" | 21 | #include "xfs_log.h" |
22 | #include "xfs_trans.h" | 22 | #include "xfs_trans.h" |
23 | #include "xfs_sb.h" | 23 | #include "xfs_sb.h" |
24 | #include "xfs_ag.h" | 24 | #include "xfs_ag.h" |
25 | #include "xfs_mount.h" | 25 | #include "xfs_mount.h" |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * XFS logging functions | 28 | * XFS logging functions |
29 | */ | 29 | */ |
30 | static void | 30 | static void |
31 | __xfs_printk( | 31 | __xfs_printk( |
32 | const char *level, | 32 | const char *level, |
33 | const struct xfs_mount *mp, | 33 | const struct xfs_mount *mp, |
34 | struct va_format *vaf) | 34 | struct va_format *vaf) |
35 | { | 35 | { |
36 | if (mp && mp->m_fsname) { | 36 | if (mp && mp->m_fsname) { |
37 | printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf); | 37 | printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf); |
38 | return; | 38 | return; |
39 | } | 39 | } |
40 | printk("%sXFS: %pV\n", level, vaf); | 40 | printk("%sXFS: %pV\n", level, vaf); |
41 | } | 41 | } |
42 | 42 | ||
43 | #define define_xfs_printk_level(func, kern_level) \ | 43 | #define define_xfs_printk_level(func, kern_level) \ |
44 | void func(const struct xfs_mount *mp, const char *fmt, ...) \ | 44 | void func(const struct xfs_mount *mp, const char *fmt, ...) \ |
45 | { \ | 45 | { \ |
46 | struct va_format vaf; \ | 46 | struct va_format vaf; \ |
47 | va_list args; \ | 47 | va_list args; \ |
48 | \ | 48 | \ |
49 | va_start(args, fmt); \ | 49 | va_start(args, fmt); \ |
50 | \ | 50 | \ |
51 | vaf.fmt = fmt; \ | 51 | vaf.fmt = fmt; \ |
52 | vaf.va = &args; \ | 52 | vaf.va = &args; \ |
53 | \ | 53 | \ |
54 | __xfs_printk(kern_level, mp, &vaf); \ | 54 | __xfs_printk(kern_level, mp, &vaf); \ |
55 | va_end(args); \ | 55 | va_end(args); \ |
56 | } \ | 56 | } \ |
57 | 57 | ||
58 | define_xfs_printk_level(xfs_emerg, KERN_EMERG); | 58 | define_xfs_printk_level(xfs_emerg, KERN_EMERG); |
59 | define_xfs_printk_level(xfs_alert, KERN_ALERT); | 59 | define_xfs_printk_level(xfs_alert, KERN_ALERT); |
60 | define_xfs_printk_level(xfs_crit, KERN_CRIT); | 60 | define_xfs_printk_level(xfs_crit, KERN_CRIT); |
61 | define_xfs_printk_level(xfs_err, KERN_ERR); | 61 | define_xfs_printk_level(xfs_err, KERN_ERR); |
62 | define_xfs_printk_level(xfs_warn, KERN_WARNING); | 62 | define_xfs_printk_level(xfs_warn, KERN_WARNING); |
63 | define_xfs_printk_level(xfs_notice, KERN_NOTICE); | 63 | define_xfs_printk_level(xfs_notice, KERN_NOTICE); |
64 | define_xfs_printk_level(xfs_info, KERN_INFO); | 64 | define_xfs_printk_level(xfs_info, KERN_INFO); |
65 | #ifdef DEBUG | 65 | #ifdef DEBUG |
66 | define_xfs_printk_level(xfs_debug, KERN_DEBUG); | 66 | define_xfs_printk_level(xfs_debug, KERN_DEBUG); |
67 | #endif | 67 | #endif |
68 | 68 | ||
69 | void | 69 | void |
70 | xfs_alert_tag( | 70 | xfs_alert_tag( |
71 | const struct xfs_mount *mp, | 71 | const struct xfs_mount *mp, |
72 | int panic_tag, | 72 | int panic_tag, |
73 | const char *fmt, ...) | 73 | const char *fmt, ...) |
74 | { | 74 | { |
75 | struct va_format vaf; | 75 | struct va_format vaf; |
76 | va_list args; | 76 | va_list args; |
77 | int do_panic = 0; | 77 | int do_panic = 0; |
78 | 78 | ||
79 | if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) { | 79 | if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) { |
80 | xfs_alert(mp, "Transforming an alert into a BUG."); | 80 | xfs_alert(mp, "Transforming an alert into a BUG."); |
81 | do_panic = 1; | 81 | do_panic = 1; |
82 | } | 82 | } |
83 | 83 | ||
84 | va_start(args, fmt); | 84 | va_start(args, fmt); |
85 | 85 | ||
86 | vaf.fmt = fmt; | 86 | vaf.fmt = fmt; |
87 | vaf.va = &args; | 87 | vaf.va = &args; |
88 | 88 | ||
89 | __xfs_printk(KERN_ALERT, mp, &vaf); | 89 | __xfs_printk(KERN_ALERT, mp, &vaf); |
90 | va_end(args); | 90 | va_end(args); |
91 | 91 | ||
92 | BUG_ON(do_panic); | 92 | BUG_ON(do_panic); |
93 | } | 93 | } |
94 | 94 | ||
95 | void | 95 | void |
96 | asswarn(char *expr, char *file, int line) | ||
97 | { | ||
98 | xfs_warn(NULL, "Assertion failed: %s, file: %s, line: %d", | ||
99 | expr, file, line); | ||
100 | WARN_ON(1); | ||
101 | } | ||
102 | |||
103 | void | ||
96 | assfail(char *expr, char *file, int line) | 104 | assfail(char *expr, char *file, int line) |
97 | { | 105 | { |
98 | xfs_emerg(NULL, "Assertion failed: %s, file: %s, line: %d", | 106 | xfs_emerg(NULL, "Assertion failed: %s, file: %s, line: %d", |
99 | expr, file, line); | 107 | expr, file, line); |
100 | BUG(); | 108 | BUG(); |
101 | } | 109 | } |
102 | 110 | ||
103 | void | 111 | void |
104 | xfs_hex_dump(void *p, int length) | 112 | xfs_hex_dump(void *p, int length) |
105 | { | 113 | { |
106 | print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_ADDRESS, 16, 1, p, length, 1); | 114 | print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_ADDRESS, 16, 1, p, length, 1); |
107 | } | 115 | } |
108 | 116 |
fs/xfs/xfs_message.h
1 | #ifndef __XFS_MESSAGE_H | 1 | #ifndef __XFS_MESSAGE_H |
2 | #define __XFS_MESSAGE_H 1 | 2 | #define __XFS_MESSAGE_H 1 |
3 | 3 | ||
4 | struct xfs_mount; | 4 | struct xfs_mount; |
5 | 5 | ||
6 | extern __printf(2, 3) | 6 | extern __printf(2, 3) |
7 | void xfs_emerg(const struct xfs_mount *mp, const char *fmt, ...); | 7 | void xfs_emerg(const struct xfs_mount *mp, const char *fmt, ...); |
8 | extern __printf(2, 3) | 8 | extern __printf(2, 3) |
9 | void xfs_alert(const struct xfs_mount *mp, const char *fmt, ...); | 9 | void xfs_alert(const struct xfs_mount *mp, const char *fmt, ...); |
10 | extern __printf(3, 4) | 10 | extern __printf(3, 4) |
11 | void xfs_alert_tag(const struct xfs_mount *mp, int tag, const char *fmt, ...); | 11 | void xfs_alert_tag(const struct xfs_mount *mp, int tag, const char *fmt, ...); |
12 | extern __printf(2, 3) | 12 | extern __printf(2, 3) |
13 | void xfs_crit(const struct xfs_mount *mp, const char *fmt, ...); | 13 | void xfs_crit(const struct xfs_mount *mp, const char *fmt, ...); |
14 | extern __printf(2, 3) | 14 | extern __printf(2, 3) |
15 | void xfs_err(const struct xfs_mount *mp, const char *fmt, ...); | 15 | void xfs_err(const struct xfs_mount *mp, const char *fmt, ...); |
16 | extern __printf(2, 3) | 16 | extern __printf(2, 3) |
17 | void xfs_warn(const struct xfs_mount *mp, const char *fmt, ...); | 17 | void xfs_warn(const struct xfs_mount *mp, const char *fmt, ...); |
18 | extern __printf(2, 3) | 18 | extern __printf(2, 3) |
19 | void xfs_notice(const struct xfs_mount *mp, const char *fmt, ...); | 19 | void xfs_notice(const struct xfs_mount *mp, const char *fmt, ...); |
20 | extern __printf(2, 3) | 20 | extern __printf(2, 3) |
21 | void xfs_info(const struct xfs_mount *mp, const char *fmt, ...); | 21 | void xfs_info(const struct xfs_mount *mp, const char *fmt, ...); |
22 | 22 | ||
23 | #ifdef DEBUG | 23 | #ifdef DEBUG |
24 | extern __printf(2, 3) | 24 | extern __printf(2, 3) |
25 | void xfs_debug(const struct xfs_mount *mp, const char *fmt, ...); | 25 | void xfs_debug(const struct xfs_mount *mp, const char *fmt, ...); |
26 | #else | 26 | #else |
27 | static inline __printf(2, 3) | 27 | static inline __printf(2, 3) |
28 | void xfs_debug(const struct xfs_mount *mp, const char *fmt, ...) | 28 | void xfs_debug(const struct xfs_mount *mp, const char *fmt, ...) |
29 | { | 29 | { |
30 | } | 30 | } |
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | #define xfs_printk_ratelimited(func, dev, fmt, ...) \ | 33 | #define xfs_printk_ratelimited(func, dev, fmt, ...) \ |
34 | do { \ | 34 | do { \ |
35 | static DEFINE_RATELIMIT_STATE(_rs, \ | 35 | static DEFINE_RATELIMIT_STATE(_rs, \ |
36 | DEFAULT_RATELIMIT_INTERVAL, \ | 36 | DEFAULT_RATELIMIT_INTERVAL, \ |
37 | DEFAULT_RATELIMIT_BURST); \ | 37 | DEFAULT_RATELIMIT_BURST); \ |
38 | if (__ratelimit(&_rs)) \ | 38 | if (__ratelimit(&_rs)) \ |
39 | func(dev, fmt, ##__VA_ARGS__); \ | 39 | func(dev, fmt, ##__VA_ARGS__); \ |
40 | } while (0) | 40 | } while (0) |
41 | 41 | ||
42 | #define xfs_emerg_ratelimited(dev, fmt, ...) \ | 42 | #define xfs_emerg_ratelimited(dev, fmt, ...) \ |
43 | xfs_printk_ratelimited(xfs_emerg, dev, fmt, ##__VA_ARGS__) | 43 | xfs_printk_ratelimited(xfs_emerg, dev, fmt, ##__VA_ARGS__) |
44 | #define xfs_alert_ratelimited(dev, fmt, ...) \ | 44 | #define xfs_alert_ratelimited(dev, fmt, ...) \ |
45 | xfs_printk_ratelimited(xfs_alert, dev, fmt, ##__VA_ARGS__) | 45 | xfs_printk_ratelimited(xfs_alert, dev, fmt, ##__VA_ARGS__) |
46 | #define xfs_crit_ratelimited(dev, fmt, ...) \ | 46 | #define xfs_crit_ratelimited(dev, fmt, ...) \ |
47 | xfs_printk_ratelimited(xfs_crit, dev, fmt, ##__VA_ARGS__) | 47 | xfs_printk_ratelimited(xfs_crit, dev, fmt, ##__VA_ARGS__) |
48 | #define xfs_err_ratelimited(dev, fmt, ...) \ | 48 | #define xfs_err_ratelimited(dev, fmt, ...) \ |
49 | xfs_printk_ratelimited(xfs_err, dev, fmt, ##__VA_ARGS__) | 49 | xfs_printk_ratelimited(xfs_err, dev, fmt, ##__VA_ARGS__) |
50 | #define xfs_warn_ratelimited(dev, fmt, ...) \ | 50 | #define xfs_warn_ratelimited(dev, fmt, ...) \ |
51 | xfs_printk_ratelimited(xfs_warn, dev, fmt, ##__VA_ARGS__) | 51 | xfs_printk_ratelimited(xfs_warn, dev, fmt, ##__VA_ARGS__) |
52 | #define xfs_notice_ratelimited(dev, fmt, ...) \ | 52 | #define xfs_notice_ratelimited(dev, fmt, ...) \ |
53 | xfs_printk_ratelimited(xfs_notice, dev, fmt, ##__VA_ARGS__) | 53 | xfs_printk_ratelimited(xfs_notice, dev, fmt, ##__VA_ARGS__) |
54 | #define xfs_info_ratelimited(dev, fmt, ...) \ | 54 | #define xfs_info_ratelimited(dev, fmt, ...) \ |
55 | xfs_printk_ratelimited(xfs_info, dev, fmt, ##__VA_ARGS__) | 55 | xfs_printk_ratelimited(xfs_info, dev, fmt, ##__VA_ARGS__) |
56 | #define xfs_debug_ratelimited(dev, fmt, ...) \ | 56 | #define xfs_debug_ratelimited(dev, fmt, ...) \ |
57 | xfs_printk_ratelimited(xfs_debug, dev, fmt, ##__VA_ARGS__) | 57 | xfs_printk_ratelimited(xfs_debug, dev, fmt, ##__VA_ARGS__) |
58 | 58 | ||
59 | extern void assfail(char *expr, char *f, int l); | 59 | extern void assfail(char *expr, char *f, int l); |
60 | extern void asswarn(char *expr, char *f, int l); | ||
60 | 61 | ||
61 | extern void xfs_hex_dump(void *p, int length); | 62 | extern void xfs_hex_dump(void *p, int length); |
62 | 63 | ||
63 | #endif /* __XFS_MESSAGE_H */ | 64 | #endif /* __XFS_MESSAGE_H */ |
64 | 65 |
fs/xfs/xfs_trans.h
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | 6 | * modify it under the terms of the GNU General Public License as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | * | 8 | * |
9 | * This program is distributed in the hope that it would be useful, | 9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | #ifndef __XFS_TRANS_H__ | 18 | #ifndef __XFS_TRANS_H__ |
19 | #define __XFS_TRANS_H__ | 19 | #define __XFS_TRANS_H__ |
20 | 20 | ||
21 | struct xfs_log_item; | 21 | struct xfs_log_item; |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * This is the structure written in the log at the head of | 24 | * This is the structure written in the log at the head of |
25 | * every transaction. It identifies the type and id of the | 25 | * every transaction. It identifies the type and id of the |
26 | * transaction, and contains the number of items logged by | 26 | * transaction, and contains the number of items logged by |
27 | * the transaction so we know how many to expect during recovery. | 27 | * the transaction so we know how many to expect during recovery. |
28 | * | 28 | * |
29 | * Do not change the below structure without redoing the code in | 29 | * Do not change the below structure without redoing the code in |
30 | * xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans(). | 30 | * xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans(). |
31 | */ | 31 | */ |
32 | typedef struct xfs_trans_header { | 32 | typedef struct xfs_trans_header { |
33 | uint th_magic; /* magic number */ | 33 | uint th_magic; /* magic number */ |
34 | uint th_type; /* transaction type */ | 34 | uint th_type; /* transaction type */ |
35 | __int32_t th_tid; /* transaction id (unused) */ | 35 | __int32_t th_tid; /* transaction id (unused) */ |
36 | uint th_num_items; /* num items logged by trans */ | 36 | uint th_num_items; /* num items logged by trans */ |
37 | } xfs_trans_header_t; | 37 | } xfs_trans_header_t; |
38 | 38 | ||
39 | #define XFS_TRANS_HEADER_MAGIC 0x5452414e /* TRAN */ | 39 | #define XFS_TRANS_HEADER_MAGIC 0x5452414e /* TRAN */ |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * Log item types. | 42 | * Log item types. |
43 | */ | 43 | */ |
44 | #define XFS_LI_EFI 0x1236 | 44 | #define XFS_LI_EFI 0x1236 |
45 | #define XFS_LI_EFD 0x1237 | 45 | #define XFS_LI_EFD 0x1237 |
46 | #define XFS_LI_IUNLINK 0x1238 | 46 | #define XFS_LI_IUNLINK 0x1238 |
47 | #define XFS_LI_INODE 0x123b /* aligned ino chunks, var-size ibufs */ | 47 | #define XFS_LI_INODE 0x123b /* aligned ino chunks, var-size ibufs */ |
48 | #define XFS_LI_BUF 0x123c /* v2 bufs, variable sized inode bufs */ | 48 | #define XFS_LI_BUF 0x123c /* v2 bufs, variable sized inode bufs */ |
49 | #define XFS_LI_DQUOT 0x123d | 49 | #define XFS_LI_DQUOT 0x123d |
50 | #define XFS_LI_QUOTAOFF 0x123e | 50 | #define XFS_LI_QUOTAOFF 0x123e |
51 | 51 | ||
52 | #define XFS_LI_TYPE_DESC \ | 52 | #define XFS_LI_TYPE_DESC \ |
53 | { XFS_LI_EFI, "XFS_LI_EFI" }, \ | 53 | { XFS_LI_EFI, "XFS_LI_EFI" }, \ |
54 | { XFS_LI_EFD, "XFS_LI_EFD" }, \ | 54 | { XFS_LI_EFD, "XFS_LI_EFD" }, \ |
55 | { XFS_LI_IUNLINK, "XFS_LI_IUNLINK" }, \ | 55 | { XFS_LI_IUNLINK, "XFS_LI_IUNLINK" }, \ |
56 | { XFS_LI_INODE, "XFS_LI_INODE" }, \ | 56 | { XFS_LI_INODE, "XFS_LI_INODE" }, \ |
57 | { XFS_LI_BUF, "XFS_LI_BUF" }, \ | 57 | { XFS_LI_BUF, "XFS_LI_BUF" }, \ |
58 | { XFS_LI_DQUOT, "XFS_LI_DQUOT" }, \ | 58 | { XFS_LI_DQUOT, "XFS_LI_DQUOT" }, \ |
59 | { XFS_LI_QUOTAOFF, "XFS_LI_QUOTAOFF" } | 59 | { XFS_LI_QUOTAOFF, "XFS_LI_QUOTAOFF" } |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * Transaction types. Used to distinguish types of buffers. | 62 | * Transaction types. Used to distinguish types of buffers. |
63 | */ | 63 | */ |
64 | #define XFS_TRANS_SETATTR_NOT_SIZE 1 | 64 | #define XFS_TRANS_SETATTR_NOT_SIZE 1 |
65 | #define XFS_TRANS_SETATTR_SIZE 2 | 65 | #define XFS_TRANS_SETATTR_SIZE 2 |
66 | #define XFS_TRANS_INACTIVE 3 | 66 | #define XFS_TRANS_INACTIVE 3 |
67 | #define XFS_TRANS_CREATE 4 | 67 | #define XFS_TRANS_CREATE 4 |
68 | #define XFS_TRANS_CREATE_TRUNC 5 | 68 | #define XFS_TRANS_CREATE_TRUNC 5 |
69 | #define XFS_TRANS_TRUNCATE_FILE 6 | 69 | #define XFS_TRANS_TRUNCATE_FILE 6 |
70 | #define XFS_TRANS_REMOVE 7 | 70 | #define XFS_TRANS_REMOVE 7 |
71 | #define XFS_TRANS_LINK 8 | 71 | #define XFS_TRANS_LINK 8 |
72 | #define XFS_TRANS_RENAME 9 | 72 | #define XFS_TRANS_RENAME 9 |
73 | #define XFS_TRANS_MKDIR 10 | 73 | #define XFS_TRANS_MKDIR 10 |
74 | #define XFS_TRANS_RMDIR 11 | 74 | #define XFS_TRANS_RMDIR 11 |
75 | #define XFS_TRANS_SYMLINK 12 | 75 | #define XFS_TRANS_SYMLINK 12 |
76 | #define XFS_TRANS_SET_DMATTRS 13 | 76 | #define XFS_TRANS_SET_DMATTRS 13 |
77 | #define XFS_TRANS_GROWFS 14 | 77 | #define XFS_TRANS_GROWFS 14 |
78 | #define XFS_TRANS_STRAT_WRITE 15 | 78 | #define XFS_TRANS_STRAT_WRITE 15 |
79 | #define XFS_TRANS_DIOSTRAT 16 | 79 | #define XFS_TRANS_DIOSTRAT 16 |
80 | /* 17 was XFS_TRANS_WRITE_SYNC */ | 80 | /* 17 was XFS_TRANS_WRITE_SYNC */ |
81 | #define XFS_TRANS_WRITEID 18 | 81 | #define XFS_TRANS_WRITEID 18 |
82 | #define XFS_TRANS_ADDAFORK 19 | 82 | #define XFS_TRANS_ADDAFORK 19 |
83 | #define XFS_TRANS_ATTRINVAL 20 | 83 | #define XFS_TRANS_ATTRINVAL 20 |
84 | #define XFS_TRANS_ATRUNCATE 21 | 84 | #define XFS_TRANS_ATRUNCATE 21 |
85 | #define XFS_TRANS_ATTR_SET 22 | 85 | #define XFS_TRANS_ATTR_SET 22 |
86 | #define XFS_TRANS_ATTR_RM 23 | 86 | #define XFS_TRANS_ATTR_RM 23 |
87 | #define XFS_TRANS_ATTR_FLAG 24 | 87 | #define XFS_TRANS_ATTR_FLAG 24 |
88 | #define XFS_TRANS_CLEAR_AGI_BUCKET 25 | 88 | #define XFS_TRANS_CLEAR_AGI_BUCKET 25 |
89 | #define XFS_TRANS_QM_SBCHANGE 26 | 89 | #define XFS_TRANS_QM_SBCHANGE 26 |
90 | /* | 90 | /* |
91 | * Dummy entries since we use the transaction type to index into the | 91 | * Dummy entries since we use the transaction type to index into the |
92 | * trans_type[] in xlog_recover_print_trans_head() | 92 | * trans_type[] in xlog_recover_print_trans_head() |
93 | */ | 93 | */ |
94 | #define XFS_TRANS_DUMMY1 27 | 94 | #define XFS_TRANS_DUMMY1 27 |
95 | #define XFS_TRANS_DUMMY2 28 | 95 | #define XFS_TRANS_DUMMY2 28 |
96 | #define XFS_TRANS_QM_QUOTAOFF 29 | 96 | #define XFS_TRANS_QM_QUOTAOFF 29 |
97 | #define XFS_TRANS_QM_DQALLOC 30 | 97 | #define XFS_TRANS_QM_DQALLOC 30 |
98 | #define XFS_TRANS_QM_SETQLIM 31 | 98 | #define XFS_TRANS_QM_SETQLIM 31 |
99 | #define XFS_TRANS_QM_DQCLUSTER 32 | 99 | #define XFS_TRANS_QM_DQCLUSTER 32 |
100 | #define XFS_TRANS_QM_QINOCREATE 33 | 100 | #define XFS_TRANS_QM_QINOCREATE 33 |
101 | #define XFS_TRANS_QM_QUOTAOFF_END 34 | 101 | #define XFS_TRANS_QM_QUOTAOFF_END 34 |
102 | #define XFS_TRANS_SB_UNIT 35 | 102 | #define XFS_TRANS_SB_UNIT 35 |
103 | #define XFS_TRANS_FSYNC_TS 36 | 103 | #define XFS_TRANS_FSYNC_TS 36 |
104 | #define XFS_TRANS_GROWFSRT_ALLOC 37 | 104 | #define XFS_TRANS_GROWFSRT_ALLOC 37 |
105 | #define XFS_TRANS_GROWFSRT_ZERO 38 | 105 | #define XFS_TRANS_GROWFSRT_ZERO 38 |
106 | #define XFS_TRANS_GROWFSRT_FREE 39 | 106 | #define XFS_TRANS_GROWFSRT_FREE 39 |
107 | #define XFS_TRANS_SWAPEXT 40 | 107 | #define XFS_TRANS_SWAPEXT 40 |
108 | #define XFS_TRANS_SB_COUNT 41 | 108 | #define XFS_TRANS_SB_COUNT 41 |
109 | #define XFS_TRANS_CHECKPOINT 42 | 109 | #define XFS_TRANS_CHECKPOINT 42 |
110 | #define XFS_TRANS_TYPE_MAX 42 | 110 | #define XFS_TRANS_TYPE_MAX 42 |
111 | /* new transaction types need to be reflected in xfs_logprint(8) */ | 111 | /* new transaction types need to be reflected in xfs_logprint(8) */ |
112 | 112 | ||
113 | #define XFS_TRANS_TYPES \ | 113 | #define XFS_TRANS_TYPES \ |
114 | { XFS_TRANS_SETATTR_NOT_SIZE, "SETATTR_NOT_SIZE" }, \ | 114 | { XFS_TRANS_SETATTR_NOT_SIZE, "SETATTR_NOT_SIZE" }, \ |
115 | { XFS_TRANS_SETATTR_SIZE, "SETATTR_SIZE" }, \ | 115 | { XFS_TRANS_SETATTR_SIZE, "SETATTR_SIZE" }, \ |
116 | { XFS_TRANS_INACTIVE, "INACTIVE" }, \ | 116 | { XFS_TRANS_INACTIVE, "INACTIVE" }, \ |
117 | { XFS_TRANS_CREATE, "CREATE" }, \ | 117 | { XFS_TRANS_CREATE, "CREATE" }, \ |
118 | { XFS_TRANS_CREATE_TRUNC, "CREATE_TRUNC" }, \ | 118 | { XFS_TRANS_CREATE_TRUNC, "CREATE_TRUNC" }, \ |
119 | { XFS_TRANS_TRUNCATE_FILE, "TRUNCATE_FILE" }, \ | 119 | { XFS_TRANS_TRUNCATE_FILE, "TRUNCATE_FILE" }, \ |
120 | { XFS_TRANS_REMOVE, "REMOVE" }, \ | 120 | { XFS_TRANS_REMOVE, "REMOVE" }, \ |
121 | { XFS_TRANS_LINK, "LINK" }, \ | 121 | { XFS_TRANS_LINK, "LINK" }, \ |
122 | { XFS_TRANS_RENAME, "RENAME" }, \ | 122 | { XFS_TRANS_RENAME, "RENAME" }, \ |
123 | { XFS_TRANS_MKDIR, "MKDIR" }, \ | 123 | { XFS_TRANS_MKDIR, "MKDIR" }, \ |
124 | { XFS_TRANS_RMDIR, "RMDIR" }, \ | 124 | { XFS_TRANS_RMDIR, "RMDIR" }, \ |
125 | { XFS_TRANS_SYMLINK, "SYMLINK" }, \ | 125 | { XFS_TRANS_SYMLINK, "SYMLINK" }, \ |
126 | { XFS_TRANS_SET_DMATTRS, "SET_DMATTRS" }, \ | 126 | { XFS_TRANS_SET_DMATTRS, "SET_DMATTRS" }, \ |
127 | { XFS_TRANS_GROWFS, "GROWFS" }, \ | 127 | { XFS_TRANS_GROWFS, "GROWFS" }, \ |
128 | { XFS_TRANS_STRAT_WRITE, "STRAT_WRITE" }, \ | 128 | { XFS_TRANS_STRAT_WRITE, "STRAT_WRITE" }, \ |
129 | { XFS_TRANS_DIOSTRAT, "DIOSTRAT" }, \ | 129 | { XFS_TRANS_DIOSTRAT, "DIOSTRAT" }, \ |
130 | { XFS_TRANS_WRITEID, "WRITEID" }, \ | 130 | { XFS_TRANS_WRITEID, "WRITEID" }, \ |
131 | { XFS_TRANS_ADDAFORK, "ADDAFORK" }, \ | 131 | { XFS_TRANS_ADDAFORK, "ADDAFORK" }, \ |
132 | { XFS_TRANS_ATTRINVAL, "ATTRINVAL" }, \ | 132 | { XFS_TRANS_ATTRINVAL, "ATTRINVAL" }, \ |
133 | { XFS_TRANS_ATRUNCATE, "ATRUNCATE" }, \ | 133 | { XFS_TRANS_ATRUNCATE, "ATRUNCATE" }, \ |
134 | { XFS_TRANS_ATTR_SET, "ATTR_SET" }, \ | 134 | { XFS_TRANS_ATTR_SET, "ATTR_SET" }, \ |
135 | { XFS_TRANS_ATTR_RM, "ATTR_RM" }, \ | 135 | { XFS_TRANS_ATTR_RM, "ATTR_RM" }, \ |
136 | { XFS_TRANS_ATTR_FLAG, "ATTR_FLAG" }, \ | 136 | { XFS_TRANS_ATTR_FLAG, "ATTR_FLAG" }, \ |
137 | { XFS_TRANS_CLEAR_AGI_BUCKET, "CLEAR_AGI_BUCKET" }, \ | 137 | { XFS_TRANS_CLEAR_AGI_BUCKET, "CLEAR_AGI_BUCKET" }, \ |
138 | { XFS_TRANS_QM_SBCHANGE, "QM_SBCHANGE" }, \ | 138 | { XFS_TRANS_QM_SBCHANGE, "QM_SBCHANGE" }, \ |
139 | { XFS_TRANS_QM_QUOTAOFF, "QM_QUOTAOFF" }, \ | 139 | { XFS_TRANS_QM_QUOTAOFF, "QM_QUOTAOFF" }, \ |
140 | { XFS_TRANS_QM_DQALLOC, "QM_DQALLOC" }, \ | 140 | { XFS_TRANS_QM_DQALLOC, "QM_DQALLOC" }, \ |
141 | { XFS_TRANS_QM_SETQLIM, "QM_SETQLIM" }, \ | 141 | { XFS_TRANS_QM_SETQLIM, "QM_SETQLIM" }, \ |
142 | { XFS_TRANS_QM_DQCLUSTER, "QM_DQCLUSTER" }, \ | 142 | { XFS_TRANS_QM_DQCLUSTER, "QM_DQCLUSTER" }, \ |
143 | { XFS_TRANS_QM_QINOCREATE, "QM_QINOCREATE" }, \ | 143 | { XFS_TRANS_QM_QINOCREATE, "QM_QINOCREATE" }, \ |
144 | { XFS_TRANS_QM_QUOTAOFF_END, "QM_QOFF_END" }, \ | 144 | { XFS_TRANS_QM_QUOTAOFF_END, "QM_QOFF_END" }, \ |
145 | { XFS_TRANS_SB_UNIT, "SB_UNIT" }, \ | 145 | { XFS_TRANS_SB_UNIT, "SB_UNIT" }, \ |
146 | { XFS_TRANS_FSYNC_TS, "FSYNC_TS" }, \ | 146 | { XFS_TRANS_FSYNC_TS, "FSYNC_TS" }, \ |
147 | { XFS_TRANS_GROWFSRT_ALLOC, "GROWFSRT_ALLOC" }, \ | 147 | { XFS_TRANS_GROWFSRT_ALLOC, "GROWFSRT_ALLOC" }, \ |
148 | { XFS_TRANS_GROWFSRT_ZERO, "GROWFSRT_ZERO" }, \ | 148 | { XFS_TRANS_GROWFSRT_ZERO, "GROWFSRT_ZERO" }, \ |
149 | { XFS_TRANS_GROWFSRT_FREE, "GROWFSRT_FREE" }, \ | 149 | { XFS_TRANS_GROWFSRT_FREE, "GROWFSRT_FREE" }, \ |
150 | { XFS_TRANS_SWAPEXT, "SWAPEXT" }, \ | 150 | { XFS_TRANS_SWAPEXT, "SWAPEXT" }, \ |
151 | { XFS_TRANS_SB_COUNT, "SB_COUNT" }, \ | 151 | { XFS_TRANS_SB_COUNT, "SB_COUNT" }, \ |
152 | { XFS_TRANS_CHECKPOINT, "CHECKPOINT" }, \ | 152 | { XFS_TRANS_CHECKPOINT, "CHECKPOINT" }, \ |
153 | { XFS_TRANS_DUMMY1, "DUMMY1" }, \ | 153 | { XFS_TRANS_DUMMY1, "DUMMY1" }, \ |
154 | { XFS_TRANS_DUMMY2, "DUMMY2" }, \ | 154 | { XFS_TRANS_DUMMY2, "DUMMY2" }, \ |
155 | { XLOG_UNMOUNT_REC_TYPE, "UNMOUNT" } | 155 | { XLOG_UNMOUNT_REC_TYPE, "UNMOUNT" } |
156 | 156 | ||
157 | /* | 157 | /* |
158 | * This structure is used to track log items associated with | 158 | * This structure is used to track log items associated with |
159 | * a transaction. It points to the log item and keeps some | 159 | * a transaction. It points to the log item and keeps some |
160 | * flags to track the state of the log item. It also tracks | 160 | * flags to track the state of the log item. It also tracks |
161 | * the amount of space needed to log the item it describes | 161 | * the amount of space needed to log the item it describes |
162 | * once we get to commit processing (see xfs_trans_commit()). | 162 | * once we get to commit processing (see xfs_trans_commit()). |
163 | */ | 163 | */ |
164 | struct xfs_log_item_desc { | 164 | struct xfs_log_item_desc { |
165 | struct xfs_log_item *lid_item; | 165 | struct xfs_log_item *lid_item; |
166 | struct list_head lid_trans; | 166 | struct list_head lid_trans; |
167 | unsigned char lid_flags; | 167 | unsigned char lid_flags; |
168 | }; | 168 | }; |
169 | 169 | ||
170 | #define XFS_LID_DIRTY 0x1 | 170 | #define XFS_LID_DIRTY 0x1 |
171 | 171 | ||
172 | #define XFS_TRANS_MAGIC 0x5452414E /* 'TRAN' */ | 172 | #define XFS_TRANS_MAGIC 0x5452414E /* 'TRAN' */ |
173 | /* | 173 | /* |
174 | * Values for t_flags. | 174 | * Values for t_flags. |
175 | */ | 175 | */ |
176 | #define XFS_TRANS_DIRTY 0x01 /* something needs to be logged */ | 176 | #define XFS_TRANS_DIRTY 0x01 /* something needs to be logged */ |
177 | #define XFS_TRANS_SB_DIRTY 0x02 /* superblock is modified */ | 177 | #define XFS_TRANS_SB_DIRTY 0x02 /* superblock is modified */ |
178 | #define XFS_TRANS_PERM_LOG_RES 0x04 /* xact took a permanent log res */ | 178 | #define XFS_TRANS_PERM_LOG_RES 0x04 /* xact took a permanent log res */ |
179 | #define XFS_TRANS_SYNC 0x08 /* make commit synchronous */ | 179 | #define XFS_TRANS_SYNC 0x08 /* make commit synchronous */ |
180 | #define XFS_TRANS_DQ_DIRTY 0x10 /* at least one dquot in trx dirty */ | 180 | #define XFS_TRANS_DQ_DIRTY 0x10 /* at least one dquot in trx dirty */ |
181 | #define XFS_TRANS_RESERVE 0x20 /* OK to use reserved data blocks */ | 181 | #define XFS_TRANS_RESERVE 0x20 /* OK to use reserved data blocks */ |
182 | #define XFS_TRANS_FREEZE_PROT 0x40 /* Transaction has elevated writer | 182 | #define XFS_TRANS_FREEZE_PROT 0x40 /* Transaction has elevated writer |
183 | count in superblock */ | 183 | count in superblock */ |
184 | 184 | ||
185 | /* | 185 | /* |
186 | * Values for call flags parameter. | 186 | * Values for call flags parameter. |
187 | */ | 187 | */ |
188 | #define XFS_TRANS_RELEASE_LOG_RES 0x4 | 188 | #define XFS_TRANS_RELEASE_LOG_RES 0x4 |
189 | #define XFS_TRANS_ABORT 0x8 | 189 | #define XFS_TRANS_ABORT 0x8 |
190 | 190 | ||
191 | /* | 191 | /* |
192 | * Field values for xfs_trans_mod_sb. | 192 | * Field values for xfs_trans_mod_sb. |
193 | */ | 193 | */ |
194 | #define XFS_TRANS_SB_ICOUNT 0x00000001 | 194 | #define XFS_TRANS_SB_ICOUNT 0x00000001 |
195 | #define XFS_TRANS_SB_IFREE 0x00000002 | 195 | #define XFS_TRANS_SB_IFREE 0x00000002 |
196 | #define XFS_TRANS_SB_FDBLOCKS 0x00000004 | 196 | #define XFS_TRANS_SB_FDBLOCKS 0x00000004 |
197 | #define XFS_TRANS_SB_RES_FDBLOCKS 0x00000008 | 197 | #define XFS_TRANS_SB_RES_FDBLOCKS 0x00000008 |
198 | #define XFS_TRANS_SB_FREXTENTS 0x00000010 | 198 | #define XFS_TRANS_SB_FREXTENTS 0x00000010 |
199 | #define XFS_TRANS_SB_RES_FREXTENTS 0x00000020 | 199 | #define XFS_TRANS_SB_RES_FREXTENTS 0x00000020 |
200 | #define XFS_TRANS_SB_DBLOCKS 0x00000040 | 200 | #define XFS_TRANS_SB_DBLOCKS 0x00000040 |
201 | #define XFS_TRANS_SB_AGCOUNT 0x00000080 | 201 | #define XFS_TRANS_SB_AGCOUNT 0x00000080 |
202 | #define XFS_TRANS_SB_IMAXPCT 0x00000100 | 202 | #define XFS_TRANS_SB_IMAXPCT 0x00000100 |
203 | #define XFS_TRANS_SB_REXTSIZE 0x00000200 | 203 | #define XFS_TRANS_SB_REXTSIZE 0x00000200 |
204 | #define XFS_TRANS_SB_RBMBLOCKS 0x00000400 | 204 | #define XFS_TRANS_SB_RBMBLOCKS 0x00000400 |
205 | #define XFS_TRANS_SB_RBLOCKS 0x00000800 | 205 | #define XFS_TRANS_SB_RBLOCKS 0x00000800 |
206 | #define XFS_TRANS_SB_REXTENTS 0x00001000 | 206 | #define XFS_TRANS_SB_REXTENTS 0x00001000 |
207 | #define XFS_TRANS_SB_REXTSLOG 0x00002000 | 207 | #define XFS_TRANS_SB_REXTSLOG 0x00002000 |
208 | 208 | ||
209 | 209 | ||
210 | /* | 210 | /* |
211 | * Per-extent log reservation for the allocation btree changes | 211 | * Per-extent log reservation for the allocation btree changes |
212 | * involved in freeing or allocating an extent. | 212 | * involved in freeing or allocating an extent. |
213 | * 2 trees * (2 blocks/level * max depth - 1) * block size | 213 | * 2 trees * (2 blocks/level * max depth - 1) * block size |
214 | */ | 214 | */ |
215 | #define XFS_ALLOCFREE_LOG_RES(mp,nx) \ | 215 | #define XFS_ALLOCFREE_LOG_RES(mp,nx) \ |
216 | ((nx) * (2 * XFS_FSB_TO_B((mp), 2 * XFS_AG_MAXLEVELS(mp) - 1))) | 216 | ((nx) * (2 * XFS_FSB_TO_B((mp), 2 * XFS_AG_MAXLEVELS(mp) - 1))) |
217 | #define XFS_ALLOCFREE_LOG_COUNT(mp,nx) \ | 217 | #define XFS_ALLOCFREE_LOG_COUNT(mp,nx) \ |
218 | ((nx) * (2 * (2 * XFS_AG_MAXLEVELS(mp) - 1))) | 218 | ((nx) * (2 * (2 * XFS_AG_MAXLEVELS(mp) - 1))) |
219 | 219 | ||
220 | /* | 220 | /* |
221 | * Per-directory log reservation for any directory change. | 221 | * Per-directory log reservation for any directory change. |
222 | * dir blocks: (1 btree block per level + data block + free block) * dblock size | 222 | * dir blocks: (1 btree block per level + data block + free block) * dblock size |
223 | * bmap btree: (levels + 2) * max depth * block size | 223 | * bmap btree: (levels + 2) * max depth * block size |
224 | * v2 directory blocks can be fragmented below the dirblksize down to the fsb | 224 | * v2 directory blocks can be fragmented below the dirblksize down to the fsb |
225 | * size, so account for that in the DAENTER macros. | 225 | * size, so account for that in the DAENTER macros. |
226 | */ | 226 | */ |
227 | #define XFS_DIROP_LOG_RES(mp) \ | 227 | #define XFS_DIROP_LOG_RES(mp) \ |
228 | (XFS_FSB_TO_B(mp, XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK)) + \ | 228 | (XFS_FSB_TO_B(mp, XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK)) + \ |
229 | (XFS_FSB_TO_B(mp, XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1))) | 229 | (XFS_FSB_TO_B(mp, XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1))) |
230 | #define XFS_DIROP_LOG_COUNT(mp) \ | 230 | #define XFS_DIROP_LOG_COUNT(mp) \ |
231 | (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \ | 231 | (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \ |
232 | XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1) | 232 | XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1) |
233 | 233 | ||
234 | 234 | ||
235 | #define XFS_WRITE_LOG_RES(mp) ((mp)->m_reservations.tr_write) | 235 | #define XFS_WRITE_LOG_RES(mp) ((mp)->m_reservations.tr_write) |
236 | #define XFS_ITRUNCATE_LOG_RES(mp) ((mp)->m_reservations.tr_itruncate) | 236 | #define XFS_ITRUNCATE_LOG_RES(mp) ((mp)->m_reservations.tr_itruncate) |
237 | #define XFS_RENAME_LOG_RES(mp) ((mp)->m_reservations.tr_rename) | 237 | #define XFS_RENAME_LOG_RES(mp) ((mp)->m_reservations.tr_rename) |
238 | #define XFS_LINK_LOG_RES(mp) ((mp)->m_reservations.tr_link) | 238 | #define XFS_LINK_LOG_RES(mp) ((mp)->m_reservations.tr_link) |
239 | #define XFS_REMOVE_LOG_RES(mp) ((mp)->m_reservations.tr_remove) | 239 | #define XFS_REMOVE_LOG_RES(mp) ((mp)->m_reservations.tr_remove) |
240 | #define XFS_SYMLINK_LOG_RES(mp) ((mp)->m_reservations.tr_symlink) | 240 | #define XFS_SYMLINK_LOG_RES(mp) ((mp)->m_reservations.tr_symlink) |
241 | #define XFS_CREATE_LOG_RES(mp) ((mp)->m_reservations.tr_create) | 241 | #define XFS_CREATE_LOG_RES(mp) ((mp)->m_reservations.tr_create) |
242 | #define XFS_MKDIR_LOG_RES(mp) ((mp)->m_reservations.tr_mkdir) | 242 | #define XFS_MKDIR_LOG_RES(mp) ((mp)->m_reservations.tr_mkdir) |
243 | #define XFS_IFREE_LOG_RES(mp) ((mp)->m_reservations.tr_ifree) | 243 | #define XFS_IFREE_LOG_RES(mp) ((mp)->m_reservations.tr_ifree) |
244 | #define XFS_ICHANGE_LOG_RES(mp) ((mp)->m_reservations.tr_ichange) | 244 | #define XFS_ICHANGE_LOG_RES(mp) ((mp)->m_reservations.tr_ichange) |
245 | #define XFS_GROWDATA_LOG_RES(mp) ((mp)->m_reservations.tr_growdata) | 245 | #define XFS_GROWDATA_LOG_RES(mp) ((mp)->m_reservations.tr_growdata) |
246 | #define XFS_GROWRTALLOC_LOG_RES(mp) ((mp)->m_reservations.tr_growrtalloc) | 246 | #define XFS_GROWRTALLOC_LOG_RES(mp) ((mp)->m_reservations.tr_growrtalloc) |
247 | #define XFS_GROWRTZERO_LOG_RES(mp) ((mp)->m_reservations.tr_growrtzero) | 247 | #define XFS_GROWRTZERO_LOG_RES(mp) ((mp)->m_reservations.tr_growrtzero) |
248 | #define XFS_GROWRTFREE_LOG_RES(mp) ((mp)->m_reservations.tr_growrtfree) | 248 | #define XFS_GROWRTFREE_LOG_RES(mp) ((mp)->m_reservations.tr_growrtfree) |
249 | #define XFS_SWRITE_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) | 249 | #define XFS_SWRITE_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) |
250 | /* | 250 | /* |
251 | * Logging the inode timestamps on an fsync -- same as SWRITE | 251 | * Logging the inode timestamps on an fsync -- same as SWRITE |
252 | * as long as SWRITE logs the entire inode core | 252 | * as long as SWRITE logs the entire inode core |
253 | */ | 253 | */ |
254 | #define XFS_FSYNC_TS_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) | 254 | #define XFS_FSYNC_TS_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) |
255 | #define XFS_WRITEID_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) | 255 | #define XFS_WRITEID_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) |
256 | #define XFS_ADDAFORK_LOG_RES(mp) ((mp)->m_reservations.tr_addafork) | 256 | #define XFS_ADDAFORK_LOG_RES(mp) ((mp)->m_reservations.tr_addafork) |
257 | #define XFS_ATTRINVAL_LOG_RES(mp) ((mp)->m_reservations.tr_attrinval) | 257 | #define XFS_ATTRINVAL_LOG_RES(mp) ((mp)->m_reservations.tr_attrinval) |
258 | #define XFS_ATTRSETM_LOG_RES(mp) ((mp)->m_reservations.tr_attrsetm) | 258 | #define XFS_ATTRSETM_LOG_RES(mp) ((mp)->m_reservations.tr_attrsetm) |
259 | #define XFS_ATTRSETRT_LOG_RES(mp) ((mp)->m_reservations.tr_attrsetrt) | 259 | #define XFS_ATTRSETRT_LOG_RES(mp) ((mp)->m_reservations.tr_attrsetrt) |
260 | #define XFS_ATTRRM_LOG_RES(mp) ((mp)->m_reservations.tr_attrrm) | 260 | #define XFS_ATTRRM_LOG_RES(mp) ((mp)->m_reservations.tr_attrrm) |
261 | #define XFS_CLEAR_AGI_BUCKET_LOG_RES(mp) ((mp)->m_reservations.tr_clearagi) | 261 | #define XFS_CLEAR_AGI_BUCKET_LOG_RES(mp) ((mp)->m_reservations.tr_clearagi) |
262 | #define XFS_QM_SBCHANGE_LOG_RES(mp) ((mp)->m_reservations.tr_qm_sbchange) | 262 | #define XFS_QM_SBCHANGE_LOG_RES(mp) ((mp)->m_reservations.tr_qm_sbchange) |
263 | #define XFS_QM_SETQLIM_LOG_RES(mp) ((mp)->m_reservations.tr_qm_setqlim) | 263 | #define XFS_QM_SETQLIM_LOG_RES(mp) ((mp)->m_reservations.tr_qm_setqlim) |
264 | #define XFS_QM_DQALLOC_LOG_RES(mp) ((mp)->m_reservations.tr_qm_dqalloc) | 264 | #define XFS_QM_DQALLOC_LOG_RES(mp) ((mp)->m_reservations.tr_qm_dqalloc) |
265 | #define XFS_QM_QUOTAOFF_LOG_RES(mp) ((mp)->m_reservations.tr_qm_quotaoff) | 265 | #define XFS_QM_QUOTAOFF_LOG_RES(mp) ((mp)->m_reservations.tr_qm_quotaoff) |
266 | #define XFS_QM_QUOTAOFF_END_LOG_RES(mp) ((mp)->m_reservations.tr_qm_equotaoff) | 266 | #define XFS_QM_QUOTAOFF_END_LOG_RES(mp) ((mp)->m_reservations.tr_qm_equotaoff) |
267 | #define XFS_SB_LOG_RES(mp) ((mp)->m_reservations.tr_sb) | 267 | #define XFS_SB_LOG_RES(mp) ((mp)->m_reservations.tr_sb) |
268 | 268 | ||
269 | /* | 269 | /* |
270 | * Various log count values. | 270 | * Various log count values. |
271 | */ | 271 | */ |
272 | #define XFS_DEFAULT_LOG_COUNT 1 | 272 | #define XFS_DEFAULT_LOG_COUNT 1 |
273 | #define XFS_DEFAULT_PERM_LOG_COUNT 2 | 273 | #define XFS_DEFAULT_PERM_LOG_COUNT 2 |
274 | #define XFS_ITRUNCATE_LOG_COUNT 2 | 274 | #define XFS_ITRUNCATE_LOG_COUNT 2 |
275 | #define XFS_INACTIVE_LOG_COUNT 2 | 275 | #define XFS_INACTIVE_LOG_COUNT 2 |
276 | #define XFS_CREATE_LOG_COUNT 2 | 276 | #define XFS_CREATE_LOG_COUNT 2 |
277 | #define XFS_MKDIR_LOG_COUNT 3 | 277 | #define XFS_MKDIR_LOG_COUNT 3 |
278 | #define XFS_SYMLINK_LOG_COUNT 3 | 278 | #define XFS_SYMLINK_LOG_COUNT 3 |
279 | #define XFS_REMOVE_LOG_COUNT 2 | 279 | #define XFS_REMOVE_LOG_COUNT 2 |
280 | #define XFS_LINK_LOG_COUNT 2 | 280 | #define XFS_LINK_LOG_COUNT 2 |
281 | #define XFS_RENAME_LOG_COUNT 2 | 281 | #define XFS_RENAME_LOG_COUNT 2 |
282 | #define XFS_WRITE_LOG_COUNT 2 | 282 | #define XFS_WRITE_LOG_COUNT 2 |
283 | #define XFS_ADDAFORK_LOG_COUNT 2 | 283 | #define XFS_ADDAFORK_LOG_COUNT 2 |
284 | #define XFS_ATTRINVAL_LOG_COUNT 1 | 284 | #define XFS_ATTRINVAL_LOG_COUNT 1 |
285 | #define XFS_ATTRSET_LOG_COUNT 3 | 285 | #define XFS_ATTRSET_LOG_COUNT 3 |
286 | #define XFS_ATTRRM_LOG_COUNT 3 | 286 | #define XFS_ATTRRM_LOG_COUNT 3 |
287 | 287 | ||
288 | /* | 288 | /* |
289 | * Here we centralize the specification of XFS meta-data buffer | 289 | * Here we centralize the specification of XFS meta-data buffer |
290 | * reference count values. This determine how hard the buffer | 290 | * reference count values. This determine how hard the buffer |
291 | * cache tries to hold onto the buffer. | 291 | * cache tries to hold onto the buffer. |
292 | */ | 292 | */ |
293 | #define XFS_AGF_REF 4 | 293 | #define XFS_AGF_REF 4 |
294 | #define XFS_AGI_REF 4 | 294 | #define XFS_AGI_REF 4 |
295 | #define XFS_AGFL_REF 3 | 295 | #define XFS_AGFL_REF 3 |
296 | #define XFS_INO_BTREE_REF 3 | 296 | #define XFS_INO_BTREE_REF 3 |
297 | #define XFS_ALLOC_BTREE_REF 2 | 297 | #define XFS_ALLOC_BTREE_REF 2 |
298 | #define XFS_BMAP_BTREE_REF 2 | 298 | #define XFS_BMAP_BTREE_REF 2 |
299 | #define XFS_DIR_BTREE_REF 2 | 299 | #define XFS_DIR_BTREE_REF 2 |
300 | #define XFS_INO_REF 2 | 300 | #define XFS_INO_REF 2 |
301 | #define XFS_ATTR_BTREE_REF 1 | 301 | #define XFS_ATTR_BTREE_REF 1 |
302 | #define XFS_DQUOT_REF 1 | 302 | #define XFS_DQUOT_REF 1 |
303 | 303 | ||
304 | #ifdef __KERNEL__ | 304 | #ifdef __KERNEL__ |
305 | 305 | ||
306 | struct xfs_buf; | 306 | struct xfs_buf; |
307 | struct xfs_buftarg; | 307 | struct xfs_buftarg; |
308 | struct xfs_efd_log_item; | 308 | struct xfs_efd_log_item; |
309 | struct xfs_efi_log_item; | 309 | struct xfs_efi_log_item; |
310 | struct xfs_inode; | 310 | struct xfs_inode; |
311 | struct xfs_item_ops; | 311 | struct xfs_item_ops; |
312 | struct xfs_log_iovec; | 312 | struct xfs_log_iovec; |
313 | struct xfs_log_item_desc; | 313 | struct xfs_log_item_desc; |
314 | struct xfs_mount; | 314 | struct xfs_mount; |
315 | struct xfs_trans; | 315 | struct xfs_trans; |
316 | struct xfs_dquot_acct; | 316 | struct xfs_dquot_acct; |
317 | struct xfs_busy_extent; | 317 | struct xfs_busy_extent; |
318 | 318 | ||
319 | typedef struct xfs_log_item { | 319 | typedef struct xfs_log_item { |
320 | struct list_head li_ail; /* AIL pointers */ | 320 | struct list_head li_ail; /* AIL pointers */ |
321 | xfs_lsn_t li_lsn; /* last on-disk lsn */ | 321 | xfs_lsn_t li_lsn; /* last on-disk lsn */ |
322 | struct xfs_log_item_desc *li_desc; /* ptr to current desc*/ | 322 | struct xfs_log_item_desc *li_desc; /* ptr to current desc*/ |
323 | struct xfs_mount *li_mountp; /* ptr to fs mount */ | 323 | struct xfs_mount *li_mountp; /* ptr to fs mount */ |
324 | struct xfs_ail *li_ailp; /* ptr to AIL */ | 324 | struct xfs_ail *li_ailp; /* ptr to AIL */ |
325 | uint li_type; /* item type */ | 325 | uint li_type; /* item type */ |
326 | uint li_flags; /* misc flags */ | 326 | uint li_flags; /* misc flags */ |
327 | struct xfs_log_item *li_bio_list; /* buffer item list */ | 327 | struct xfs_log_item *li_bio_list; /* buffer item list */ |
328 | void (*li_cb)(struct xfs_buf *, | 328 | void (*li_cb)(struct xfs_buf *, |
329 | struct xfs_log_item *); | 329 | struct xfs_log_item *); |
330 | /* buffer item iodone */ | 330 | /* buffer item iodone */ |
331 | /* callback func */ | 331 | /* callback func */ |
332 | const struct xfs_item_ops *li_ops; /* function list */ | 332 | const struct xfs_item_ops *li_ops; /* function list */ |
333 | 333 | ||
334 | /* delayed logging */ | 334 | /* delayed logging */ |
335 | struct list_head li_cil; /* CIL pointers */ | 335 | struct list_head li_cil; /* CIL pointers */ |
336 | struct xfs_log_vec *li_lv; /* active log vector */ | 336 | struct xfs_log_vec *li_lv; /* active log vector */ |
337 | xfs_lsn_t li_seq; /* CIL commit seq */ | 337 | xfs_lsn_t li_seq; /* CIL commit seq */ |
338 | } xfs_log_item_t; | 338 | } xfs_log_item_t; |
339 | 339 | ||
340 | #define XFS_LI_IN_AIL 0x1 | 340 | #define XFS_LI_IN_AIL 0x1 |
341 | #define XFS_LI_ABORTED 0x2 | 341 | #define XFS_LI_ABORTED 0x2 |
342 | 342 | ||
343 | #define XFS_LI_FLAGS \ | 343 | #define XFS_LI_FLAGS \ |
344 | { XFS_LI_IN_AIL, "IN_AIL" }, \ | 344 | { XFS_LI_IN_AIL, "IN_AIL" }, \ |
345 | { XFS_LI_ABORTED, "ABORTED" } | 345 | { XFS_LI_ABORTED, "ABORTED" } |
346 | 346 | ||
347 | struct xfs_item_ops { | 347 | struct xfs_item_ops { |
348 | uint (*iop_size)(xfs_log_item_t *); | 348 | uint (*iop_size)(xfs_log_item_t *); |
349 | void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *); | 349 | void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *); |
350 | void (*iop_pin)(xfs_log_item_t *); | 350 | void (*iop_pin)(xfs_log_item_t *); |
351 | void (*iop_unpin)(xfs_log_item_t *, int remove); | 351 | void (*iop_unpin)(xfs_log_item_t *, int remove); |
352 | uint (*iop_push)(struct xfs_log_item *, struct list_head *); | 352 | uint (*iop_push)(struct xfs_log_item *, struct list_head *); |
353 | void (*iop_unlock)(xfs_log_item_t *); | 353 | void (*iop_unlock)(xfs_log_item_t *); |
354 | xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t); | 354 | xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t); |
355 | void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t); | 355 | void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t); |
356 | }; | 356 | }; |
357 | 357 | ||
358 | #define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip) | 358 | #define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip) |
359 | #define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp) | 359 | #define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp) |
360 | #define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip) | 360 | #define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip) |
361 | #define IOP_UNPIN(ip, remove) (*(ip)->li_ops->iop_unpin)(ip, remove) | 361 | #define IOP_UNPIN(ip, remove) (*(ip)->li_ops->iop_unpin)(ip, remove) |
362 | #define IOP_PUSH(ip, list) (*(ip)->li_ops->iop_push)(ip, list) | 362 | #define IOP_PUSH(ip, list) (*(ip)->li_ops->iop_push)(ip, list) |
363 | #define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip) | 363 | #define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip) |
364 | #define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn) | 364 | #define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn) |
365 | #define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn) | 365 | #define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn) |
366 | 366 | ||
367 | /* | 367 | /* |
368 | * Return values for the IOP_PUSH() routines. | 368 | * Return values for the IOP_PUSH() routines. |
369 | */ | 369 | */ |
370 | #define XFS_ITEM_SUCCESS 0 | 370 | #define XFS_ITEM_SUCCESS 0 |
371 | #define XFS_ITEM_PINNED 1 | 371 | #define XFS_ITEM_PINNED 1 |
372 | #define XFS_ITEM_LOCKED 2 | 372 | #define XFS_ITEM_LOCKED 2 |
373 | #define XFS_ITEM_FLUSHING 3 | 373 | #define XFS_ITEM_FLUSHING 3 |
374 | 374 | ||
375 | /* | 375 | /* |
376 | * This is the type of function which can be given to xfs_trans_callback() | 376 | * This is the type of function which can be given to xfs_trans_callback() |
377 | * to be called upon the transaction's commit to disk. | 377 | * to be called upon the transaction's commit to disk. |
378 | */ | 378 | */ |
379 | typedef void (*xfs_trans_callback_t)(struct xfs_trans *, void *); | 379 | typedef void (*xfs_trans_callback_t)(struct xfs_trans *, void *); |
380 | 380 | ||
381 | /* | 381 | /* |
382 | * This is the structure maintained for every active transaction. | 382 | * This is the structure maintained for every active transaction. |
383 | */ | 383 | */ |
384 | typedef struct xfs_trans { | 384 | typedef struct xfs_trans { |
385 | unsigned int t_magic; /* magic number */ | 385 | unsigned int t_magic; /* magic number */ |
386 | xfs_log_callback_t t_logcb; /* log callback struct */ | 386 | xfs_log_callback_t t_logcb; /* log callback struct */ |
387 | unsigned int t_type; /* transaction type */ | 387 | unsigned int t_type; /* transaction type */ |
388 | unsigned int t_log_res; /* amt of log space resvd */ | 388 | unsigned int t_log_res; /* amt of log space resvd */ |
389 | unsigned int t_log_count; /* count for perm log res */ | 389 | unsigned int t_log_count; /* count for perm log res */ |
390 | unsigned int t_blk_res; /* # of blocks resvd */ | 390 | unsigned int t_blk_res; /* # of blocks resvd */ |
391 | unsigned int t_blk_res_used; /* # of resvd blocks used */ | 391 | unsigned int t_blk_res_used; /* # of resvd blocks used */ |
392 | unsigned int t_rtx_res; /* # of rt extents resvd */ | 392 | unsigned int t_rtx_res; /* # of rt extents resvd */ |
393 | unsigned int t_rtx_res_used; /* # of resvd rt extents used */ | 393 | unsigned int t_rtx_res_used; /* # of resvd rt extents used */ |
394 | struct xlog_ticket *t_ticket; /* log mgr ticket */ | 394 | struct xlog_ticket *t_ticket; /* log mgr ticket */ |
395 | xfs_lsn_t t_lsn; /* log seq num of start of | 395 | xfs_lsn_t t_lsn; /* log seq num of start of |
396 | * transaction. */ | 396 | * transaction. */ |
397 | xfs_lsn_t t_commit_lsn; /* log seq num of end of | 397 | xfs_lsn_t t_commit_lsn; /* log seq num of end of |
398 | * transaction. */ | 398 | * transaction. */ |
399 | struct xfs_mount *t_mountp; /* ptr to fs mount struct */ | 399 | struct xfs_mount *t_mountp; /* ptr to fs mount struct */ |
400 | struct xfs_dquot_acct *t_dqinfo; /* acctg info for dquots */ | 400 | struct xfs_dquot_acct *t_dqinfo; /* acctg info for dquots */ |
401 | unsigned int t_flags; /* misc flags */ | 401 | unsigned int t_flags; /* misc flags */ |
402 | int64_t t_icount_delta; /* superblock icount change */ | 402 | int64_t t_icount_delta; /* superblock icount change */ |
403 | int64_t t_ifree_delta; /* superblock ifree change */ | 403 | int64_t t_ifree_delta; /* superblock ifree change */ |
404 | int64_t t_fdblocks_delta; /* superblock fdblocks chg */ | 404 | int64_t t_fdblocks_delta; /* superblock fdblocks chg */ |
405 | int64_t t_res_fdblocks_delta; /* on-disk only chg */ | 405 | int64_t t_res_fdblocks_delta; /* on-disk only chg */ |
406 | int64_t t_frextents_delta;/* superblock freextents chg*/ | 406 | int64_t t_frextents_delta;/* superblock freextents chg*/ |
407 | int64_t t_res_frextents_delta; /* on-disk only chg */ | 407 | int64_t t_res_frextents_delta; /* on-disk only chg */ |
408 | #ifdef DEBUG | 408 | #if defined(DEBUG) || defined(XFS_WARN) |
409 | int64_t t_ag_freeblks_delta; /* debugging counter */ | 409 | int64_t t_ag_freeblks_delta; /* debugging counter */ |
410 | int64_t t_ag_flist_delta; /* debugging counter */ | 410 | int64_t t_ag_flist_delta; /* debugging counter */ |
411 | int64_t t_ag_btree_delta; /* debugging counter */ | 411 | int64_t t_ag_btree_delta; /* debugging counter */ |
412 | #endif | 412 | #endif |
413 | int64_t t_dblocks_delta;/* superblock dblocks change */ | 413 | int64_t t_dblocks_delta;/* superblock dblocks change */ |
414 | int64_t t_agcount_delta;/* superblock agcount change */ | 414 | int64_t t_agcount_delta;/* superblock agcount change */ |
415 | int64_t t_imaxpct_delta;/* superblock imaxpct change */ | 415 | int64_t t_imaxpct_delta;/* superblock imaxpct change */ |
416 | int64_t t_rextsize_delta;/* superblock rextsize chg */ | 416 | int64_t t_rextsize_delta;/* superblock rextsize chg */ |
417 | int64_t t_rbmblocks_delta;/* superblock rbmblocks chg */ | 417 | int64_t t_rbmblocks_delta;/* superblock rbmblocks chg */ |
418 | int64_t t_rblocks_delta;/* superblock rblocks change */ | 418 | int64_t t_rblocks_delta;/* superblock rblocks change */ |
419 | int64_t t_rextents_delta;/* superblocks rextents chg */ | 419 | int64_t t_rextents_delta;/* superblocks rextents chg */ |
420 | int64_t t_rextslog_delta;/* superblocks rextslog chg */ | 420 | int64_t t_rextslog_delta;/* superblocks rextslog chg */ |
421 | struct list_head t_items; /* log item descriptors */ | 421 | struct list_head t_items; /* log item descriptors */ |
422 | xfs_trans_header_t t_header; /* header for in-log trans */ | 422 | xfs_trans_header_t t_header; /* header for in-log trans */ |
423 | struct list_head t_busy; /* list of busy extents */ | 423 | struct list_head t_busy; /* list of busy extents */ |
424 | unsigned long t_pflags; /* saved process flags state */ | 424 | unsigned long t_pflags; /* saved process flags state */ |
425 | } xfs_trans_t; | 425 | } xfs_trans_t; |
426 | 426 | ||
427 | /* | 427 | /* |
428 | * XFS transaction mechanism exported interfaces that are | 428 | * XFS transaction mechanism exported interfaces that are |
429 | * actually macros. | 429 | * actually macros. |
430 | */ | 430 | */ |
431 | #define xfs_trans_get_log_res(tp) ((tp)->t_log_res) | 431 | #define xfs_trans_get_log_res(tp) ((tp)->t_log_res) |
432 | #define xfs_trans_get_log_count(tp) ((tp)->t_log_count) | 432 | #define xfs_trans_get_log_count(tp) ((tp)->t_log_count) |
433 | #define xfs_trans_get_block_res(tp) ((tp)->t_blk_res) | 433 | #define xfs_trans_get_block_res(tp) ((tp)->t_blk_res) |
434 | #define xfs_trans_set_sync(tp) ((tp)->t_flags |= XFS_TRANS_SYNC) | 434 | #define xfs_trans_set_sync(tp) ((tp)->t_flags |= XFS_TRANS_SYNC) |
435 | 435 | ||
436 | #ifdef DEBUG | 436 | #if defined(DEBUG) || defined(XFS_WARN) |
437 | #define xfs_trans_agblocks_delta(tp, d) ((tp)->t_ag_freeblks_delta += (int64_t)d) | 437 | #define xfs_trans_agblocks_delta(tp, d) ((tp)->t_ag_freeblks_delta += (int64_t)d) |
438 | #define xfs_trans_agflist_delta(tp, d) ((tp)->t_ag_flist_delta += (int64_t)d) | 438 | #define xfs_trans_agflist_delta(tp, d) ((tp)->t_ag_flist_delta += (int64_t)d) |
439 | #define xfs_trans_agbtree_delta(tp, d) ((tp)->t_ag_btree_delta += (int64_t)d) | 439 | #define xfs_trans_agbtree_delta(tp, d) ((tp)->t_ag_btree_delta += (int64_t)d) |
440 | #else | 440 | #else |
441 | #define xfs_trans_agblocks_delta(tp, d) | 441 | #define xfs_trans_agblocks_delta(tp, d) |
442 | #define xfs_trans_agflist_delta(tp, d) | 442 | #define xfs_trans_agflist_delta(tp, d) |
443 | #define xfs_trans_agbtree_delta(tp, d) | 443 | #define xfs_trans_agbtree_delta(tp, d) |
444 | #endif | 444 | #endif |
445 | 445 | ||
446 | /* | 446 | /* |
447 | * XFS transaction mechanism exported interfaces. | 447 | * XFS transaction mechanism exported interfaces. |
448 | */ | 448 | */ |
449 | xfs_trans_t *xfs_trans_alloc(struct xfs_mount *, uint); | 449 | xfs_trans_t *xfs_trans_alloc(struct xfs_mount *, uint); |
450 | xfs_trans_t *_xfs_trans_alloc(struct xfs_mount *, uint, xfs_km_flags_t); | 450 | xfs_trans_t *_xfs_trans_alloc(struct xfs_mount *, uint, xfs_km_flags_t); |
451 | xfs_trans_t *xfs_trans_dup(xfs_trans_t *); | 451 | xfs_trans_t *xfs_trans_dup(xfs_trans_t *); |
452 | int xfs_trans_reserve(xfs_trans_t *, uint, uint, uint, | 452 | int xfs_trans_reserve(xfs_trans_t *, uint, uint, uint, |
453 | uint, uint); | 453 | uint, uint); |
454 | void xfs_trans_mod_sb(xfs_trans_t *, uint, int64_t); | 454 | void xfs_trans_mod_sb(xfs_trans_t *, uint, int64_t); |
455 | 455 | ||
456 | struct xfs_buf *xfs_trans_get_buf_map(struct xfs_trans *tp, | 456 | struct xfs_buf *xfs_trans_get_buf_map(struct xfs_trans *tp, |
457 | struct xfs_buftarg *target, | 457 | struct xfs_buftarg *target, |
458 | struct xfs_buf_map *map, int nmaps, | 458 | struct xfs_buf_map *map, int nmaps, |
459 | uint flags); | 459 | uint flags); |
460 | 460 | ||
461 | static inline struct xfs_buf * | 461 | static inline struct xfs_buf * |
462 | xfs_trans_get_buf( | 462 | xfs_trans_get_buf( |
463 | struct xfs_trans *tp, | 463 | struct xfs_trans *tp, |
464 | struct xfs_buftarg *target, | 464 | struct xfs_buftarg *target, |
465 | xfs_daddr_t blkno, | 465 | xfs_daddr_t blkno, |
466 | int numblks, | 466 | int numblks, |
467 | uint flags) | 467 | uint flags) |
468 | { | 468 | { |
469 | DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); | 469 | DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); |
470 | return xfs_trans_get_buf_map(tp, target, &map, 1, flags); | 470 | return xfs_trans_get_buf_map(tp, target, &map, 1, flags); |
471 | } | 471 | } |
472 | 472 | ||
473 | int xfs_trans_read_buf_map(struct xfs_mount *mp, | 473 | int xfs_trans_read_buf_map(struct xfs_mount *mp, |
474 | struct xfs_trans *tp, | 474 | struct xfs_trans *tp, |
475 | struct xfs_buftarg *target, | 475 | struct xfs_buftarg *target, |
476 | struct xfs_buf_map *map, int nmaps, | 476 | struct xfs_buf_map *map, int nmaps, |
477 | xfs_buf_flags_t flags, | 477 | xfs_buf_flags_t flags, |
478 | struct xfs_buf **bpp, | 478 | struct xfs_buf **bpp, |
479 | const struct xfs_buf_ops *ops); | 479 | const struct xfs_buf_ops *ops); |
480 | 480 | ||
481 | static inline int | 481 | static inline int |
482 | xfs_trans_read_buf( | 482 | xfs_trans_read_buf( |
483 | struct xfs_mount *mp, | 483 | struct xfs_mount *mp, |
484 | struct xfs_trans *tp, | 484 | struct xfs_trans *tp, |
485 | struct xfs_buftarg *target, | 485 | struct xfs_buftarg *target, |
486 | xfs_daddr_t blkno, | 486 | xfs_daddr_t blkno, |
487 | int numblks, | 487 | int numblks, |
488 | xfs_buf_flags_t flags, | 488 | xfs_buf_flags_t flags, |
489 | struct xfs_buf **bpp, | 489 | struct xfs_buf **bpp, |
490 | const struct xfs_buf_ops *ops) | 490 | const struct xfs_buf_ops *ops) |
491 | { | 491 | { |
492 | DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); | 492 | DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); |
493 | return xfs_trans_read_buf_map(mp, tp, target, &map, 1, | 493 | return xfs_trans_read_buf_map(mp, tp, target, &map, 1, |
494 | flags, bpp, ops); | 494 | flags, bpp, ops); |
495 | } | 495 | } |
496 | 496 | ||
497 | struct xfs_buf *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *, int); | 497 | struct xfs_buf *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *, int); |
498 | 498 | ||
499 | void xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *); | 499 | void xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *); |
500 | void xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *); | 500 | void xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *); |
501 | void xfs_trans_bhold(xfs_trans_t *, struct xfs_buf *); | 501 | void xfs_trans_bhold(xfs_trans_t *, struct xfs_buf *); |
502 | void xfs_trans_bhold_release(xfs_trans_t *, struct xfs_buf *); | 502 | void xfs_trans_bhold_release(xfs_trans_t *, struct xfs_buf *); |
503 | void xfs_trans_binval(xfs_trans_t *, struct xfs_buf *); | 503 | void xfs_trans_binval(xfs_trans_t *, struct xfs_buf *); |
504 | void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *); | 504 | void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *); |
505 | void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *); | 505 | void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *); |
506 | void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); | 506 | void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); |
507 | void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); | 507 | void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); |
508 | void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int); | 508 | void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int); |
509 | void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint); | 509 | void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint); |
510 | void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); | 510 | void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); |
511 | void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); | 511 | void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); |
512 | struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint); | 512 | struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint); |
513 | void xfs_efi_release(struct xfs_efi_log_item *, uint); | 513 | void xfs_efi_release(struct xfs_efi_log_item *, uint); |
514 | void xfs_trans_log_efi_extent(xfs_trans_t *, | 514 | void xfs_trans_log_efi_extent(xfs_trans_t *, |
515 | struct xfs_efi_log_item *, | 515 | struct xfs_efi_log_item *, |
516 | xfs_fsblock_t, | 516 | xfs_fsblock_t, |
517 | xfs_extlen_t); | 517 | xfs_extlen_t); |
518 | struct xfs_efd_log_item *xfs_trans_get_efd(xfs_trans_t *, | 518 | struct xfs_efd_log_item *xfs_trans_get_efd(xfs_trans_t *, |
519 | struct xfs_efi_log_item *, | 519 | struct xfs_efi_log_item *, |
520 | uint); | 520 | uint); |
521 | void xfs_trans_log_efd_extent(xfs_trans_t *, | 521 | void xfs_trans_log_efd_extent(xfs_trans_t *, |
522 | struct xfs_efd_log_item *, | 522 | struct xfs_efd_log_item *, |
523 | xfs_fsblock_t, | 523 | xfs_fsblock_t, |
524 | xfs_extlen_t); | 524 | xfs_extlen_t); |
525 | int xfs_trans_commit(xfs_trans_t *, uint flags); | 525 | int xfs_trans_commit(xfs_trans_t *, uint flags); |
526 | void xfs_trans_cancel(xfs_trans_t *, int); | 526 | void xfs_trans_cancel(xfs_trans_t *, int); |
527 | int xfs_trans_ail_init(struct xfs_mount *); | 527 | int xfs_trans_ail_init(struct xfs_mount *); |
528 | void xfs_trans_ail_destroy(struct xfs_mount *); | 528 | void xfs_trans_ail_destroy(struct xfs_mount *); |
529 | 529 | ||
530 | extern kmem_zone_t *xfs_trans_zone; | 530 | extern kmem_zone_t *xfs_trans_zone; |
531 | extern kmem_zone_t *xfs_log_item_desc_zone; | 531 | extern kmem_zone_t *xfs_log_item_desc_zone; |
532 | 532 | ||
533 | #endif /* __KERNEL__ */ | 533 | #endif /* __KERNEL__ */ |
534 | 534 | ||
535 | void xfs_trans_init(struct xfs_mount *); | 535 | void xfs_trans_init(struct xfs_mount *); |
536 | int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *); | 536 | int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *); |
537 | 537 | ||
538 | #endif /* __XFS_TRANS_H__ */ | 538 | #endif /* __XFS_TRANS_H__ */ |
539 | 539 |