Commit 42173f6860af7e016a950a9a19a66679cfc46d98
Committed by
Lachlan McIlroy
1 parent
a01e035ebb
Exists in
master
and in
20 other branches
[XFS] Remove VN_IS* macros and related cruft.
We can just check i_mode / di_mode directly. SGI-PV: 976035 SGI-Modid: xfs-linux-melb:xfs-kern:30896a Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Showing 3 changed files with 7 additions and 43 deletions Inline Diff
fs/xfs/linux-2.6/xfs_vnode.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_VNODE_H__ | 18 | #ifndef __XFS_VNODE_H__ |
19 | #define __XFS_VNODE_H__ | 19 | #define __XFS_VNODE_H__ |
20 | 20 | ||
21 | struct file; | 21 | struct file; |
22 | struct bhv_vattr; | 22 | struct bhv_vattr; |
23 | struct xfs_iomap; | 23 | struct xfs_iomap; |
24 | struct attrlist_cursor_kern; | 24 | struct attrlist_cursor_kern; |
25 | 25 | ||
26 | typedef struct inode bhv_vnode_t; | 26 | typedef struct inode bhv_vnode_t; |
27 | 27 | ||
28 | #define VN_ISLNK(vp) S_ISLNK((vp)->i_mode) | ||
29 | #define VN_ISREG(vp) S_ISREG((vp)->i_mode) | ||
30 | #define VN_ISDIR(vp) S_ISDIR((vp)->i_mode) | ||
31 | #define VN_ISCHR(vp) S_ISCHR((vp)->i_mode) | ||
32 | #define VN_ISBLK(vp) S_ISBLK((vp)->i_mode) | ||
33 | |||
34 | /* | 28 | /* |
35 | * Vnode to Linux inode mapping. | 29 | * Vnode to Linux inode mapping. |
36 | */ | 30 | */ |
37 | static inline bhv_vnode_t *vn_from_inode(struct inode *inode) | 31 | static inline bhv_vnode_t *vn_from_inode(struct inode *inode) |
38 | { | 32 | { |
39 | return inode; | 33 | return inode; |
40 | } | 34 | } |
41 | static inline struct inode *vn_to_inode(bhv_vnode_t *vnode) | 35 | static inline struct inode *vn_to_inode(bhv_vnode_t *vnode) |
42 | { | 36 | { |
43 | return vnode; | 37 | return vnode; |
44 | } | 38 | } |
45 | 39 | ||
46 | /* | 40 | /* |
47 | * Return values for xfs_inactive. A return value of | 41 | * Return values for xfs_inactive. A return value of |
48 | * VN_INACTIVE_NOCACHE implies that the file system behavior | 42 | * VN_INACTIVE_NOCACHE implies that the file system behavior |
49 | * has disassociated its state and bhv_desc_t from the vnode. | 43 | * has disassociated its state and bhv_desc_t from the vnode. |
50 | */ | 44 | */ |
51 | #define VN_INACTIVE_CACHE 0 | 45 | #define VN_INACTIVE_CACHE 0 |
52 | #define VN_INACTIVE_NOCACHE 1 | 46 | #define VN_INACTIVE_NOCACHE 1 |
53 | 47 | ||
54 | /* | 48 | /* |
55 | * Flags for read/write calls - same values as IRIX | 49 | * Flags for read/write calls - same values as IRIX |
56 | */ | 50 | */ |
57 | #define IO_ISAIO 0x00001 /* don't wait for completion */ | 51 | #define IO_ISAIO 0x00001 /* don't wait for completion */ |
58 | #define IO_ISDIRECT 0x00004 /* bypass page cache */ | 52 | #define IO_ISDIRECT 0x00004 /* bypass page cache */ |
59 | #define IO_INVIS 0x00020 /* don't update inode timestamps */ | 53 | #define IO_INVIS 0x00020 /* don't update inode timestamps */ |
60 | 54 | ||
61 | /* | 55 | /* |
62 | * Flags for xfs_inode_flush | 56 | * Flags for xfs_inode_flush |
63 | */ | 57 | */ |
64 | #define FLUSH_SYNC 1 /* wait for flush to complete */ | 58 | #define FLUSH_SYNC 1 /* wait for flush to complete */ |
65 | 59 | ||
66 | /* | 60 | /* |
67 | * Flush/Invalidate options for vop_toss/flush/flushinval_pages. | 61 | * Flush/Invalidate options for vop_toss/flush/flushinval_pages. |
68 | */ | 62 | */ |
69 | #define FI_NONE 0 /* none */ | 63 | #define FI_NONE 0 /* none */ |
70 | #define FI_REMAPF 1 /* Do a remapf prior to the operation */ | 64 | #define FI_REMAPF 1 /* Do a remapf prior to the operation */ |
71 | #define FI_REMAPF_LOCKED 2 /* Do a remapf prior to the operation. | 65 | #define FI_REMAPF_LOCKED 2 /* Do a remapf prior to the operation. |
72 | Prevent VM access to the pages until | 66 | Prevent VM access to the pages until |
73 | the operation completes. */ | 67 | the operation completes. */ |
74 | 68 | ||
75 | /* | 69 | /* |
76 | * Vnode attributes. va_mask indicates those attributes the caller | 70 | * Vnode attributes. va_mask indicates those attributes the caller |
77 | * wants to set or extract. | 71 | * wants to set or extract. |
78 | */ | 72 | */ |
79 | typedef struct bhv_vattr { | 73 | typedef struct bhv_vattr { |
80 | int va_mask; /* bit-mask of attributes present */ | 74 | int va_mask; /* bit-mask of attributes present */ |
81 | mode_t va_mode; /* file access mode and type */ | 75 | mode_t va_mode; /* file access mode and type */ |
82 | xfs_nlink_t va_nlink; /* number of references to file */ | 76 | xfs_nlink_t va_nlink; /* number of references to file */ |
83 | uid_t va_uid; /* owner user id */ | 77 | uid_t va_uid; /* owner user id */ |
84 | gid_t va_gid; /* owner group id */ | 78 | gid_t va_gid; /* owner group id */ |
85 | xfs_ino_t va_nodeid; /* file id */ | 79 | xfs_ino_t va_nodeid; /* file id */ |
86 | xfs_off_t va_size; /* file size in bytes */ | 80 | xfs_off_t va_size; /* file size in bytes */ |
87 | u_long va_blocksize; /* blocksize preferred for i/o */ | 81 | u_long va_blocksize; /* blocksize preferred for i/o */ |
88 | struct timespec va_atime; /* time of last access */ | 82 | struct timespec va_atime; /* time of last access */ |
89 | struct timespec va_mtime; /* time of last modification */ | 83 | struct timespec va_mtime; /* time of last modification */ |
90 | struct timespec va_ctime; /* time file changed */ | 84 | struct timespec va_ctime; /* time file changed */ |
91 | u_int va_gen; /* generation number of file */ | 85 | u_int va_gen; /* generation number of file */ |
92 | xfs_dev_t va_rdev; /* device the special file represents */ | 86 | xfs_dev_t va_rdev; /* device the special file represents */ |
93 | __int64_t va_nblocks; /* number of blocks allocated */ | 87 | __int64_t va_nblocks; /* number of blocks allocated */ |
94 | u_long va_xflags; /* random extended file flags */ | 88 | u_long va_xflags; /* random extended file flags */ |
95 | u_long va_extsize; /* file extent size */ | 89 | u_long va_extsize; /* file extent size */ |
96 | u_long va_nextents; /* number of extents in file */ | 90 | u_long va_nextents; /* number of extents in file */ |
97 | u_long va_anextents; /* number of attr extents in file */ | 91 | u_long va_anextents; /* number of attr extents in file */ |
98 | prid_t va_projid; /* project id */ | 92 | prid_t va_projid; /* project id */ |
99 | } bhv_vattr_t; | 93 | } bhv_vattr_t; |
100 | 94 | ||
101 | /* | 95 | /* |
102 | * setattr or getattr attributes | 96 | * setattr or getattr attributes |
103 | */ | 97 | */ |
104 | #define XFS_AT_TYPE 0x00000001 | 98 | #define XFS_AT_TYPE 0x00000001 |
105 | #define XFS_AT_MODE 0x00000002 | 99 | #define XFS_AT_MODE 0x00000002 |
106 | #define XFS_AT_UID 0x00000004 | 100 | #define XFS_AT_UID 0x00000004 |
107 | #define XFS_AT_GID 0x00000008 | 101 | #define XFS_AT_GID 0x00000008 |
108 | #define XFS_AT_FSID 0x00000010 | 102 | #define XFS_AT_FSID 0x00000010 |
109 | #define XFS_AT_NODEID 0x00000020 | 103 | #define XFS_AT_NODEID 0x00000020 |
110 | #define XFS_AT_NLINK 0x00000040 | 104 | #define XFS_AT_NLINK 0x00000040 |
111 | #define XFS_AT_SIZE 0x00000080 | 105 | #define XFS_AT_SIZE 0x00000080 |
112 | #define XFS_AT_ATIME 0x00000100 | 106 | #define XFS_AT_ATIME 0x00000100 |
113 | #define XFS_AT_MTIME 0x00000200 | 107 | #define XFS_AT_MTIME 0x00000200 |
114 | #define XFS_AT_CTIME 0x00000400 | 108 | #define XFS_AT_CTIME 0x00000400 |
115 | #define XFS_AT_RDEV 0x00000800 | 109 | #define XFS_AT_RDEV 0x00000800 |
116 | #define XFS_AT_BLKSIZE 0x00001000 | 110 | #define XFS_AT_BLKSIZE 0x00001000 |
117 | #define XFS_AT_NBLOCKS 0x00002000 | 111 | #define XFS_AT_NBLOCKS 0x00002000 |
118 | #define XFS_AT_VCODE 0x00004000 | 112 | #define XFS_AT_VCODE 0x00004000 |
119 | #define XFS_AT_MAC 0x00008000 | 113 | #define XFS_AT_MAC 0x00008000 |
120 | #define XFS_AT_UPDATIME 0x00010000 | 114 | #define XFS_AT_UPDATIME 0x00010000 |
121 | #define XFS_AT_UPDMTIME 0x00020000 | 115 | #define XFS_AT_UPDMTIME 0x00020000 |
122 | #define XFS_AT_UPDCTIME 0x00040000 | 116 | #define XFS_AT_UPDCTIME 0x00040000 |
123 | #define XFS_AT_ACL 0x00080000 | 117 | #define XFS_AT_ACL 0x00080000 |
124 | #define XFS_AT_CAP 0x00100000 | 118 | #define XFS_AT_CAP 0x00100000 |
125 | #define XFS_AT_INF 0x00200000 | 119 | #define XFS_AT_INF 0x00200000 |
126 | #define XFS_AT_XFLAGS 0x00400000 | 120 | #define XFS_AT_XFLAGS 0x00400000 |
127 | #define XFS_AT_EXTSIZE 0x00800000 | 121 | #define XFS_AT_EXTSIZE 0x00800000 |
128 | #define XFS_AT_NEXTENTS 0x01000000 | 122 | #define XFS_AT_NEXTENTS 0x01000000 |
129 | #define XFS_AT_ANEXTENTS 0x02000000 | 123 | #define XFS_AT_ANEXTENTS 0x02000000 |
130 | #define XFS_AT_PROJID 0x04000000 | 124 | #define XFS_AT_PROJID 0x04000000 |
131 | #define XFS_AT_SIZE_NOPERM 0x08000000 | 125 | #define XFS_AT_SIZE_NOPERM 0x08000000 |
132 | #define XFS_AT_GENCOUNT 0x10000000 | 126 | #define XFS_AT_GENCOUNT 0x10000000 |
133 | 127 | ||
134 | #define XFS_AT_ALL (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\ | 128 | #define XFS_AT_ALL (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\ |
135 | XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\ | 129 | XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\ |
136 | XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\ | 130 | XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\ |
137 | XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|XFS_AT_MAC|\ | 131 | XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|XFS_AT_MAC|\ |
138 | XFS_AT_ACL|XFS_AT_CAP|XFS_AT_INF|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|\ | 132 | XFS_AT_ACL|XFS_AT_CAP|XFS_AT_INF|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|\ |
139 | XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_PROJID|XFS_AT_GENCOUNT) | 133 | XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_PROJID|XFS_AT_GENCOUNT) |
140 | 134 | ||
141 | #define XFS_AT_STAT (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\ | 135 | #define XFS_AT_STAT (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\ |
142 | XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\ | 136 | XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\ |
143 | XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\ | 137 | XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\ |
144 | XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_PROJID) | 138 | XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_PROJID) |
145 | 139 | ||
146 | #define XFS_AT_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME) | 140 | #define XFS_AT_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME) |
147 | 141 | ||
148 | #define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME) | 142 | #define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME) |
149 | 143 | ||
150 | #define XFS_AT_NOSET (XFS_AT_NLINK|XFS_AT_RDEV|XFS_AT_FSID|XFS_AT_NODEID|\ | 144 | #define XFS_AT_NOSET (XFS_AT_NLINK|XFS_AT_RDEV|XFS_AT_FSID|XFS_AT_NODEID|\ |
151 | XFS_AT_TYPE|XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|\ | 145 | XFS_AT_TYPE|XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|\ |
152 | XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_GENCOUNT) | 146 | XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_GENCOUNT) |
153 | |||
154 | /* | ||
155 | * Modes. | ||
156 | */ | ||
157 | #define VSUID S_ISUID /* set user id on execution */ | ||
158 | #define VSGID S_ISGID /* set group id on execution */ | ||
159 | #define VSVTX S_ISVTX /* save swapped text even after use */ | ||
160 | #define VREAD S_IRUSR /* read, write, execute permissions */ | ||
161 | #define VWRITE S_IWUSR | ||
162 | #define VEXEC S_IXUSR | ||
163 | |||
164 | #define MODEMASK S_IALLUGO /* mode bits plus permission bits */ | ||
165 | |||
166 | /* | ||
167 | * Check whether mandatory file locking is enabled. | ||
168 | */ | ||
169 | #define MANDLOCK(vp, mode) \ | ||
170 | (VN_ISREG(vp) && ((mode) & (VSGID|(VEXEC>>3))) == VSGID) | ||
171 | 147 | ||
172 | extern void vn_init(void); | 148 | extern void vn_init(void); |
173 | extern int vn_revalidate(bhv_vnode_t *); | 149 | extern int vn_revalidate(bhv_vnode_t *); |
174 | 150 | ||
175 | /* | 151 | /* |
176 | * Yeah, these don't take vnode anymore at all, all this should be | 152 | * Yeah, these don't take vnode anymore at all, all this should be |
177 | * cleaned up at some point. | 153 | * cleaned up at some point. |
178 | */ | 154 | */ |
179 | extern void vn_iowait(struct xfs_inode *ip); | 155 | extern void vn_iowait(struct xfs_inode *ip); |
180 | extern void vn_iowake(struct xfs_inode *ip); | 156 | extern void vn_iowake(struct xfs_inode *ip); |
181 | extern void vn_ioerror(struct xfs_inode *ip, int error, char *f, int l); | 157 | extern void vn_ioerror(struct xfs_inode *ip, int error, char *f, int l); |
182 | 158 | ||
183 | static inline int vn_count(bhv_vnode_t *vp) | 159 | static inline int vn_count(bhv_vnode_t *vp) |
184 | { | 160 | { |
185 | return atomic_read(&vn_to_inode(vp)->i_count); | 161 | return atomic_read(&vn_to_inode(vp)->i_count); |
186 | } | 162 | } |
187 | 163 | ||
188 | /* | 164 | /* |
189 | * Vnode reference counting functions (and macros for compatibility). | 165 | * Vnode reference counting functions (and macros for compatibility). |
190 | */ | 166 | */ |
191 | extern bhv_vnode_t *vn_hold(bhv_vnode_t *); | 167 | extern bhv_vnode_t *vn_hold(bhv_vnode_t *); |
192 | 168 | ||
193 | #if defined(XFS_INODE_TRACE) | 169 | #if defined(XFS_INODE_TRACE) |
194 | #define VN_HOLD(vp) \ | 170 | #define VN_HOLD(vp) \ |
195 | ((void)vn_hold(vp), \ | 171 | ((void)vn_hold(vp), \ |
196 | xfs_itrace_hold(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address)) | 172 | xfs_itrace_hold(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address)) |
197 | #define VN_RELE(vp) \ | 173 | #define VN_RELE(vp) \ |
198 | (xfs_itrace_rele(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address), \ | 174 | (xfs_itrace_rele(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address), \ |
199 | iput(vn_to_inode(vp))) | 175 | iput(vn_to_inode(vp))) |
200 | #else | 176 | #else |
201 | #define VN_HOLD(vp) ((void)vn_hold(vp)) | 177 | #define VN_HOLD(vp) ((void)vn_hold(vp)) |
202 | #define VN_RELE(vp) (iput(vn_to_inode(vp))) | 178 | #define VN_RELE(vp) (iput(vn_to_inode(vp))) |
203 | #endif | 179 | #endif |
204 | 180 | ||
205 | static inline bhv_vnode_t *vn_grab(bhv_vnode_t *vp) | 181 | static inline bhv_vnode_t *vn_grab(bhv_vnode_t *vp) |
206 | { | 182 | { |
207 | struct inode *inode = igrab(vn_to_inode(vp)); | 183 | struct inode *inode = igrab(vn_to_inode(vp)); |
208 | return inode ? vn_from_inode(inode) : NULL; | 184 | return inode ? vn_from_inode(inode) : NULL; |
209 | } | 185 | } |
210 | 186 | ||
211 | /* | 187 | /* |
212 | * Dealing with bad inodes | 188 | * Dealing with bad inodes |
213 | */ | 189 | */ |
214 | static inline int VN_BAD(bhv_vnode_t *vp) | 190 | static inline int VN_BAD(bhv_vnode_t *vp) |
215 | { | 191 | { |
216 | return is_bad_inode(vn_to_inode(vp)); | 192 | return is_bad_inode(vn_to_inode(vp)); |
217 | } | 193 | } |
218 | 194 | ||
219 | /* | 195 | /* |
220 | * Extracting atime values in various formats | 196 | * Extracting atime values in various formats |
221 | */ | 197 | */ |
222 | static inline void vn_atime_to_bstime(bhv_vnode_t *vp, xfs_bstime_t *bs_atime) | 198 | static inline void vn_atime_to_bstime(bhv_vnode_t *vp, xfs_bstime_t *bs_atime) |
223 | { | 199 | { |
224 | bs_atime->tv_sec = vp->i_atime.tv_sec; | 200 | bs_atime->tv_sec = vp->i_atime.tv_sec; |
225 | bs_atime->tv_nsec = vp->i_atime.tv_nsec; | 201 | bs_atime->tv_nsec = vp->i_atime.tv_nsec; |
226 | } | 202 | } |
227 | 203 | ||
228 | static inline void vn_atime_to_timespec(bhv_vnode_t *vp, struct timespec *ts) | 204 | static inline void vn_atime_to_timespec(bhv_vnode_t *vp, struct timespec *ts) |
229 | { | 205 | { |
230 | *ts = vp->i_atime; | 206 | *ts = vp->i_atime; |
231 | } | 207 | } |
232 | 208 | ||
233 | static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) | 209 | static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) |
234 | { | 210 | { |
235 | *tt = vp->i_atime.tv_sec; | 211 | *tt = vp->i_atime.tv_sec; |
236 | } | 212 | } |
237 | 213 | ||
238 | /* | 214 | /* |
239 | * Some useful predicates. | 215 | * Some useful predicates. |
240 | */ | 216 | */ |
241 | #define VN_MAPPED(vp) mapping_mapped(vn_to_inode(vp)->i_mapping) | 217 | #define VN_MAPPED(vp) mapping_mapped(vn_to_inode(vp)->i_mapping) |
242 | #define VN_CACHED(vp) (vn_to_inode(vp)->i_mapping->nrpages) | 218 | #define VN_CACHED(vp) (vn_to_inode(vp)->i_mapping->nrpages) |
243 | #define VN_DIRTY(vp) mapping_tagged(vn_to_inode(vp)->i_mapping, \ | 219 | #define VN_DIRTY(vp) mapping_tagged(vn_to_inode(vp)->i_mapping, \ |
244 | PAGECACHE_TAG_DIRTY) | 220 | PAGECACHE_TAG_DIRTY) |
245 | 221 | ||
246 | /* | 222 | /* |
247 | * Flags to vop_setattr/getattr. | 223 | * Flags to vop_setattr/getattr. |
248 | */ | 224 | */ |
249 | #define ATTR_UTIME 0x01 /* non-default utime(2) request */ | 225 | #define ATTR_UTIME 0x01 /* non-default utime(2) request */ |
250 | #define ATTR_DMI 0x08 /* invocation from a DMI function */ | 226 | #define ATTR_DMI 0x08 /* invocation from a DMI function */ |
251 | #define ATTR_LAZY 0x80 /* set/get attributes lazily */ | 227 | #define ATTR_LAZY 0x80 /* set/get attributes lazily */ |
252 | #define ATTR_NONBLOCK 0x100 /* return EAGAIN if operation would block */ | 228 | #define ATTR_NONBLOCK 0x100 /* return EAGAIN if operation would block */ |
253 | #define ATTR_NOLOCK 0x200 /* Don't grab any conflicting locks */ | 229 | #define ATTR_NOLOCK 0x200 /* Don't grab any conflicting locks */ |
254 | #define ATTR_NOSIZETOK 0x400 /* Don't get the SIZE token */ | 230 | #define ATTR_NOSIZETOK 0x400 /* Don't get the SIZE token */ |
255 | 231 | ||
256 | /* | 232 | /* |
257 | * Flags to vop_fsync/reclaim. | 233 | * Flags to vop_fsync/reclaim. |
258 | */ | 234 | */ |
259 | #define FSYNC_NOWAIT 0 /* asynchronous flush */ | 235 | #define FSYNC_NOWAIT 0 /* asynchronous flush */ |
260 | #define FSYNC_WAIT 0x1 /* synchronous fsync or forced reclaim */ | 236 | #define FSYNC_WAIT 0x1 /* synchronous fsync or forced reclaim */ |
261 | #define FSYNC_INVAL 0x2 /* flush and invalidate cached data */ | 237 | #define FSYNC_INVAL 0x2 /* flush and invalidate cached data */ |
262 | #define FSYNC_DATA 0x4 /* synchronous fsync of data only */ | 238 | #define FSYNC_DATA 0x4 /* synchronous fsync of data only */ |
263 | 239 | ||
264 | /* | 240 | /* |
265 | * Tracking vnode activity. | 241 | * Tracking vnode activity. |
266 | */ | 242 | */ |
267 | #if defined(XFS_INODE_TRACE) | 243 | #if defined(XFS_INODE_TRACE) |
268 | 244 | ||
269 | #define INODE_TRACE_SIZE 16 /* number of trace entries */ | 245 | #define INODE_TRACE_SIZE 16 /* number of trace entries */ |
270 | #define INODE_KTRACE_ENTRY 1 | 246 | #define INODE_KTRACE_ENTRY 1 |
271 | #define INODE_KTRACE_EXIT 2 | 247 | #define INODE_KTRACE_EXIT 2 |
272 | #define INODE_KTRACE_HOLD 3 | 248 | #define INODE_KTRACE_HOLD 3 |
273 | #define INODE_KTRACE_REF 4 | 249 | #define INODE_KTRACE_REF 4 |
274 | #define INODE_KTRACE_RELE 5 | 250 | #define INODE_KTRACE_RELE 5 |
275 | 251 | ||
276 | extern void _xfs_itrace_entry(struct xfs_inode *, const char *, inst_t *); | 252 | extern void _xfs_itrace_entry(struct xfs_inode *, const char *, inst_t *); |
277 | extern void _xfs_itrace_exit(struct xfs_inode *, const char *, inst_t *); | 253 | extern void _xfs_itrace_exit(struct xfs_inode *, const char *, inst_t *); |
278 | extern void xfs_itrace_hold(struct xfs_inode *, char *, int, inst_t *); | 254 | extern void xfs_itrace_hold(struct xfs_inode *, char *, int, inst_t *); |
279 | extern void _xfs_itrace_ref(struct xfs_inode *, char *, int, inst_t *); | 255 | extern void _xfs_itrace_ref(struct xfs_inode *, char *, int, inst_t *); |
280 | extern void xfs_itrace_rele(struct xfs_inode *, char *, int, inst_t *); | 256 | extern void xfs_itrace_rele(struct xfs_inode *, char *, int, inst_t *); |
281 | #define xfs_itrace_entry(ip) \ | 257 | #define xfs_itrace_entry(ip) \ |
282 | _xfs_itrace_entry(ip, __func__, (inst_t *)__return_address) | 258 | _xfs_itrace_entry(ip, __func__, (inst_t *)__return_address) |
283 | #define xfs_itrace_exit(ip) \ | 259 | #define xfs_itrace_exit(ip) \ |
284 | _xfs_itrace_exit(ip, __func__, (inst_t *)__return_address) | 260 | _xfs_itrace_exit(ip, __func__, (inst_t *)__return_address) |
285 | #define xfs_itrace_exit_tag(ip, tag) \ | 261 | #define xfs_itrace_exit_tag(ip, tag) \ |
286 | _xfs_itrace_exit(ip, tag, (inst_t *)__return_address) | 262 | _xfs_itrace_exit(ip, tag, (inst_t *)__return_address) |
287 | #define xfs_itrace_ref(ip) \ | 263 | #define xfs_itrace_ref(ip) \ |
288 | _xfs_itrace_ref(ip, __FILE__, __LINE__, (inst_t *)__return_address) | 264 | _xfs_itrace_ref(ip, __FILE__, __LINE__, (inst_t *)__return_address) |
289 | 265 | ||
290 | #else | 266 | #else |
291 | #define xfs_itrace_entry(a) | 267 | #define xfs_itrace_entry(a) |
292 | #define xfs_itrace_exit(a) | 268 | #define xfs_itrace_exit(a) |
293 | #define xfs_itrace_exit_tag(a, b) | 269 | #define xfs_itrace_exit_tag(a, b) |
294 | #define xfs_itrace_hold(a, b, c, d) | 270 | #define xfs_itrace_hold(a, b, c, d) |
295 | #define xfs_itrace_ref(a) | 271 | #define xfs_itrace_ref(a) |
296 | #define xfs_itrace_rele(a, b, c, d) | 272 | #define xfs_itrace_rele(a, b, c, d) |
297 | #endif | 273 | #endif |
298 | 274 | ||
299 | #endif /* __XFS_VNODE_H__ */ | 275 | #endif /* __XFS_VNODE_H__ */ |
300 | 276 |
fs/xfs/xfs_acl.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2001-2002,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2001-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 | #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_inum.h" | 22 | #include "xfs_inum.h" |
23 | #include "xfs_ag.h" | 23 | #include "xfs_ag.h" |
24 | #include "xfs_dir2.h" | 24 | #include "xfs_dir2.h" |
25 | #include "xfs_bmap_btree.h" | 25 | #include "xfs_bmap_btree.h" |
26 | #include "xfs_alloc_btree.h" | 26 | #include "xfs_alloc_btree.h" |
27 | #include "xfs_ialloc_btree.h" | 27 | #include "xfs_ialloc_btree.h" |
28 | #include "xfs_dir2_sf.h" | 28 | #include "xfs_dir2_sf.h" |
29 | #include "xfs_attr_sf.h" | 29 | #include "xfs_attr_sf.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_acl.h" | 33 | #include "xfs_acl.h" |
34 | #include "xfs_attr.h" | 34 | #include "xfs_attr.h" |
35 | #include "xfs_vnodeops.h" | 35 | #include "xfs_vnodeops.h" |
36 | 36 | ||
37 | #include <linux/capability.h> | 37 | #include <linux/capability.h> |
38 | #include <linux/posix_acl_xattr.h> | 38 | #include <linux/posix_acl_xattr.h> |
39 | 39 | ||
40 | STATIC int xfs_acl_setmode(bhv_vnode_t *, xfs_acl_t *, int *); | 40 | STATIC int xfs_acl_setmode(bhv_vnode_t *, xfs_acl_t *, int *); |
41 | STATIC void xfs_acl_filter_mode(mode_t, xfs_acl_t *); | 41 | STATIC void xfs_acl_filter_mode(mode_t, xfs_acl_t *); |
42 | STATIC void xfs_acl_get_endian(xfs_acl_t *); | 42 | STATIC void xfs_acl_get_endian(xfs_acl_t *); |
43 | STATIC int xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *); | 43 | STATIC int xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *); |
44 | STATIC int xfs_acl_invalid(xfs_acl_t *); | 44 | STATIC int xfs_acl_invalid(xfs_acl_t *); |
45 | STATIC void xfs_acl_sync_mode(mode_t, xfs_acl_t *); | 45 | STATIC void xfs_acl_sync_mode(mode_t, xfs_acl_t *); |
46 | STATIC void xfs_acl_get_attr(bhv_vnode_t *, xfs_acl_t *, int, int, int *); | 46 | STATIC void xfs_acl_get_attr(bhv_vnode_t *, xfs_acl_t *, int, int, int *); |
47 | STATIC void xfs_acl_set_attr(bhv_vnode_t *, xfs_acl_t *, int, int *); | 47 | STATIC void xfs_acl_set_attr(bhv_vnode_t *, xfs_acl_t *, int, int *); |
48 | STATIC int xfs_acl_allow_set(bhv_vnode_t *, int); | 48 | STATIC int xfs_acl_allow_set(bhv_vnode_t *, int); |
49 | 49 | ||
50 | kmem_zone_t *xfs_acl_zone; | 50 | kmem_zone_t *xfs_acl_zone; |
51 | 51 | ||
52 | 52 | ||
53 | /* | 53 | /* |
54 | * Test for existence of access ACL attribute as efficiently as possible. | 54 | * Test for existence of access ACL attribute as efficiently as possible. |
55 | */ | 55 | */ |
56 | int | 56 | int |
57 | xfs_acl_vhasacl_access( | 57 | xfs_acl_vhasacl_access( |
58 | bhv_vnode_t *vp) | 58 | bhv_vnode_t *vp) |
59 | { | 59 | { |
60 | int error; | 60 | int error; |
61 | 61 | ||
62 | xfs_acl_get_attr(vp, NULL, _ACL_TYPE_ACCESS, ATTR_KERNOVAL, &error); | 62 | xfs_acl_get_attr(vp, NULL, _ACL_TYPE_ACCESS, ATTR_KERNOVAL, &error); |
63 | return (error == 0); | 63 | return (error == 0); |
64 | } | 64 | } |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * Test for existence of default ACL attribute as efficiently as possible. | 67 | * Test for existence of default ACL attribute as efficiently as possible. |
68 | */ | 68 | */ |
69 | int | 69 | int |
70 | xfs_acl_vhasacl_default( | 70 | xfs_acl_vhasacl_default( |
71 | bhv_vnode_t *vp) | 71 | bhv_vnode_t *vp) |
72 | { | 72 | { |
73 | int error; | 73 | int error; |
74 | 74 | ||
75 | if (!VN_ISDIR(vp)) | 75 | if (!S_ISDIR(vp->i_mode)) |
76 | return 0; | 76 | return 0; |
77 | xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error); | 77 | xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error); |
78 | return (error == 0); | 78 | return (error == 0); |
79 | } | 79 | } |
80 | 80 | ||
81 | /* | 81 | /* |
82 | * Convert from extended attribute representation to in-memory for XFS. | 82 | * Convert from extended attribute representation to in-memory for XFS. |
83 | */ | 83 | */ |
84 | STATIC int | 84 | STATIC int |
85 | posix_acl_xattr_to_xfs( | 85 | posix_acl_xattr_to_xfs( |
86 | posix_acl_xattr_header *src, | 86 | posix_acl_xattr_header *src, |
87 | size_t size, | 87 | size_t size, |
88 | xfs_acl_t *dest) | 88 | xfs_acl_t *dest) |
89 | { | 89 | { |
90 | posix_acl_xattr_entry *src_entry; | 90 | posix_acl_xattr_entry *src_entry; |
91 | xfs_acl_entry_t *dest_entry; | 91 | xfs_acl_entry_t *dest_entry; |
92 | int n; | 92 | int n; |
93 | 93 | ||
94 | if (!src || !dest) | 94 | if (!src || !dest) |
95 | return EINVAL; | 95 | return EINVAL; |
96 | 96 | ||
97 | if (size < sizeof(posix_acl_xattr_header)) | 97 | if (size < sizeof(posix_acl_xattr_header)) |
98 | return EINVAL; | 98 | return EINVAL; |
99 | 99 | ||
100 | if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) | 100 | if (src->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) |
101 | return EOPNOTSUPP; | 101 | return EOPNOTSUPP; |
102 | 102 | ||
103 | memset(dest, 0, sizeof(xfs_acl_t)); | 103 | memset(dest, 0, sizeof(xfs_acl_t)); |
104 | dest->acl_cnt = posix_acl_xattr_count(size); | 104 | dest->acl_cnt = posix_acl_xattr_count(size); |
105 | if (dest->acl_cnt < 0 || dest->acl_cnt > XFS_ACL_MAX_ENTRIES) | 105 | if (dest->acl_cnt < 0 || dest->acl_cnt > XFS_ACL_MAX_ENTRIES) |
106 | return EINVAL; | 106 | return EINVAL; |
107 | 107 | ||
108 | /* | 108 | /* |
109 | * acl_set_file(3) may request that we set default ACLs with | 109 | * acl_set_file(3) may request that we set default ACLs with |
110 | * zero length -- defend (gracefully) against that here. | 110 | * zero length -- defend (gracefully) against that here. |
111 | */ | 111 | */ |
112 | if (!dest->acl_cnt) | 112 | if (!dest->acl_cnt) |
113 | return 0; | 113 | return 0; |
114 | 114 | ||
115 | src_entry = (posix_acl_xattr_entry *)((char *)src + sizeof(*src)); | 115 | src_entry = (posix_acl_xattr_entry *)((char *)src + sizeof(*src)); |
116 | dest_entry = &dest->acl_entry[0]; | 116 | dest_entry = &dest->acl_entry[0]; |
117 | 117 | ||
118 | for (n = 0; n < dest->acl_cnt; n++, src_entry++, dest_entry++) { | 118 | for (n = 0; n < dest->acl_cnt; n++, src_entry++, dest_entry++) { |
119 | dest_entry->ae_perm = le16_to_cpu(src_entry->e_perm); | 119 | dest_entry->ae_perm = le16_to_cpu(src_entry->e_perm); |
120 | if (_ACL_PERM_INVALID(dest_entry->ae_perm)) | 120 | if (_ACL_PERM_INVALID(dest_entry->ae_perm)) |
121 | return EINVAL; | 121 | return EINVAL; |
122 | dest_entry->ae_tag = le16_to_cpu(src_entry->e_tag); | 122 | dest_entry->ae_tag = le16_to_cpu(src_entry->e_tag); |
123 | switch(dest_entry->ae_tag) { | 123 | switch(dest_entry->ae_tag) { |
124 | case ACL_USER: | 124 | case ACL_USER: |
125 | case ACL_GROUP: | 125 | case ACL_GROUP: |
126 | dest_entry->ae_id = le32_to_cpu(src_entry->e_id); | 126 | dest_entry->ae_id = le32_to_cpu(src_entry->e_id); |
127 | break; | 127 | break; |
128 | case ACL_USER_OBJ: | 128 | case ACL_USER_OBJ: |
129 | case ACL_GROUP_OBJ: | 129 | case ACL_GROUP_OBJ: |
130 | case ACL_MASK: | 130 | case ACL_MASK: |
131 | case ACL_OTHER: | 131 | case ACL_OTHER: |
132 | dest_entry->ae_id = ACL_UNDEFINED_ID; | 132 | dest_entry->ae_id = ACL_UNDEFINED_ID; |
133 | break; | 133 | break; |
134 | default: | 134 | default: |
135 | return EINVAL; | 135 | return EINVAL; |
136 | } | 136 | } |
137 | } | 137 | } |
138 | if (xfs_acl_invalid(dest)) | 138 | if (xfs_acl_invalid(dest)) |
139 | return EINVAL; | 139 | return EINVAL; |
140 | 140 | ||
141 | return 0; | 141 | return 0; |
142 | } | 142 | } |
143 | 143 | ||
144 | /* | 144 | /* |
145 | * Comparison function called from xfs_sort(). | 145 | * Comparison function called from xfs_sort(). |
146 | * Primary key is ae_tag, secondary key is ae_id. | 146 | * Primary key is ae_tag, secondary key is ae_id. |
147 | */ | 147 | */ |
148 | STATIC int | 148 | STATIC int |
149 | xfs_acl_entry_compare( | 149 | xfs_acl_entry_compare( |
150 | const void *va, | 150 | const void *va, |
151 | const void *vb) | 151 | const void *vb) |
152 | { | 152 | { |
153 | xfs_acl_entry_t *a = (xfs_acl_entry_t *)va, | 153 | xfs_acl_entry_t *a = (xfs_acl_entry_t *)va, |
154 | *b = (xfs_acl_entry_t *)vb; | 154 | *b = (xfs_acl_entry_t *)vb; |
155 | 155 | ||
156 | if (a->ae_tag == b->ae_tag) | 156 | if (a->ae_tag == b->ae_tag) |
157 | return (a->ae_id - b->ae_id); | 157 | return (a->ae_id - b->ae_id); |
158 | return (a->ae_tag - b->ae_tag); | 158 | return (a->ae_tag - b->ae_tag); |
159 | } | 159 | } |
160 | 160 | ||
161 | /* | 161 | /* |
162 | * Convert from in-memory XFS to extended attribute representation. | 162 | * Convert from in-memory XFS to extended attribute representation. |
163 | */ | 163 | */ |
164 | STATIC int | 164 | STATIC int |
165 | posix_acl_xfs_to_xattr( | 165 | posix_acl_xfs_to_xattr( |
166 | xfs_acl_t *src, | 166 | xfs_acl_t *src, |
167 | posix_acl_xattr_header *dest, | 167 | posix_acl_xattr_header *dest, |
168 | size_t size) | 168 | size_t size) |
169 | { | 169 | { |
170 | int n; | 170 | int n; |
171 | size_t new_size = posix_acl_xattr_size(src->acl_cnt); | 171 | size_t new_size = posix_acl_xattr_size(src->acl_cnt); |
172 | posix_acl_xattr_entry *dest_entry; | 172 | posix_acl_xattr_entry *dest_entry; |
173 | xfs_acl_entry_t *src_entry; | 173 | xfs_acl_entry_t *src_entry; |
174 | 174 | ||
175 | if (size < new_size) | 175 | if (size < new_size) |
176 | return -ERANGE; | 176 | return -ERANGE; |
177 | 177 | ||
178 | /* Need to sort src XFS ACL by <ae_tag,ae_id> */ | 178 | /* Need to sort src XFS ACL by <ae_tag,ae_id> */ |
179 | xfs_sort(src->acl_entry, src->acl_cnt, sizeof(src->acl_entry[0]), | 179 | xfs_sort(src->acl_entry, src->acl_cnt, sizeof(src->acl_entry[0]), |
180 | xfs_acl_entry_compare); | 180 | xfs_acl_entry_compare); |
181 | 181 | ||
182 | dest->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); | 182 | dest->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); |
183 | dest_entry = &dest->a_entries[0]; | 183 | dest_entry = &dest->a_entries[0]; |
184 | src_entry = &src->acl_entry[0]; | 184 | src_entry = &src->acl_entry[0]; |
185 | for (n = 0; n < src->acl_cnt; n++, dest_entry++, src_entry++) { | 185 | for (n = 0; n < src->acl_cnt; n++, dest_entry++, src_entry++) { |
186 | dest_entry->e_perm = cpu_to_le16(src_entry->ae_perm); | 186 | dest_entry->e_perm = cpu_to_le16(src_entry->ae_perm); |
187 | if (_ACL_PERM_INVALID(src_entry->ae_perm)) | 187 | if (_ACL_PERM_INVALID(src_entry->ae_perm)) |
188 | return -EINVAL; | 188 | return -EINVAL; |
189 | dest_entry->e_tag = cpu_to_le16(src_entry->ae_tag); | 189 | dest_entry->e_tag = cpu_to_le16(src_entry->ae_tag); |
190 | switch (src_entry->ae_tag) { | 190 | switch (src_entry->ae_tag) { |
191 | case ACL_USER: | 191 | case ACL_USER: |
192 | case ACL_GROUP: | 192 | case ACL_GROUP: |
193 | dest_entry->e_id = cpu_to_le32(src_entry->ae_id); | 193 | dest_entry->e_id = cpu_to_le32(src_entry->ae_id); |
194 | break; | 194 | break; |
195 | case ACL_USER_OBJ: | 195 | case ACL_USER_OBJ: |
196 | case ACL_GROUP_OBJ: | 196 | case ACL_GROUP_OBJ: |
197 | case ACL_MASK: | 197 | case ACL_MASK: |
198 | case ACL_OTHER: | 198 | case ACL_OTHER: |
199 | dest_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); | 199 | dest_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); |
200 | break; | 200 | break; |
201 | default: | 201 | default: |
202 | return -EINVAL; | 202 | return -EINVAL; |
203 | } | 203 | } |
204 | } | 204 | } |
205 | return new_size; | 205 | return new_size; |
206 | } | 206 | } |
207 | 207 | ||
208 | int | 208 | int |
209 | xfs_acl_vget( | 209 | xfs_acl_vget( |
210 | bhv_vnode_t *vp, | 210 | bhv_vnode_t *vp, |
211 | void *acl, | 211 | void *acl, |
212 | size_t size, | 212 | size_t size, |
213 | int kind) | 213 | int kind) |
214 | { | 214 | { |
215 | int error; | 215 | int error; |
216 | xfs_acl_t *xfs_acl = NULL; | 216 | xfs_acl_t *xfs_acl = NULL; |
217 | posix_acl_xattr_header *ext_acl = acl; | 217 | posix_acl_xattr_header *ext_acl = acl; |
218 | int flags = 0; | 218 | int flags = 0; |
219 | 219 | ||
220 | VN_HOLD(vp); | 220 | VN_HOLD(vp); |
221 | if(size) { | 221 | if(size) { |
222 | if (!(_ACL_ALLOC(xfs_acl))) { | 222 | if (!(_ACL_ALLOC(xfs_acl))) { |
223 | error = ENOMEM; | 223 | error = ENOMEM; |
224 | goto out; | 224 | goto out; |
225 | } | 225 | } |
226 | memset(xfs_acl, 0, sizeof(xfs_acl_t)); | 226 | memset(xfs_acl, 0, sizeof(xfs_acl_t)); |
227 | } else | 227 | } else |
228 | flags = ATTR_KERNOVAL; | 228 | flags = ATTR_KERNOVAL; |
229 | 229 | ||
230 | xfs_acl_get_attr(vp, xfs_acl, kind, flags, &error); | 230 | xfs_acl_get_attr(vp, xfs_acl, kind, flags, &error); |
231 | if (error) | 231 | if (error) |
232 | goto out; | 232 | goto out; |
233 | 233 | ||
234 | if (!size) { | 234 | if (!size) { |
235 | error = -posix_acl_xattr_size(XFS_ACL_MAX_ENTRIES); | 235 | error = -posix_acl_xattr_size(XFS_ACL_MAX_ENTRIES); |
236 | } else { | 236 | } else { |
237 | if (xfs_acl_invalid(xfs_acl)) { | 237 | if (xfs_acl_invalid(xfs_acl)) { |
238 | error = EINVAL; | 238 | error = EINVAL; |
239 | goto out; | 239 | goto out; |
240 | } | 240 | } |
241 | if (kind == _ACL_TYPE_ACCESS) { | 241 | if (kind == _ACL_TYPE_ACCESS) { |
242 | bhv_vattr_t va; | 242 | bhv_vattr_t va; |
243 | 243 | ||
244 | va.va_mask = XFS_AT_MODE; | 244 | va.va_mask = XFS_AT_MODE; |
245 | error = xfs_getattr(xfs_vtoi(vp), &va, 0); | 245 | error = xfs_getattr(xfs_vtoi(vp), &va, 0); |
246 | if (error) | 246 | if (error) |
247 | goto out; | 247 | goto out; |
248 | xfs_acl_sync_mode(va.va_mode, xfs_acl); | 248 | xfs_acl_sync_mode(va.va_mode, xfs_acl); |
249 | } | 249 | } |
250 | error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size); | 250 | error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size); |
251 | } | 251 | } |
252 | out: | 252 | out: |
253 | VN_RELE(vp); | 253 | VN_RELE(vp); |
254 | if(xfs_acl) | 254 | if(xfs_acl) |
255 | _ACL_FREE(xfs_acl); | 255 | _ACL_FREE(xfs_acl); |
256 | return -error; | 256 | return -error; |
257 | } | 257 | } |
258 | 258 | ||
259 | int | 259 | int |
260 | xfs_acl_vremove( | 260 | xfs_acl_vremove( |
261 | bhv_vnode_t *vp, | 261 | bhv_vnode_t *vp, |
262 | int kind) | 262 | int kind) |
263 | { | 263 | { |
264 | int error; | 264 | int error; |
265 | 265 | ||
266 | VN_HOLD(vp); | 266 | VN_HOLD(vp); |
267 | error = xfs_acl_allow_set(vp, kind); | 267 | error = xfs_acl_allow_set(vp, kind); |
268 | if (!error) { | 268 | if (!error) { |
269 | error = xfs_attr_remove(xfs_vtoi(vp), | 269 | error = xfs_attr_remove(xfs_vtoi(vp), |
270 | kind == _ACL_TYPE_DEFAULT? | 270 | kind == _ACL_TYPE_DEFAULT? |
271 | SGI_ACL_DEFAULT: SGI_ACL_FILE, | 271 | SGI_ACL_DEFAULT: SGI_ACL_FILE, |
272 | ATTR_ROOT); | 272 | ATTR_ROOT); |
273 | if (error == ENOATTR) | 273 | if (error == ENOATTR) |
274 | error = 0; /* 'scool */ | 274 | error = 0; /* 'scool */ |
275 | } | 275 | } |
276 | VN_RELE(vp); | 276 | VN_RELE(vp); |
277 | return -error; | 277 | return -error; |
278 | } | 278 | } |
279 | 279 | ||
280 | int | 280 | int |
281 | xfs_acl_vset( | 281 | xfs_acl_vset( |
282 | bhv_vnode_t *vp, | 282 | bhv_vnode_t *vp, |
283 | void *acl, | 283 | void *acl, |
284 | size_t size, | 284 | size_t size, |
285 | int kind) | 285 | int kind) |
286 | { | 286 | { |
287 | posix_acl_xattr_header *ext_acl = acl; | 287 | posix_acl_xattr_header *ext_acl = acl; |
288 | xfs_acl_t *xfs_acl; | 288 | xfs_acl_t *xfs_acl; |
289 | int error; | 289 | int error; |
290 | int basicperms = 0; /* more than std unix perms? */ | 290 | int basicperms = 0; /* more than std unix perms? */ |
291 | 291 | ||
292 | if (!acl) | 292 | if (!acl) |
293 | return -EINVAL; | 293 | return -EINVAL; |
294 | 294 | ||
295 | if (!(_ACL_ALLOC(xfs_acl))) | 295 | if (!(_ACL_ALLOC(xfs_acl))) |
296 | return -ENOMEM; | 296 | return -ENOMEM; |
297 | 297 | ||
298 | error = posix_acl_xattr_to_xfs(ext_acl, size, xfs_acl); | 298 | error = posix_acl_xattr_to_xfs(ext_acl, size, xfs_acl); |
299 | if (error) { | 299 | if (error) { |
300 | _ACL_FREE(xfs_acl); | 300 | _ACL_FREE(xfs_acl); |
301 | return -error; | 301 | return -error; |
302 | } | 302 | } |
303 | if (!xfs_acl->acl_cnt) { | 303 | if (!xfs_acl->acl_cnt) { |
304 | _ACL_FREE(xfs_acl); | 304 | _ACL_FREE(xfs_acl); |
305 | return 0; | 305 | return 0; |
306 | } | 306 | } |
307 | 307 | ||
308 | VN_HOLD(vp); | 308 | VN_HOLD(vp); |
309 | error = xfs_acl_allow_set(vp, kind); | 309 | error = xfs_acl_allow_set(vp, kind); |
310 | 310 | ||
311 | /* Incoming ACL exists, set file mode based on its value */ | 311 | /* Incoming ACL exists, set file mode based on its value */ |
312 | if (!error && kind == _ACL_TYPE_ACCESS) | 312 | if (!error && kind == _ACL_TYPE_ACCESS) |
313 | error = xfs_acl_setmode(vp, xfs_acl, &basicperms); | 313 | error = xfs_acl_setmode(vp, xfs_acl, &basicperms); |
314 | 314 | ||
315 | if (error) | 315 | if (error) |
316 | goto out; | 316 | goto out; |
317 | 317 | ||
318 | /* | 318 | /* |
319 | * If we have more than std unix permissions, set up the actual attr. | 319 | * If we have more than std unix permissions, set up the actual attr. |
320 | * Otherwise, delete any existing attr. This prevents us from | 320 | * Otherwise, delete any existing attr. This prevents us from |
321 | * having actual attrs for permissions that can be stored in the | 321 | * having actual attrs for permissions that can be stored in the |
322 | * standard permission bits. | 322 | * standard permission bits. |
323 | */ | 323 | */ |
324 | if (!basicperms) { | 324 | if (!basicperms) { |
325 | xfs_acl_set_attr(vp, xfs_acl, kind, &error); | 325 | xfs_acl_set_attr(vp, xfs_acl, kind, &error); |
326 | } else { | 326 | } else { |
327 | error = -xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); | 327 | error = -xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); |
328 | } | 328 | } |
329 | 329 | ||
330 | out: | 330 | out: |
331 | VN_RELE(vp); | 331 | VN_RELE(vp); |
332 | _ACL_FREE(xfs_acl); | 332 | _ACL_FREE(xfs_acl); |
333 | return -error; | 333 | return -error; |
334 | } | 334 | } |
335 | 335 | ||
336 | int | 336 | int |
337 | xfs_acl_iaccess( | 337 | xfs_acl_iaccess( |
338 | xfs_inode_t *ip, | 338 | xfs_inode_t *ip, |
339 | mode_t mode, | 339 | mode_t mode, |
340 | cred_t *cr) | 340 | cred_t *cr) |
341 | { | 341 | { |
342 | xfs_acl_t *acl; | 342 | xfs_acl_t *acl; |
343 | int rval; | 343 | int rval; |
344 | 344 | ||
345 | if (!(_ACL_ALLOC(acl))) | 345 | if (!(_ACL_ALLOC(acl))) |
346 | return -1; | 346 | return -1; |
347 | 347 | ||
348 | /* If the file has no ACL return -1. */ | 348 | /* If the file has no ACL return -1. */ |
349 | rval = sizeof(xfs_acl_t); | 349 | rval = sizeof(xfs_acl_t); |
350 | if (xfs_attr_fetch(ip, SGI_ACL_FILE, SGI_ACL_FILE_SIZE, | 350 | if (xfs_attr_fetch(ip, SGI_ACL_FILE, SGI_ACL_FILE_SIZE, |
351 | (char *)acl, &rval, ATTR_ROOT | ATTR_KERNACCESS, cr)) { | 351 | (char *)acl, &rval, ATTR_ROOT | ATTR_KERNACCESS, cr)) { |
352 | _ACL_FREE(acl); | 352 | _ACL_FREE(acl); |
353 | return -1; | 353 | return -1; |
354 | } | 354 | } |
355 | xfs_acl_get_endian(acl); | 355 | xfs_acl_get_endian(acl); |
356 | 356 | ||
357 | /* If the file has an empty ACL return -1. */ | 357 | /* If the file has an empty ACL return -1. */ |
358 | if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) { | 358 | if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) { |
359 | _ACL_FREE(acl); | 359 | _ACL_FREE(acl); |
360 | return -1; | 360 | return -1; |
361 | } | 361 | } |
362 | 362 | ||
363 | /* Synchronize ACL with mode bits */ | 363 | /* Synchronize ACL with mode bits */ |
364 | xfs_acl_sync_mode(ip->i_d.di_mode, acl); | 364 | xfs_acl_sync_mode(ip->i_d.di_mode, acl); |
365 | 365 | ||
366 | rval = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr); | 366 | rval = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, acl, mode, cr); |
367 | _ACL_FREE(acl); | 367 | _ACL_FREE(acl); |
368 | return rval; | 368 | return rval; |
369 | } | 369 | } |
370 | 370 | ||
371 | STATIC int | 371 | STATIC int |
372 | xfs_acl_allow_set( | 372 | xfs_acl_allow_set( |
373 | bhv_vnode_t *vp, | 373 | bhv_vnode_t *vp, |
374 | int kind) | 374 | int kind) |
375 | { | 375 | { |
376 | xfs_inode_t *ip = xfs_vtoi(vp); | 376 | xfs_inode_t *ip = xfs_vtoi(vp); |
377 | bhv_vattr_t va; | 377 | bhv_vattr_t va; |
378 | int error; | 378 | int error; |
379 | 379 | ||
380 | if (vp->i_flags & (S_IMMUTABLE|S_APPEND)) | 380 | if (vp->i_flags & (S_IMMUTABLE|S_APPEND)) |
381 | return EPERM; | 381 | return EPERM; |
382 | if (kind == _ACL_TYPE_DEFAULT && !VN_ISDIR(vp)) | 382 | if (kind == _ACL_TYPE_DEFAULT && !S_ISDIR(vp->i_mode)) |
383 | return ENOTDIR; | 383 | return ENOTDIR; |
384 | if (vp->i_sb->s_flags & MS_RDONLY) | 384 | if (vp->i_sb->s_flags & MS_RDONLY) |
385 | return EROFS; | 385 | return EROFS; |
386 | va.va_mask = XFS_AT_UID; | 386 | va.va_mask = XFS_AT_UID; |
387 | error = xfs_getattr(ip, &va, 0); | 387 | error = xfs_getattr(ip, &va, 0); |
388 | if (error) | 388 | if (error) |
389 | return error; | 389 | return error; |
390 | if (va.va_uid != current->fsuid && !capable(CAP_FOWNER)) | 390 | if (va.va_uid != current->fsuid && !capable(CAP_FOWNER)) |
391 | return EPERM; | 391 | return EPERM; |
392 | return error; | 392 | return error; |
393 | } | 393 | } |
394 | 394 | ||
395 | /* | 395 | /* |
396 | * Note: cr is only used here for the capability check if the ACL test fails. | 396 | * Note: cr is only used here for the capability check if the ACL test fails. |
397 | * It is not used to find out the credentials uid or groups etc, as was | 397 | * It is not used to find out the credentials uid or groups etc, as was |
398 | * done in IRIX. It is assumed that the uid and groups for the current | 398 | * done in IRIX. It is assumed that the uid and groups for the current |
399 | * thread are taken from "current" instead of the cr parameter. | 399 | * thread are taken from "current" instead of the cr parameter. |
400 | */ | 400 | */ |
401 | STATIC int | 401 | STATIC int |
402 | xfs_acl_access( | 402 | xfs_acl_access( |
403 | uid_t fuid, | 403 | uid_t fuid, |
404 | gid_t fgid, | 404 | gid_t fgid, |
405 | xfs_acl_t *fap, | 405 | xfs_acl_t *fap, |
406 | mode_t md, | 406 | mode_t md, |
407 | cred_t *cr) | 407 | cred_t *cr) |
408 | { | 408 | { |
409 | xfs_acl_entry_t matched; | 409 | xfs_acl_entry_t matched; |
410 | int i, allows; | 410 | int i, allows; |
411 | int maskallows = -1; /* true, but not 1, either */ | 411 | int maskallows = -1; /* true, but not 1, either */ |
412 | int seen_userobj = 0; | 412 | int seen_userobj = 0; |
413 | 413 | ||
414 | matched.ae_tag = 0; /* Invalid type */ | 414 | matched.ae_tag = 0; /* Invalid type */ |
415 | matched.ae_perm = 0; | 415 | matched.ae_perm = 0; |
416 | 416 | ||
417 | for (i = 0; i < fap->acl_cnt; i++) { | 417 | for (i = 0; i < fap->acl_cnt; i++) { |
418 | /* | 418 | /* |
419 | * Break out if we've got a user_obj entry or | 419 | * Break out if we've got a user_obj entry or |
420 | * a user entry and the mask (and have processed USER_OBJ) | 420 | * a user entry and the mask (and have processed USER_OBJ) |
421 | */ | 421 | */ |
422 | if (matched.ae_tag == ACL_USER_OBJ) | 422 | if (matched.ae_tag == ACL_USER_OBJ) |
423 | break; | 423 | break; |
424 | if (matched.ae_tag == ACL_USER) { | 424 | if (matched.ae_tag == ACL_USER) { |
425 | if (maskallows != -1 && seen_userobj) | 425 | if (maskallows != -1 && seen_userobj) |
426 | break; | 426 | break; |
427 | if (fap->acl_entry[i].ae_tag != ACL_MASK && | 427 | if (fap->acl_entry[i].ae_tag != ACL_MASK && |
428 | fap->acl_entry[i].ae_tag != ACL_USER_OBJ) | 428 | fap->acl_entry[i].ae_tag != ACL_USER_OBJ) |
429 | continue; | 429 | continue; |
430 | } | 430 | } |
431 | /* True if this entry allows the requested access */ | 431 | /* True if this entry allows the requested access */ |
432 | allows = ((fap->acl_entry[i].ae_perm & md) == md); | 432 | allows = ((fap->acl_entry[i].ae_perm & md) == md); |
433 | 433 | ||
434 | switch (fap->acl_entry[i].ae_tag) { | 434 | switch (fap->acl_entry[i].ae_tag) { |
435 | case ACL_USER_OBJ: | 435 | case ACL_USER_OBJ: |
436 | seen_userobj = 1; | 436 | seen_userobj = 1; |
437 | if (fuid != current->fsuid) | 437 | if (fuid != current->fsuid) |
438 | continue; | 438 | continue; |
439 | matched.ae_tag = ACL_USER_OBJ; | 439 | matched.ae_tag = ACL_USER_OBJ; |
440 | matched.ae_perm = allows; | 440 | matched.ae_perm = allows; |
441 | break; | 441 | break; |
442 | case ACL_USER: | 442 | case ACL_USER: |
443 | if (fap->acl_entry[i].ae_id != current->fsuid) | 443 | if (fap->acl_entry[i].ae_id != current->fsuid) |
444 | continue; | 444 | continue; |
445 | matched.ae_tag = ACL_USER; | 445 | matched.ae_tag = ACL_USER; |
446 | matched.ae_perm = allows; | 446 | matched.ae_perm = allows; |
447 | break; | 447 | break; |
448 | case ACL_GROUP_OBJ: | 448 | case ACL_GROUP_OBJ: |
449 | if ((matched.ae_tag == ACL_GROUP_OBJ || | 449 | if ((matched.ae_tag == ACL_GROUP_OBJ || |
450 | matched.ae_tag == ACL_GROUP) && !allows) | 450 | matched.ae_tag == ACL_GROUP) && !allows) |
451 | continue; | 451 | continue; |
452 | if (!in_group_p(fgid)) | 452 | if (!in_group_p(fgid)) |
453 | continue; | 453 | continue; |
454 | matched.ae_tag = ACL_GROUP_OBJ; | 454 | matched.ae_tag = ACL_GROUP_OBJ; |
455 | matched.ae_perm = allows; | 455 | matched.ae_perm = allows; |
456 | break; | 456 | break; |
457 | case ACL_GROUP: | 457 | case ACL_GROUP: |
458 | if ((matched.ae_tag == ACL_GROUP_OBJ || | 458 | if ((matched.ae_tag == ACL_GROUP_OBJ || |
459 | matched.ae_tag == ACL_GROUP) && !allows) | 459 | matched.ae_tag == ACL_GROUP) && !allows) |
460 | continue; | 460 | continue; |
461 | if (!in_group_p(fap->acl_entry[i].ae_id)) | 461 | if (!in_group_p(fap->acl_entry[i].ae_id)) |
462 | continue; | 462 | continue; |
463 | matched.ae_tag = ACL_GROUP; | 463 | matched.ae_tag = ACL_GROUP; |
464 | matched.ae_perm = allows; | 464 | matched.ae_perm = allows; |
465 | break; | 465 | break; |
466 | case ACL_MASK: | 466 | case ACL_MASK: |
467 | maskallows = allows; | 467 | maskallows = allows; |
468 | break; | 468 | break; |
469 | case ACL_OTHER: | 469 | case ACL_OTHER: |
470 | if (matched.ae_tag != 0) | 470 | if (matched.ae_tag != 0) |
471 | continue; | 471 | continue; |
472 | matched.ae_tag = ACL_OTHER; | 472 | matched.ae_tag = ACL_OTHER; |
473 | matched.ae_perm = allows; | 473 | matched.ae_perm = allows; |
474 | break; | 474 | break; |
475 | } | 475 | } |
476 | } | 476 | } |
477 | /* | 477 | /* |
478 | * First possibility is that no matched entry allows access. | 478 | * First possibility is that no matched entry allows access. |
479 | * The capability to override DAC may exist, so check for it. | 479 | * The capability to override DAC may exist, so check for it. |
480 | */ | 480 | */ |
481 | switch (matched.ae_tag) { | 481 | switch (matched.ae_tag) { |
482 | case ACL_OTHER: | 482 | case ACL_OTHER: |
483 | case ACL_USER_OBJ: | 483 | case ACL_USER_OBJ: |
484 | if (matched.ae_perm) | 484 | if (matched.ae_perm) |
485 | return 0; | 485 | return 0; |
486 | break; | 486 | break; |
487 | case ACL_USER: | 487 | case ACL_USER: |
488 | case ACL_GROUP_OBJ: | 488 | case ACL_GROUP_OBJ: |
489 | case ACL_GROUP: | 489 | case ACL_GROUP: |
490 | if (maskallows && matched.ae_perm) | 490 | if (maskallows && matched.ae_perm) |
491 | return 0; | 491 | return 0; |
492 | break; | 492 | break; |
493 | case 0: | 493 | case 0: |
494 | break; | 494 | break; |
495 | } | 495 | } |
496 | 496 | ||
497 | /* EACCES tells generic_permission to check for capability overrides */ | 497 | /* EACCES tells generic_permission to check for capability overrides */ |
498 | return EACCES; | 498 | return EACCES; |
499 | } | 499 | } |
500 | 500 | ||
501 | /* | 501 | /* |
502 | * ACL validity checker. | 502 | * ACL validity checker. |
503 | * This acl validation routine checks each ACL entry read in makes sense. | 503 | * This acl validation routine checks each ACL entry read in makes sense. |
504 | */ | 504 | */ |
505 | STATIC int | 505 | STATIC int |
506 | xfs_acl_invalid( | 506 | xfs_acl_invalid( |
507 | xfs_acl_t *aclp) | 507 | xfs_acl_t *aclp) |
508 | { | 508 | { |
509 | xfs_acl_entry_t *entry, *e; | 509 | xfs_acl_entry_t *entry, *e; |
510 | int user = 0, group = 0, other = 0, mask = 0; | 510 | int user = 0, group = 0, other = 0, mask = 0; |
511 | int mask_required = 0; | 511 | int mask_required = 0; |
512 | int i, j; | 512 | int i, j; |
513 | 513 | ||
514 | if (!aclp) | 514 | if (!aclp) |
515 | goto acl_invalid; | 515 | goto acl_invalid; |
516 | 516 | ||
517 | if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES) | 517 | if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES) |
518 | goto acl_invalid; | 518 | goto acl_invalid; |
519 | 519 | ||
520 | for (i = 0; i < aclp->acl_cnt; i++) { | 520 | for (i = 0; i < aclp->acl_cnt; i++) { |
521 | entry = &aclp->acl_entry[i]; | 521 | entry = &aclp->acl_entry[i]; |
522 | switch (entry->ae_tag) { | 522 | switch (entry->ae_tag) { |
523 | case ACL_USER_OBJ: | 523 | case ACL_USER_OBJ: |
524 | if (user++) | 524 | if (user++) |
525 | goto acl_invalid; | 525 | goto acl_invalid; |
526 | break; | 526 | break; |
527 | case ACL_GROUP_OBJ: | 527 | case ACL_GROUP_OBJ: |
528 | if (group++) | 528 | if (group++) |
529 | goto acl_invalid; | 529 | goto acl_invalid; |
530 | break; | 530 | break; |
531 | case ACL_OTHER: | 531 | case ACL_OTHER: |
532 | if (other++) | 532 | if (other++) |
533 | goto acl_invalid; | 533 | goto acl_invalid; |
534 | break; | 534 | break; |
535 | case ACL_USER: | 535 | case ACL_USER: |
536 | case ACL_GROUP: | 536 | case ACL_GROUP: |
537 | for (j = i + 1; j < aclp->acl_cnt; j++) { | 537 | for (j = i + 1; j < aclp->acl_cnt; j++) { |
538 | e = &aclp->acl_entry[j]; | 538 | e = &aclp->acl_entry[j]; |
539 | if (e->ae_id == entry->ae_id && | 539 | if (e->ae_id == entry->ae_id && |
540 | e->ae_tag == entry->ae_tag) | 540 | e->ae_tag == entry->ae_tag) |
541 | goto acl_invalid; | 541 | goto acl_invalid; |
542 | } | 542 | } |
543 | mask_required++; | 543 | mask_required++; |
544 | break; | 544 | break; |
545 | case ACL_MASK: | 545 | case ACL_MASK: |
546 | if (mask++) | 546 | if (mask++) |
547 | goto acl_invalid; | 547 | goto acl_invalid; |
548 | break; | 548 | break; |
549 | default: | 549 | default: |
550 | goto acl_invalid; | 550 | goto acl_invalid; |
551 | } | 551 | } |
552 | } | 552 | } |
553 | if (!user || !group || !other || (mask_required && !mask)) | 553 | if (!user || !group || !other || (mask_required && !mask)) |
554 | goto acl_invalid; | 554 | goto acl_invalid; |
555 | else | 555 | else |
556 | return 0; | 556 | return 0; |
557 | acl_invalid: | 557 | acl_invalid: |
558 | return EINVAL; | 558 | return EINVAL; |
559 | } | 559 | } |
560 | 560 | ||
561 | /* | 561 | /* |
562 | * Do ACL endian conversion. | 562 | * Do ACL endian conversion. |
563 | */ | 563 | */ |
564 | STATIC void | 564 | STATIC void |
565 | xfs_acl_get_endian( | 565 | xfs_acl_get_endian( |
566 | xfs_acl_t *aclp) | 566 | xfs_acl_t *aclp) |
567 | { | 567 | { |
568 | xfs_acl_entry_t *ace, *end; | 568 | xfs_acl_entry_t *ace, *end; |
569 | 569 | ||
570 | INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); | 570 | INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); |
571 | end = &aclp->acl_entry[0]+aclp->acl_cnt; | 571 | end = &aclp->acl_entry[0]+aclp->acl_cnt; |
572 | for (ace = &aclp->acl_entry[0]; ace < end; ace++) { | 572 | for (ace = &aclp->acl_entry[0]; ace < end; ace++) { |
573 | INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag); | 573 | INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag); |
574 | INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id); | 574 | INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id); |
575 | INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm); | 575 | INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm); |
576 | } | 576 | } |
577 | } | 577 | } |
578 | 578 | ||
579 | /* | 579 | /* |
580 | * Get the ACL from the EA and do endian conversion. | 580 | * Get the ACL from the EA and do endian conversion. |
581 | */ | 581 | */ |
582 | STATIC void | 582 | STATIC void |
583 | xfs_acl_get_attr( | 583 | xfs_acl_get_attr( |
584 | bhv_vnode_t *vp, | 584 | bhv_vnode_t *vp, |
585 | xfs_acl_t *aclp, | 585 | xfs_acl_t *aclp, |
586 | int kind, | 586 | int kind, |
587 | int flags, | 587 | int flags, |
588 | int *error) | 588 | int *error) |
589 | { | 589 | { |
590 | int len = sizeof(xfs_acl_t); | 590 | int len = sizeof(xfs_acl_t); |
591 | 591 | ||
592 | ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1); | 592 | ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1); |
593 | flags |= ATTR_ROOT; | 593 | flags |= ATTR_ROOT; |
594 | *error = xfs_attr_get(xfs_vtoi(vp), | 594 | *error = xfs_attr_get(xfs_vtoi(vp), |
595 | kind == _ACL_TYPE_ACCESS ? | 595 | kind == _ACL_TYPE_ACCESS ? |
596 | SGI_ACL_FILE : SGI_ACL_DEFAULT, | 596 | SGI_ACL_FILE : SGI_ACL_DEFAULT, |
597 | (char *)aclp, &len, flags, sys_cred); | 597 | (char *)aclp, &len, flags, sys_cred); |
598 | if (*error || (flags & ATTR_KERNOVAL)) | 598 | if (*error || (flags & ATTR_KERNOVAL)) |
599 | return; | 599 | return; |
600 | xfs_acl_get_endian(aclp); | 600 | xfs_acl_get_endian(aclp); |
601 | } | 601 | } |
602 | 602 | ||
603 | /* | 603 | /* |
604 | * Set the EA with the ACL and do endian conversion. | 604 | * Set the EA with the ACL and do endian conversion. |
605 | */ | 605 | */ |
606 | STATIC void | 606 | STATIC void |
607 | xfs_acl_set_attr( | 607 | xfs_acl_set_attr( |
608 | bhv_vnode_t *vp, | 608 | bhv_vnode_t *vp, |
609 | xfs_acl_t *aclp, | 609 | xfs_acl_t *aclp, |
610 | int kind, | 610 | int kind, |
611 | int *error) | 611 | int *error) |
612 | { | 612 | { |
613 | xfs_acl_entry_t *ace, *newace, *end; | 613 | xfs_acl_entry_t *ace, *newace, *end; |
614 | xfs_acl_t *newacl; | 614 | xfs_acl_t *newacl; |
615 | int len; | 615 | int len; |
616 | 616 | ||
617 | if (!(_ACL_ALLOC(newacl))) { | 617 | if (!(_ACL_ALLOC(newacl))) { |
618 | *error = ENOMEM; | 618 | *error = ENOMEM; |
619 | return; | 619 | return; |
620 | } | 620 | } |
621 | 621 | ||
622 | len = sizeof(xfs_acl_t) - | 622 | len = sizeof(xfs_acl_t) - |
623 | (sizeof(xfs_acl_entry_t) * (XFS_ACL_MAX_ENTRIES - aclp->acl_cnt)); | 623 | (sizeof(xfs_acl_entry_t) * (XFS_ACL_MAX_ENTRIES - aclp->acl_cnt)); |
624 | end = &aclp->acl_entry[0]+aclp->acl_cnt; | 624 | end = &aclp->acl_entry[0]+aclp->acl_cnt; |
625 | for (ace = &aclp->acl_entry[0], newace = &newacl->acl_entry[0]; | 625 | for (ace = &aclp->acl_entry[0], newace = &newacl->acl_entry[0]; |
626 | ace < end; | 626 | ace < end; |
627 | ace++, newace++) { | 627 | ace++, newace++) { |
628 | INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag); | 628 | INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag); |
629 | INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id); | 629 | INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id); |
630 | INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm); | 630 | INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm); |
631 | } | 631 | } |
632 | INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); | 632 | INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); |
633 | *error = xfs_attr_set(xfs_vtoi(vp), | 633 | *error = xfs_attr_set(xfs_vtoi(vp), |
634 | kind == _ACL_TYPE_ACCESS ? | 634 | kind == _ACL_TYPE_ACCESS ? |
635 | SGI_ACL_FILE: SGI_ACL_DEFAULT, | 635 | SGI_ACL_FILE: SGI_ACL_DEFAULT, |
636 | (char *)newacl, len, ATTR_ROOT); | 636 | (char *)newacl, len, ATTR_ROOT); |
637 | _ACL_FREE(newacl); | 637 | _ACL_FREE(newacl); |
638 | } | 638 | } |
639 | 639 | ||
640 | int | 640 | int |
641 | xfs_acl_vtoacl( | 641 | xfs_acl_vtoacl( |
642 | bhv_vnode_t *vp, | 642 | bhv_vnode_t *vp, |
643 | xfs_acl_t *access_acl, | 643 | xfs_acl_t *access_acl, |
644 | xfs_acl_t *default_acl) | 644 | xfs_acl_t *default_acl) |
645 | { | 645 | { |
646 | bhv_vattr_t va; | 646 | bhv_vattr_t va; |
647 | int error = 0; | 647 | int error = 0; |
648 | 648 | ||
649 | if (access_acl) { | 649 | if (access_acl) { |
650 | /* | 650 | /* |
651 | * Get the Access ACL and the mode. If either cannot | 651 | * Get the Access ACL and the mode. If either cannot |
652 | * be obtained for some reason, invalidate the access ACL. | 652 | * be obtained for some reason, invalidate the access ACL. |
653 | */ | 653 | */ |
654 | xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error); | 654 | xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error); |
655 | if (!error) { | 655 | if (!error) { |
656 | /* Got the ACL, need the mode... */ | 656 | /* Got the ACL, need the mode... */ |
657 | va.va_mask = XFS_AT_MODE; | 657 | va.va_mask = XFS_AT_MODE; |
658 | error = xfs_getattr(xfs_vtoi(vp), &va, 0); | 658 | error = xfs_getattr(xfs_vtoi(vp), &va, 0); |
659 | } | 659 | } |
660 | 660 | ||
661 | if (error) | 661 | if (error) |
662 | access_acl->acl_cnt = XFS_ACL_NOT_PRESENT; | 662 | access_acl->acl_cnt = XFS_ACL_NOT_PRESENT; |
663 | else /* We have a good ACL and the file mode, synchronize. */ | 663 | else /* We have a good ACL and the file mode, synchronize. */ |
664 | xfs_acl_sync_mode(va.va_mode, access_acl); | 664 | xfs_acl_sync_mode(va.va_mode, access_acl); |
665 | } | 665 | } |
666 | 666 | ||
667 | if (default_acl) { | 667 | if (default_acl) { |
668 | xfs_acl_get_attr(vp, default_acl, _ACL_TYPE_DEFAULT, 0, &error); | 668 | xfs_acl_get_attr(vp, default_acl, _ACL_TYPE_DEFAULT, 0, &error); |
669 | if (error) | 669 | if (error) |
670 | default_acl->acl_cnt = XFS_ACL_NOT_PRESENT; | 670 | default_acl->acl_cnt = XFS_ACL_NOT_PRESENT; |
671 | } | 671 | } |
672 | return error; | 672 | return error; |
673 | } | 673 | } |
674 | 674 | ||
675 | /* | 675 | /* |
676 | * This function retrieves the parent directory's acl, processes it | 676 | * This function retrieves the parent directory's acl, processes it |
677 | * and lets the child inherit the acl(s) that it should. | 677 | * and lets the child inherit the acl(s) that it should. |
678 | */ | 678 | */ |
679 | int | 679 | int |
680 | xfs_acl_inherit( | 680 | xfs_acl_inherit( |
681 | bhv_vnode_t *vp, | 681 | bhv_vnode_t *vp, |
682 | mode_t mode, | 682 | mode_t mode, |
683 | xfs_acl_t *pdaclp) | 683 | xfs_acl_t *pdaclp) |
684 | { | 684 | { |
685 | xfs_acl_t *cacl; | 685 | xfs_acl_t *cacl; |
686 | int error = 0; | 686 | int error = 0; |
687 | int basicperms = 0; | 687 | int basicperms = 0; |
688 | 688 | ||
689 | /* | 689 | /* |
690 | * If the parent does not have a default ACL, or it's an | 690 | * If the parent does not have a default ACL, or it's an |
691 | * invalid ACL, we're done. | 691 | * invalid ACL, we're done. |
692 | */ | 692 | */ |
693 | if (!vp) | 693 | if (!vp) |
694 | return 0; | 694 | return 0; |
695 | if (!pdaclp || xfs_acl_invalid(pdaclp)) | 695 | if (!pdaclp || xfs_acl_invalid(pdaclp)) |
696 | return 0; | 696 | return 0; |
697 | 697 | ||
698 | /* | 698 | /* |
699 | * Copy the default ACL of the containing directory to | 699 | * Copy the default ACL of the containing directory to |
700 | * the access ACL of the new file and use the mode that | 700 | * the access ACL of the new file and use the mode that |
701 | * was passed in to set up the correct initial values for | 701 | * was passed in to set up the correct initial values for |
702 | * the u::,g::[m::], and o:: entries. This is what makes | 702 | * the u::,g::[m::], and o:: entries. This is what makes |
703 | * umask() "work" with ACL's. | 703 | * umask() "work" with ACL's. |
704 | */ | 704 | */ |
705 | 705 | ||
706 | if (!(_ACL_ALLOC(cacl))) | 706 | if (!(_ACL_ALLOC(cacl))) |
707 | return ENOMEM; | 707 | return ENOMEM; |
708 | 708 | ||
709 | memcpy(cacl, pdaclp, sizeof(xfs_acl_t)); | 709 | memcpy(cacl, pdaclp, sizeof(xfs_acl_t)); |
710 | xfs_acl_filter_mode(mode, cacl); | 710 | xfs_acl_filter_mode(mode, cacl); |
711 | error = xfs_acl_setmode(vp, cacl, &basicperms); | 711 | error = xfs_acl_setmode(vp, cacl, &basicperms); |
712 | if (error) | 712 | if (error) |
713 | goto out_error; | 713 | goto out_error; |
714 | 714 | ||
715 | /* | 715 | /* |
716 | * Set the Default and Access ACL on the file. The mode is already | 716 | * Set the Default and Access ACL on the file. The mode is already |
717 | * set on the file, so we don't need to worry about that. | 717 | * set on the file, so we don't need to worry about that. |
718 | * | 718 | * |
719 | * If the new file is a directory, its default ACL is a copy of | 719 | * If the new file is a directory, its default ACL is a copy of |
720 | * the containing directory's default ACL. | 720 | * the containing directory's default ACL. |
721 | */ | 721 | */ |
722 | if (VN_ISDIR(vp)) | 722 | if (S_ISDIR(vp->i_mode)) |
723 | xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error); | 723 | xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error); |
724 | if (!error && !basicperms) | 724 | if (!error && !basicperms) |
725 | xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error); | 725 | xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error); |
726 | out_error: | 726 | out_error: |
727 | _ACL_FREE(cacl); | 727 | _ACL_FREE(cacl); |
728 | return error; | 728 | return error; |
729 | } | 729 | } |
730 | 730 | ||
731 | /* | 731 | /* |
732 | * Set up the correct mode on the file based on the supplied ACL. This | 732 | * Set up the correct mode on the file based on the supplied ACL. This |
733 | * makes sure that the mode on the file reflects the state of the | 733 | * makes sure that the mode on the file reflects the state of the |
734 | * u::,g::[m::], and o:: entries in the ACL. Since the mode is where | 734 | * u::,g::[m::], and o:: entries in the ACL. Since the mode is where |
735 | * the ACL is going to get the permissions for these entries, we must | 735 | * the ACL is going to get the permissions for these entries, we must |
736 | * synchronize the mode whenever we set the ACL on a file. | 736 | * synchronize the mode whenever we set the ACL on a file. |
737 | */ | 737 | */ |
738 | STATIC int | 738 | STATIC int |
739 | xfs_acl_setmode( | 739 | xfs_acl_setmode( |
740 | bhv_vnode_t *vp, | 740 | bhv_vnode_t *vp, |
741 | xfs_acl_t *acl, | 741 | xfs_acl_t *acl, |
742 | int *basicperms) | 742 | int *basicperms) |
743 | { | 743 | { |
744 | bhv_vattr_t va; | 744 | bhv_vattr_t va; |
745 | xfs_acl_entry_t *ap; | 745 | xfs_acl_entry_t *ap; |
746 | xfs_acl_entry_t *gap = NULL; | 746 | xfs_acl_entry_t *gap = NULL; |
747 | int i, error, nomask = 1; | 747 | int i, error, nomask = 1; |
748 | 748 | ||
749 | *basicperms = 1; | 749 | *basicperms = 1; |
750 | 750 | ||
751 | if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) | 751 | if (acl->acl_cnt == XFS_ACL_NOT_PRESENT) |
752 | return 0; | 752 | return 0; |
753 | 753 | ||
754 | /* | 754 | /* |
755 | * Copy the u::, g::, o::, and m:: bits from the ACL into the | 755 | * Copy the u::, g::, o::, and m:: bits from the ACL into the |
756 | * mode. The m:: bits take precedence over the g:: bits. | 756 | * mode. The m:: bits take precedence over the g:: bits. |
757 | */ | 757 | */ |
758 | va.va_mask = XFS_AT_MODE; | 758 | va.va_mask = XFS_AT_MODE; |
759 | error = xfs_getattr(xfs_vtoi(vp), &va, 0); | 759 | error = xfs_getattr(xfs_vtoi(vp), &va, 0); |
760 | if (error) | 760 | if (error) |
761 | return error; | 761 | return error; |
762 | 762 | ||
763 | va.va_mask = XFS_AT_MODE; | 763 | va.va_mask = XFS_AT_MODE; |
764 | va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); | 764 | va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); |
765 | ap = acl->acl_entry; | 765 | ap = acl->acl_entry; |
766 | for (i = 0; i < acl->acl_cnt; ++i) { | 766 | for (i = 0; i < acl->acl_cnt; ++i) { |
767 | switch (ap->ae_tag) { | 767 | switch (ap->ae_tag) { |
768 | case ACL_USER_OBJ: | 768 | case ACL_USER_OBJ: |
769 | va.va_mode |= ap->ae_perm << 6; | 769 | va.va_mode |= ap->ae_perm << 6; |
770 | break; | 770 | break; |
771 | case ACL_GROUP_OBJ: | 771 | case ACL_GROUP_OBJ: |
772 | gap = ap; | 772 | gap = ap; |
773 | break; | 773 | break; |
774 | case ACL_MASK: /* more than just standard modes */ | 774 | case ACL_MASK: /* more than just standard modes */ |
775 | nomask = 0; | 775 | nomask = 0; |
776 | va.va_mode |= ap->ae_perm << 3; | 776 | va.va_mode |= ap->ae_perm << 3; |
777 | *basicperms = 0; | 777 | *basicperms = 0; |
778 | break; | 778 | break; |
779 | case ACL_OTHER: | 779 | case ACL_OTHER: |
780 | va.va_mode |= ap->ae_perm; | 780 | va.va_mode |= ap->ae_perm; |
781 | break; | 781 | break; |
782 | default: /* more than just standard modes */ | 782 | default: /* more than just standard modes */ |
783 | *basicperms = 0; | 783 | *basicperms = 0; |
784 | break; | 784 | break; |
785 | } | 785 | } |
786 | ap++; | 786 | ap++; |
787 | } | 787 | } |
788 | 788 | ||
789 | /* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */ | 789 | /* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */ |
790 | if (gap && nomask) | 790 | if (gap && nomask) |
791 | va.va_mode |= gap->ae_perm << 3; | 791 | va.va_mode |= gap->ae_perm << 3; |
792 | 792 | ||
793 | return xfs_setattr(xfs_vtoi(vp), &va, 0, sys_cred); | 793 | return xfs_setattr(xfs_vtoi(vp), &va, 0, sys_cred); |
794 | } | 794 | } |
795 | 795 | ||
796 | /* | 796 | /* |
797 | * The permissions for the special ACL entries (u::, g::[m::], o::) are | 797 | * The permissions for the special ACL entries (u::, g::[m::], o::) are |
798 | * actually stored in the file mode (if there is both a group and a mask, | 798 | * actually stored in the file mode (if there is both a group and a mask, |
799 | * the group is stored in the ACL entry and the mask is stored on the file). | 799 | * the group is stored in the ACL entry and the mask is stored on the file). |
800 | * This allows the mode to remain automatically in sync with the ACL without | 800 | * This allows the mode to remain automatically in sync with the ACL without |
801 | * the need for a call-back to the ACL system at every point where the mode | 801 | * the need for a call-back to the ACL system at every point where the mode |
802 | * could change. This function takes the permissions from the specified mode | 802 | * could change. This function takes the permissions from the specified mode |
803 | * and places it in the supplied ACL. | 803 | * and places it in the supplied ACL. |
804 | * | 804 | * |
805 | * This implementation draws its validity from the fact that, when the ACL | 805 | * This implementation draws its validity from the fact that, when the ACL |
806 | * was assigned, the mode was copied from the ACL. | 806 | * was assigned, the mode was copied from the ACL. |
807 | * If the mode did not change, therefore, the mode remains exactly what was | 807 | * If the mode did not change, therefore, the mode remains exactly what was |
808 | * taken from the special ACL entries at assignment. | 808 | * taken from the special ACL entries at assignment. |
809 | * If a subsequent chmod() was done, the POSIX spec says that the change in | 809 | * If a subsequent chmod() was done, the POSIX spec says that the change in |
810 | * mode must cause an update to the ACL seen at user level and used for | 810 | * mode must cause an update to the ACL seen at user level and used for |
811 | * access checks. Before and after a mode change, therefore, the file mode | 811 | * access checks. Before and after a mode change, therefore, the file mode |
812 | * most accurately reflects what the special ACL entries should permit/deny. | 812 | * most accurately reflects what the special ACL entries should permit/deny. |
813 | * | 813 | * |
814 | * CAVEAT: If someone sets the SGI_ACL_FILE attribute directly, | 814 | * CAVEAT: If someone sets the SGI_ACL_FILE attribute directly, |
815 | * the existing mode bits will override whatever is in the | 815 | * the existing mode bits will override whatever is in the |
816 | * ACL. Similarly, if there is a pre-existing ACL that was | 816 | * ACL. Similarly, if there is a pre-existing ACL that was |
817 | * never in sync with its mode (owing to a bug in 6.5 and | 817 | * never in sync with its mode (owing to a bug in 6.5 and |
818 | * before), it will now magically (or mystically) be | 818 | * before), it will now magically (or mystically) be |
819 | * synchronized. This could cause slight astonishment, but | 819 | * synchronized. This could cause slight astonishment, but |
820 | * it is better than inconsistent permissions. | 820 | * it is better than inconsistent permissions. |
821 | * | 821 | * |
822 | * The supplied ACL is a template that may contain any combination | 822 | * The supplied ACL is a template that may contain any combination |
823 | * of special entries. These are treated as place holders when we fill | 823 | * of special entries. These are treated as place holders when we fill |
824 | * out the ACL. This routine does not add or remove special entries, it | 824 | * out the ACL. This routine does not add or remove special entries, it |
825 | * simply unites each special entry with its associated set of permissions. | 825 | * simply unites each special entry with its associated set of permissions. |
826 | */ | 826 | */ |
827 | STATIC void | 827 | STATIC void |
828 | xfs_acl_sync_mode( | 828 | xfs_acl_sync_mode( |
829 | mode_t mode, | 829 | mode_t mode, |
830 | xfs_acl_t *acl) | 830 | xfs_acl_t *acl) |
831 | { | 831 | { |
832 | int i, nomask = 1; | 832 | int i, nomask = 1; |
833 | xfs_acl_entry_t *ap; | 833 | xfs_acl_entry_t *ap; |
834 | xfs_acl_entry_t *gap = NULL; | 834 | xfs_acl_entry_t *gap = NULL; |
835 | 835 | ||
836 | /* | 836 | /* |
837 | * Set ACL entries. POSIX1003.1eD16 requires that the MASK | 837 | * Set ACL entries. POSIX1003.1eD16 requires that the MASK |
838 | * be set instead of the GROUP entry, if there is a MASK. | 838 | * be set instead of the GROUP entry, if there is a MASK. |
839 | */ | 839 | */ |
840 | for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) { | 840 | for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) { |
841 | switch (ap->ae_tag) { | 841 | switch (ap->ae_tag) { |
842 | case ACL_USER_OBJ: | 842 | case ACL_USER_OBJ: |
843 | ap->ae_perm = (mode >> 6) & 0x7; | 843 | ap->ae_perm = (mode >> 6) & 0x7; |
844 | break; | 844 | break; |
845 | case ACL_GROUP_OBJ: | 845 | case ACL_GROUP_OBJ: |
846 | gap = ap; | 846 | gap = ap; |
847 | break; | 847 | break; |
848 | case ACL_MASK: | 848 | case ACL_MASK: |
849 | nomask = 0; | 849 | nomask = 0; |
850 | ap->ae_perm = (mode >> 3) & 0x7; | 850 | ap->ae_perm = (mode >> 3) & 0x7; |
851 | break; | 851 | break; |
852 | case ACL_OTHER: | 852 | case ACL_OTHER: |
853 | ap->ae_perm = mode & 0x7; | 853 | ap->ae_perm = mode & 0x7; |
854 | break; | 854 | break; |
855 | default: | 855 | default: |
856 | break; | 856 | break; |
857 | } | 857 | } |
858 | } | 858 | } |
859 | /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */ | 859 | /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */ |
860 | if (gap && nomask) | 860 | if (gap && nomask) |
861 | gap->ae_perm = (mode >> 3) & 0x7; | 861 | gap->ae_perm = (mode >> 3) & 0x7; |
862 | } | 862 | } |
863 | 863 | ||
864 | /* | 864 | /* |
865 | * When inheriting an Access ACL from a directory Default ACL, | 865 | * When inheriting an Access ACL from a directory Default ACL, |
866 | * the ACL bits are set to the intersection of the ACL default | 866 | * the ACL bits are set to the intersection of the ACL default |
867 | * permission bits and the file permission bits in mode. If there | 867 | * permission bits and the file permission bits in mode. If there |
868 | * are no permission bits on the file then we must not give them | 868 | * are no permission bits on the file then we must not give them |
869 | * the ACL. This is what what makes umask() work with ACLs. | 869 | * the ACL. This is what what makes umask() work with ACLs. |
870 | */ | 870 | */ |
871 | STATIC void | 871 | STATIC void |
872 | xfs_acl_filter_mode( | 872 | xfs_acl_filter_mode( |
873 | mode_t mode, | 873 | mode_t mode, |
874 | xfs_acl_t *acl) | 874 | xfs_acl_t *acl) |
875 | { | 875 | { |
876 | int i, nomask = 1; | 876 | int i, nomask = 1; |
877 | xfs_acl_entry_t *ap; | 877 | xfs_acl_entry_t *ap; |
878 | xfs_acl_entry_t *gap = NULL; | 878 | xfs_acl_entry_t *gap = NULL; |
879 | 879 | ||
880 | /* | 880 | /* |
881 | * Set ACL entries. POSIX1003.1eD16 requires that the MASK | 881 | * Set ACL entries. POSIX1003.1eD16 requires that the MASK |
882 | * be merged with GROUP entry, if there is a MASK. | 882 | * be merged with GROUP entry, if there is a MASK. |
883 | */ | 883 | */ |
884 | for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) { | 884 | for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) { |
885 | switch (ap->ae_tag) { | 885 | switch (ap->ae_tag) { |
886 | case ACL_USER_OBJ: | 886 | case ACL_USER_OBJ: |
887 | ap->ae_perm &= (mode >> 6) & 0x7; | 887 | ap->ae_perm &= (mode >> 6) & 0x7; |
888 | break; | 888 | break; |
889 | case ACL_GROUP_OBJ: | 889 | case ACL_GROUP_OBJ: |
890 | gap = ap; | 890 | gap = ap; |
891 | break; | 891 | break; |
892 | case ACL_MASK: | 892 | case ACL_MASK: |
893 | nomask = 0; | 893 | nomask = 0; |
894 | ap->ae_perm &= (mode >> 3) & 0x7; | 894 | ap->ae_perm &= (mode >> 3) & 0x7; |
895 | break; | 895 | break; |
896 | case ACL_OTHER: | 896 | case ACL_OTHER: |
897 | ap->ae_perm &= mode & 0x7; | 897 | ap->ae_perm &= mode & 0x7; |
898 | break; | 898 | break; |
899 | default: | 899 | default: |
900 | break; | 900 | break; |
901 | } | 901 | } |
902 | } | 902 | } |
903 | /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */ | 903 | /* Set the ACL_GROUP_OBJ if there's no ACL_MASK */ |
904 | if (gap && nomask) | 904 | if (gap && nomask) |
905 | gap->ae_perm &= (mode >> 3) & 0x7; | 905 | gap->ae_perm &= (mode >> 3) & 0x7; |
906 | } | 906 | } |
907 | 907 |
fs/xfs/xfs_vnodeops.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 | 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_bit.h" | 22 | #include "xfs_bit.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_sb.h" | 26 | #include "xfs_sb.h" |
27 | #include "xfs_ag.h" | 27 | #include "xfs_ag.h" |
28 | #include "xfs_dir2.h" | 28 | #include "xfs_dir2.h" |
29 | #include "xfs_dmapi.h" | 29 | #include "xfs_dmapi.h" |
30 | #include "xfs_mount.h" | 30 | #include "xfs_mount.h" |
31 | #include "xfs_da_btree.h" | 31 | #include "xfs_da_btree.h" |
32 | #include "xfs_bmap_btree.h" | 32 | #include "xfs_bmap_btree.h" |
33 | #include "xfs_alloc_btree.h" | 33 | #include "xfs_alloc_btree.h" |
34 | #include "xfs_ialloc_btree.h" | 34 | #include "xfs_ialloc_btree.h" |
35 | #include "xfs_dir2_sf.h" | 35 | #include "xfs_dir2_sf.h" |
36 | #include "xfs_attr_sf.h" | 36 | #include "xfs_attr_sf.h" |
37 | #include "xfs_dinode.h" | 37 | #include "xfs_dinode.h" |
38 | #include "xfs_inode.h" | 38 | #include "xfs_inode.h" |
39 | #include "xfs_inode_item.h" | 39 | #include "xfs_inode_item.h" |
40 | #include "xfs_itable.h" | 40 | #include "xfs_itable.h" |
41 | #include "xfs_btree.h" | 41 | #include "xfs_btree.h" |
42 | #include "xfs_ialloc.h" | 42 | #include "xfs_ialloc.h" |
43 | #include "xfs_alloc.h" | 43 | #include "xfs_alloc.h" |
44 | #include "xfs_bmap.h" | 44 | #include "xfs_bmap.h" |
45 | #include "xfs_attr.h" | 45 | #include "xfs_attr.h" |
46 | #include "xfs_rw.h" | 46 | #include "xfs_rw.h" |
47 | #include "xfs_error.h" | 47 | #include "xfs_error.h" |
48 | #include "xfs_quota.h" | 48 | #include "xfs_quota.h" |
49 | #include "xfs_utils.h" | 49 | #include "xfs_utils.h" |
50 | #include "xfs_rtalloc.h" | 50 | #include "xfs_rtalloc.h" |
51 | #include "xfs_trans_space.h" | 51 | #include "xfs_trans_space.h" |
52 | #include "xfs_log_priv.h" | 52 | #include "xfs_log_priv.h" |
53 | #include "xfs_filestream.h" | 53 | #include "xfs_filestream.h" |
54 | #include "xfs_vnodeops.h" | 54 | #include "xfs_vnodeops.h" |
55 | 55 | ||
56 | int | 56 | int |
57 | xfs_open( | 57 | xfs_open( |
58 | xfs_inode_t *ip) | 58 | xfs_inode_t *ip) |
59 | { | 59 | { |
60 | int mode; | 60 | int mode; |
61 | 61 | ||
62 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | 62 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) |
63 | return XFS_ERROR(EIO); | 63 | return XFS_ERROR(EIO); |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * If it's a directory with any blocks, read-ahead block 0 | 66 | * If it's a directory with any blocks, read-ahead block 0 |
67 | * as we're almost certain to have the next operation be a read there. | 67 | * as we're almost certain to have the next operation be a read there. |
68 | */ | 68 | */ |
69 | if (S_ISDIR(ip->i_d.di_mode) && ip->i_d.di_nextents > 0) { | 69 | if (S_ISDIR(ip->i_d.di_mode) && ip->i_d.di_nextents > 0) { |
70 | mode = xfs_ilock_map_shared(ip); | 70 | mode = xfs_ilock_map_shared(ip); |
71 | if (ip->i_d.di_nextents > 0) | 71 | if (ip->i_d.di_nextents > 0) |
72 | (void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK); | 72 | (void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK); |
73 | xfs_iunlock(ip, mode); | 73 | xfs_iunlock(ip, mode); |
74 | } | 74 | } |
75 | return 0; | 75 | return 0; |
76 | } | 76 | } |
77 | 77 | ||
78 | /* | 78 | /* |
79 | * xfs_getattr | 79 | * xfs_getattr |
80 | */ | 80 | */ |
81 | int | 81 | int |
82 | xfs_getattr( | 82 | xfs_getattr( |
83 | xfs_inode_t *ip, | 83 | xfs_inode_t *ip, |
84 | bhv_vattr_t *vap, | 84 | bhv_vattr_t *vap, |
85 | int flags) | 85 | int flags) |
86 | { | 86 | { |
87 | bhv_vnode_t *vp = XFS_ITOV(ip); | 87 | bhv_vnode_t *vp = XFS_ITOV(ip); |
88 | xfs_mount_t *mp = ip->i_mount; | 88 | xfs_mount_t *mp = ip->i_mount; |
89 | 89 | ||
90 | xfs_itrace_entry(ip); | 90 | xfs_itrace_entry(ip); |
91 | 91 | ||
92 | if (XFS_FORCED_SHUTDOWN(mp)) | 92 | if (XFS_FORCED_SHUTDOWN(mp)) |
93 | return XFS_ERROR(EIO); | 93 | return XFS_ERROR(EIO); |
94 | 94 | ||
95 | if (!(flags & ATTR_LAZY)) | 95 | if (!(flags & ATTR_LAZY)) |
96 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 96 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
97 | 97 | ||
98 | vap->va_size = XFS_ISIZE(ip); | 98 | vap->va_size = XFS_ISIZE(ip); |
99 | if (vap->va_mask == XFS_AT_SIZE) | 99 | if (vap->va_mask == XFS_AT_SIZE) |
100 | goto all_done; | 100 | goto all_done; |
101 | 101 | ||
102 | vap->va_nblocks = | 102 | vap->va_nblocks = |
103 | XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); | 103 | XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); |
104 | vap->va_nodeid = ip->i_ino; | 104 | vap->va_nodeid = ip->i_ino; |
105 | #if XFS_BIG_INUMS | 105 | #if XFS_BIG_INUMS |
106 | vap->va_nodeid += mp->m_inoadd; | 106 | vap->va_nodeid += mp->m_inoadd; |
107 | #endif | 107 | #endif |
108 | vap->va_nlink = ip->i_d.di_nlink; | 108 | vap->va_nlink = ip->i_d.di_nlink; |
109 | 109 | ||
110 | /* | 110 | /* |
111 | * Quick exit for non-stat callers | 111 | * Quick exit for non-stat callers |
112 | */ | 112 | */ |
113 | if ((vap->va_mask & | 113 | if ((vap->va_mask & |
114 | ~(XFS_AT_SIZE|XFS_AT_FSID|XFS_AT_NODEID| | 114 | ~(XFS_AT_SIZE|XFS_AT_FSID|XFS_AT_NODEID| |
115 | XFS_AT_NLINK|XFS_AT_BLKSIZE)) == 0) | 115 | XFS_AT_NLINK|XFS_AT_BLKSIZE)) == 0) |
116 | goto all_done; | 116 | goto all_done; |
117 | 117 | ||
118 | /* | 118 | /* |
119 | * Copy from in-core inode. | 119 | * Copy from in-core inode. |
120 | */ | 120 | */ |
121 | vap->va_mode = ip->i_d.di_mode; | 121 | vap->va_mode = ip->i_d.di_mode; |
122 | vap->va_uid = ip->i_d.di_uid; | 122 | vap->va_uid = ip->i_d.di_uid; |
123 | vap->va_gid = ip->i_d.di_gid; | 123 | vap->va_gid = ip->i_d.di_gid; |
124 | vap->va_projid = ip->i_d.di_projid; | 124 | vap->va_projid = ip->i_d.di_projid; |
125 | 125 | ||
126 | /* | 126 | /* |
127 | * Check vnode type block/char vs. everything else. | 127 | * Check vnode type block/char vs. everything else. |
128 | */ | 128 | */ |
129 | switch (ip->i_d.di_mode & S_IFMT) { | 129 | switch (ip->i_d.di_mode & S_IFMT) { |
130 | case S_IFBLK: | 130 | case S_IFBLK: |
131 | case S_IFCHR: | 131 | case S_IFCHR: |
132 | vap->va_rdev = ip->i_df.if_u2.if_rdev; | 132 | vap->va_rdev = ip->i_df.if_u2.if_rdev; |
133 | vap->va_blocksize = BLKDEV_IOSIZE; | 133 | vap->va_blocksize = BLKDEV_IOSIZE; |
134 | break; | 134 | break; |
135 | default: | 135 | default: |
136 | vap->va_rdev = 0; | 136 | vap->va_rdev = 0; |
137 | 137 | ||
138 | if (!(XFS_IS_REALTIME_INODE(ip))) { | 138 | if (!(XFS_IS_REALTIME_INODE(ip))) { |
139 | vap->va_blocksize = xfs_preferred_iosize(mp); | 139 | vap->va_blocksize = xfs_preferred_iosize(mp); |
140 | } else { | 140 | } else { |
141 | 141 | ||
142 | /* | 142 | /* |
143 | * If the file blocks are being allocated from a | 143 | * If the file blocks are being allocated from a |
144 | * realtime partition, then return the inode's | 144 | * realtime partition, then return the inode's |
145 | * realtime extent size or the realtime volume's | 145 | * realtime extent size or the realtime volume's |
146 | * extent size. | 146 | * extent size. |
147 | */ | 147 | */ |
148 | vap->va_blocksize = | 148 | vap->va_blocksize = |
149 | xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog; | 149 | xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog; |
150 | } | 150 | } |
151 | break; | 151 | break; |
152 | } | 152 | } |
153 | 153 | ||
154 | vn_atime_to_timespec(vp, &vap->va_atime); | 154 | vn_atime_to_timespec(vp, &vap->va_atime); |
155 | vap->va_mtime.tv_sec = ip->i_d.di_mtime.t_sec; | 155 | vap->va_mtime.tv_sec = ip->i_d.di_mtime.t_sec; |
156 | vap->va_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; | 156 | vap->va_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; |
157 | vap->va_ctime.tv_sec = ip->i_d.di_ctime.t_sec; | 157 | vap->va_ctime.tv_sec = ip->i_d.di_ctime.t_sec; |
158 | vap->va_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; | 158 | vap->va_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; |
159 | 159 | ||
160 | /* | 160 | /* |
161 | * Exit for stat callers. See if any of the rest of the fields | 161 | * Exit for stat callers. See if any of the rest of the fields |
162 | * to be filled in are needed. | 162 | * to be filled in are needed. |
163 | */ | 163 | */ |
164 | if ((vap->va_mask & | 164 | if ((vap->va_mask & |
165 | (XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS| | 165 | (XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS| |
166 | XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0) | 166 | XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0) |
167 | goto all_done; | 167 | goto all_done; |
168 | 168 | ||
169 | /* | 169 | /* |
170 | * Convert di_flags to xflags. | 170 | * Convert di_flags to xflags. |
171 | */ | 171 | */ |
172 | vap->va_xflags = xfs_ip2xflags(ip); | 172 | vap->va_xflags = xfs_ip2xflags(ip); |
173 | 173 | ||
174 | /* | 174 | /* |
175 | * Exit for inode revalidate. See if any of the rest of | 175 | * Exit for inode revalidate. See if any of the rest of |
176 | * the fields to be filled in are needed. | 176 | * the fields to be filled in are needed. |
177 | */ | 177 | */ |
178 | if ((vap->va_mask & | 178 | if ((vap->va_mask & |
179 | (XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS| | 179 | (XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS| |
180 | XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0) | 180 | XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0) |
181 | goto all_done; | 181 | goto all_done; |
182 | 182 | ||
183 | vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog; | 183 | vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog; |
184 | vap->va_nextents = | 184 | vap->va_nextents = |
185 | (ip->i_df.if_flags & XFS_IFEXTENTS) ? | 185 | (ip->i_df.if_flags & XFS_IFEXTENTS) ? |
186 | ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) : | 186 | ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) : |
187 | ip->i_d.di_nextents; | 187 | ip->i_d.di_nextents; |
188 | if (ip->i_afp) | 188 | if (ip->i_afp) |
189 | vap->va_anextents = | 189 | vap->va_anextents = |
190 | (ip->i_afp->if_flags & XFS_IFEXTENTS) ? | 190 | (ip->i_afp->if_flags & XFS_IFEXTENTS) ? |
191 | ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) : | 191 | ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) : |
192 | ip->i_d.di_anextents; | 192 | ip->i_d.di_anextents; |
193 | else | 193 | else |
194 | vap->va_anextents = 0; | 194 | vap->va_anextents = 0; |
195 | vap->va_gen = ip->i_d.di_gen; | 195 | vap->va_gen = ip->i_d.di_gen; |
196 | 196 | ||
197 | all_done: | 197 | all_done: |
198 | if (!(flags & ATTR_LAZY)) | 198 | if (!(flags & ATTR_LAZY)) |
199 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 199 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
200 | return 0; | 200 | return 0; |
201 | } | 201 | } |
202 | 202 | ||
203 | 203 | ||
204 | /* | 204 | /* |
205 | * xfs_setattr | 205 | * xfs_setattr |
206 | */ | 206 | */ |
207 | int | 207 | int |
208 | xfs_setattr( | 208 | xfs_setattr( |
209 | xfs_inode_t *ip, | 209 | xfs_inode_t *ip, |
210 | bhv_vattr_t *vap, | 210 | bhv_vattr_t *vap, |
211 | int flags, | 211 | int flags, |
212 | cred_t *credp) | 212 | cred_t *credp) |
213 | { | 213 | { |
214 | bhv_vnode_t *vp = XFS_ITOV(ip); | ||
215 | xfs_mount_t *mp = ip->i_mount; | 214 | xfs_mount_t *mp = ip->i_mount; |
216 | xfs_trans_t *tp; | 215 | xfs_trans_t *tp; |
217 | int mask; | 216 | int mask; |
218 | int code; | 217 | int code; |
219 | uint lock_flags; | 218 | uint lock_flags; |
220 | uint commit_flags=0; | 219 | uint commit_flags=0; |
221 | uid_t uid=0, iuid=0; | 220 | uid_t uid=0, iuid=0; |
222 | gid_t gid=0, igid=0; | 221 | gid_t gid=0, igid=0; |
223 | int timeflags = 0; | 222 | int timeflags = 0; |
224 | xfs_prid_t projid=0, iprojid=0; | 223 | xfs_prid_t projid=0, iprojid=0; |
225 | int mandlock_before, mandlock_after; | ||
226 | struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; | 224 | struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; |
227 | int file_owner; | 225 | int file_owner; |
228 | int need_iolock = 1; | 226 | int need_iolock = 1; |
229 | 227 | ||
230 | xfs_itrace_entry(ip); | 228 | xfs_itrace_entry(ip); |
231 | 229 | ||
232 | if (mp->m_flags & XFS_MOUNT_RDONLY) | 230 | if (mp->m_flags & XFS_MOUNT_RDONLY) |
233 | return XFS_ERROR(EROFS); | 231 | return XFS_ERROR(EROFS); |
234 | 232 | ||
235 | /* | 233 | /* |
236 | * Cannot set certain attributes. | 234 | * Cannot set certain attributes. |
237 | */ | 235 | */ |
238 | mask = vap->va_mask; | 236 | mask = vap->va_mask; |
239 | if (mask & XFS_AT_NOSET) { | 237 | if (mask & XFS_AT_NOSET) { |
240 | return XFS_ERROR(EINVAL); | 238 | return XFS_ERROR(EINVAL); |
241 | } | 239 | } |
242 | 240 | ||
243 | if (XFS_FORCED_SHUTDOWN(mp)) | 241 | if (XFS_FORCED_SHUTDOWN(mp)) |
244 | return XFS_ERROR(EIO); | 242 | return XFS_ERROR(EIO); |
245 | 243 | ||
246 | /* | 244 | /* |
247 | * Timestamps do not need to be logged and hence do not | 245 | * Timestamps do not need to be logged and hence do not |
248 | * need to be done within a transaction. | 246 | * need to be done within a transaction. |
249 | */ | 247 | */ |
250 | if (mask & XFS_AT_UPDTIMES) { | 248 | if (mask & XFS_AT_UPDTIMES) { |
251 | ASSERT((mask & ~XFS_AT_UPDTIMES) == 0); | 249 | ASSERT((mask & ~XFS_AT_UPDTIMES) == 0); |
252 | timeflags = ((mask & XFS_AT_UPDATIME) ? XFS_ICHGTIME_ACC : 0) | | 250 | timeflags = ((mask & XFS_AT_UPDATIME) ? XFS_ICHGTIME_ACC : 0) | |
253 | ((mask & XFS_AT_UPDCTIME) ? XFS_ICHGTIME_CHG : 0) | | 251 | ((mask & XFS_AT_UPDCTIME) ? XFS_ICHGTIME_CHG : 0) | |
254 | ((mask & XFS_AT_UPDMTIME) ? XFS_ICHGTIME_MOD : 0); | 252 | ((mask & XFS_AT_UPDMTIME) ? XFS_ICHGTIME_MOD : 0); |
255 | xfs_ichgtime(ip, timeflags); | 253 | xfs_ichgtime(ip, timeflags); |
256 | return 0; | 254 | return 0; |
257 | } | 255 | } |
258 | 256 | ||
259 | olddquot1 = olddquot2 = NULL; | 257 | olddquot1 = olddquot2 = NULL; |
260 | udqp = gdqp = NULL; | 258 | udqp = gdqp = NULL; |
261 | 259 | ||
262 | /* | 260 | /* |
263 | * If disk quotas is on, we make sure that the dquots do exist on disk, | 261 | * If disk quotas is on, we make sure that the dquots do exist on disk, |
264 | * before we start any other transactions. Trying to do this later | 262 | * before we start any other transactions. Trying to do this later |
265 | * is messy. We don't care to take a readlock to look at the ids | 263 | * is messy. We don't care to take a readlock to look at the ids |
266 | * in inode here, because we can't hold it across the trans_reserve. | 264 | * in inode here, because we can't hold it across the trans_reserve. |
267 | * If the IDs do change before we take the ilock, we're covered | 265 | * If the IDs do change before we take the ilock, we're covered |
268 | * because the i_*dquot fields will get updated anyway. | 266 | * because the i_*dquot fields will get updated anyway. |
269 | */ | 267 | */ |
270 | if (XFS_IS_QUOTA_ON(mp) && | 268 | if (XFS_IS_QUOTA_ON(mp) && |
271 | (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) { | 269 | (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) { |
272 | uint qflags = 0; | 270 | uint qflags = 0; |
273 | 271 | ||
274 | if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) { | 272 | if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) { |
275 | uid = vap->va_uid; | 273 | uid = vap->va_uid; |
276 | qflags |= XFS_QMOPT_UQUOTA; | 274 | qflags |= XFS_QMOPT_UQUOTA; |
277 | } else { | 275 | } else { |
278 | uid = ip->i_d.di_uid; | 276 | uid = ip->i_d.di_uid; |
279 | } | 277 | } |
280 | if ((mask & XFS_AT_GID) && XFS_IS_GQUOTA_ON(mp)) { | 278 | if ((mask & XFS_AT_GID) && XFS_IS_GQUOTA_ON(mp)) { |
281 | gid = vap->va_gid; | 279 | gid = vap->va_gid; |
282 | qflags |= XFS_QMOPT_GQUOTA; | 280 | qflags |= XFS_QMOPT_GQUOTA; |
283 | } else { | 281 | } else { |
284 | gid = ip->i_d.di_gid; | 282 | gid = ip->i_d.di_gid; |
285 | } | 283 | } |
286 | if ((mask & XFS_AT_PROJID) && XFS_IS_PQUOTA_ON(mp)) { | 284 | if ((mask & XFS_AT_PROJID) && XFS_IS_PQUOTA_ON(mp)) { |
287 | projid = vap->va_projid; | 285 | projid = vap->va_projid; |
288 | qflags |= XFS_QMOPT_PQUOTA; | 286 | qflags |= XFS_QMOPT_PQUOTA; |
289 | } else { | 287 | } else { |
290 | projid = ip->i_d.di_projid; | 288 | projid = ip->i_d.di_projid; |
291 | } | 289 | } |
292 | /* | 290 | /* |
293 | * We take a reference when we initialize udqp and gdqp, | 291 | * We take a reference when we initialize udqp and gdqp, |
294 | * so it is important that we never blindly double trip on | 292 | * so it is important that we never blindly double trip on |
295 | * the same variable. See xfs_create() for an example. | 293 | * the same variable. See xfs_create() for an example. |
296 | */ | 294 | */ |
297 | ASSERT(udqp == NULL); | 295 | ASSERT(udqp == NULL); |
298 | ASSERT(gdqp == NULL); | 296 | ASSERT(gdqp == NULL); |
299 | code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags, | 297 | code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags, |
300 | &udqp, &gdqp); | 298 | &udqp, &gdqp); |
301 | if (code) | 299 | if (code) |
302 | return code; | 300 | return code; |
303 | } | 301 | } |
304 | 302 | ||
305 | /* | 303 | /* |
306 | * For the other attributes, we acquire the inode lock and | 304 | * For the other attributes, we acquire the inode lock and |
307 | * first do an error checking pass. | 305 | * first do an error checking pass. |
308 | */ | 306 | */ |
309 | tp = NULL; | 307 | tp = NULL; |
310 | lock_flags = XFS_ILOCK_EXCL; | 308 | lock_flags = XFS_ILOCK_EXCL; |
311 | if (flags & ATTR_NOLOCK) | 309 | if (flags & ATTR_NOLOCK) |
312 | need_iolock = 0; | 310 | need_iolock = 0; |
313 | if (!(mask & XFS_AT_SIZE)) { | 311 | if (!(mask & XFS_AT_SIZE)) { |
314 | if ((mask != (XFS_AT_CTIME|XFS_AT_ATIME|XFS_AT_MTIME)) || | 312 | if ((mask != (XFS_AT_CTIME|XFS_AT_ATIME|XFS_AT_MTIME)) || |
315 | (mp->m_flags & XFS_MOUNT_WSYNC)) { | 313 | (mp->m_flags & XFS_MOUNT_WSYNC)) { |
316 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); | 314 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); |
317 | commit_flags = 0; | 315 | commit_flags = 0; |
318 | if ((code = xfs_trans_reserve(tp, 0, | 316 | if ((code = xfs_trans_reserve(tp, 0, |
319 | XFS_ICHANGE_LOG_RES(mp), 0, | 317 | XFS_ICHANGE_LOG_RES(mp), 0, |
320 | 0, 0))) { | 318 | 0, 0))) { |
321 | lock_flags = 0; | 319 | lock_flags = 0; |
322 | goto error_return; | 320 | goto error_return; |
323 | } | 321 | } |
324 | } | 322 | } |
325 | } else { | 323 | } else { |
326 | if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) && | 324 | if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) && |
327 | !(flags & ATTR_DMI)) { | 325 | !(flags & ATTR_DMI)) { |
328 | int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR; | 326 | int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR; |
329 | code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, ip, | 327 | code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, ip, |
330 | vap->va_size, 0, dmflags, NULL); | 328 | vap->va_size, 0, dmflags, NULL); |
331 | if (code) { | 329 | if (code) { |
332 | lock_flags = 0; | 330 | lock_flags = 0; |
333 | goto error_return; | 331 | goto error_return; |
334 | } | 332 | } |
335 | } | 333 | } |
336 | if (need_iolock) | 334 | if (need_iolock) |
337 | lock_flags |= XFS_IOLOCK_EXCL; | 335 | lock_flags |= XFS_IOLOCK_EXCL; |
338 | } | 336 | } |
339 | 337 | ||
340 | xfs_ilock(ip, lock_flags); | 338 | xfs_ilock(ip, lock_flags); |
341 | 339 | ||
342 | /* boolean: are we the file owner? */ | 340 | /* boolean: are we the file owner? */ |
343 | file_owner = (current_fsuid(credp) == ip->i_d.di_uid); | 341 | file_owner = (current_fsuid(credp) == ip->i_d.di_uid); |
344 | 342 | ||
345 | /* | 343 | /* |
346 | * Change various properties of a file. | 344 | * Change various properties of a file. |
347 | * Only the owner or users with CAP_FOWNER | 345 | * Only the owner or users with CAP_FOWNER |
348 | * capability may do these things. | 346 | * capability may do these things. |
349 | */ | 347 | */ |
350 | if (mask & | 348 | if (mask & |
351 | (XFS_AT_MODE|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_UID| | 349 | (XFS_AT_MODE|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_UID| |
352 | XFS_AT_GID|XFS_AT_PROJID)) { | 350 | XFS_AT_GID|XFS_AT_PROJID)) { |
353 | /* | 351 | /* |
354 | * CAP_FOWNER overrides the following restrictions: | 352 | * CAP_FOWNER overrides the following restrictions: |
355 | * | 353 | * |
356 | * The user ID of the calling process must be equal | 354 | * The user ID of the calling process must be equal |
357 | * to the file owner ID, except in cases where the | 355 | * to the file owner ID, except in cases where the |
358 | * CAP_FSETID capability is applicable. | 356 | * CAP_FSETID capability is applicable. |
359 | */ | 357 | */ |
360 | if (!file_owner && !capable(CAP_FOWNER)) { | 358 | if (!file_owner && !capable(CAP_FOWNER)) { |
361 | code = XFS_ERROR(EPERM); | 359 | code = XFS_ERROR(EPERM); |
362 | goto error_return; | 360 | goto error_return; |
363 | } | 361 | } |
364 | 362 | ||
365 | /* | 363 | /* |
366 | * CAP_FSETID overrides the following restrictions: | 364 | * CAP_FSETID overrides the following restrictions: |
367 | * | 365 | * |
368 | * The effective user ID of the calling process shall match | 366 | * The effective user ID of the calling process shall match |
369 | * the file owner when setting the set-user-ID and | 367 | * the file owner when setting the set-user-ID and |
370 | * set-group-ID bits on that file. | 368 | * set-group-ID bits on that file. |
371 | * | 369 | * |
372 | * The effective group ID or one of the supplementary group | 370 | * The effective group ID or one of the supplementary group |
373 | * IDs of the calling process shall match the group owner of | 371 | * IDs of the calling process shall match the group owner of |
374 | * the file when setting the set-group-ID bit on that file | 372 | * the file when setting the set-group-ID bit on that file |
375 | */ | 373 | */ |
376 | if (mask & XFS_AT_MODE) { | 374 | if (mask & XFS_AT_MODE) { |
377 | mode_t m = 0; | 375 | mode_t m = 0; |
378 | 376 | ||
379 | if ((vap->va_mode & S_ISUID) && !file_owner) | 377 | if ((vap->va_mode & S_ISUID) && !file_owner) |
380 | m |= S_ISUID; | 378 | m |= S_ISUID; |
381 | if ((vap->va_mode & S_ISGID) && | 379 | if ((vap->va_mode & S_ISGID) && |
382 | !in_group_p((gid_t)ip->i_d.di_gid)) | 380 | !in_group_p((gid_t)ip->i_d.di_gid)) |
383 | m |= S_ISGID; | 381 | m |= S_ISGID; |
384 | #if 0 | 382 | #if 0 |
385 | /* Linux allows this, Irix doesn't. */ | 383 | /* Linux allows this, Irix doesn't. */ |
386 | if ((vap->va_mode & S_ISVTX) && !VN_ISDIR(vp)) | 384 | if ((vap->va_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode)) |
387 | m |= S_ISVTX; | 385 | m |= S_ISVTX; |
388 | #endif | 386 | #endif |
389 | if (m && !capable(CAP_FSETID)) | 387 | if (m && !capable(CAP_FSETID)) |
390 | vap->va_mode &= ~m; | 388 | vap->va_mode &= ~m; |
391 | } | 389 | } |
392 | } | 390 | } |
393 | 391 | ||
394 | /* | 392 | /* |
395 | * Change file ownership. Must be the owner or privileged. | 393 | * Change file ownership. Must be the owner or privileged. |
396 | * If the system was configured with the "restricted_chown" | 394 | * If the system was configured with the "restricted_chown" |
397 | * option, the owner is not permitted to give away the file, | 395 | * option, the owner is not permitted to give away the file, |
398 | * and can change the group id only to a group of which he | 396 | * and can change the group id only to a group of which he |
399 | * or she is a member. | 397 | * or she is a member. |
400 | */ | 398 | */ |
401 | if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) { | 399 | if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) { |
402 | /* | 400 | /* |
403 | * These IDs could have changed since we last looked at them. | 401 | * These IDs could have changed since we last looked at them. |
404 | * But, we're assured that if the ownership did change | 402 | * But, we're assured that if the ownership did change |
405 | * while we didn't have the inode locked, inode's dquot(s) | 403 | * while we didn't have the inode locked, inode's dquot(s) |
406 | * would have changed also. | 404 | * would have changed also. |
407 | */ | 405 | */ |
408 | iuid = ip->i_d.di_uid; | 406 | iuid = ip->i_d.di_uid; |
409 | iprojid = ip->i_d.di_projid; | 407 | iprojid = ip->i_d.di_projid; |
410 | igid = ip->i_d.di_gid; | 408 | igid = ip->i_d.di_gid; |
411 | gid = (mask & XFS_AT_GID) ? vap->va_gid : igid; | 409 | gid = (mask & XFS_AT_GID) ? vap->va_gid : igid; |
412 | uid = (mask & XFS_AT_UID) ? vap->va_uid : iuid; | 410 | uid = (mask & XFS_AT_UID) ? vap->va_uid : iuid; |
413 | projid = (mask & XFS_AT_PROJID) ? (xfs_prid_t)vap->va_projid : | 411 | projid = (mask & XFS_AT_PROJID) ? (xfs_prid_t)vap->va_projid : |
414 | iprojid; | 412 | iprojid; |
415 | 413 | ||
416 | /* | 414 | /* |
417 | * CAP_CHOWN overrides the following restrictions: | 415 | * CAP_CHOWN overrides the following restrictions: |
418 | * | 416 | * |
419 | * If _POSIX_CHOWN_RESTRICTED is defined, this capability | 417 | * If _POSIX_CHOWN_RESTRICTED is defined, this capability |
420 | * shall override the restriction that a process cannot | 418 | * shall override the restriction that a process cannot |
421 | * change the user ID of a file it owns and the restriction | 419 | * change the user ID of a file it owns and the restriction |
422 | * that the group ID supplied to the chown() function | 420 | * that the group ID supplied to the chown() function |
423 | * shall be equal to either the group ID or one of the | 421 | * shall be equal to either the group ID or one of the |
424 | * supplementary group IDs of the calling process. | 422 | * supplementary group IDs of the calling process. |
425 | */ | 423 | */ |
426 | if (restricted_chown && | 424 | if (restricted_chown && |
427 | (iuid != uid || (igid != gid && | 425 | (iuid != uid || (igid != gid && |
428 | !in_group_p((gid_t)gid))) && | 426 | !in_group_p((gid_t)gid))) && |
429 | !capable(CAP_CHOWN)) { | 427 | !capable(CAP_CHOWN)) { |
430 | code = XFS_ERROR(EPERM); | 428 | code = XFS_ERROR(EPERM); |
431 | goto error_return; | 429 | goto error_return; |
432 | } | 430 | } |
433 | /* | 431 | /* |
434 | * Do a quota reservation only if uid/projid/gid is actually | 432 | * Do a quota reservation only if uid/projid/gid is actually |
435 | * going to change. | 433 | * going to change. |
436 | */ | 434 | */ |
437 | if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || | 435 | if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || |
438 | (XFS_IS_PQUOTA_ON(mp) && iprojid != projid) || | 436 | (XFS_IS_PQUOTA_ON(mp) && iprojid != projid) || |
439 | (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { | 437 | (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { |
440 | ASSERT(tp); | 438 | ASSERT(tp); |
441 | code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, | 439 | code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, |
442 | capable(CAP_FOWNER) ? | 440 | capable(CAP_FOWNER) ? |
443 | XFS_QMOPT_FORCE_RES : 0); | 441 | XFS_QMOPT_FORCE_RES : 0); |
444 | if (code) /* out of quota */ | 442 | if (code) /* out of quota */ |
445 | goto error_return; | 443 | goto error_return; |
446 | } | 444 | } |
447 | } | 445 | } |
448 | 446 | ||
449 | /* | 447 | /* |
450 | * Truncate file. Must have write permission and not be a directory. | 448 | * Truncate file. Must have write permission and not be a directory. |
451 | */ | 449 | */ |
452 | if (mask & XFS_AT_SIZE) { | 450 | if (mask & XFS_AT_SIZE) { |
453 | /* Short circuit the truncate case for zero length files */ | 451 | /* Short circuit the truncate case for zero length files */ |
454 | if ((vap->va_size == 0) && | 452 | if ((vap->va_size == 0) && |
455 | (ip->i_size == 0) && (ip->i_d.di_nextents == 0)) { | 453 | (ip->i_size == 0) && (ip->i_d.di_nextents == 0)) { |
456 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 454 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
457 | lock_flags &= ~XFS_ILOCK_EXCL; | 455 | lock_flags &= ~XFS_ILOCK_EXCL; |
458 | if (mask & XFS_AT_CTIME) | 456 | if (mask & XFS_AT_CTIME) |
459 | xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 457 | xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
460 | code = 0; | 458 | code = 0; |
461 | goto error_return; | 459 | goto error_return; |
462 | } | 460 | } |
463 | 461 | ||
464 | if (VN_ISDIR(vp)) { | 462 | if (S_ISDIR(ip->i_d.di_mode)) { |
465 | code = XFS_ERROR(EISDIR); | 463 | code = XFS_ERROR(EISDIR); |
466 | goto error_return; | 464 | goto error_return; |
467 | } else if (!VN_ISREG(vp)) { | 465 | } else if (!S_ISREG(ip->i_d.di_mode)) { |
468 | code = XFS_ERROR(EINVAL); | 466 | code = XFS_ERROR(EINVAL); |
469 | goto error_return; | 467 | goto error_return; |
470 | } | 468 | } |
471 | /* | 469 | /* |
472 | * Make sure that the dquots are attached to the inode. | 470 | * Make sure that the dquots are attached to the inode. |
473 | */ | 471 | */ |
474 | if ((code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED))) | 472 | if ((code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED))) |
475 | goto error_return; | 473 | goto error_return; |
476 | } | 474 | } |
477 | 475 | ||
478 | /* | 476 | /* |
479 | * Change file access or modified times. | 477 | * Change file access or modified times. |
480 | */ | 478 | */ |
481 | if (mask & (XFS_AT_ATIME|XFS_AT_MTIME)) { | 479 | if (mask & (XFS_AT_ATIME|XFS_AT_MTIME)) { |
482 | if (!file_owner) { | 480 | if (!file_owner) { |
483 | if ((flags & ATTR_UTIME) && | 481 | if ((flags & ATTR_UTIME) && |
484 | !capable(CAP_FOWNER)) { | 482 | !capable(CAP_FOWNER)) { |
485 | code = XFS_ERROR(EPERM); | 483 | code = XFS_ERROR(EPERM); |
486 | goto error_return; | 484 | goto error_return; |
487 | } | 485 | } |
488 | } | 486 | } |
489 | } | 487 | } |
490 | 488 | ||
491 | /* | 489 | /* |
492 | * Change extent size or realtime flag. | 490 | * Change extent size or realtime flag. |
493 | */ | 491 | */ |
494 | if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) { | 492 | if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) { |
495 | /* | 493 | /* |
496 | * Can't change extent size if any extents are allocated. | 494 | * Can't change extent size if any extents are allocated. |
497 | */ | 495 | */ |
498 | if (ip->i_d.di_nextents && (mask & XFS_AT_EXTSIZE) && | 496 | if (ip->i_d.di_nextents && (mask & XFS_AT_EXTSIZE) && |
499 | ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != | 497 | ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != |
500 | vap->va_extsize) ) { | 498 | vap->va_extsize) ) { |
501 | code = XFS_ERROR(EINVAL); /* EFBIG? */ | 499 | code = XFS_ERROR(EINVAL); /* EFBIG? */ |
502 | goto error_return; | 500 | goto error_return; |
503 | } | 501 | } |
504 | 502 | ||
505 | /* | 503 | /* |
506 | * Can't change realtime flag if any extents are allocated. | 504 | * Can't change realtime flag if any extents are allocated. |
507 | */ | 505 | */ |
508 | if ((ip->i_d.di_nextents || ip->i_delayed_blks) && | 506 | if ((ip->i_d.di_nextents || ip->i_delayed_blks) && |
509 | (mask & XFS_AT_XFLAGS) && | 507 | (mask & XFS_AT_XFLAGS) && |
510 | (XFS_IS_REALTIME_INODE(ip)) != | 508 | (XFS_IS_REALTIME_INODE(ip)) != |
511 | (vap->va_xflags & XFS_XFLAG_REALTIME)) { | 509 | (vap->va_xflags & XFS_XFLAG_REALTIME)) { |
512 | code = XFS_ERROR(EINVAL); /* EFBIG? */ | 510 | code = XFS_ERROR(EINVAL); /* EFBIG? */ |
513 | goto error_return; | 511 | goto error_return; |
514 | } | 512 | } |
515 | /* | 513 | /* |
516 | * Extent size must be a multiple of the appropriate block | 514 | * Extent size must be a multiple of the appropriate block |
517 | * size, if set at all. | 515 | * size, if set at all. |
518 | */ | 516 | */ |
519 | if ((mask & XFS_AT_EXTSIZE) && vap->va_extsize != 0) { | 517 | if ((mask & XFS_AT_EXTSIZE) && vap->va_extsize != 0) { |
520 | xfs_extlen_t size; | 518 | xfs_extlen_t size; |
521 | 519 | ||
522 | if (XFS_IS_REALTIME_INODE(ip) || | 520 | if (XFS_IS_REALTIME_INODE(ip) || |
523 | ((mask & XFS_AT_XFLAGS) && | 521 | ((mask & XFS_AT_XFLAGS) && |
524 | (vap->va_xflags & XFS_XFLAG_REALTIME))) { | 522 | (vap->va_xflags & XFS_XFLAG_REALTIME))) { |
525 | size = mp->m_sb.sb_rextsize << | 523 | size = mp->m_sb.sb_rextsize << |
526 | mp->m_sb.sb_blocklog; | 524 | mp->m_sb.sb_blocklog; |
527 | } else { | 525 | } else { |
528 | size = mp->m_sb.sb_blocksize; | 526 | size = mp->m_sb.sb_blocksize; |
529 | } | 527 | } |
530 | if (vap->va_extsize % size) { | 528 | if (vap->va_extsize % size) { |
531 | code = XFS_ERROR(EINVAL); | 529 | code = XFS_ERROR(EINVAL); |
532 | goto error_return; | 530 | goto error_return; |
533 | } | 531 | } |
534 | } | 532 | } |
535 | /* | 533 | /* |
536 | * If realtime flag is set then must have realtime data. | 534 | * If realtime flag is set then must have realtime data. |
537 | */ | 535 | */ |
538 | if ((mask & XFS_AT_XFLAGS) && | 536 | if ((mask & XFS_AT_XFLAGS) && |
539 | (vap->va_xflags & XFS_XFLAG_REALTIME)) { | 537 | (vap->va_xflags & XFS_XFLAG_REALTIME)) { |
540 | if ((mp->m_sb.sb_rblocks == 0) || | 538 | if ((mp->m_sb.sb_rblocks == 0) || |
541 | (mp->m_sb.sb_rextsize == 0) || | 539 | (mp->m_sb.sb_rextsize == 0) || |
542 | (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) { | 540 | (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) { |
543 | code = XFS_ERROR(EINVAL); | 541 | code = XFS_ERROR(EINVAL); |
544 | goto error_return; | 542 | goto error_return; |
545 | } | 543 | } |
546 | } | 544 | } |
547 | 545 | ||
548 | /* | 546 | /* |
549 | * Can't modify an immutable/append-only file unless | 547 | * Can't modify an immutable/append-only file unless |
550 | * we have appropriate permission. | 548 | * we have appropriate permission. |
551 | */ | 549 | */ |
552 | if ((mask & XFS_AT_XFLAGS) && | 550 | if ((mask & XFS_AT_XFLAGS) && |
553 | (ip->i_d.di_flags & | 551 | (ip->i_d.di_flags & |
554 | (XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) || | 552 | (XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) || |
555 | (vap->va_xflags & | 553 | (vap->va_xflags & |
556 | (XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) && | 554 | (XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) && |
557 | !capable(CAP_LINUX_IMMUTABLE)) { | 555 | !capable(CAP_LINUX_IMMUTABLE)) { |
558 | code = XFS_ERROR(EPERM); | 556 | code = XFS_ERROR(EPERM); |
559 | goto error_return; | 557 | goto error_return; |
560 | } | 558 | } |
561 | } | 559 | } |
562 | 560 | ||
563 | /* | 561 | /* |
564 | * Now we can make the changes. Before we join the inode | 562 | * Now we can make the changes. Before we join the inode |
565 | * to the transaction, if XFS_AT_SIZE is set then take care of | 563 | * to the transaction, if XFS_AT_SIZE is set then take care of |
566 | * the part of the truncation that must be done without the | 564 | * the part of the truncation that must be done without the |
567 | * inode lock. This needs to be done before joining the inode | 565 | * inode lock. This needs to be done before joining the inode |
568 | * to the transaction, because the inode cannot be unlocked | 566 | * to the transaction, because the inode cannot be unlocked |
569 | * once it is a part of the transaction. | 567 | * once it is a part of the transaction. |
570 | */ | 568 | */ |
571 | if (mask & XFS_AT_SIZE) { | 569 | if (mask & XFS_AT_SIZE) { |
572 | code = 0; | 570 | code = 0; |
573 | if ((vap->va_size > ip->i_size) && | 571 | if ((vap->va_size > ip->i_size) && |
574 | (flags & ATTR_NOSIZETOK) == 0) { | 572 | (flags & ATTR_NOSIZETOK) == 0) { |
575 | code = xfs_igrow_start(ip, vap->va_size, credp); | 573 | code = xfs_igrow_start(ip, vap->va_size, credp); |
576 | } | 574 | } |
577 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 575 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
578 | 576 | ||
579 | /* | 577 | /* |
580 | * We are going to log the inode size change in this | 578 | * We are going to log the inode size change in this |
581 | * transaction so any previous writes that are beyond the on | 579 | * transaction so any previous writes that are beyond the on |
582 | * disk EOF and the new EOF that have not been written out need | 580 | * disk EOF and the new EOF that have not been written out need |
583 | * to be written here. If we do not write the data out, we | 581 | * to be written here. If we do not write the data out, we |
584 | * expose ourselves to the null files problem. | 582 | * expose ourselves to the null files problem. |
585 | * | 583 | * |
586 | * Only flush from the on disk size to the smaller of the in | 584 | * Only flush from the on disk size to the smaller of the in |
587 | * memory file size or the new size as that's the range we | 585 | * memory file size or the new size as that's the range we |
588 | * really care about here and prevents waiting for other data | 586 | * really care about here and prevents waiting for other data |
589 | * not within the range we care about here. | 587 | * not within the range we care about here. |
590 | */ | 588 | */ |
591 | if (!code && | 589 | if (!code && |
592 | (ip->i_size != ip->i_d.di_size) && | 590 | (ip->i_size != ip->i_d.di_size) && |
593 | (vap->va_size > ip->i_d.di_size)) { | 591 | (vap->va_size > ip->i_d.di_size)) { |
594 | code = xfs_flush_pages(ip, | 592 | code = xfs_flush_pages(ip, |
595 | ip->i_d.di_size, vap->va_size, | 593 | ip->i_d.di_size, vap->va_size, |
596 | XFS_B_ASYNC, FI_NONE); | 594 | XFS_B_ASYNC, FI_NONE); |
597 | } | 595 | } |
598 | 596 | ||
599 | /* wait for all I/O to complete */ | 597 | /* wait for all I/O to complete */ |
600 | vn_iowait(ip); | 598 | vn_iowait(ip); |
601 | 599 | ||
602 | if (!code) | 600 | if (!code) |
603 | code = xfs_itruncate_data(ip, vap->va_size); | 601 | code = xfs_itruncate_data(ip, vap->va_size); |
604 | if (code) { | 602 | if (code) { |
605 | ASSERT(tp == NULL); | 603 | ASSERT(tp == NULL); |
606 | lock_flags &= ~XFS_ILOCK_EXCL; | 604 | lock_flags &= ~XFS_ILOCK_EXCL; |
607 | ASSERT(lock_flags == XFS_IOLOCK_EXCL); | 605 | ASSERT(lock_flags == XFS_IOLOCK_EXCL); |
608 | goto error_return; | 606 | goto error_return; |
609 | } | 607 | } |
610 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); | 608 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); |
611 | if ((code = xfs_trans_reserve(tp, 0, | 609 | if ((code = xfs_trans_reserve(tp, 0, |
612 | XFS_ITRUNCATE_LOG_RES(mp), 0, | 610 | XFS_ITRUNCATE_LOG_RES(mp), 0, |
613 | XFS_TRANS_PERM_LOG_RES, | 611 | XFS_TRANS_PERM_LOG_RES, |
614 | XFS_ITRUNCATE_LOG_COUNT))) { | 612 | XFS_ITRUNCATE_LOG_COUNT))) { |
615 | xfs_trans_cancel(tp, 0); | 613 | xfs_trans_cancel(tp, 0); |
616 | if (need_iolock) | 614 | if (need_iolock) |
617 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 615 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
618 | return code; | 616 | return code; |
619 | } | 617 | } |
620 | commit_flags = XFS_TRANS_RELEASE_LOG_RES; | 618 | commit_flags = XFS_TRANS_RELEASE_LOG_RES; |
621 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 619 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
622 | } | 620 | } |
623 | 621 | ||
624 | if (tp) { | 622 | if (tp) { |
625 | xfs_trans_ijoin(tp, ip, lock_flags); | 623 | xfs_trans_ijoin(tp, ip, lock_flags); |
626 | xfs_trans_ihold(tp, ip); | 624 | xfs_trans_ihold(tp, ip); |
627 | } | 625 | } |
628 | 626 | ||
629 | /* determine whether mandatory locking mode changes */ | ||
630 | mandlock_before = MANDLOCK(vp, ip->i_d.di_mode); | ||
631 | |||
632 | /* | 627 | /* |
633 | * Truncate file. Must have write permission and not be a directory. | 628 | * Truncate file. Must have write permission and not be a directory. |
634 | */ | 629 | */ |
635 | if (mask & XFS_AT_SIZE) { | 630 | if (mask & XFS_AT_SIZE) { |
636 | /* | 631 | /* |
637 | * Only change the c/mtime if we are changing the size | 632 | * Only change the c/mtime if we are changing the size |
638 | * or we are explicitly asked to change it. This handles | 633 | * or we are explicitly asked to change it. This handles |
639 | * the semantic difference between truncate() and ftruncate() | 634 | * the semantic difference between truncate() and ftruncate() |
640 | * as implemented in the VFS. | 635 | * as implemented in the VFS. |
641 | */ | 636 | */ |
642 | if (vap->va_size != ip->i_size || (mask & XFS_AT_CTIME)) | 637 | if (vap->va_size != ip->i_size || (mask & XFS_AT_CTIME)) |
643 | timeflags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; | 638 | timeflags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; |
644 | 639 | ||
645 | if (vap->va_size > ip->i_size) { | 640 | if (vap->va_size > ip->i_size) { |
646 | xfs_igrow_finish(tp, ip, vap->va_size, | 641 | xfs_igrow_finish(tp, ip, vap->va_size, |
647 | !(flags & ATTR_DMI)); | 642 | !(flags & ATTR_DMI)); |
648 | } else if ((vap->va_size <= ip->i_size) || | 643 | } else if ((vap->va_size <= ip->i_size) || |
649 | ((vap->va_size == 0) && ip->i_d.di_nextents)) { | 644 | ((vap->va_size == 0) && ip->i_d.di_nextents)) { |
650 | /* | 645 | /* |
651 | * signal a sync transaction unless | 646 | * signal a sync transaction unless |
652 | * we're truncating an already unlinked | 647 | * we're truncating an already unlinked |
653 | * file on a wsync filesystem | 648 | * file on a wsync filesystem |
654 | */ | 649 | */ |
655 | code = xfs_itruncate_finish(&tp, ip, | 650 | code = xfs_itruncate_finish(&tp, ip, |
656 | (xfs_fsize_t)vap->va_size, | 651 | (xfs_fsize_t)vap->va_size, |
657 | XFS_DATA_FORK, | 652 | XFS_DATA_FORK, |
658 | ((ip->i_d.di_nlink != 0 || | 653 | ((ip->i_d.di_nlink != 0 || |
659 | !(mp->m_flags & XFS_MOUNT_WSYNC)) | 654 | !(mp->m_flags & XFS_MOUNT_WSYNC)) |
660 | ? 1 : 0)); | 655 | ? 1 : 0)); |
661 | if (code) | 656 | if (code) |
662 | goto abort_return; | 657 | goto abort_return; |
663 | /* | 658 | /* |
664 | * Truncated "down", so we're removing references | 659 | * Truncated "down", so we're removing references |
665 | * to old data here - if we now delay flushing for | 660 | * to old data here - if we now delay flushing for |
666 | * a long time, we expose ourselves unduly to the | 661 | * a long time, we expose ourselves unduly to the |
667 | * notorious NULL files problem. So, we mark this | 662 | * notorious NULL files problem. So, we mark this |
668 | * vnode and flush it when the file is closed, and | 663 | * vnode and flush it when the file is closed, and |
669 | * do not wait the usual (long) time for writeout. | 664 | * do not wait the usual (long) time for writeout. |
670 | */ | 665 | */ |
671 | xfs_iflags_set(ip, XFS_ITRUNCATED); | 666 | xfs_iflags_set(ip, XFS_ITRUNCATED); |
672 | } | 667 | } |
673 | } | 668 | } |
674 | 669 | ||
675 | /* | 670 | /* |
676 | * Change file access modes. | 671 | * Change file access modes. |
677 | */ | 672 | */ |
678 | if (mask & XFS_AT_MODE) { | 673 | if (mask & XFS_AT_MODE) { |
679 | ip->i_d.di_mode &= S_IFMT; | 674 | ip->i_d.di_mode &= S_IFMT; |
680 | ip->i_d.di_mode |= vap->va_mode & ~S_IFMT; | 675 | ip->i_d.di_mode |= vap->va_mode & ~S_IFMT; |
681 | 676 | ||
682 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); | 677 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); |
683 | timeflags |= XFS_ICHGTIME_CHG; | 678 | timeflags |= XFS_ICHGTIME_CHG; |
684 | } | 679 | } |
685 | 680 | ||
686 | /* | 681 | /* |
687 | * Change file ownership. Must be the owner or privileged. | 682 | * Change file ownership. Must be the owner or privileged. |
688 | * If the system was configured with the "restricted_chown" | 683 | * If the system was configured with the "restricted_chown" |
689 | * option, the owner is not permitted to give away the file, | 684 | * option, the owner is not permitted to give away the file, |
690 | * and can change the group id only to a group of which he | 685 | * and can change the group id only to a group of which he |
691 | * or she is a member. | 686 | * or she is a member. |
692 | */ | 687 | */ |
693 | if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) { | 688 | if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) { |
694 | /* | 689 | /* |
695 | * CAP_FSETID overrides the following restrictions: | 690 | * CAP_FSETID overrides the following restrictions: |
696 | * | 691 | * |
697 | * The set-user-ID and set-group-ID bits of a file will be | 692 | * The set-user-ID and set-group-ID bits of a file will be |
698 | * cleared upon successful return from chown() | 693 | * cleared upon successful return from chown() |
699 | */ | 694 | */ |
700 | if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) && | 695 | if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) && |
701 | !capable(CAP_FSETID)) { | 696 | !capable(CAP_FSETID)) { |
702 | ip->i_d.di_mode &= ~(S_ISUID|S_ISGID); | 697 | ip->i_d.di_mode &= ~(S_ISUID|S_ISGID); |
703 | } | 698 | } |
704 | 699 | ||
705 | /* | 700 | /* |
706 | * Change the ownerships and register quota modifications | 701 | * Change the ownerships and register quota modifications |
707 | * in the transaction. | 702 | * in the transaction. |
708 | */ | 703 | */ |
709 | if (iuid != uid) { | 704 | if (iuid != uid) { |
710 | if (XFS_IS_UQUOTA_ON(mp)) { | 705 | if (XFS_IS_UQUOTA_ON(mp)) { |
711 | ASSERT(mask & XFS_AT_UID); | 706 | ASSERT(mask & XFS_AT_UID); |
712 | ASSERT(udqp); | 707 | ASSERT(udqp); |
713 | olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip, | 708 | olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip, |
714 | &ip->i_udquot, udqp); | 709 | &ip->i_udquot, udqp); |
715 | } | 710 | } |
716 | ip->i_d.di_uid = uid; | 711 | ip->i_d.di_uid = uid; |
717 | } | 712 | } |
718 | if (igid != gid) { | 713 | if (igid != gid) { |
719 | if (XFS_IS_GQUOTA_ON(mp)) { | 714 | if (XFS_IS_GQUOTA_ON(mp)) { |
720 | ASSERT(!XFS_IS_PQUOTA_ON(mp)); | 715 | ASSERT(!XFS_IS_PQUOTA_ON(mp)); |
721 | ASSERT(mask & XFS_AT_GID); | 716 | ASSERT(mask & XFS_AT_GID); |
722 | ASSERT(gdqp); | 717 | ASSERT(gdqp); |
723 | olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, | 718 | olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, |
724 | &ip->i_gdquot, gdqp); | 719 | &ip->i_gdquot, gdqp); |
725 | } | 720 | } |
726 | ip->i_d.di_gid = gid; | 721 | ip->i_d.di_gid = gid; |
727 | } | 722 | } |
728 | if (iprojid != projid) { | 723 | if (iprojid != projid) { |
729 | if (XFS_IS_PQUOTA_ON(mp)) { | 724 | if (XFS_IS_PQUOTA_ON(mp)) { |
730 | ASSERT(!XFS_IS_GQUOTA_ON(mp)); | 725 | ASSERT(!XFS_IS_GQUOTA_ON(mp)); |
731 | ASSERT(mask & XFS_AT_PROJID); | 726 | ASSERT(mask & XFS_AT_PROJID); |
732 | ASSERT(gdqp); | 727 | ASSERT(gdqp); |
733 | olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, | 728 | olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, |
734 | &ip->i_gdquot, gdqp); | 729 | &ip->i_gdquot, gdqp); |
735 | } | 730 | } |
736 | ip->i_d.di_projid = projid; | 731 | ip->i_d.di_projid = projid; |
737 | /* | 732 | /* |
738 | * We may have to rev the inode as well as | 733 | * We may have to rev the inode as well as |
739 | * the superblock version number since projids didn't | 734 | * the superblock version number since projids didn't |
740 | * exist before DINODE_VERSION_2 and SB_VERSION_NLINK. | 735 | * exist before DINODE_VERSION_2 and SB_VERSION_NLINK. |
741 | */ | 736 | */ |
742 | if (ip->i_d.di_version == XFS_DINODE_VERSION_1) | 737 | if (ip->i_d.di_version == XFS_DINODE_VERSION_1) |
743 | xfs_bump_ino_vers2(tp, ip); | 738 | xfs_bump_ino_vers2(tp, ip); |
744 | } | 739 | } |
745 | 740 | ||
746 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); | 741 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); |
747 | timeflags |= XFS_ICHGTIME_CHG; | 742 | timeflags |= XFS_ICHGTIME_CHG; |
748 | } | 743 | } |
749 | 744 | ||
750 | 745 | ||
751 | /* | 746 | /* |
752 | * Change file access or modified times. | 747 | * Change file access or modified times. |
753 | */ | 748 | */ |
754 | if (mask & (XFS_AT_ATIME|XFS_AT_MTIME)) { | 749 | if (mask & (XFS_AT_ATIME|XFS_AT_MTIME)) { |
755 | if (mask & XFS_AT_ATIME) { | 750 | if (mask & XFS_AT_ATIME) { |
756 | ip->i_d.di_atime.t_sec = vap->va_atime.tv_sec; | 751 | ip->i_d.di_atime.t_sec = vap->va_atime.tv_sec; |
757 | ip->i_d.di_atime.t_nsec = vap->va_atime.tv_nsec; | 752 | ip->i_d.di_atime.t_nsec = vap->va_atime.tv_nsec; |
758 | ip->i_update_core = 1; | 753 | ip->i_update_core = 1; |
759 | timeflags &= ~XFS_ICHGTIME_ACC; | 754 | timeflags &= ~XFS_ICHGTIME_ACC; |
760 | } | 755 | } |
761 | if (mask & XFS_AT_MTIME) { | 756 | if (mask & XFS_AT_MTIME) { |
762 | ip->i_d.di_mtime.t_sec = vap->va_mtime.tv_sec; | 757 | ip->i_d.di_mtime.t_sec = vap->va_mtime.tv_sec; |
763 | ip->i_d.di_mtime.t_nsec = vap->va_mtime.tv_nsec; | 758 | ip->i_d.di_mtime.t_nsec = vap->va_mtime.tv_nsec; |
764 | timeflags &= ~XFS_ICHGTIME_MOD; | 759 | timeflags &= ~XFS_ICHGTIME_MOD; |
765 | timeflags |= XFS_ICHGTIME_CHG; | 760 | timeflags |= XFS_ICHGTIME_CHG; |
766 | } | 761 | } |
767 | if (tp && (flags & ATTR_UTIME)) | 762 | if (tp && (flags & ATTR_UTIME)) |
768 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); | 763 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); |
769 | } | 764 | } |
770 | 765 | ||
771 | /* | 766 | /* |
772 | * Change XFS-added attributes. | 767 | * Change XFS-added attributes. |
773 | */ | 768 | */ |
774 | if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) { | 769 | if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) { |
775 | if (mask & XFS_AT_EXTSIZE) { | 770 | if (mask & XFS_AT_EXTSIZE) { |
776 | /* | 771 | /* |
777 | * Converting bytes to fs blocks. | 772 | * Converting bytes to fs blocks. |
778 | */ | 773 | */ |
779 | ip->i_d.di_extsize = vap->va_extsize >> | 774 | ip->i_d.di_extsize = vap->va_extsize >> |
780 | mp->m_sb.sb_blocklog; | 775 | mp->m_sb.sb_blocklog; |
781 | } | 776 | } |
782 | if (mask & XFS_AT_XFLAGS) { | 777 | if (mask & XFS_AT_XFLAGS) { |
783 | uint di_flags; | 778 | uint di_flags; |
784 | 779 | ||
785 | /* can't set PREALLOC this way, just preserve it */ | 780 | /* can't set PREALLOC this way, just preserve it */ |
786 | di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); | 781 | di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); |
787 | if (vap->va_xflags & XFS_XFLAG_IMMUTABLE) | 782 | if (vap->va_xflags & XFS_XFLAG_IMMUTABLE) |
788 | di_flags |= XFS_DIFLAG_IMMUTABLE; | 783 | di_flags |= XFS_DIFLAG_IMMUTABLE; |
789 | if (vap->va_xflags & XFS_XFLAG_APPEND) | 784 | if (vap->va_xflags & XFS_XFLAG_APPEND) |
790 | di_flags |= XFS_DIFLAG_APPEND; | 785 | di_flags |= XFS_DIFLAG_APPEND; |
791 | if (vap->va_xflags & XFS_XFLAG_SYNC) | 786 | if (vap->va_xflags & XFS_XFLAG_SYNC) |
792 | di_flags |= XFS_DIFLAG_SYNC; | 787 | di_flags |= XFS_DIFLAG_SYNC; |
793 | if (vap->va_xflags & XFS_XFLAG_NOATIME) | 788 | if (vap->va_xflags & XFS_XFLAG_NOATIME) |
794 | di_flags |= XFS_DIFLAG_NOATIME; | 789 | di_flags |= XFS_DIFLAG_NOATIME; |
795 | if (vap->va_xflags & XFS_XFLAG_NODUMP) | 790 | if (vap->va_xflags & XFS_XFLAG_NODUMP) |
796 | di_flags |= XFS_DIFLAG_NODUMP; | 791 | di_flags |= XFS_DIFLAG_NODUMP; |
797 | if (vap->va_xflags & XFS_XFLAG_PROJINHERIT) | 792 | if (vap->va_xflags & XFS_XFLAG_PROJINHERIT) |
798 | di_flags |= XFS_DIFLAG_PROJINHERIT; | 793 | di_flags |= XFS_DIFLAG_PROJINHERIT; |
799 | if (vap->va_xflags & XFS_XFLAG_NODEFRAG) | 794 | if (vap->va_xflags & XFS_XFLAG_NODEFRAG) |
800 | di_flags |= XFS_DIFLAG_NODEFRAG; | 795 | di_flags |= XFS_DIFLAG_NODEFRAG; |
801 | if (vap->va_xflags & XFS_XFLAG_FILESTREAM) | 796 | if (vap->va_xflags & XFS_XFLAG_FILESTREAM) |
802 | di_flags |= XFS_DIFLAG_FILESTREAM; | 797 | di_flags |= XFS_DIFLAG_FILESTREAM; |
803 | if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { | 798 | if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { |
804 | if (vap->va_xflags & XFS_XFLAG_RTINHERIT) | 799 | if (vap->va_xflags & XFS_XFLAG_RTINHERIT) |
805 | di_flags |= XFS_DIFLAG_RTINHERIT; | 800 | di_flags |= XFS_DIFLAG_RTINHERIT; |
806 | if (vap->va_xflags & XFS_XFLAG_NOSYMLINKS) | 801 | if (vap->va_xflags & XFS_XFLAG_NOSYMLINKS) |
807 | di_flags |= XFS_DIFLAG_NOSYMLINKS; | 802 | di_flags |= XFS_DIFLAG_NOSYMLINKS; |
808 | if (vap->va_xflags & XFS_XFLAG_EXTSZINHERIT) | 803 | if (vap->va_xflags & XFS_XFLAG_EXTSZINHERIT) |
809 | di_flags |= XFS_DIFLAG_EXTSZINHERIT; | 804 | di_flags |= XFS_DIFLAG_EXTSZINHERIT; |
810 | } else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) { | 805 | } else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) { |
811 | if (vap->va_xflags & XFS_XFLAG_REALTIME) | 806 | if (vap->va_xflags & XFS_XFLAG_REALTIME) |
812 | di_flags |= XFS_DIFLAG_REALTIME; | 807 | di_flags |= XFS_DIFLAG_REALTIME; |
813 | if (vap->va_xflags & XFS_XFLAG_EXTSIZE) | 808 | if (vap->va_xflags & XFS_XFLAG_EXTSIZE) |
814 | di_flags |= XFS_DIFLAG_EXTSIZE; | 809 | di_flags |= XFS_DIFLAG_EXTSIZE; |
815 | } | 810 | } |
816 | ip->i_d.di_flags = di_flags; | 811 | ip->i_d.di_flags = di_flags; |
817 | } | 812 | } |
818 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 813 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
819 | timeflags |= XFS_ICHGTIME_CHG; | 814 | timeflags |= XFS_ICHGTIME_CHG; |
820 | } | 815 | } |
821 | 816 | ||
822 | /* | 817 | /* |
823 | * Change file inode change time only if XFS_AT_CTIME set | 818 | * Change file inode change time only if XFS_AT_CTIME set |
824 | * AND we have been called by a DMI function. | 819 | * AND we have been called by a DMI function. |
825 | */ | 820 | */ |
826 | 821 | ||
827 | if ( (flags & ATTR_DMI) && (mask & XFS_AT_CTIME) ) { | 822 | if ( (flags & ATTR_DMI) && (mask & XFS_AT_CTIME) ) { |
828 | ip->i_d.di_ctime.t_sec = vap->va_ctime.tv_sec; | 823 | ip->i_d.di_ctime.t_sec = vap->va_ctime.tv_sec; |
829 | ip->i_d.di_ctime.t_nsec = vap->va_ctime.tv_nsec; | 824 | ip->i_d.di_ctime.t_nsec = vap->va_ctime.tv_nsec; |
830 | ip->i_update_core = 1; | 825 | ip->i_update_core = 1; |
831 | timeflags &= ~XFS_ICHGTIME_CHG; | 826 | timeflags &= ~XFS_ICHGTIME_CHG; |
832 | } | 827 | } |
833 | 828 | ||
834 | /* | 829 | /* |
835 | * Send out timestamp changes that need to be set to the | 830 | * Send out timestamp changes that need to be set to the |
836 | * current time. Not done when called by a DMI function. | 831 | * current time. Not done when called by a DMI function. |
837 | */ | 832 | */ |
838 | if (timeflags && !(flags & ATTR_DMI)) | 833 | if (timeflags && !(flags & ATTR_DMI)) |
839 | xfs_ichgtime(ip, timeflags); | 834 | xfs_ichgtime(ip, timeflags); |
840 | 835 | ||
841 | XFS_STATS_INC(xs_ig_attrchg); | 836 | XFS_STATS_INC(xs_ig_attrchg); |
842 | 837 | ||
843 | /* | 838 | /* |
844 | * If this is a synchronous mount, make sure that the | 839 | * If this is a synchronous mount, make sure that the |
845 | * transaction goes to disk before returning to the user. | 840 | * transaction goes to disk before returning to the user. |
846 | * This is slightly sub-optimal in that truncates require | 841 | * This is slightly sub-optimal in that truncates require |
847 | * two sync transactions instead of one for wsync filesystems. | 842 | * two sync transactions instead of one for wsync filesystems. |
848 | * One for the truncate and one for the timestamps since we | 843 | * One for the truncate and one for the timestamps since we |
849 | * don't want to change the timestamps unless we're sure the | 844 | * don't want to change the timestamps unless we're sure the |
850 | * truncate worked. Truncates are less than 1% of the laddis | 845 | * truncate worked. Truncates are less than 1% of the laddis |
851 | * mix so this probably isn't worth the trouble to optimize. | 846 | * mix so this probably isn't worth the trouble to optimize. |
852 | */ | 847 | */ |
853 | code = 0; | 848 | code = 0; |
854 | if (tp) { | 849 | if (tp) { |
855 | if (mp->m_flags & XFS_MOUNT_WSYNC) | 850 | if (mp->m_flags & XFS_MOUNT_WSYNC) |
856 | xfs_trans_set_sync(tp); | 851 | xfs_trans_set_sync(tp); |
857 | 852 | ||
858 | code = xfs_trans_commit(tp, commit_flags); | 853 | code = xfs_trans_commit(tp, commit_flags); |
859 | } | 854 | } |
860 | 855 | ||
861 | /* | ||
862 | * If the (regular) file's mandatory locking mode changed, then | ||
863 | * notify the vnode. We do this under the inode lock to prevent | ||
864 | * racing calls to vop_vnode_change. | ||
865 | */ | ||
866 | mandlock_after = MANDLOCK(vp, ip->i_d.di_mode); | ||
867 | |||
868 | xfs_iunlock(ip, lock_flags); | 856 | xfs_iunlock(ip, lock_flags); |
869 | 857 | ||
870 | /* | 858 | /* |
871 | * Release any dquot(s) the inode had kept before chown. | 859 | * Release any dquot(s) the inode had kept before chown. |
872 | */ | 860 | */ |
873 | XFS_QM_DQRELE(mp, olddquot1); | 861 | XFS_QM_DQRELE(mp, olddquot1); |
874 | XFS_QM_DQRELE(mp, olddquot2); | 862 | XFS_QM_DQRELE(mp, olddquot2); |
875 | XFS_QM_DQRELE(mp, udqp); | 863 | XFS_QM_DQRELE(mp, udqp); |
876 | XFS_QM_DQRELE(mp, gdqp); | 864 | XFS_QM_DQRELE(mp, gdqp); |
877 | 865 | ||
878 | if (code) { | 866 | if (code) { |
879 | return code; | 867 | return code; |
880 | } | 868 | } |
881 | 869 | ||
882 | if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) && | 870 | if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) && |
883 | !(flags & ATTR_DMI)) { | 871 | !(flags & ATTR_DMI)) { |
884 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL, | 872 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL, |
885 | NULL, DM_RIGHT_NULL, NULL, NULL, | 873 | NULL, DM_RIGHT_NULL, NULL, NULL, |
886 | 0, 0, AT_DELAY_FLAG(flags)); | 874 | 0, 0, AT_DELAY_FLAG(flags)); |
887 | } | 875 | } |
888 | return 0; | 876 | return 0; |
889 | 877 | ||
890 | abort_return: | 878 | abort_return: |
891 | commit_flags |= XFS_TRANS_ABORT; | 879 | commit_flags |= XFS_TRANS_ABORT; |
892 | /* FALLTHROUGH */ | 880 | /* FALLTHROUGH */ |
893 | error_return: | 881 | error_return: |
894 | XFS_QM_DQRELE(mp, udqp); | 882 | XFS_QM_DQRELE(mp, udqp); |
895 | XFS_QM_DQRELE(mp, gdqp); | 883 | XFS_QM_DQRELE(mp, gdqp); |
896 | if (tp) { | 884 | if (tp) { |
897 | xfs_trans_cancel(tp, commit_flags); | 885 | xfs_trans_cancel(tp, commit_flags); |
898 | } | 886 | } |
899 | if (lock_flags != 0) { | 887 | if (lock_flags != 0) { |
900 | xfs_iunlock(ip, lock_flags); | 888 | xfs_iunlock(ip, lock_flags); |
901 | } | 889 | } |
902 | return code; | 890 | return code; |
903 | } | 891 | } |
904 | 892 | ||
905 | /* | 893 | /* |
906 | * The maximum pathlen is 1024 bytes. Since the minimum file system | 894 | * The maximum pathlen is 1024 bytes. Since the minimum file system |
907 | * blocksize is 512 bytes, we can get a max of 2 extents back from | 895 | * blocksize is 512 bytes, we can get a max of 2 extents back from |
908 | * bmapi. | 896 | * bmapi. |
909 | */ | 897 | */ |
910 | #define SYMLINK_MAPS 2 | 898 | #define SYMLINK_MAPS 2 |
911 | 899 | ||
912 | STATIC int | 900 | STATIC int |
913 | xfs_readlink_bmap( | 901 | xfs_readlink_bmap( |
914 | xfs_inode_t *ip, | 902 | xfs_inode_t *ip, |
915 | char *link) | 903 | char *link) |
916 | { | 904 | { |
917 | xfs_mount_t *mp = ip->i_mount; | 905 | xfs_mount_t *mp = ip->i_mount; |
918 | int pathlen = ip->i_d.di_size; | 906 | int pathlen = ip->i_d.di_size; |
919 | int nmaps = SYMLINK_MAPS; | 907 | int nmaps = SYMLINK_MAPS; |
920 | xfs_bmbt_irec_t mval[SYMLINK_MAPS]; | 908 | xfs_bmbt_irec_t mval[SYMLINK_MAPS]; |
921 | xfs_daddr_t d; | 909 | xfs_daddr_t d; |
922 | int byte_cnt; | 910 | int byte_cnt; |
923 | int n; | 911 | int n; |
924 | xfs_buf_t *bp; | 912 | xfs_buf_t *bp; |
925 | int error = 0; | 913 | int error = 0; |
926 | 914 | ||
927 | error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0, | 915 | error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), 0, NULL, 0, |
928 | mval, &nmaps, NULL, NULL); | 916 | mval, &nmaps, NULL, NULL); |
929 | if (error) | 917 | if (error) |
930 | goto out; | 918 | goto out; |
931 | 919 | ||
932 | for (n = 0; n < nmaps; n++) { | 920 | for (n = 0; n < nmaps; n++) { |
933 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); | 921 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); |
934 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); | 922 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); |
935 | 923 | ||
936 | bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0); | 924 | bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0); |
937 | error = XFS_BUF_GETERROR(bp); | 925 | error = XFS_BUF_GETERROR(bp); |
938 | if (error) { | 926 | if (error) { |
939 | xfs_ioerror_alert("xfs_readlink", | 927 | xfs_ioerror_alert("xfs_readlink", |
940 | ip->i_mount, bp, XFS_BUF_ADDR(bp)); | 928 | ip->i_mount, bp, XFS_BUF_ADDR(bp)); |
941 | xfs_buf_relse(bp); | 929 | xfs_buf_relse(bp); |
942 | goto out; | 930 | goto out; |
943 | } | 931 | } |
944 | if (pathlen < byte_cnt) | 932 | if (pathlen < byte_cnt) |
945 | byte_cnt = pathlen; | 933 | byte_cnt = pathlen; |
946 | pathlen -= byte_cnt; | 934 | pathlen -= byte_cnt; |
947 | 935 | ||
948 | memcpy(link, XFS_BUF_PTR(bp), byte_cnt); | 936 | memcpy(link, XFS_BUF_PTR(bp), byte_cnt); |
949 | xfs_buf_relse(bp); | 937 | xfs_buf_relse(bp); |
950 | } | 938 | } |
951 | 939 | ||
952 | link[ip->i_d.di_size] = '\0'; | 940 | link[ip->i_d.di_size] = '\0'; |
953 | error = 0; | 941 | error = 0; |
954 | 942 | ||
955 | out: | 943 | out: |
956 | return error; | 944 | return error; |
957 | } | 945 | } |
958 | 946 | ||
959 | int | 947 | int |
960 | xfs_readlink( | 948 | xfs_readlink( |
961 | xfs_inode_t *ip, | 949 | xfs_inode_t *ip, |
962 | char *link) | 950 | char *link) |
963 | { | 951 | { |
964 | xfs_mount_t *mp = ip->i_mount; | 952 | xfs_mount_t *mp = ip->i_mount; |
965 | int pathlen; | 953 | int pathlen; |
966 | int error = 0; | 954 | int error = 0; |
967 | 955 | ||
968 | xfs_itrace_entry(ip); | 956 | xfs_itrace_entry(ip); |
969 | 957 | ||
970 | if (XFS_FORCED_SHUTDOWN(mp)) | 958 | if (XFS_FORCED_SHUTDOWN(mp)) |
971 | return XFS_ERROR(EIO); | 959 | return XFS_ERROR(EIO); |
972 | 960 | ||
973 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 961 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
974 | 962 | ||
975 | ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK); | 963 | ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK); |
976 | ASSERT(ip->i_d.di_size <= MAXPATHLEN); | 964 | ASSERT(ip->i_d.di_size <= MAXPATHLEN); |
977 | 965 | ||
978 | pathlen = ip->i_d.di_size; | 966 | pathlen = ip->i_d.di_size; |
979 | if (!pathlen) | 967 | if (!pathlen) |
980 | goto out; | 968 | goto out; |
981 | 969 | ||
982 | if (ip->i_df.if_flags & XFS_IFINLINE) { | 970 | if (ip->i_df.if_flags & XFS_IFINLINE) { |
983 | memcpy(link, ip->i_df.if_u1.if_data, pathlen); | 971 | memcpy(link, ip->i_df.if_u1.if_data, pathlen); |
984 | link[pathlen] = '\0'; | 972 | link[pathlen] = '\0'; |
985 | } else { | 973 | } else { |
986 | error = xfs_readlink_bmap(ip, link); | 974 | error = xfs_readlink_bmap(ip, link); |
987 | } | 975 | } |
988 | 976 | ||
989 | out: | 977 | out: |
990 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 978 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
991 | return error; | 979 | return error; |
992 | } | 980 | } |
993 | 981 | ||
994 | /* | 982 | /* |
995 | * xfs_fsync | 983 | * xfs_fsync |
996 | * | 984 | * |
997 | * This is called to sync the inode and its data out to disk. | 985 | * This is called to sync the inode and its data out to disk. |
998 | * We need to hold the I/O lock while flushing the data, and | 986 | * We need to hold the I/O lock while flushing the data, and |
999 | * the inode lock while flushing the inode. The inode lock CANNOT | 987 | * the inode lock while flushing the inode. The inode lock CANNOT |
1000 | * be held while flushing the data, so acquire after we're done | 988 | * be held while flushing the data, so acquire after we're done |
1001 | * with that. | 989 | * with that. |
1002 | */ | 990 | */ |
1003 | int | 991 | int |
1004 | xfs_fsync( | 992 | xfs_fsync( |
1005 | xfs_inode_t *ip, | 993 | xfs_inode_t *ip, |
1006 | int flag, | 994 | int flag, |
1007 | xfs_off_t start, | 995 | xfs_off_t start, |
1008 | xfs_off_t stop) | 996 | xfs_off_t stop) |
1009 | { | 997 | { |
1010 | xfs_trans_t *tp; | 998 | xfs_trans_t *tp; |
1011 | int error; | 999 | int error; |
1012 | int log_flushed = 0, changed = 1; | 1000 | int log_flushed = 0, changed = 1; |
1013 | 1001 | ||
1014 | xfs_itrace_entry(ip); | 1002 | xfs_itrace_entry(ip); |
1015 | 1003 | ||
1016 | ASSERT(start >= 0 && stop >= -1); | 1004 | ASSERT(start >= 0 && stop >= -1); |
1017 | 1005 | ||
1018 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | 1006 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) |
1019 | return XFS_ERROR(EIO); | 1007 | return XFS_ERROR(EIO); |
1020 | 1008 | ||
1021 | if (flag & FSYNC_DATA) | 1009 | if (flag & FSYNC_DATA) |
1022 | filemap_fdatawait(vn_to_inode(XFS_ITOV(ip))->i_mapping); | 1010 | filemap_fdatawait(vn_to_inode(XFS_ITOV(ip))->i_mapping); |
1023 | 1011 | ||
1024 | /* | 1012 | /* |
1025 | * We always need to make sure that the required inode state | 1013 | * We always need to make sure that the required inode state |
1026 | * is safe on disk. The vnode might be clean but because | 1014 | * is safe on disk. The vnode might be clean but because |
1027 | * of committed transactions that haven't hit the disk yet. | 1015 | * of committed transactions that haven't hit the disk yet. |
1028 | * Likewise, there could be unflushed non-transactional | 1016 | * Likewise, there could be unflushed non-transactional |
1029 | * changes to the inode core that have to go to disk. | 1017 | * changes to the inode core that have to go to disk. |
1030 | * | 1018 | * |
1031 | * The following code depends on one assumption: that | 1019 | * The following code depends on one assumption: that |
1032 | * any transaction that changes an inode logs the core | 1020 | * any transaction that changes an inode logs the core |
1033 | * because it has to change some field in the inode core | 1021 | * because it has to change some field in the inode core |
1034 | * (typically nextents or nblocks). That assumption | 1022 | * (typically nextents or nblocks). That assumption |
1035 | * implies that any transactions against an inode will | 1023 | * implies that any transactions against an inode will |
1036 | * catch any non-transactional updates. If inode-altering | 1024 | * catch any non-transactional updates. If inode-altering |
1037 | * transactions exist that violate this assumption, the | 1025 | * transactions exist that violate this assumption, the |
1038 | * code breaks. Right now, it figures that if the involved | 1026 | * code breaks. Right now, it figures that if the involved |
1039 | * update_* field is clear and the inode is unpinned, the | 1027 | * update_* field is clear and the inode is unpinned, the |
1040 | * inode is clean. Either it's been flushed or it's been | 1028 | * inode is clean. Either it's been flushed or it's been |
1041 | * committed and the commit has hit the disk unpinning the inode. | 1029 | * committed and the commit has hit the disk unpinning the inode. |
1042 | * (Note that xfs_inode_item_format() called at commit clears | 1030 | * (Note that xfs_inode_item_format() called at commit clears |
1043 | * the update_* fields.) | 1031 | * the update_* fields.) |
1044 | */ | 1032 | */ |
1045 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 1033 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
1046 | 1034 | ||
1047 | /* If we are flushing data then we care about update_size | 1035 | /* If we are flushing data then we care about update_size |
1048 | * being set, otherwise we care about update_core | 1036 | * being set, otherwise we care about update_core |
1049 | */ | 1037 | */ |
1050 | if ((flag & FSYNC_DATA) ? | 1038 | if ((flag & FSYNC_DATA) ? |
1051 | (ip->i_update_size == 0) : | 1039 | (ip->i_update_size == 0) : |
1052 | (ip->i_update_core == 0)) { | 1040 | (ip->i_update_core == 0)) { |
1053 | /* | 1041 | /* |
1054 | * Timestamps/size haven't changed since last inode | 1042 | * Timestamps/size haven't changed since last inode |
1055 | * flush or inode transaction commit. That means | 1043 | * flush or inode transaction commit. That means |
1056 | * either nothing got written or a transaction | 1044 | * either nothing got written or a transaction |
1057 | * committed which caught the updates. If the | 1045 | * committed which caught the updates. If the |
1058 | * latter happened and the transaction hasn't | 1046 | * latter happened and the transaction hasn't |
1059 | * hit the disk yet, the inode will be still | 1047 | * hit the disk yet, the inode will be still |
1060 | * be pinned. If it is, force the log. | 1048 | * be pinned. If it is, force the log. |
1061 | */ | 1049 | */ |
1062 | 1050 | ||
1063 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 1051 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
1064 | 1052 | ||
1065 | if (xfs_ipincount(ip)) { | 1053 | if (xfs_ipincount(ip)) { |
1066 | _xfs_log_force(ip->i_mount, (xfs_lsn_t)0, | 1054 | _xfs_log_force(ip->i_mount, (xfs_lsn_t)0, |
1067 | XFS_LOG_FORCE | | 1055 | XFS_LOG_FORCE | |
1068 | ((flag & FSYNC_WAIT) | 1056 | ((flag & FSYNC_WAIT) |
1069 | ? XFS_LOG_SYNC : 0), | 1057 | ? XFS_LOG_SYNC : 0), |
1070 | &log_flushed); | 1058 | &log_flushed); |
1071 | } else { | 1059 | } else { |
1072 | /* | 1060 | /* |
1073 | * If the inode is not pinned and nothing | 1061 | * If the inode is not pinned and nothing |
1074 | * has changed we don't need to flush the | 1062 | * has changed we don't need to flush the |
1075 | * cache. | 1063 | * cache. |
1076 | */ | 1064 | */ |
1077 | changed = 0; | 1065 | changed = 0; |
1078 | } | 1066 | } |
1079 | error = 0; | 1067 | error = 0; |
1080 | } else { | 1068 | } else { |
1081 | /* | 1069 | /* |
1082 | * Kick off a transaction to log the inode | 1070 | * Kick off a transaction to log the inode |
1083 | * core to get the updates. Make it | 1071 | * core to get the updates. Make it |
1084 | * sync if FSYNC_WAIT is passed in (which | 1072 | * sync if FSYNC_WAIT is passed in (which |
1085 | * is done by everybody but specfs). The | 1073 | * is done by everybody but specfs). The |
1086 | * sync transaction will also force the log. | 1074 | * sync transaction will also force the log. |
1087 | */ | 1075 | */ |
1088 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 1076 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
1089 | tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS); | 1077 | tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS); |
1090 | if ((error = xfs_trans_reserve(tp, 0, | 1078 | if ((error = xfs_trans_reserve(tp, 0, |
1091 | XFS_FSYNC_TS_LOG_RES(ip->i_mount), | 1079 | XFS_FSYNC_TS_LOG_RES(ip->i_mount), |
1092 | 0, 0, 0))) { | 1080 | 0, 0, 0))) { |
1093 | xfs_trans_cancel(tp, 0); | 1081 | xfs_trans_cancel(tp, 0); |
1094 | return error; | 1082 | return error; |
1095 | } | 1083 | } |
1096 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 1084 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
1097 | 1085 | ||
1098 | /* | 1086 | /* |
1099 | * Note - it's possible that we might have pushed | 1087 | * Note - it's possible that we might have pushed |
1100 | * ourselves out of the way during trans_reserve | 1088 | * ourselves out of the way during trans_reserve |
1101 | * which would flush the inode. But there's no | 1089 | * which would flush the inode. But there's no |
1102 | * guarantee that the inode buffer has actually | 1090 | * guarantee that the inode buffer has actually |
1103 | * gone out yet (it's delwri). Plus the buffer | 1091 | * gone out yet (it's delwri). Plus the buffer |
1104 | * could be pinned anyway if it's part of an | 1092 | * could be pinned anyway if it's part of an |
1105 | * inode in another recent transaction. So we | 1093 | * inode in another recent transaction. So we |
1106 | * play it safe and fire off the transaction anyway. | 1094 | * play it safe and fire off the transaction anyway. |
1107 | */ | 1095 | */ |
1108 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 1096 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
1109 | xfs_trans_ihold(tp, ip); | 1097 | xfs_trans_ihold(tp, ip); |
1110 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 1098 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
1111 | if (flag & FSYNC_WAIT) | 1099 | if (flag & FSYNC_WAIT) |
1112 | xfs_trans_set_sync(tp); | 1100 | xfs_trans_set_sync(tp); |
1113 | error = _xfs_trans_commit(tp, 0, &log_flushed); | 1101 | error = _xfs_trans_commit(tp, 0, &log_flushed); |
1114 | 1102 | ||
1115 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 1103 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
1116 | } | 1104 | } |
1117 | 1105 | ||
1118 | if ((ip->i_mount->m_flags & XFS_MOUNT_BARRIER) && changed) { | 1106 | if ((ip->i_mount->m_flags & XFS_MOUNT_BARRIER) && changed) { |
1119 | /* | 1107 | /* |
1120 | * If the log write didn't issue an ordered tag we need | 1108 | * If the log write didn't issue an ordered tag we need |
1121 | * to flush the disk cache for the data device now. | 1109 | * to flush the disk cache for the data device now. |
1122 | */ | 1110 | */ |
1123 | if (!log_flushed) | 1111 | if (!log_flushed) |
1124 | xfs_blkdev_issue_flush(ip->i_mount->m_ddev_targp); | 1112 | xfs_blkdev_issue_flush(ip->i_mount->m_ddev_targp); |
1125 | 1113 | ||
1126 | /* | 1114 | /* |
1127 | * If this inode is on the RT dev we need to flush that | 1115 | * If this inode is on the RT dev we need to flush that |
1128 | * cache as well. | 1116 | * cache as well. |
1129 | */ | 1117 | */ |
1130 | if (XFS_IS_REALTIME_INODE(ip)) | 1118 | if (XFS_IS_REALTIME_INODE(ip)) |
1131 | xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp); | 1119 | xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp); |
1132 | } | 1120 | } |
1133 | 1121 | ||
1134 | return error; | 1122 | return error; |
1135 | } | 1123 | } |
1136 | 1124 | ||
1137 | /* | 1125 | /* |
1138 | * This is called by xfs_inactive to free any blocks beyond eof | 1126 | * This is called by xfs_inactive to free any blocks beyond eof |
1139 | * when the link count isn't zero and by xfs_dm_punch_hole() when | 1127 | * when the link count isn't zero and by xfs_dm_punch_hole() when |
1140 | * punching a hole to EOF. | 1128 | * punching a hole to EOF. |
1141 | */ | 1129 | */ |
1142 | int | 1130 | int |
1143 | xfs_free_eofblocks( | 1131 | xfs_free_eofblocks( |
1144 | xfs_mount_t *mp, | 1132 | xfs_mount_t *mp, |
1145 | xfs_inode_t *ip, | 1133 | xfs_inode_t *ip, |
1146 | int flags) | 1134 | int flags) |
1147 | { | 1135 | { |
1148 | xfs_trans_t *tp; | 1136 | xfs_trans_t *tp; |
1149 | int error; | 1137 | int error; |
1150 | xfs_fileoff_t end_fsb; | 1138 | xfs_fileoff_t end_fsb; |
1151 | xfs_fileoff_t last_fsb; | 1139 | xfs_fileoff_t last_fsb; |
1152 | xfs_filblks_t map_len; | 1140 | xfs_filblks_t map_len; |
1153 | int nimaps; | 1141 | int nimaps; |
1154 | xfs_bmbt_irec_t imap; | 1142 | xfs_bmbt_irec_t imap; |
1155 | int use_iolock = (flags & XFS_FREE_EOF_LOCK); | 1143 | int use_iolock = (flags & XFS_FREE_EOF_LOCK); |
1156 | 1144 | ||
1157 | /* | 1145 | /* |
1158 | * Figure out if there are any blocks beyond the end | 1146 | * Figure out if there are any blocks beyond the end |
1159 | * of the file. If not, then there is nothing to do. | 1147 | * of the file. If not, then there is nothing to do. |
1160 | */ | 1148 | */ |
1161 | end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size)); | 1149 | end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size)); |
1162 | last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp)); | 1150 | last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp)); |
1163 | map_len = last_fsb - end_fsb; | 1151 | map_len = last_fsb - end_fsb; |
1164 | if (map_len <= 0) | 1152 | if (map_len <= 0) |
1165 | return 0; | 1153 | return 0; |
1166 | 1154 | ||
1167 | nimaps = 1; | 1155 | nimaps = 1; |
1168 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 1156 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
1169 | error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0, | 1157 | error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0, |
1170 | NULL, 0, &imap, &nimaps, NULL, NULL); | 1158 | NULL, 0, &imap, &nimaps, NULL, NULL); |
1171 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 1159 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
1172 | 1160 | ||
1173 | if (!error && (nimaps != 0) && | 1161 | if (!error && (nimaps != 0) && |
1174 | (imap.br_startblock != HOLESTARTBLOCK || | 1162 | (imap.br_startblock != HOLESTARTBLOCK || |
1175 | ip->i_delayed_blks)) { | 1163 | ip->i_delayed_blks)) { |
1176 | /* | 1164 | /* |
1177 | * Attach the dquots to the inode up front. | 1165 | * Attach the dquots to the inode up front. |
1178 | */ | 1166 | */ |
1179 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) | 1167 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) |
1180 | return error; | 1168 | return error; |
1181 | 1169 | ||
1182 | /* | 1170 | /* |
1183 | * There are blocks after the end of file. | 1171 | * There are blocks after the end of file. |
1184 | * Free them up now by truncating the file to | 1172 | * Free them up now by truncating the file to |
1185 | * its current size. | 1173 | * its current size. |
1186 | */ | 1174 | */ |
1187 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); | 1175 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); |
1188 | 1176 | ||
1189 | /* | 1177 | /* |
1190 | * Do the xfs_itruncate_start() call before | 1178 | * Do the xfs_itruncate_start() call before |
1191 | * reserving any log space because | 1179 | * reserving any log space because |
1192 | * itruncate_start will call into the buffer | 1180 | * itruncate_start will call into the buffer |
1193 | * cache and we can't | 1181 | * cache and we can't |
1194 | * do that within a transaction. | 1182 | * do that within a transaction. |
1195 | */ | 1183 | */ |
1196 | if (use_iolock) | 1184 | if (use_iolock) |
1197 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 1185 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
1198 | error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, | 1186 | error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, |
1199 | ip->i_size); | 1187 | ip->i_size); |
1200 | if (error) { | 1188 | if (error) { |
1201 | xfs_trans_cancel(tp, 0); | 1189 | xfs_trans_cancel(tp, 0); |
1202 | if (use_iolock) | 1190 | if (use_iolock) |
1203 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 1191 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
1204 | return error; | 1192 | return error; |
1205 | } | 1193 | } |
1206 | 1194 | ||
1207 | error = xfs_trans_reserve(tp, 0, | 1195 | error = xfs_trans_reserve(tp, 0, |
1208 | XFS_ITRUNCATE_LOG_RES(mp), | 1196 | XFS_ITRUNCATE_LOG_RES(mp), |
1209 | 0, XFS_TRANS_PERM_LOG_RES, | 1197 | 0, XFS_TRANS_PERM_LOG_RES, |
1210 | XFS_ITRUNCATE_LOG_COUNT); | 1198 | XFS_ITRUNCATE_LOG_COUNT); |
1211 | if (error) { | 1199 | if (error) { |
1212 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | 1200 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); |
1213 | xfs_trans_cancel(tp, 0); | 1201 | xfs_trans_cancel(tp, 0); |
1214 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 1202 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
1215 | return error; | 1203 | return error; |
1216 | } | 1204 | } |
1217 | 1205 | ||
1218 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 1206 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
1219 | xfs_trans_ijoin(tp, ip, | 1207 | xfs_trans_ijoin(tp, ip, |
1220 | XFS_IOLOCK_EXCL | | 1208 | XFS_IOLOCK_EXCL | |
1221 | XFS_ILOCK_EXCL); | 1209 | XFS_ILOCK_EXCL); |
1222 | xfs_trans_ihold(tp, ip); | 1210 | xfs_trans_ihold(tp, ip); |
1223 | 1211 | ||
1224 | error = xfs_itruncate_finish(&tp, ip, | 1212 | error = xfs_itruncate_finish(&tp, ip, |
1225 | ip->i_size, | 1213 | ip->i_size, |
1226 | XFS_DATA_FORK, | 1214 | XFS_DATA_FORK, |
1227 | 0); | 1215 | 0); |
1228 | /* | 1216 | /* |
1229 | * If we get an error at this point we | 1217 | * If we get an error at this point we |
1230 | * simply don't bother truncating the file. | 1218 | * simply don't bother truncating the file. |
1231 | */ | 1219 | */ |
1232 | if (error) { | 1220 | if (error) { |
1233 | xfs_trans_cancel(tp, | 1221 | xfs_trans_cancel(tp, |
1234 | (XFS_TRANS_RELEASE_LOG_RES | | 1222 | (XFS_TRANS_RELEASE_LOG_RES | |
1235 | XFS_TRANS_ABORT)); | 1223 | XFS_TRANS_ABORT)); |
1236 | } else { | 1224 | } else { |
1237 | error = xfs_trans_commit(tp, | 1225 | error = xfs_trans_commit(tp, |
1238 | XFS_TRANS_RELEASE_LOG_RES); | 1226 | XFS_TRANS_RELEASE_LOG_RES); |
1239 | } | 1227 | } |
1240 | xfs_iunlock(ip, (use_iolock ? (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL) | 1228 | xfs_iunlock(ip, (use_iolock ? (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL) |
1241 | : XFS_ILOCK_EXCL)); | 1229 | : XFS_ILOCK_EXCL)); |
1242 | } | 1230 | } |
1243 | return error; | 1231 | return error; |
1244 | } | 1232 | } |
1245 | 1233 | ||
1246 | /* | 1234 | /* |
1247 | * Free a symlink that has blocks associated with it. | 1235 | * Free a symlink that has blocks associated with it. |
1248 | */ | 1236 | */ |
1249 | STATIC int | 1237 | STATIC int |
1250 | xfs_inactive_symlink_rmt( | 1238 | xfs_inactive_symlink_rmt( |
1251 | xfs_inode_t *ip, | 1239 | xfs_inode_t *ip, |
1252 | xfs_trans_t **tpp) | 1240 | xfs_trans_t **tpp) |
1253 | { | 1241 | { |
1254 | xfs_buf_t *bp; | 1242 | xfs_buf_t *bp; |
1255 | int committed; | 1243 | int committed; |
1256 | int done; | 1244 | int done; |
1257 | int error; | 1245 | int error; |
1258 | xfs_fsblock_t first_block; | 1246 | xfs_fsblock_t first_block; |
1259 | xfs_bmap_free_t free_list; | 1247 | xfs_bmap_free_t free_list; |
1260 | int i; | 1248 | int i; |
1261 | xfs_mount_t *mp; | 1249 | xfs_mount_t *mp; |
1262 | xfs_bmbt_irec_t mval[SYMLINK_MAPS]; | 1250 | xfs_bmbt_irec_t mval[SYMLINK_MAPS]; |
1263 | int nmaps; | 1251 | int nmaps; |
1264 | xfs_trans_t *ntp; | 1252 | xfs_trans_t *ntp; |
1265 | int size; | 1253 | int size; |
1266 | xfs_trans_t *tp; | 1254 | xfs_trans_t *tp; |
1267 | 1255 | ||
1268 | tp = *tpp; | 1256 | tp = *tpp; |
1269 | mp = ip->i_mount; | 1257 | mp = ip->i_mount; |
1270 | ASSERT(ip->i_d.di_size > XFS_IFORK_DSIZE(ip)); | 1258 | ASSERT(ip->i_d.di_size > XFS_IFORK_DSIZE(ip)); |
1271 | /* | 1259 | /* |
1272 | * We're freeing a symlink that has some | 1260 | * We're freeing a symlink that has some |
1273 | * blocks allocated to it. Free the | 1261 | * blocks allocated to it. Free the |
1274 | * blocks here. We know that we've got | 1262 | * blocks here. We know that we've got |
1275 | * either 1 or 2 extents and that we can | 1263 | * either 1 or 2 extents and that we can |
1276 | * free them all in one bunmapi call. | 1264 | * free them all in one bunmapi call. |
1277 | */ | 1265 | */ |
1278 | ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2); | 1266 | ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2); |
1279 | if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, | 1267 | if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, |
1280 | XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { | 1268 | XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { |
1281 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | 1269 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); |
1282 | xfs_trans_cancel(tp, 0); | 1270 | xfs_trans_cancel(tp, 0); |
1283 | *tpp = NULL; | 1271 | *tpp = NULL; |
1284 | return error; | 1272 | return error; |
1285 | } | 1273 | } |
1286 | /* | 1274 | /* |
1287 | * Lock the inode, fix the size, and join it to the transaction. | 1275 | * Lock the inode, fix the size, and join it to the transaction. |
1288 | * Hold it so in the normal path, we still have it locked for | 1276 | * Hold it so in the normal path, we still have it locked for |
1289 | * the second transaction. In the error paths we need it | 1277 | * the second transaction. In the error paths we need it |
1290 | * held so the cancel won't rele it, see below. | 1278 | * held so the cancel won't rele it, see below. |
1291 | */ | 1279 | */ |
1292 | xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 1280 | xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
1293 | size = (int)ip->i_d.di_size; | 1281 | size = (int)ip->i_d.di_size; |
1294 | ip->i_d.di_size = 0; | 1282 | ip->i_d.di_size = 0; |
1295 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | 1283 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); |
1296 | xfs_trans_ihold(tp, ip); | 1284 | xfs_trans_ihold(tp, ip); |
1297 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 1285 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
1298 | /* | 1286 | /* |
1299 | * Find the block(s) so we can inval and unmap them. | 1287 | * Find the block(s) so we can inval and unmap them. |
1300 | */ | 1288 | */ |
1301 | done = 0; | 1289 | done = 0; |
1302 | XFS_BMAP_INIT(&free_list, &first_block); | 1290 | XFS_BMAP_INIT(&free_list, &first_block); |
1303 | nmaps = ARRAY_SIZE(mval); | 1291 | nmaps = ARRAY_SIZE(mval); |
1304 | if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size), | 1292 | if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size), |
1305 | XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps, | 1293 | XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps, |
1306 | &free_list, NULL))) | 1294 | &free_list, NULL))) |
1307 | goto error0; | 1295 | goto error0; |
1308 | /* | 1296 | /* |
1309 | * Invalidate the block(s). | 1297 | * Invalidate the block(s). |
1310 | */ | 1298 | */ |
1311 | for (i = 0; i < nmaps; i++) { | 1299 | for (i = 0; i < nmaps; i++) { |
1312 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, | 1300 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, |
1313 | XFS_FSB_TO_DADDR(mp, mval[i].br_startblock), | 1301 | XFS_FSB_TO_DADDR(mp, mval[i].br_startblock), |
1314 | XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0); | 1302 | XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0); |
1315 | xfs_trans_binval(tp, bp); | 1303 | xfs_trans_binval(tp, bp); |
1316 | } | 1304 | } |
1317 | /* | 1305 | /* |
1318 | * Unmap the dead block(s) to the free_list. | 1306 | * Unmap the dead block(s) to the free_list. |
1319 | */ | 1307 | */ |
1320 | if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps, | 1308 | if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps, |
1321 | &first_block, &free_list, NULL, &done))) | 1309 | &first_block, &free_list, NULL, &done))) |
1322 | goto error1; | 1310 | goto error1; |
1323 | ASSERT(done); | 1311 | ASSERT(done); |
1324 | /* | 1312 | /* |
1325 | * Commit the first transaction. This logs the EFI and the inode. | 1313 | * Commit the first transaction. This logs the EFI and the inode. |
1326 | */ | 1314 | */ |
1327 | if ((error = xfs_bmap_finish(&tp, &free_list, &committed))) | 1315 | if ((error = xfs_bmap_finish(&tp, &free_list, &committed))) |
1328 | goto error1; | 1316 | goto error1; |
1329 | /* | 1317 | /* |
1330 | * The transaction must have been committed, since there were | 1318 | * The transaction must have been committed, since there were |
1331 | * actually extents freed by xfs_bunmapi. See xfs_bmap_finish. | 1319 | * actually extents freed by xfs_bunmapi. See xfs_bmap_finish. |
1332 | * The new tp has the extent freeing and EFDs. | 1320 | * The new tp has the extent freeing and EFDs. |
1333 | */ | 1321 | */ |
1334 | ASSERT(committed); | 1322 | ASSERT(committed); |
1335 | /* | 1323 | /* |
1336 | * The first xact was committed, so add the inode to the new one. | 1324 | * The first xact was committed, so add the inode to the new one. |
1337 | * Mark it dirty so it will be logged and moved forward in the log as | 1325 | * Mark it dirty so it will be logged and moved forward in the log as |
1338 | * part of every commit. | 1326 | * part of every commit. |
1339 | */ | 1327 | */ |
1340 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | 1328 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); |
1341 | xfs_trans_ihold(tp, ip); | 1329 | xfs_trans_ihold(tp, ip); |
1342 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 1330 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
1343 | /* | 1331 | /* |
1344 | * Get a new, empty transaction to return to our caller. | 1332 | * Get a new, empty transaction to return to our caller. |
1345 | */ | 1333 | */ |
1346 | ntp = xfs_trans_dup(tp); | 1334 | ntp = xfs_trans_dup(tp); |
1347 | /* | 1335 | /* |
1348 | * Commit the transaction containing extent freeing and EFDs. | 1336 | * Commit the transaction containing extent freeing and EFDs. |
1349 | * If we get an error on the commit here or on the reserve below, | 1337 | * If we get an error on the commit here or on the reserve below, |
1350 | * we need to unlock the inode since the new transaction doesn't | 1338 | * we need to unlock the inode since the new transaction doesn't |
1351 | * have the inode attached. | 1339 | * have the inode attached. |
1352 | */ | 1340 | */ |
1353 | error = xfs_trans_commit(tp, 0); | 1341 | error = xfs_trans_commit(tp, 0); |
1354 | tp = ntp; | 1342 | tp = ntp; |
1355 | if (error) { | 1343 | if (error) { |
1356 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | 1344 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); |
1357 | goto error0; | 1345 | goto error0; |
1358 | } | 1346 | } |
1359 | /* | 1347 | /* |
1360 | * Remove the memory for extent descriptions (just bookkeeping). | 1348 | * Remove the memory for extent descriptions (just bookkeeping). |
1361 | */ | 1349 | */ |
1362 | if (ip->i_df.if_bytes) | 1350 | if (ip->i_df.if_bytes) |
1363 | xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK); | 1351 | xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK); |
1364 | ASSERT(ip->i_df.if_bytes == 0); | 1352 | ASSERT(ip->i_df.if_bytes == 0); |
1365 | /* | 1353 | /* |
1366 | * Put an itruncate log reservation in the new transaction | 1354 | * Put an itruncate log reservation in the new transaction |
1367 | * for our caller. | 1355 | * for our caller. |
1368 | */ | 1356 | */ |
1369 | if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, | 1357 | if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, |
1370 | XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { | 1358 | XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { |
1371 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | 1359 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); |
1372 | goto error0; | 1360 | goto error0; |
1373 | } | 1361 | } |
1374 | /* | 1362 | /* |
1375 | * Return with the inode locked but not joined to the transaction. | 1363 | * Return with the inode locked but not joined to the transaction. |
1376 | */ | 1364 | */ |
1377 | *tpp = tp; | 1365 | *tpp = tp; |
1378 | return 0; | 1366 | return 0; |
1379 | 1367 | ||
1380 | error1: | 1368 | error1: |
1381 | xfs_bmap_cancel(&free_list); | 1369 | xfs_bmap_cancel(&free_list); |
1382 | error0: | 1370 | error0: |
1383 | /* | 1371 | /* |
1384 | * Have to come here with the inode locked and either | 1372 | * Have to come here with the inode locked and either |
1385 | * (held and in the transaction) or (not in the transaction). | 1373 | * (held and in the transaction) or (not in the transaction). |
1386 | * If the inode isn't held then cancel would iput it, but | 1374 | * If the inode isn't held then cancel would iput it, but |
1387 | * that's wrong since this is inactive and the vnode ref | 1375 | * that's wrong since this is inactive and the vnode ref |
1388 | * count is 0 already. | 1376 | * count is 0 already. |
1389 | * Cancel won't do anything to the inode if held, but it still | 1377 | * Cancel won't do anything to the inode if held, but it still |
1390 | * needs to be locked until the cancel is done, if it was | 1378 | * needs to be locked until the cancel is done, if it was |
1391 | * joined to the transaction. | 1379 | * joined to the transaction. |
1392 | */ | 1380 | */ |
1393 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | 1381 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); |
1394 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 1382 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
1395 | *tpp = NULL; | 1383 | *tpp = NULL; |
1396 | return error; | 1384 | return error; |
1397 | 1385 | ||
1398 | } | 1386 | } |
1399 | 1387 | ||
1400 | STATIC int | 1388 | STATIC int |
1401 | xfs_inactive_symlink_local( | 1389 | xfs_inactive_symlink_local( |
1402 | xfs_inode_t *ip, | 1390 | xfs_inode_t *ip, |
1403 | xfs_trans_t **tpp) | 1391 | xfs_trans_t **tpp) |
1404 | { | 1392 | { |
1405 | int error; | 1393 | int error; |
1406 | 1394 | ||
1407 | ASSERT(ip->i_d.di_size <= XFS_IFORK_DSIZE(ip)); | 1395 | ASSERT(ip->i_d.di_size <= XFS_IFORK_DSIZE(ip)); |
1408 | /* | 1396 | /* |
1409 | * We're freeing a symlink which fit into | 1397 | * We're freeing a symlink which fit into |
1410 | * the inode. Just free the memory used | 1398 | * the inode. Just free the memory used |
1411 | * to hold the old symlink. | 1399 | * to hold the old symlink. |
1412 | */ | 1400 | */ |
1413 | error = xfs_trans_reserve(*tpp, 0, | 1401 | error = xfs_trans_reserve(*tpp, 0, |
1414 | XFS_ITRUNCATE_LOG_RES(ip->i_mount), | 1402 | XFS_ITRUNCATE_LOG_RES(ip->i_mount), |
1415 | 0, XFS_TRANS_PERM_LOG_RES, | 1403 | 0, XFS_TRANS_PERM_LOG_RES, |
1416 | XFS_ITRUNCATE_LOG_COUNT); | 1404 | XFS_ITRUNCATE_LOG_COUNT); |
1417 | 1405 | ||
1418 | if (error) { | 1406 | if (error) { |
1419 | xfs_trans_cancel(*tpp, 0); | 1407 | xfs_trans_cancel(*tpp, 0); |
1420 | *tpp = NULL; | 1408 | *tpp = NULL; |
1421 | return error; | 1409 | return error; |
1422 | } | 1410 | } |
1423 | xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | 1411 | xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); |
1424 | 1412 | ||
1425 | /* | 1413 | /* |
1426 | * Zero length symlinks _can_ exist. | 1414 | * Zero length symlinks _can_ exist. |
1427 | */ | 1415 | */ |
1428 | if (ip->i_df.if_bytes > 0) { | 1416 | if (ip->i_df.if_bytes > 0) { |
1429 | xfs_idata_realloc(ip, | 1417 | xfs_idata_realloc(ip, |
1430 | -(ip->i_df.if_bytes), | 1418 | -(ip->i_df.if_bytes), |
1431 | XFS_DATA_FORK); | 1419 | XFS_DATA_FORK); |
1432 | ASSERT(ip->i_df.if_bytes == 0); | 1420 | ASSERT(ip->i_df.if_bytes == 0); |
1433 | } | 1421 | } |
1434 | return 0; | 1422 | return 0; |
1435 | } | 1423 | } |
1436 | 1424 | ||
1437 | STATIC int | 1425 | STATIC int |
1438 | xfs_inactive_attrs( | 1426 | xfs_inactive_attrs( |
1439 | xfs_inode_t *ip, | 1427 | xfs_inode_t *ip, |
1440 | xfs_trans_t **tpp) | 1428 | xfs_trans_t **tpp) |
1441 | { | 1429 | { |
1442 | xfs_trans_t *tp; | 1430 | xfs_trans_t *tp; |
1443 | int error; | 1431 | int error; |
1444 | xfs_mount_t *mp; | 1432 | xfs_mount_t *mp; |
1445 | 1433 | ||
1446 | ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); | 1434 | ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); |
1447 | tp = *tpp; | 1435 | tp = *tpp; |
1448 | mp = ip->i_mount; | 1436 | mp = ip->i_mount; |
1449 | ASSERT(ip->i_d.di_forkoff != 0); | 1437 | ASSERT(ip->i_d.di_forkoff != 0); |
1450 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 1438 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
1451 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 1439 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
1452 | if (error) | 1440 | if (error) |
1453 | goto error_unlock; | 1441 | goto error_unlock; |
1454 | 1442 | ||
1455 | error = xfs_attr_inactive(ip); | 1443 | error = xfs_attr_inactive(ip); |
1456 | if (error) | 1444 | if (error) |
1457 | goto error_unlock; | 1445 | goto error_unlock; |
1458 | 1446 | ||
1459 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); | 1447 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); |
1460 | error = xfs_trans_reserve(tp, 0, | 1448 | error = xfs_trans_reserve(tp, 0, |
1461 | XFS_IFREE_LOG_RES(mp), | 1449 | XFS_IFREE_LOG_RES(mp), |
1462 | 0, XFS_TRANS_PERM_LOG_RES, | 1450 | 0, XFS_TRANS_PERM_LOG_RES, |
1463 | XFS_INACTIVE_LOG_COUNT); | 1451 | XFS_INACTIVE_LOG_COUNT); |
1464 | if (error) | 1452 | if (error) |
1465 | goto error_cancel; | 1453 | goto error_cancel; |
1466 | 1454 | ||
1467 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 1455 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
1468 | xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 1456 | xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
1469 | xfs_trans_ihold(tp, ip); | 1457 | xfs_trans_ihold(tp, ip); |
1470 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); | 1458 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); |
1471 | 1459 | ||
1472 | ASSERT(ip->i_d.di_anextents == 0); | 1460 | ASSERT(ip->i_d.di_anextents == 0); |
1473 | 1461 | ||
1474 | *tpp = tp; | 1462 | *tpp = tp; |
1475 | return 0; | 1463 | return 0; |
1476 | 1464 | ||
1477 | error_cancel: | 1465 | error_cancel: |
1478 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | 1466 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); |
1479 | xfs_trans_cancel(tp, 0); | 1467 | xfs_trans_cancel(tp, 0); |
1480 | error_unlock: | 1468 | error_unlock: |
1481 | *tpp = NULL; | 1469 | *tpp = NULL; |
1482 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 1470 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
1483 | return error; | 1471 | return error; |
1484 | } | 1472 | } |
1485 | 1473 | ||
1486 | int | 1474 | int |
1487 | xfs_release( | 1475 | xfs_release( |
1488 | xfs_inode_t *ip) | 1476 | xfs_inode_t *ip) |
1489 | { | 1477 | { |
1490 | bhv_vnode_t *vp = XFS_ITOV(ip); | 1478 | bhv_vnode_t *vp = XFS_ITOV(ip); |
1491 | xfs_mount_t *mp = ip->i_mount; | 1479 | xfs_mount_t *mp = ip->i_mount; |
1492 | int error; | 1480 | int error; |
1493 | 1481 | ||
1494 | if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0)) | 1482 | if (!S_ISREG(ip->i_d.di_mode) || (ip->i_d.di_mode == 0)) |
1495 | return 0; | 1483 | return 0; |
1496 | 1484 | ||
1497 | /* If this is a read-only mount, don't do this (would generate I/O) */ | 1485 | /* If this is a read-only mount, don't do this (would generate I/O) */ |
1498 | if (mp->m_flags & XFS_MOUNT_RDONLY) | 1486 | if (mp->m_flags & XFS_MOUNT_RDONLY) |
1499 | return 0; | 1487 | return 0; |
1500 | 1488 | ||
1501 | if (!XFS_FORCED_SHUTDOWN(mp)) { | 1489 | if (!XFS_FORCED_SHUTDOWN(mp)) { |
1502 | int truncated; | 1490 | int truncated; |
1503 | 1491 | ||
1504 | /* | 1492 | /* |
1505 | * If we are using filestreams, and we have an unlinked | 1493 | * If we are using filestreams, and we have an unlinked |
1506 | * file that we are processing the last close on, then nothing | 1494 | * file that we are processing the last close on, then nothing |
1507 | * will be able to reopen and write to this file. Purge this | 1495 | * will be able to reopen and write to this file. Purge this |
1508 | * inode from the filestreams cache so that it doesn't delay | 1496 | * inode from the filestreams cache so that it doesn't delay |
1509 | * teardown of the inode. | 1497 | * teardown of the inode. |
1510 | */ | 1498 | */ |
1511 | if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip)) | 1499 | if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip)) |
1512 | xfs_filestream_deassociate(ip); | 1500 | xfs_filestream_deassociate(ip); |
1513 | 1501 | ||
1514 | /* | 1502 | /* |
1515 | * If we previously truncated this file and removed old data | 1503 | * If we previously truncated this file and removed old data |
1516 | * in the process, we want to initiate "early" writeout on | 1504 | * in the process, we want to initiate "early" writeout on |
1517 | * the last close. This is an attempt to combat the notorious | 1505 | * the last close. This is an attempt to combat the notorious |
1518 | * NULL files problem which is particularly noticable from a | 1506 | * NULL files problem which is particularly noticable from a |
1519 | * truncate down, buffered (re-)write (delalloc), followed by | 1507 | * truncate down, buffered (re-)write (delalloc), followed by |
1520 | * a crash. What we are effectively doing here is | 1508 | * a crash. What we are effectively doing here is |
1521 | * significantly reducing the time window where we'd otherwise | 1509 | * significantly reducing the time window where we'd otherwise |
1522 | * be exposed to that problem. | 1510 | * be exposed to that problem. |
1523 | */ | 1511 | */ |
1524 | truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); | 1512 | truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); |
1525 | if (truncated && VN_DIRTY(vp) && ip->i_delayed_blks > 0) | 1513 | if (truncated && VN_DIRTY(vp) && ip->i_delayed_blks > 0) |
1526 | xfs_flush_pages(ip, 0, -1, XFS_B_ASYNC, FI_NONE); | 1514 | xfs_flush_pages(ip, 0, -1, XFS_B_ASYNC, FI_NONE); |
1527 | } | 1515 | } |
1528 | 1516 | ||
1529 | if (ip->i_d.di_nlink != 0) { | 1517 | if (ip->i_d.di_nlink != 0) { |
1530 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && | 1518 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && |
1531 | ((ip->i_size > 0) || (VN_CACHED(vp) > 0 || | 1519 | ((ip->i_size > 0) || (VN_CACHED(vp) > 0 || |
1532 | ip->i_delayed_blks > 0)) && | 1520 | ip->i_delayed_blks > 0)) && |
1533 | (ip->i_df.if_flags & XFS_IFEXTENTS)) && | 1521 | (ip->i_df.if_flags & XFS_IFEXTENTS)) && |
1534 | (!(ip->i_d.di_flags & | 1522 | (!(ip->i_d.di_flags & |
1535 | (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) { | 1523 | (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) { |
1536 | error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK); | 1524 | error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK); |
1537 | if (error) | 1525 | if (error) |
1538 | return error; | 1526 | return error; |
1539 | } | 1527 | } |
1540 | } | 1528 | } |
1541 | 1529 | ||
1542 | return 0; | 1530 | return 0; |
1543 | } | 1531 | } |
1544 | 1532 | ||
1545 | /* | 1533 | /* |
1546 | * xfs_inactive | 1534 | * xfs_inactive |
1547 | * | 1535 | * |
1548 | * This is called when the vnode reference count for the vnode | 1536 | * This is called when the vnode reference count for the vnode |
1549 | * goes to zero. If the file has been unlinked, then it must | 1537 | * goes to zero. If the file has been unlinked, then it must |
1550 | * now be truncated. Also, we clear all of the read-ahead state | 1538 | * now be truncated. Also, we clear all of the read-ahead state |
1551 | * kept for the inode here since the file is now closed. | 1539 | * kept for the inode here since the file is now closed. |
1552 | */ | 1540 | */ |
1553 | int | 1541 | int |
1554 | xfs_inactive( | 1542 | xfs_inactive( |
1555 | xfs_inode_t *ip) | 1543 | xfs_inode_t *ip) |
1556 | { | 1544 | { |
1557 | bhv_vnode_t *vp = XFS_ITOV(ip); | 1545 | bhv_vnode_t *vp = XFS_ITOV(ip); |
1558 | xfs_bmap_free_t free_list; | 1546 | xfs_bmap_free_t free_list; |
1559 | xfs_fsblock_t first_block; | 1547 | xfs_fsblock_t first_block; |
1560 | int committed; | 1548 | int committed; |
1561 | xfs_trans_t *tp; | 1549 | xfs_trans_t *tp; |
1562 | xfs_mount_t *mp; | 1550 | xfs_mount_t *mp; |
1563 | int error; | 1551 | int error; |
1564 | int truncate; | 1552 | int truncate; |
1565 | 1553 | ||
1566 | xfs_itrace_entry(ip); | 1554 | xfs_itrace_entry(ip); |
1567 | 1555 | ||
1568 | /* | 1556 | /* |
1569 | * If the inode is already free, then there can be nothing | 1557 | * If the inode is already free, then there can be nothing |
1570 | * to clean up here. | 1558 | * to clean up here. |
1571 | */ | 1559 | */ |
1572 | if (ip->i_d.di_mode == 0 || VN_BAD(vp)) { | 1560 | if (ip->i_d.di_mode == 0 || VN_BAD(vp)) { |
1573 | ASSERT(ip->i_df.if_real_bytes == 0); | 1561 | ASSERT(ip->i_df.if_real_bytes == 0); |
1574 | ASSERT(ip->i_df.if_broot_bytes == 0); | 1562 | ASSERT(ip->i_df.if_broot_bytes == 0); |
1575 | return VN_INACTIVE_CACHE; | 1563 | return VN_INACTIVE_CACHE; |
1576 | } | 1564 | } |
1577 | 1565 | ||
1578 | /* | 1566 | /* |
1579 | * Only do a truncate if it's a regular file with | 1567 | * Only do a truncate if it's a regular file with |
1580 | * some actual space in it. It's OK to look at the | 1568 | * some actual space in it. It's OK to look at the |
1581 | * inode's fields without the lock because we're the | 1569 | * inode's fields without the lock because we're the |
1582 | * only one with a reference to the inode. | 1570 | * only one with a reference to the inode. |
1583 | */ | 1571 | */ |
1584 | truncate = ((ip->i_d.di_nlink == 0) && | 1572 | truncate = ((ip->i_d.di_nlink == 0) && |
1585 | ((ip->i_d.di_size != 0) || (ip->i_size != 0) || | 1573 | ((ip->i_d.di_size != 0) || (ip->i_size != 0) || |
1586 | (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) && | 1574 | (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) && |
1587 | ((ip->i_d.di_mode & S_IFMT) == S_IFREG)); | 1575 | ((ip->i_d.di_mode & S_IFMT) == S_IFREG)); |
1588 | 1576 | ||
1589 | mp = ip->i_mount; | 1577 | mp = ip->i_mount; |
1590 | 1578 | ||
1591 | if (ip->i_d.di_nlink == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_DESTROY)) | 1579 | if (ip->i_d.di_nlink == 0 && DM_EVENT_ENABLED(ip, DM_EVENT_DESTROY)) |
1592 | XFS_SEND_DESTROY(mp, ip, DM_RIGHT_NULL); | 1580 | XFS_SEND_DESTROY(mp, ip, DM_RIGHT_NULL); |
1593 | 1581 | ||
1594 | error = 0; | 1582 | error = 0; |
1595 | 1583 | ||
1596 | /* If this is a read-only mount, don't do this (would generate I/O) */ | 1584 | /* If this is a read-only mount, don't do this (would generate I/O) */ |
1597 | if (mp->m_flags & XFS_MOUNT_RDONLY) | 1585 | if (mp->m_flags & XFS_MOUNT_RDONLY) |
1598 | goto out; | 1586 | goto out; |
1599 | 1587 | ||
1600 | if (ip->i_d.di_nlink != 0) { | 1588 | if (ip->i_d.di_nlink != 0) { |
1601 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && | 1589 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && |
1602 | ((ip->i_size > 0) || (VN_CACHED(vp) > 0 || | 1590 | ((ip->i_size > 0) || (VN_CACHED(vp) > 0 || |
1603 | ip->i_delayed_blks > 0)) && | 1591 | ip->i_delayed_blks > 0)) && |
1604 | (ip->i_df.if_flags & XFS_IFEXTENTS) && | 1592 | (ip->i_df.if_flags & XFS_IFEXTENTS) && |
1605 | (!(ip->i_d.di_flags & | 1593 | (!(ip->i_d.di_flags & |
1606 | (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) || | 1594 | (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) || |
1607 | (ip->i_delayed_blks != 0)))) { | 1595 | (ip->i_delayed_blks != 0)))) { |
1608 | error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK); | 1596 | error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK); |
1609 | if (error) | 1597 | if (error) |
1610 | return VN_INACTIVE_CACHE; | 1598 | return VN_INACTIVE_CACHE; |
1611 | } | 1599 | } |
1612 | goto out; | 1600 | goto out; |
1613 | } | 1601 | } |
1614 | 1602 | ||
1615 | ASSERT(ip->i_d.di_nlink == 0); | 1603 | ASSERT(ip->i_d.di_nlink == 0); |
1616 | 1604 | ||
1617 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) | 1605 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) |
1618 | return VN_INACTIVE_CACHE; | 1606 | return VN_INACTIVE_CACHE; |
1619 | 1607 | ||
1620 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); | 1608 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); |
1621 | if (truncate) { | 1609 | if (truncate) { |
1622 | /* | 1610 | /* |
1623 | * Do the xfs_itruncate_start() call before | 1611 | * Do the xfs_itruncate_start() call before |
1624 | * reserving any log space because itruncate_start | 1612 | * reserving any log space because itruncate_start |
1625 | * will call into the buffer cache and we can't | 1613 | * will call into the buffer cache and we can't |
1626 | * do that within a transaction. | 1614 | * do that within a transaction. |
1627 | */ | 1615 | */ |
1628 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 1616 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
1629 | 1617 | ||
1630 | error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0); | 1618 | error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0); |
1631 | if (error) { | 1619 | if (error) { |
1632 | xfs_trans_cancel(tp, 0); | 1620 | xfs_trans_cancel(tp, 0); |
1633 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 1621 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
1634 | return VN_INACTIVE_CACHE; | 1622 | return VN_INACTIVE_CACHE; |
1635 | } | 1623 | } |
1636 | 1624 | ||
1637 | error = xfs_trans_reserve(tp, 0, | 1625 | error = xfs_trans_reserve(tp, 0, |
1638 | XFS_ITRUNCATE_LOG_RES(mp), | 1626 | XFS_ITRUNCATE_LOG_RES(mp), |
1639 | 0, XFS_TRANS_PERM_LOG_RES, | 1627 | 0, XFS_TRANS_PERM_LOG_RES, |
1640 | XFS_ITRUNCATE_LOG_COUNT); | 1628 | XFS_ITRUNCATE_LOG_COUNT); |
1641 | if (error) { | 1629 | if (error) { |
1642 | /* Don't call itruncate_cleanup */ | 1630 | /* Don't call itruncate_cleanup */ |
1643 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | 1631 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); |
1644 | xfs_trans_cancel(tp, 0); | 1632 | xfs_trans_cancel(tp, 0); |
1645 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 1633 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
1646 | return VN_INACTIVE_CACHE; | 1634 | return VN_INACTIVE_CACHE; |
1647 | } | 1635 | } |
1648 | 1636 | ||
1649 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 1637 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
1650 | xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 1638 | xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
1651 | xfs_trans_ihold(tp, ip); | 1639 | xfs_trans_ihold(tp, ip); |
1652 | 1640 | ||
1653 | /* | 1641 | /* |
1654 | * normally, we have to run xfs_itruncate_finish sync. | 1642 | * normally, we have to run xfs_itruncate_finish sync. |
1655 | * But if filesystem is wsync and we're in the inactive | 1643 | * But if filesystem is wsync and we're in the inactive |
1656 | * path, then we know that nlink == 0, and that the | 1644 | * path, then we know that nlink == 0, and that the |
1657 | * xaction that made nlink == 0 is permanently committed | 1645 | * xaction that made nlink == 0 is permanently committed |
1658 | * since xfs_remove runs as a synchronous transaction. | 1646 | * since xfs_remove runs as a synchronous transaction. |
1659 | */ | 1647 | */ |
1660 | error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK, | 1648 | error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK, |
1661 | (!(mp->m_flags & XFS_MOUNT_WSYNC) ? 1 : 0)); | 1649 | (!(mp->m_flags & XFS_MOUNT_WSYNC) ? 1 : 0)); |
1662 | 1650 | ||
1663 | if (error) { | 1651 | if (error) { |
1664 | xfs_trans_cancel(tp, | 1652 | xfs_trans_cancel(tp, |
1665 | XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | 1653 | XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); |
1666 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 1654 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
1667 | return VN_INACTIVE_CACHE; | 1655 | return VN_INACTIVE_CACHE; |
1668 | } | 1656 | } |
1669 | } else if ((ip->i_d.di_mode & S_IFMT) == S_IFLNK) { | 1657 | } else if ((ip->i_d.di_mode & S_IFMT) == S_IFLNK) { |
1670 | 1658 | ||
1671 | /* | 1659 | /* |
1672 | * If we get an error while cleaning up a | 1660 | * If we get an error while cleaning up a |
1673 | * symlink we bail out. | 1661 | * symlink we bail out. |
1674 | */ | 1662 | */ |
1675 | error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ? | 1663 | error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ? |
1676 | xfs_inactive_symlink_rmt(ip, &tp) : | 1664 | xfs_inactive_symlink_rmt(ip, &tp) : |
1677 | xfs_inactive_symlink_local(ip, &tp); | 1665 | xfs_inactive_symlink_local(ip, &tp); |
1678 | 1666 | ||
1679 | if (error) { | 1667 | if (error) { |
1680 | ASSERT(tp == NULL); | 1668 | ASSERT(tp == NULL); |
1681 | return VN_INACTIVE_CACHE; | 1669 | return VN_INACTIVE_CACHE; |
1682 | } | 1670 | } |
1683 | 1671 | ||
1684 | xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 1672 | xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
1685 | xfs_trans_ihold(tp, ip); | 1673 | xfs_trans_ihold(tp, ip); |
1686 | } else { | 1674 | } else { |
1687 | error = xfs_trans_reserve(tp, 0, | 1675 | error = xfs_trans_reserve(tp, 0, |
1688 | XFS_IFREE_LOG_RES(mp), | 1676 | XFS_IFREE_LOG_RES(mp), |
1689 | 0, XFS_TRANS_PERM_LOG_RES, | 1677 | 0, XFS_TRANS_PERM_LOG_RES, |
1690 | XFS_INACTIVE_LOG_COUNT); | 1678 | XFS_INACTIVE_LOG_COUNT); |
1691 | if (error) { | 1679 | if (error) { |
1692 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); | 1680 | ASSERT(XFS_FORCED_SHUTDOWN(mp)); |
1693 | xfs_trans_cancel(tp, 0); | 1681 | xfs_trans_cancel(tp, 0); |
1694 | return VN_INACTIVE_CACHE; | 1682 | return VN_INACTIVE_CACHE; |
1695 | } | 1683 | } |
1696 | 1684 | ||
1697 | xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | 1685 | xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); |
1698 | xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 1686 | xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
1699 | xfs_trans_ihold(tp, ip); | 1687 | xfs_trans_ihold(tp, ip); |
1700 | } | 1688 | } |
1701 | 1689 | ||
1702 | /* | 1690 | /* |
1703 | * If there are attributes associated with the file | 1691 | * If there are attributes associated with the file |
1704 | * then blow them away now. The code calls a routine | 1692 | * then blow them away now. The code calls a routine |
1705 | * that recursively deconstructs the attribute fork. | 1693 | * that recursively deconstructs the attribute fork. |
1706 | * We need to just commit the current transaction | 1694 | * We need to just commit the current transaction |
1707 | * because we can't use it for xfs_attr_inactive(). | 1695 | * because we can't use it for xfs_attr_inactive(). |
1708 | */ | 1696 | */ |
1709 | if (ip->i_d.di_anextents > 0) { | 1697 | if (ip->i_d.di_anextents > 0) { |
1710 | error = xfs_inactive_attrs(ip, &tp); | 1698 | error = xfs_inactive_attrs(ip, &tp); |
1711 | /* | 1699 | /* |
1712 | * If we got an error, the transaction is already | 1700 | * If we got an error, the transaction is already |
1713 | * cancelled, and the inode is unlocked. Just get out. | 1701 | * cancelled, and the inode is unlocked. Just get out. |
1714 | */ | 1702 | */ |
1715 | if (error) | 1703 | if (error) |
1716 | return VN_INACTIVE_CACHE; | 1704 | return VN_INACTIVE_CACHE; |
1717 | } else if (ip->i_afp) { | 1705 | } else if (ip->i_afp) { |
1718 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); | 1706 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); |
1719 | } | 1707 | } |
1720 | 1708 | ||
1721 | /* | 1709 | /* |
1722 | * Free the inode. | 1710 | * Free the inode. |
1723 | */ | 1711 | */ |
1724 | XFS_BMAP_INIT(&free_list, &first_block); | 1712 | XFS_BMAP_INIT(&free_list, &first_block); |
1725 | error = xfs_ifree(tp, ip, &free_list); | 1713 | error = xfs_ifree(tp, ip, &free_list); |
1726 | if (error) { | 1714 | if (error) { |
1727 | /* | 1715 | /* |
1728 | * If we fail to free the inode, shut down. The cancel | 1716 | * If we fail to free the inode, shut down. The cancel |
1729 | * might do that, we need to make sure. Otherwise the | 1717 | * might do that, we need to make sure. Otherwise the |
1730 | * inode might be lost for a long time or forever. | 1718 | * inode might be lost for a long time or forever. |
1731 | */ | 1719 | */ |
1732 | if (!XFS_FORCED_SHUTDOWN(mp)) { | 1720 | if (!XFS_FORCED_SHUTDOWN(mp)) { |
1733 | cmn_err(CE_NOTE, | 1721 | cmn_err(CE_NOTE, |
1734 | "xfs_inactive: xfs_ifree() returned an error = %d on %s", | 1722 | "xfs_inactive: xfs_ifree() returned an error = %d on %s", |
1735 | error, mp->m_fsname); | 1723 | error, mp->m_fsname); |
1736 | xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); | 1724 | xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); |
1737 | } | 1725 | } |
1738 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); | 1726 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); |
1739 | } else { | 1727 | } else { |
1740 | /* | 1728 | /* |
1741 | * Credit the quota account(s). The inode is gone. | 1729 | * Credit the quota account(s). The inode is gone. |
1742 | */ | 1730 | */ |
1743 | XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_ICOUNT, -1); | 1731 | XFS_TRANS_MOD_DQUOT_BYINO(mp, tp, ip, XFS_TRANS_DQ_ICOUNT, -1); |
1744 | 1732 | ||
1745 | /* | 1733 | /* |
1746 | * Just ignore errors at this point. There is nothing we can | 1734 | * Just ignore errors at this point. There is nothing we can |
1747 | * do except to try to keep going. Make sure it's not a silent | 1735 | * do except to try to keep going. Make sure it's not a silent |
1748 | * error. | 1736 | * error. |
1749 | */ | 1737 | */ |
1750 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 1738 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
1751 | if (error) | 1739 | if (error) |
1752 | xfs_fs_cmn_err(CE_NOTE, mp, "xfs_inactive: " | 1740 | xfs_fs_cmn_err(CE_NOTE, mp, "xfs_inactive: " |
1753 | "xfs_bmap_finish() returned error %d", error); | 1741 | "xfs_bmap_finish() returned error %d", error); |
1754 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 1742 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
1755 | if (error) | 1743 | if (error) |
1756 | xfs_fs_cmn_err(CE_NOTE, mp, "xfs_inactive: " | 1744 | xfs_fs_cmn_err(CE_NOTE, mp, "xfs_inactive: " |
1757 | "xfs_trans_commit() returned error %d", error); | 1745 | "xfs_trans_commit() returned error %d", error); |
1758 | } | 1746 | } |
1759 | /* | 1747 | /* |
1760 | * Release the dquots held by inode, if any. | 1748 | * Release the dquots held by inode, if any. |
1761 | */ | 1749 | */ |
1762 | XFS_QM_DQDETACH(mp, ip); | 1750 | XFS_QM_DQDETACH(mp, ip); |
1763 | 1751 | ||
1764 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 1752 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
1765 | 1753 | ||
1766 | out: | 1754 | out: |
1767 | return VN_INACTIVE_CACHE; | 1755 | return VN_INACTIVE_CACHE; |
1768 | } | 1756 | } |
1769 | 1757 | ||
1770 | 1758 | ||
1771 | int | 1759 | int |
1772 | xfs_lookup( | 1760 | xfs_lookup( |
1773 | xfs_inode_t *dp, | 1761 | xfs_inode_t *dp, |
1774 | struct xfs_name *name, | 1762 | struct xfs_name *name, |
1775 | xfs_inode_t **ipp) | 1763 | xfs_inode_t **ipp) |
1776 | { | 1764 | { |
1777 | xfs_inode_t *ip; | 1765 | xfs_inode_t *ip; |
1778 | xfs_ino_t e_inum; | 1766 | xfs_ino_t e_inum; |
1779 | int error; | 1767 | int error; |
1780 | uint lock_mode; | 1768 | uint lock_mode; |
1781 | 1769 | ||
1782 | xfs_itrace_entry(dp); | 1770 | xfs_itrace_entry(dp); |
1783 | 1771 | ||
1784 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | 1772 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) |
1785 | return XFS_ERROR(EIO); | 1773 | return XFS_ERROR(EIO); |
1786 | 1774 | ||
1787 | lock_mode = xfs_ilock_map_shared(dp); | 1775 | lock_mode = xfs_ilock_map_shared(dp); |
1788 | error = xfs_dir_lookup_int(dp, lock_mode, name, &e_inum, &ip); | 1776 | error = xfs_dir_lookup_int(dp, lock_mode, name, &e_inum, &ip); |
1789 | if (!error) { | 1777 | if (!error) { |
1790 | *ipp = ip; | 1778 | *ipp = ip; |
1791 | xfs_itrace_ref(ip); | 1779 | xfs_itrace_ref(ip); |
1792 | } | 1780 | } |
1793 | xfs_iunlock_map_shared(dp, lock_mode); | 1781 | xfs_iunlock_map_shared(dp, lock_mode); |
1794 | return error; | 1782 | return error; |
1795 | } | 1783 | } |
1796 | 1784 | ||
1797 | int | 1785 | int |
1798 | xfs_create( | 1786 | xfs_create( |
1799 | xfs_inode_t *dp, | 1787 | xfs_inode_t *dp, |
1800 | struct xfs_name *name, | 1788 | struct xfs_name *name, |
1801 | mode_t mode, | 1789 | mode_t mode, |
1802 | xfs_dev_t rdev, | 1790 | xfs_dev_t rdev, |
1803 | xfs_inode_t **ipp, | 1791 | xfs_inode_t **ipp, |
1804 | cred_t *credp) | 1792 | cred_t *credp) |
1805 | { | 1793 | { |
1806 | xfs_mount_t *mp = dp->i_mount; | 1794 | xfs_mount_t *mp = dp->i_mount; |
1807 | xfs_inode_t *ip; | 1795 | xfs_inode_t *ip; |
1808 | xfs_trans_t *tp; | 1796 | xfs_trans_t *tp; |
1809 | int error; | 1797 | int error; |
1810 | xfs_bmap_free_t free_list; | 1798 | xfs_bmap_free_t free_list; |
1811 | xfs_fsblock_t first_block; | 1799 | xfs_fsblock_t first_block; |
1812 | boolean_t unlock_dp_on_error = B_FALSE; | 1800 | boolean_t unlock_dp_on_error = B_FALSE; |
1813 | int dm_event_sent = 0; | 1801 | int dm_event_sent = 0; |
1814 | uint cancel_flags; | 1802 | uint cancel_flags; |
1815 | int committed; | 1803 | int committed; |
1816 | xfs_prid_t prid; | 1804 | xfs_prid_t prid; |
1817 | struct xfs_dquot *udqp, *gdqp; | 1805 | struct xfs_dquot *udqp, *gdqp; |
1818 | uint resblks; | 1806 | uint resblks; |
1819 | 1807 | ||
1820 | ASSERT(!*ipp); | 1808 | ASSERT(!*ipp); |
1821 | xfs_itrace_entry(dp); | 1809 | xfs_itrace_entry(dp); |
1822 | 1810 | ||
1823 | if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) { | 1811 | if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) { |
1824 | error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE, | 1812 | error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE, |
1825 | dp, DM_RIGHT_NULL, NULL, | 1813 | dp, DM_RIGHT_NULL, NULL, |
1826 | DM_RIGHT_NULL, name->name, NULL, | 1814 | DM_RIGHT_NULL, name->name, NULL, |
1827 | mode, 0, 0); | 1815 | mode, 0, 0); |
1828 | 1816 | ||
1829 | if (error) | 1817 | if (error) |
1830 | return error; | 1818 | return error; |
1831 | dm_event_sent = 1; | 1819 | dm_event_sent = 1; |
1832 | } | 1820 | } |
1833 | 1821 | ||
1834 | if (XFS_FORCED_SHUTDOWN(mp)) | 1822 | if (XFS_FORCED_SHUTDOWN(mp)) |
1835 | return XFS_ERROR(EIO); | 1823 | return XFS_ERROR(EIO); |
1836 | 1824 | ||
1837 | /* Return through std_return after this point. */ | 1825 | /* Return through std_return after this point. */ |
1838 | 1826 | ||
1839 | udqp = gdqp = NULL; | 1827 | udqp = gdqp = NULL; |
1840 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) | 1828 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) |
1841 | prid = dp->i_d.di_projid; | 1829 | prid = dp->i_d.di_projid; |
1842 | else | 1830 | else |
1843 | prid = (xfs_prid_t)dfltprid; | 1831 | prid = (xfs_prid_t)dfltprid; |
1844 | 1832 | ||
1845 | /* | 1833 | /* |
1846 | * Make sure that we have allocated dquot(s) on disk. | 1834 | * Make sure that we have allocated dquot(s) on disk. |
1847 | */ | 1835 | */ |
1848 | error = XFS_QM_DQVOPALLOC(mp, dp, | 1836 | error = XFS_QM_DQVOPALLOC(mp, dp, |
1849 | current_fsuid(credp), current_fsgid(credp), prid, | 1837 | current_fsuid(credp), current_fsgid(credp), prid, |
1850 | XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp); | 1838 | XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp); |
1851 | if (error) | 1839 | if (error) |
1852 | goto std_return; | 1840 | goto std_return; |
1853 | 1841 | ||
1854 | ip = NULL; | 1842 | ip = NULL; |
1855 | 1843 | ||
1856 | tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE); | 1844 | tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE); |
1857 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | 1845 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
1858 | resblks = XFS_CREATE_SPACE_RES(mp, name->len); | 1846 | resblks = XFS_CREATE_SPACE_RES(mp, name->len); |
1859 | /* | 1847 | /* |
1860 | * Initially assume that the file does not exist and | 1848 | * Initially assume that the file does not exist and |
1861 | * reserve the resources for that case. If that is not | 1849 | * reserve the resources for that case. If that is not |
1862 | * the case we'll drop the one we have and get a more | 1850 | * the case we'll drop the one we have and get a more |
1863 | * appropriate transaction later. | 1851 | * appropriate transaction later. |
1864 | */ | 1852 | */ |
1865 | error = xfs_trans_reserve(tp, resblks, XFS_CREATE_LOG_RES(mp), 0, | 1853 | error = xfs_trans_reserve(tp, resblks, XFS_CREATE_LOG_RES(mp), 0, |
1866 | XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); | 1854 | XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); |
1867 | if (error == ENOSPC) { | 1855 | if (error == ENOSPC) { |
1868 | resblks = 0; | 1856 | resblks = 0; |
1869 | error = xfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0, | 1857 | error = xfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0, |
1870 | XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); | 1858 | XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); |
1871 | } | 1859 | } |
1872 | if (error) { | 1860 | if (error) { |
1873 | cancel_flags = 0; | 1861 | cancel_flags = 0; |
1874 | goto error_return; | 1862 | goto error_return; |
1875 | } | 1863 | } |
1876 | 1864 | ||
1877 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); | 1865 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); |
1878 | unlock_dp_on_error = B_TRUE; | 1866 | unlock_dp_on_error = B_TRUE; |
1879 | 1867 | ||
1880 | XFS_BMAP_INIT(&free_list, &first_block); | 1868 | XFS_BMAP_INIT(&free_list, &first_block); |
1881 | 1869 | ||
1882 | ASSERT(ip == NULL); | 1870 | ASSERT(ip == NULL); |
1883 | 1871 | ||
1884 | /* | 1872 | /* |
1885 | * Reserve disk quota and the inode. | 1873 | * Reserve disk quota and the inode. |
1886 | */ | 1874 | */ |
1887 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0); | 1875 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0); |
1888 | if (error) | 1876 | if (error) |
1889 | goto error_return; | 1877 | goto error_return; |
1890 | 1878 | ||
1891 | error = xfs_dir_canenter(tp, dp, name, resblks); | 1879 | error = xfs_dir_canenter(tp, dp, name, resblks); |
1892 | if (error) | 1880 | if (error) |
1893 | goto error_return; | 1881 | goto error_return; |
1894 | error = xfs_dir_ialloc(&tp, dp, mode, 1, | 1882 | error = xfs_dir_ialloc(&tp, dp, mode, 1, |
1895 | rdev, credp, prid, resblks > 0, | 1883 | rdev, credp, prid, resblks > 0, |
1896 | &ip, &committed); | 1884 | &ip, &committed); |
1897 | if (error) { | 1885 | if (error) { |
1898 | if (error == ENOSPC) | 1886 | if (error == ENOSPC) |
1899 | goto error_return; | 1887 | goto error_return; |
1900 | goto abort_return; | 1888 | goto abort_return; |
1901 | } | 1889 | } |
1902 | xfs_itrace_ref(ip); | 1890 | xfs_itrace_ref(ip); |
1903 | 1891 | ||
1904 | /* | 1892 | /* |
1905 | * At this point, we've gotten a newly allocated inode. | 1893 | * At this point, we've gotten a newly allocated inode. |
1906 | * It is locked (and joined to the transaction). | 1894 | * It is locked (and joined to the transaction). |
1907 | */ | 1895 | */ |
1908 | 1896 | ||
1909 | ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); | 1897 | ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); |
1910 | 1898 | ||
1911 | /* | 1899 | /* |
1912 | * Now we join the directory inode to the transaction. We do not do it | 1900 | * Now we join the directory inode to the transaction. We do not do it |
1913 | * earlier because xfs_dir_ialloc might commit the previous transaction | 1901 | * earlier because xfs_dir_ialloc might commit the previous transaction |
1914 | * (and release all the locks). An error from here on will result in | 1902 | * (and release all the locks). An error from here on will result in |
1915 | * the transaction cancel unlocking dp so don't do it explicitly in the | 1903 | * the transaction cancel unlocking dp so don't do it explicitly in the |
1916 | * error path. | 1904 | * error path. |
1917 | */ | 1905 | */ |
1918 | IHOLD(dp); | 1906 | IHOLD(dp); |
1919 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); | 1907 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); |
1920 | unlock_dp_on_error = B_FALSE; | 1908 | unlock_dp_on_error = B_FALSE; |
1921 | 1909 | ||
1922 | error = xfs_dir_createname(tp, dp, name, ip->i_ino, | 1910 | error = xfs_dir_createname(tp, dp, name, ip->i_ino, |
1923 | &first_block, &free_list, resblks ? | 1911 | &first_block, &free_list, resblks ? |
1924 | resblks - XFS_IALLOC_SPACE_RES(mp) : 0); | 1912 | resblks - XFS_IALLOC_SPACE_RES(mp) : 0); |
1925 | if (error) { | 1913 | if (error) { |
1926 | ASSERT(error != ENOSPC); | 1914 | ASSERT(error != ENOSPC); |
1927 | goto abort_return; | 1915 | goto abort_return; |
1928 | } | 1916 | } |
1929 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 1917 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
1930 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | 1918 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); |
1931 | 1919 | ||
1932 | /* | 1920 | /* |
1933 | * If this is a synchronous mount, make sure that the | 1921 | * If this is a synchronous mount, make sure that the |
1934 | * create transaction goes to disk before returning to | 1922 | * create transaction goes to disk before returning to |
1935 | * the user. | 1923 | * the user. |
1936 | */ | 1924 | */ |
1937 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | 1925 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { |
1938 | xfs_trans_set_sync(tp); | 1926 | xfs_trans_set_sync(tp); |
1939 | } | 1927 | } |
1940 | 1928 | ||
1941 | dp->i_gen++; | 1929 | dp->i_gen++; |
1942 | 1930 | ||
1943 | /* | 1931 | /* |
1944 | * Attach the dquot(s) to the inodes and modify them incore. | 1932 | * Attach the dquot(s) to the inodes and modify them incore. |
1945 | * These ids of the inode couldn't have changed since the new | 1933 | * These ids of the inode couldn't have changed since the new |
1946 | * inode has been locked ever since it was created. | 1934 | * inode has been locked ever since it was created. |
1947 | */ | 1935 | */ |
1948 | XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp); | 1936 | XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp); |
1949 | 1937 | ||
1950 | /* | 1938 | /* |
1951 | * xfs_trans_commit normally decrements the vnode ref count | 1939 | * xfs_trans_commit normally decrements the vnode ref count |
1952 | * when it unlocks the inode. Since we want to return the | 1940 | * when it unlocks the inode. Since we want to return the |
1953 | * vnode to the caller, we bump the vnode ref count now. | 1941 | * vnode to the caller, we bump the vnode ref count now. |
1954 | */ | 1942 | */ |
1955 | IHOLD(ip); | 1943 | IHOLD(ip); |
1956 | 1944 | ||
1957 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 1945 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
1958 | if (error) { | 1946 | if (error) { |
1959 | xfs_bmap_cancel(&free_list); | 1947 | xfs_bmap_cancel(&free_list); |
1960 | goto abort_rele; | 1948 | goto abort_rele; |
1961 | } | 1949 | } |
1962 | 1950 | ||
1963 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 1951 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
1964 | if (error) { | 1952 | if (error) { |
1965 | IRELE(ip); | 1953 | IRELE(ip); |
1966 | tp = NULL; | 1954 | tp = NULL; |
1967 | goto error_return; | 1955 | goto error_return; |
1968 | } | 1956 | } |
1969 | 1957 | ||
1970 | XFS_QM_DQRELE(mp, udqp); | 1958 | XFS_QM_DQRELE(mp, udqp); |
1971 | XFS_QM_DQRELE(mp, gdqp); | 1959 | XFS_QM_DQRELE(mp, gdqp); |
1972 | 1960 | ||
1973 | *ipp = ip; | 1961 | *ipp = ip; |
1974 | 1962 | ||
1975 | /* Fallthrough to std_return with error = 0 */ | 1963 | /* Fallthrough to std_return with error = 0 */ |
1976 | 1964 | ||
1977 | std_return: | 1965 | std_return: |
1978 | if ((*ipp || (error != 0 && dm_event_sent != 0)) && | 1966 | if ((*ipp || (error != 0 && dm_event_sent != 0)) && |
1979 | DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) { | 1967 | DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) { |
1980 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, | 1968 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, |
1981 | dp, DM_RIGHT_NULL, | 1969 | dp, DM_RIGHT_NULL, |
1982 | *ipp ? ip : NULL, | 1970 | *ipp ? ip : NULL, |
1983 | DM_RIGHT_NULL, name->name, NULL, | 1971 | DM_RIGHT_NULL, name->name, NULL, |
1984 | mode, error, 0); | 1972 | mode, error, 0); |
1985 | } | 1973 | } |
1986 | return error; | 1974 | return error; |
1987 | 1975 | ||
1988 | abort_return: | 1976 | abort_return: |
1989 | cancel_flags |= XFS_TRANS_ABORT; | 1977 | cancel_flags |= XFS_TRANS_ABORT; |
1990 | /* FALLTHROUGH */ | 1978 | /* FALLTHROUGH */ |
1991 | 1979 | ||
1992 | error_return: | 1980 | error_return: |
1993 | if (tp != NULL) | 1981 | if (tp != NULL) |
1994 | xfs_trans_cancel(tp, cancel_flags); | 1982 | xfs_trans_cancel(tp, cancel_flags); |
1995 | 1983 | ||
1996 | XFS_QM_DQRELE(mp, udqp); | 1984 | XFS_QM_DQRELE(mp, udqp); |
1997 | XFS_QM_DQRELE(mp, gdqp); | 1985 | XFS_QM_DQRELE(mp, gdqp); |
1998 | 1986 | ||
1999 | if (unlock_dp_on_error) | 1987 | if (unlock_dp_on_error) |
2000 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 1988 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
2001 | 1989 | ||
2002 | goto std_return; | 1990 | goto std_return; |
2003 | 1991 | ||
2004 | abort_rele: | 1992 | abort_rele: |
2005 | /* | 1993 | /* |
2006 | * Wait until after the current transaction is aborted to | 1994 | * Wait until after the current transaction is aborted to |
2007 | * release the inode. This prevents recursive transactions | 1995 | * release the inode. This prevents recursive transactions |
2008 | * and deadlocks from xfs_inactive. | 1996 | * and deadlocks from xfs_inactive. |
2009 | */ | 1997 | */ |
2010 | cancel_flags |= XFS_TRANS_ABORT; | 1998 | cancel_flags |= XFS_TRANS_ABORT; |
2011 | xfs_trans_cancel(tp, cancel_flags); | 1999 | xfs_trans_cancel(tp, cancel_flags); |
2012 | IRELE(ip); | 2000 | IRELE(ip); |
2013 | 2001 | ||
2014 | XFS_QM_DQRELE(mp, udqp); | 2002 | XFS_QM_DQRELE(mp, udqp); |
2015 | XFS_QM_DQRELE(mp, gdqp); | 2003 | XFS_QM_DQRELE(mp, gdqp); |
2016 | 2004 | ||
2017 | goto std_return; | 2005 | goto std_return; |
2018 | } | 2006 | } |
2019 | 2007 | ||
2020 | #ifdef DEBUG | 2008 | #ifdef DEBUG |
2021 | /* | 2009 | /* |
2022 | * Some counters to see if (and how often) we are hitting some deadlock | 2010 | * Some counters to see if (and how often) we are hitting some deadlock |
2023 | * prevention code paths. | 2011 | * prevention code paths. |
2024 | */ | 2012 | */ |
2025 | 2013 | ||
2026 | int xfs_rm_locks; | 2014 | int xfs_rm_locks; |
2027 | int xfs_rm_lock_delays; | 2015 | int xfs_rm_lock_delays; |
2028 | int xfs_rm_attempts; | 2016 | int xfs_rm_attempts; |
2029 | #endif | 2017 | #endif |
2030 | 2018 | ||
2031 | /* | 2019 | /* |
2032 | * The following routine will lock the inodes associated with the | 2020 | * The following routine will lock the inodes associated with the |
2033 | * directory and the named entry in the directory. The locks are | 2021 | * directory and the named entry in the directory. The locks are |
2034 | * acquired in increasing inode number. | 2022 | * acquired in increasing inode number. |
2035 | * | 2023 | * |
2036 | * If the entry is "..", then only the directory is locked. The | 2024 | * If the entry is "..", then only the directory is locked. The |
2037 | * vnode ref count will still include that from the .. entry in | 2025 | * vnode ref count will still include that from the .. entry in |
2038 | * this case. | 2026 | * this case. |
2039 | * | 2027 | * |
2040 | * There is a deadlock we need to worry about. If the locked directory is | 2028 | * There is a deadlock we need to worry about. If the locked directory is |
2041 | * in the AIL, it might be blocking up the log. The next inode we lock | 2029 | * in the AIL, it might be blocking up the log. The next inode we lock |
2042 | * could be already locked by another thread waiting for log space (e.g | 2030 | * could be already locked by another thread waiting for log space (e.g |
2043 | * a permanent log reservation with a long running transaction (see | 2031 | * a permanent log reservation with a long running transaction (see |
2044 | * xfs_itruncate_finish)). To solve this, we must check if the directory | 2032 | * xfs_itruncate_finish)). To solve this, we must check if the directory |
2045 | * is in the ail and use lock_nowait. If we can't lock, we need to | 2033 | * is in the ail and use lock_nowait. If we can't lock, we need to |
2046 | * drop the inode lock on the directory and try again. xfs_iunlock will | 2034 | * drop the inode lock on the directory and try again. xfs_iunlock will |
2047 | * potentially push the tail if we were holding up the log. | 2035 | * potentially push the tail if we were holding up the log. |
2048 | */ | 2036 | */ |
2049 | STATIC int | 2037 | STATIC int |
2050 | xfs_lock_dir_and_entry( | 2038 | xfs_lock_dir_and_entry( |
2051 | xfs_inode_t *dp, | 2039 | xfs_inode_t *dp, |
2052 | xfs_inode_t *ip) /* inode of entry 'name' */ | 2040 | xfs_inode_t *ip) /* inode of entry 'name' */ |
2053 | { | 2041 | { |
2054 | int attempts; | 2042 | int attempts; |
2055 | xfs_ino_t e_inum; | 2043 | xfs_ino_t e_inum; |
2056 | xfs_inode_t *ips[2]; | 2044 | xfs_inode_t *ips[2]; |
2057 | xfs_log_item_t *lp; | 2045 | xfs_log_item_t *lp; |
2058 | 2046 | ||
2059 | #ifdef DEBUG | 2047 | #ifdef DEBUG |
2060 | xfs_rm_locks++; | 2048 | xfs_rm_locks++; |
2061 | #endif | 2049 | #endif |
2062 | attempts = 0; | 2050 | attempts = 0; |
2063 | 2051 | ||
2064 | again: | 2052 | again: |
2065 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); | 2053 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); |
2066 | 2054 | ||
2067 | e_inum = ip->i_ino; | 2055 | e_inum = ip->i_ino; |
2068 | 2056 | ||
2069 | xfs_itrace_ref(ip); | 2057 | xfs_itrace_ref(ip); |
2070 | 2058 | ||
2071 | /* | 2059 | /* |
2072 | * We want to lock in increasing inum. Since we've already | 2060 | * We want to lock in increasing inum. Since we've already |
2073 | * acquired the lock on the directory, we may need to release | 2061 | * acquired the lock on the directory, we may need to release |
2074 | * if if the inum of the entry turns out to be less. | 2062 | * if if the inum of the entry turns out to be less. |
2075 | */ | 2063 | */ |
2076 | if (e_inum > dp->i_ino) { | 2064 | if (e_inum > dp->i_ino) { |
2077 | /* | 2065 | /* |
2078 | * We are already in the right order, so just | 2066 | * We are already in the right order, so just |
2079 | * lock on the inode of the entry. | 2067 | * lock on the inode of the entry. |
2080 | * We need to use nowait if dp is in the AIL. | 2068 | * We need to use nowait if dp is in the AIL. |
2081 | */ | 2069 | */ |
2082 | 2070 | ||
2083 | lp = (xfs_log_item_t *)dp->i_itemp; | 2071 | lp = (xfs_log_item_t *)dp->i_itemp; |
2084 | if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { | 2072 | if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { |
2085 | if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { | 2073 | if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { |
2086 | attempts++; | 2074 | attempts++; |
2087 | #ifdef DEBUG | 2075 | #ifdef DEBUG |
2088 | xfs_rm_attempts++; | 2076 | xfs_rm_attempts++; |
2089 | #endif | 2077 | #endif |
2090 | 2078 | ||
2091 | /* | 2079 | /* |
2092 | * Unlock dp and try again. | 2080 | * Unlock dp and try again. |
2093 | * xfs_iunlock will try to push the tail | 2081 | * xfs_iunlock will try to push the tail |
2094 | * if the inode is in the AIL. | 2082 | * if the inode is in the AIL. |
2095 | */ | 2083 | */ |
2096 | 2084 | ||
2097 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 2085 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
2098 | 2086 | ||
2099 | if ((attempts % 5) == 0) { | 2087 | if ((attempts % 5) == 0) { |
2100 | delay(1); /* Don't just spin the CPU */ | 2088 | delay(1); /* Don't just spin the CPU */ |
2101 | #ifdef DEBUG | 2089 | #ifdef DEBUG |
2102 | xfs_rm_lock_delays++; | 2090 | xfs_rm_lock_delays++; |
2103 | #endif | 2091 | #endif |
2104 | } | 2092 | } |
2105 | goto again; | 2093 | goto again; |
2106 | } | 2094 | } |
2107 | } else { | 2095 | } else { |
2108 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 2096 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
2109 | } | 2097 | } |
2110 | } else if (e_inum < dp->i_ino) { | 2098 | } else if (e_inum < dp->i_ino) { |
2111 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 2099 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
2112 | 2100 | ||
2113 | ips[0] = ip; | 2101 | ips[0] = ip; |
2114 | ips[1] = dp; | 2102 | ips[1] = dp; |
2115 | xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); | 2103 | xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); |
2116 | } | 2104 | } |
2117 | /* else e_inum == dp->i_ino */ | 2105 | /* else e_inum == dp->i_ino */ |
2118 | /* This can happen if we're asked to lock /x/.. | 2106 | /* This can happen if we're asked to lock /x/.. |
2119 | * the entry is "..", which is also the parent directory. | 2107 | * the entry is "..", which is also the parent directory. |
2120 | */ | 2108 | */ |
2121 | 2109 | ||
2122 | return 0; | 2110 | return 0; |
2123 | } | 2111 | } |
2124 | 2112 | ||
2125 | #ifdef DEBUG | 2113 | #ifdef DEBUG |
2126 | int xfs_locked_n; | 2114 | int xfs_locked_n; |
2127 | int xfs_small_retries; | 2115 | int xfs_small_retries; |
2128 | int xfs_middle_retries; | 2116 | int xfs_middle_retries; |
2129 | int xfs_lots_retries; | 2117 | int xfs_lots_retries; |
2130 | int xfs_lock_delays; | 2118 | int xfs_lock_delays; |
2131 | #endif | 2119 | #endif |
2132 | 2120 | ||
2133 | /* | 2121 | /* |
2134 | * Bump the subclass so xfs_lock_inodes() acquires each lock with | 2122 | * Bump the subclass so xfs_lock_inodes() acquires each lock with |
2135 | * a different value | 2123 | * a different value |
2136 | */ | 2124 | */ |
2137 | static inline int | 2125 | static inline int |
2138 | xfs_lock_inumorder(int lock_mode, int subclass) | 2126 | xfs_lock_inumorder(int lock_mode, int subclass) |
2139 | { | 2127 | { |
2140 | if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)) | 2128 | if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)) |
2141 | lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_IOLOCK_SHIFT; | 2129 | lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_IOLOCK_SHIFT; |
2142 | if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) | 2130 | if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) |
2143 | lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_ILOCK_SHIFT; | 2131 | lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_ILOCK_SHIFT; |
2144 | 2132 | ||
2145 | return lock_mode; | 2133 | return lock_mode; |
2146 | } | 2134 | } |
2147 | 2135 | ||
2148 | /* | 2136 | /* |
2149 | * The following routine will lock n inodes in exclusive mode. | 2137 | * The following routine will lock n inodes in exclusive mode. |
2150 | * We assume the caller calls us with the inodes in i_ino order. | 2138 | * We assume the caller calls us with the inodes in i_ino order. |
2151 | * | 2139 | * |
2152 | * We need to detect deadlock where an inode that we lock | 2140 | * We need to detect deadlock where an inode that we lock |
2153 | * is in the AIL and we start waiting for another inode that is locked | 2141 | * is in the AIL and we start waiting for another inode that is locked |
2154 | * by a thread in a long running transaction (such as truncate). This can | 2142 | * by a thread in a long running transaction (such as truncate). This can |
2155 | * result in deadlock since the long running trans might need to wait | 2143 | * result in deadlock since the long running trans might need to wait |
2156 | * for the inode we just locked in order to push the tail and free space | 2144 | * for the inode we just locked in order to push the tail and free space |
2157 | * in the log. | 2145 | * in the log. |
2158 | */ | 2146 | */ |
2159 | void | 2147 | void |
2160 | xfs_lock_inodes( | 2148 | xfs_lock_inodes( |
2161 | xfs_inode_t **ips, | 2149 | xfs_inode_t **ips, |
2162 | int inodes, | 2150 | int inodes, |
2163 | int first_locked, | 2151 | int first_locked, |
2164 | uint lock_mode) | 2152 | uint lock_mode) |
2165 | { | 2153 | { |
2166 | int attempts = 0, i, j, try_lock; | 2154 | int attempts = 0, i, j, try_lock; |
2167 | xfs_log_item_t *lp; | 2155 | xfs_log_item_t *lp; |
2168 | 2156 | ||
2169 | ASSERT(ips && (inodes >= 2)); /* we need at least two */ | 2157 | ASSERT(ips && (inodes >= 2)); /* we need at least two */ |
2170 | 2158 | ||
2171 | if (first_locked) { | 2159 | if (first_locked) { |
2172 | try_lock = 1; | 2160 | try_lock = 1; |
2173 | i = 1; | 2161 | i = 1; |
2174 | } else { | 2162 | } else { |
2175 | try_lock = 0; | 2163 | try_lock = 0; |
2176 | i = 0; | 2164 | i = 0; |
2177 | } | 2165 | } |
2178 | 2166 | ||
2179 | again: | 2167 | again: |
2180 | for (; i < inodes; i++) { | 2168 | for (; i < inodes; i++) { |
2181 | ASSERT(ips[i]); | 2169 | ASSERT(ips[i]); |
2182 | 2170 | ||
2183 | if (i && (ips[i] == ips[i-1])) /* Already locked */ | 2171 | if (i && (ips[i] == ips[i-1])) /* Already locked */ |
2184 | continue; | 2172 | continue; |
2185 | 2173 | ||
2186 | /* | 2174 | /* |
2187 | * If try_lock is not set yet, make sure all locked inodes | 2175 | * If try_lock is not set yet, make sure all locked inodes |
2188 | * are not in the AIL. | 2176 | * are not in the AIL. |
2189 | * If any are, set try_lock to be used later. | 2177 | * If any are, set try_lock to be used later. |
2190 | */ | 2178 | */ |
2191 | 2179 | ||
2192 | if (!try_lock) { | 2180 | if (!try_lock) { |
2193 | for (j = (i - 1); j >= 0 && !try_lock; j--) { | 2181 | for (j = (i - 1); j >= 0 && !try_lock; j--) { |
2194 | lp = (xfs_log_item_t *)ips[j]->i_itemp; | 2182 | lp = (xfs_log_item_t *)ips[j]->i_itemp; |
2195 | if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { | 2183 | if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { |
2196 | try_lock++; | 2184 | try_lock++; |
2197 | } | 2185 | } |
2198 | } | 2186 | } |
2199 | } | 2187 | } |
2200 | 2188 | ||
2201 | /* | 2189 | /* |
2202 | * If any of the previous locks we have locked is in the AIL, | 2190 | * If any of the previous locks we have locked is in the AIL, |
2203 | * we must TRY to get the second and subsequent locks. If | 2191 | * we must TRY to get the second and subsequent locks. If |
2204 | * we can't get any, we must release all we have | 2192 | * we can't get any, we must release all we have |
2205 | * and try again. | 2193 | * and try again. |
2206 | */ | 2194 | */ |
2207 | 2195 | ||
2208 | if (try_lock) { | 2196 | if (try_lock) { |
2209 | /* try_lock must be 0 if i is 0. */ | 2197 | /* try_lock must be 0 if i is 0. */ |
2210 | /* | 2198 | /* |
2211 | * try_lock means we have an inode locked | 2199 | * try_lock means we have an inode locked |
2212 | * that is in the AIL. | 2200 | * that is in the AIL. |
2213 | */ | 2201 | */ |
2214 | ASSERT(i != 0); | 2202 | ASSERT(i != 0); |
2215 | if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) { | 2203 | if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) { |
2216 | attempts++; | 2204 | attempts++; |
2217 | 2205 | ||
2218 | /* | 2206 | /* |
2219 | * Unlock all previous guys and try again. | 2207 | * Unlock all previous guys and try again. |
2220 | * xfs_iunlock will try to push the tail | 2208 | * xfs_iunlock will try to push the tail |
2221 | * if the inode is in the AIL. | 2209 | * if the inode is in the AIL. |
2222 | */ | 2210 | */ |
2223 | 2211 | ||
2224 | for(j = i - 1; j >= 0; j--) { | 2212 | for(j = i - 1; j >= 0; j--) { |
2225 | 2213 | ||
2226 | /* | 2214 | /* |
2227 | * Check to see if we've already | 2215 | * Check to see if we've already |
2228 | * unlocked this one. | 2216 | * unlocked this one. |
2229 | * Not the first one going back, | 2217 | * Not the first one going back, |
2230 | * and the inode ptr is the same. | 2218 | * and the inode ptr is the same. |
2231 | */ | 2219 | */ |
2232 | if ((j != (i - 1)) && ips[j] == | 2220 | if ((j != (i - 1)) && ips[j] == |
2233 | ips[j+1]) | 2221 | ips[j+1]) |
2234 | continue; | 2222 | continue; |
2235 | 2223 | ||
2236 | xfs_iunlock(ips[j], lock_mode); | 2224 | xfs_iunlock(ips[j], lock_mode); |
2237 | } | 2225 | } |
2238 | 2226 | ||
2239 | if ((attempts % 5) == 0) { | 2227 | if ((attempts % 5) == 0) { |
2240 | delay(1); /* Don't just spin the CPU */ | 2228 | delay(1); /* Don't just spin the CPU */ |
2241 | #ifdef DEBUG | 2229 | #ifdef DEBUG |
2242 | xfs_lock_delays++; | 2230 | xfs_lock_delays++; |
2243 | #endif | 2231 | #endif |
2244 | } | 2232 | } |
2245 | i = 0; | 2233 | i = 0; |
2246 | try_lock = 0; | 2234 | try_lock = 0; |
2247 | goto again; | 2235 | goto again; |
2248 | } | 2236 | } |
2249 | } else { | 2237 | } else { |
2250 | xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i)); | 2238 | xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i)); |
2251 | } | 2239 | } |
2252 | } | 2240 | } |
2253 | 2241 | ||
2254 | #ifdef DEBUG | 2242 | #ifdef DEBUG |
2255 | if (attempts) { | 2243 | if (attempts) { |
2256 | if (attempts < 5) xfs_small_retries++; | 2244 | if (attempts < 5) xfs_small_retries++; |
2257 | else if (attempts < 100) xfs_middle_retries++; | 2245 | else if (attempts < 100) xfs_middle_retries++; |
2258 | else xfs_lots_retries++; | 2246 | else xfs_lots_retries++; |
2259 | } else { | 2247 | } else { |
2260 | xfs_locked_n++; | 2248 | xfs_locked_n++; |
2261 | } | 2249 | } |
2262 | #endif | 2250 | #endif |
2263 | } | 2251 | } |
2264 | 2252 | ||
2265 | #ifdef DEBUG | 2253 | #ifdef DEBUG |
2266 | #define REMOVE_DEBUG_TRACE(x) {remove_which_error_return = (x);} | 2254 | #define REMOVE_DEBUG_TRACE(x) {remove_which_error_return = (x);} |
2267 | int remove_which_error_return = 0; | 2255 | int remove_which_error_return = 0; |
2268 | #else /* ! DEBUG */ | 2256 | #else /* ! DEBUG */ |
2269 | #define REMOVE_DEBUG_TRACE(x) | 2257 | #define REMOVE_DEBUG_TRACE(x) |
2270 | #endif /* ! DEBUG */ | 2258 | #endif /* ! DEBUG */ |
2271 | 2259 | ||
2272 | int | 2260 | int |
2273 | xfs_remove( | 2261 | xfs_remove( |
2274 | xfs_inode_t *dp, | 2262 | xfs_inode_t *dp, |
2275 | struct xfs_name *name, | 2263 | struct xfs_name *name, |
2276 | xfs_inode_t *ip) | 2264 | xfs_inode_t *ip) |
2277 | { | 2265 | { |
2278 | xfs_mount_t *mp = dp->i_mount; | 2266 | xfs_mount_t *mp = dp->i_mount; |
2279 | xfs_trans_t *tp = NULL; | 2267 | xfs_trans_t *tp = NULL; |
2280 | int error = 0; | 2268 | int error = 0; |
2281 | xfs_bmap_free_t free_list; | 2269 | xfs_bmap_free_t free_list; |
2282 | xfs_fsblock_t first_block; | 2270 | xfs_fsblock_t first_block; |
2283 | int cancel_flags; | 2271 | int cancel_flags; |
2284 | int committed; | 2272 | int committed; |
2285 | int link_zero; | 2273 | int link_zero; |
2286 | uint resblks; | 2274 | uint resblks; |
2287 | 2275 | ||
2288 | xfs_itrace_entry(dp); | 2276 | xfs_itrace_entry(dp); |
2289 | 2277 | ||
2290 | if (XFS_FORCED_SHUTDOWN(mp)) | 2278 | if (XFS_FORCED_SHUTDOWN(mp)) |
2291 | return XFS_ERROR(EIO); | 2279 | return XFS_ERROR(EIO); |
2292 | 2280 | ||
2293 | if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) { | 2281 | if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) { |
2294 | error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dp, DM_RIGHT_NULL, | 2282 | error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dp, DM_RIGHT_NULL, |
2295 | NULL, DM_RIGHT_NULL, name->name, NULL, | 2283 | NULL, DM_RIGHT_NULL, name->name, NULL, |
2296 | ip->i_d.di_mode, 0, 0); | 2284 | ip->i_d.di_mode, 0, 0); |
2297 | if (error) | 2285 | if (error) |
2298 | return error; | 2286 | return error; |
2299 | } | 2287 | } |
2300 | 2288 | ||
2301 | /* | 2289 | /* |
2302 | * We need to get a reference to ip before we get our log | 2290 | * We need to get a reference to ip before we get our log |
2303 | * reservation. The reason for this is that we cannot call | 2291 | * reservation. The reason for this is that we cannot call |
2304 | * xfs_iget for an inode for which we do not have a reference | 2292 | * xfs_iget for an inode for which we do not have a reference |
2305 | * once we've acquired a log reservation. This is because the | 2293 | * once we've acquired a log reservation. This is because the |
2306 | * inode we are trying to get might be in xfs_inactive going | 2294 | * inode we are trying to get might be in xfs_inactive going |
2307 | * for a log reservation. Since we'll have to wait for the | 2295 | * for a log reservation. Since we'll have to wait for the |
2308 | * inactive code to complete before returning from xfs_iget, | 2296 | * inactive code to complete before returning from xfs_iget, |
2309 | * we need to make sure that we don't have log space reserved | 2297 | * we need to make sure that we don't have log space reserved |
2310 | * when we call xfs_iget. Instead we get an unlocked reference | 2298 | * when we call xfs_iget. Instead we get an unlocked reference |
2311 | * to the inode before getting our log reservation. | 2299 | * to the inode before getting our log reservation. |
2312 | */ | 2300 | */ |
2313 | IHOLD(ip); | 2301 | IHOLD(ip); |
2314 | 2302 | ||
2315 | xfs_itrace_entry(ip); | 2303 | xfs_itrace_entry(ip); |
2316 | xfs_itrace_ref(ip); | 2304 | xfs_itrace_ref(ip); |
2317 | 2305 | ||
2318 | error = XFS_QM_DQATTACH(mp, dp, 0); | 2306 | error = XFS_QM_DQATTACH(mp, dp, 0); |
2319 | if (!error && dp != ip) | 2307 | if (!error && dp != ip) |
2320 | error = XFS_QM_DQATTACH(mp, ip, 0); | 2308 | error = XFS_QM_DQATTACH(mp, ip, 0); |
2321 | if (error) { | 2309 | if (error) { |
2322 | REMOVE_DEBUG_TRACE(__LINE__); | 2310 | REMOVE_DEBUG_TRACE(__LINE__); |
2323 | IRELE(ip); | 2311 | IRELE(ip); |
2324 | goto std_return; | 2312 | goto std_return; |
2325 | } | 2313 | } |
2326 | 2314 | ||
2327 | tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE); | 2315 | tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE); |
2328 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | 2316 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
2329 | /* | 2317 | /* |
2330 | * We try to get the real space reservation first, | 2318 | * We try to get the real space reservation first, |
2331 | * allowing for directory btree deletion(s) implying | 2319 | * allowing for directory btree deletion(s) implying |
2332 | * possible bmap insert(s). If we can't get the space | 2320 | * possible bmap insert(s). If we can't get the space |
2333 | * reservation then we use 0 instead, and avoid the bmap | 2321 | * reservation then we use 0 instead, and avoid the bmap |
2334 | * btree insert(s) in the directory code by, if the bmap | 2322 | * btree insert(s) in the directory code by, if the bmap |
2335 | * insert tries to happen, instead trimming the LAST | 2323 | * insert tries to happen, instead trimming the LAST |
2336 | * block from the directory. | 2324 | * block from the directory. |
2337 | */ | 2325 | */ |
2338 | resblks = XFS_REMOVE_SPACE_RES(mp); | 2326 | resblks = XFS_REMOVE_SPACE_RES(mp); |
2339 | error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, | 2327 | error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, |
2340 | XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); | 2328 | XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); |
2341 | if (error == ENOSPC) { | 2329 | if (error == ENOSPC) { |
2342 | resblks = 0; | 2330 | resblks = 0; |
2343 | error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, | 2331 | error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, |
2344 | XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); | 2332 | XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); |
2345 | } | 2333 | } |
2346 | if (error) { | 2334 | if (error) { |
2347 | ASSERT(error != ENOSPC); | 2335 | ASSERT(error != ENOSPC); |
2348 | REMOVE_DEBUG_TRACE(__LINE__); | 2336 | REMOVE_DEBUG_TRACE(__LINE__); |
2349 | xfs_trans_cancel(tp, 0); | 2337 | xfs_trans_cancel(tp, 0); |
2350 | IRELE(ip); | 2338 | IRELE(ip); |
2351 | return error; | 2339 | return error; |
2352 | } | 2340 | } |
2353 | 2341 | ||
2354 | error = xfs_lock_dir_and_entry(dp, ip); | 2342 | error = xfs_lock_dir_and_entry(dp, ip); |
2355 | if (error) { | 2343 | if (error) { |
2356 | REMOVE_DEBUG_TRACE(__LINE__); | 2344 | REMOVE_DEBUG_TRACE(__LINE__); |
2357 | xfs_trans_cancel(tp, cancel_flags); | 2345 | xfs_trans_cancel(tp, cancel_flags); |
2358 | IRELE(ip); | 2346 | IRELE(ip); |
2359 | goto std_return; | 2347 | goto std_return; |
2360 | } | 2348 | } |
2361 | 2349 | ||
2362 | /* | 2350 | /* |
2363 | * At this point, we've gotten both the directory and the entry | 2351 | * At this point, we've gotten both the directory and the entry |
2364 | * inodes locked. | 2352 | * inodes locked. |
2365 | */ | 2353 | */ |
2366 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); | 2354 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); |
2367 | if (dp != ip) { | 2355 | if (dp != ip) { |
2368 | /* | 2356 | /* |
2369 | * Increment vnode ref count only in this case since | 2357 | * Increment vnode ref count only in this case since |
2370 | * there's an extra vnode reference in the case where | 2358 | * there's an extra vnode reference in the case where |
2371 | * dp == ip. | 2359 | * dp == ip. |
2372 | */ | 2360 | */ |
2373 | IHOLD(dp); | 2361 | IHOLD(dp); |
2374 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 2362 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
2375 | } | 2363 | } |
2376 | 2364 | ||
2377 | /* | 2365 | /* |
2378 | * Entry must exist since we did a lookup in xfs_lock_dir_and_entry. | 2366 | * Entry must exist since we did a lookup in xfs_lock_dir_and_entry. |
2379 | */ | 2367 | */ |
2380 | XFS_BMAP_INIT(&free_list, &first_block); | 2368 | XFS_BMAP_INIT(&free_list, &first_block); |
2381 | error = xfs_dir_removename(tp, dp, name, ip->i_ino, | 2369 | error = xfs_dir_removename(tp, dp, name, ip->i_ino, |
2382 | &first_block, &free_list, 0); | 2370 | &first_block, &free_list, 0); |
2383 | if (error) { | 2371 | if (error) { |
2384 | ASSERT(error != ENOENT); | 2372 | ASSERT(error != ENOENT); |
2385 | REMOVE_DEBUG_TRACE(__LINE__); | 2373 | REMOVE_DEBUG_TRACE(__LINE__); |
2386 | goto error1; | 2374 | goto error1; |
2387 | } | 2375 | } |
2388 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 2376 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
2389 | 2377 | ||
2390 | dp->i_gen++; | 2378 | dp->i_gen++; |
2391 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | 2379 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); |
2392 | 2380 | ||
2393 | error = xfs_droplink(tp, ip); | 2381 | error = xfs_droplink(tp, ip); |
2394 | if (error) { | 2382 | if (error) { |
2395 | REMOVE_DEBUG_TRACE(__LINE__); | 2383 | REMOVE_DEBUG_TRACE(__LINE__); |
2396 | goto error1; | 2384 | goto error1; |
2397 | } | 2385 | } |
2398 | 2386 | ||
2399 | /* Determine if this is the last link while | 2387 | /* Determine if this is the last link while |
2400 | * we are in the transaction. | 2388 | * we are in the transaction. |
2401 | */ | 2389 | */ |
2402 | link_zero = (ip)->i_d.di_nlink==0; | 2390 | link_zero = (ip)->i_d.di_nlink==0; |
2403 | 2391 | ||
2404 | /* | 2392 | /* |
2405 | * Take an extra ref on the inode so that it doesn't | 2393 | * Take an extra ref on the inode so that it doesn't |
2406 | * go to xfs_inactive() from within the commit. | 2394 | * go to xfs_inactive() from within the commit. |
2407 | */ | 2395 | */ |
2408 | IHOLD(ip); | 2396 | IHOLD(ip); |
2409 | 2397 | ||
2410 | /* | 2398 | /* |
2411 | * If this is a synchronous mount, make sure that the | 2399 | * If this is a synchronous mount, make sure that the |
2412 | * remove transaction goes to disk before returning to | 2400 | * remove transaction goes to disk before returning to |
2413 | * the user. | 2401 | * the user. |
2414 | */ | 2402 | */ |
2415 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | 2403 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { |
2416 | xfs_trans_set_sync(tp); | 2404 | xfs_trans_set_sync(tp); |
2417 | } | 2405 | } |
2418 | 2406 | ||
2419 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 2407 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
2420 | if (error) { | 2408 | if (error) { |
2421 | REMOVE_DEBUG_TRACE(__LINE__); | 2409 | REMOVE_DEBUG_TRACE(__LINE__); |
2422 | goto error_rele; | 2410 | goto error_rele; |
2423 | } | 2411 | } |
2424 | 2412 | ||
2425 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 2413 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
2426 | if (error) { | 2414 | if (error) { |
2427 | IRELE(ip); | 2415 | IRELE(ip); |
2428 | goto std_return; | 2416 | goto std_return; |
2429 | } | 2417 | } |
2430 | 2418 | ||
2431 | /* | 2419 | /* |
2432 | * If we are using filestreams, kill the stream association. | 2420 | * If we are using filestreams, kill the stream association. |
2433 | * If the file is still open it may get a new one but that | 2421 | * If the file is still open it may get a new one but that |
2434 | * will get killed on last close in xfs_close() so we don't | 2422 | * will get killed on last close in xfs_close() so we don't |
2435 | * have to worry about that. | 2423 | * have to worry about that. |
2436 | */ | 2424 | */ |
2437 | if (link_zero && xfs_inode_is_filestream(ip)) | 2425 | if (link_zero && xfs_inode_is_filestream(ip)) |
2438 | xfs_filestream_deassociate(ip); | 2426 | xfs_filestream_deassociate(ip); |
2439 | 2427 | ||
2440 | xfs_itrace_exit(ip); | 2428 | xfs_itrace_exit(ip); |
2441 | IRELE(ip); | 2429 | IRELE(ip); |
2442 | 2430 | ||
2443 | /* Fall through to std_return with error = 0 */ | 2431 | /* Fall through to std_return with error = 0 */ |
2444 | std_return: | 2432 | std_return: |
2445 | if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { | 2433 | if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { |
2446 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, | 2434 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, |
2447 | dp, DM_RIGHT_NULL, | 2435 | dp, DM_RIGHT_NULL, |
2448 | NULL, DM_RIGHT_NULL, | 2436 | NULL, DM_RIGHT_NULL, |
2449 | name->name, NULL, ip->i_d.di_mode, error, 0); | 2437 | name->name, NULL, ip->i_d.di_mode, error, 0); |
2450 | } | 2438 | } |
2451 | return error; | 2439 | return error; |
2452 | 2440 | ||
2453 | error1: | 2441 | error1: |
2454 | xfs_bmap_cancel(&free_list); | 2442 | xfs_bmap_cancel(&free_list); |
2455 | cancel_flags |= XFS_TRANS_ABORT; | 2443 | cancel_flags |= XFS_TRANS_ABORT; |
2456 | xfs_trans_cancel(tp, cancel_flags); | 2444 | xfs_trans_cancel(tp, cancel_flags); |
2457 | goto std_return; | 2445 | goto std_return; |
2458 | 2446 | ||
2459 | error_rele: | 2447 | error_rele: |
2460 | /* | 2448 | /* |
2461 | * In this case make sure to not release the inode until after | 2449 | * In this case make sure to not release the inode until after |
2462 | * the current transaction is aborted. Releasing it beforehand | 2450 | * the current transaction is aborted. Releasing it beforehand |
2463 | * can cause us to go to xfs_inactive and start a recursive | 2451 | * can cause us to go to xfs_inactive and start a recursive |
2464 | * transaction which can easily deadlock with the current one. | 2452 | * transaction which can easily deadlock with the current one. |
2465 | */ | 2453 | */ |
2466 | xfs_bmap_cancel(&free_list); | 2454 | xfs_bmap_cancel(&free_list); |
2467 | cancel_flags |= XFS_TRANS_ABORT; | 2455 | cancel_flags |= XFS_TRANS_ABORT; |
2468 | xfs_trans_cancel(tp, cancel_flags); | 2456 | xfs_trans_cancel(tp, cancel_flags); |
2469 | 2457 | ||
2470 | IRELE(ip); | 2458 | IRELE(ip); |
2471 | 2459 | ||
2472 | goto std_return; | 2460 | goto std_return; |
2473 | } | 2461 | } |
2474 | 2462 | ||
2475 | int | 2463 | int |
2476 | xfs_link( | 2464 | xfs_link( |
2477 | xfs_inode_t *tdp, | 2465 | xfs_inode_t *tdp, |
2478 | xfs_inode_t *sip, | 2466 | xfs_inode_t *sip, |
2479 | struct xfs_name *target_name) | 2467 | struct xfs_name *target_name) |
2480 | { | 2468 | { |
2481 | xfs_mount_t *mp = tdp->i_mount; | 2469 | xfs_mount_t *mp = tdp->i_mount; |
2482 | xfs_trans_t *tp; | 2470 | xfs_trans_t *tp; |
2483 | xfs_inode_t *ips[2]; | 2471 | xfs_inode_t *ips[2]; |
2484 | int error; | 2472 | int error; |
2485 | xfs_bmap_free_t free_list; | 2473 | xfs_bmap_free_t free_list; |
2486 | xfs_fsblock_t first_block; | 2474 | xfs_fsblock_t first_block; |
2487 | int cancel_flags; | 2475 | int cancel_flags; |
2488 | int committed; | 2476 | int committed; |
2489 | int resblks; | 2477 | int resblks; |
2490 | 2478 | ||
2491 | xfs_itrace_entry(tdp); | 2479 | xfs_itrace_entry(tdp); |
2492 | xfs_itrace_entry(sip); | 2480 | xfs_itrace_entry(sip); |
2493 | 2481 | ||
2494 | ASSERT(!S_ISDIR(sip->i_d.di_mode)); | 2482 | ASSERT(!S_ISDIR(sip->i_d.di_mode)); |
2495 | 2483 | ||
2496 | if (XFS_FORCED_SHUTDOWN(mp)) | 2484 | if (XFS_FORCED_SHUTDOWN(mp)) |
2497 | return XFS_ERROR(EIO); | 2485 | return XFS_ERROR(EIO); |
2498 | 2486 | ||
2499 | if (DM_EVENT_ENABLED(tdp, DM_EVENT_LINK)) { | 2487 | if (DM_EVENT_ENABLED(tdp, DM_EVENT_LINK)) { |
2500 | error = XFS_SEND_NAMESP(mp, DM_EVENT_LINK, | 2488 | error = XFS_SEND_NAMESP(mp, DM_EVENT_LINK, |
2501 | tdp, DM_RIGHT_NULL, | 2489 | tdp, DM_RIGHT_NULL, |
2502 | sip, DM_RIGHT_NULL, | 2490 | sip, DM_RIGHT_NULL, |
2503 | target_name->name, NULL, 0, 0, 0); | 2491 | target_name->name, NULL, 0, 0, 0); |
2504 | if (error) | 2492 | if (error) |
2505 | return error; | 2493 | return error; |
2506 | } | 2494 | } |
2507 | 2495 | ||
2508 | /* Return through std_return after this point. */ | 2496 | /* Return through std_return after this point. */ |
2509 | 2497 | ||
2510 | error = XFS_QM_DQATTACH(mp, sip, 0); | 2498 | error = XFS_QM_DQATTACH(mp, sip, 0); |
2511 | if (!error && sip != tdp) | 2499 | if (!error && sip != tdp) |
2512 | error = XFS_QM_DQATTACH(mp, tdp, 0); | 2500 | error = XFS_QM_DQATTACH(mp, tdp, 0); |
2513 | if (error) | 2501 | if (error) |
2514 | goto std_return; | 2502 | goto std_return; |
2515 | 2503 | ||
2516 | tp = xfs_trans_alloc(mp, XFS_TRANS_LINK); | 2504 | tp = xfs_trans_alloc(mp, XFS_TRANS_LINK); |
2517 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | 2505 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
2518 | resblks = XFS_LINK_SPACE_RES(mp, target_name->len); | 2506 | resblks = XFS_LINK_SPACE_RES(mp, target_name->len); |
2519 | error = xfs_trans_reserve(tp, resblks, XFS_LINK_LOG_RES(mp), 0, | 2507 | error = xfs_trans_reserve(tp, resblks, XFS_LINK_LOG_RES(mp), 0, |
2520 | XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT); | 2508 | XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT); |
2521 | if (error == ENOSPC) { | 2509 | if (error == ENOSPC) { |
2522 | resblks = 0; | 2510 | resblks = 0; |
2523 | error = xfs_trans_reserve(tp, 0, XFS_LINK_LOG_RES(mp), 0, | 2511 | error = xfs_trans_reserve(tp, 0, XFS_LINK_LOG_RES(mp), 0, |
2524 | XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT); | 2512 | XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT); |
2525 | } | 2513 | } |
2526 | if (error) { | 2514 | if (error) { |
2527 | cancel_flags = 0; | 2515 | cancel_flags = 0; |
2528 | goto error_return; | 2516 | goto error_return; |
2529 | } | 2517 | } |
2530 | 2518 | ||
2531 | if (sip->i_ino < tdp->i_ino) { | 2519 | if (sip->i_ino < tdp->i_ino) { |
2532 | ips[0] = sip; | 2520 | ips[0] = sip; |
2533 | ips[1] = tdp; | 2521 | ips[1] = tdp; |
2534 | } else { | 2522 | } else { |
2535 | ips[0] = tdp; | 2523 | ips[0] = tdp; |
2536 | ips[1] = sip; | 2524 | ips[1] = sip; |
2537 | } | 2525 | } |
2538 | 2526 | ||
2539 | xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); | 2527 | xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); |
2540 | 2528 | ||
2541 | /* | 2529 | /* |
2542 | * Increment vnode ref counts since xfs_trans_commit & | 2530 | * Increment vnode ref counts since xfs_trans_commit & |
2543 | * xfs_trans_cancel will both unlock the inodes and | 2531 | * xfs_trans_cancel will both unlock the inodes and |
2544 | * decrement the associated ref counts. | 2532 | * decrement the associated ref counts. |
2545 | */ | 2533 | */ |
2546 | IHOLD(sip); | 2534 | IHOLD(sip); |
2547 | IHOLD(tdp); | 2535 | IHOLD(tdp); |
2548 | xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL); | 2536 | xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL); |
2549 | xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL); | 2537 | xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL); |
2550 | 2538 | ||
2551 | /* | 2539 | /* |
2552 | * If the source has too many links, we can't make any more to it. | 2540 | * If the source has too many links, we can't make any more to it. |
2553 | */ | 2541 | */ |
2554 | if (sip->i_d.di_nlink >= XFS_MAXLINK) { | 2542 | if (sip->i_d.di_nlink >= XFS_MAXLINK) { |
2555 | error = XFS_ERROR(EMLINK); | 2543 | error = XFS_ERROR(EMLINK); |
2556 | goto error_return; | 2544 | goto error_return; |
2557 | } | 2545 | } |
2558 | 2546 | ||
2559 | /* | 2547 | /* |
2560 | * If we are using project inheritance, we only allow hard link | 2548 | * If we are using project inheritance, we only allow hard link |
2561 | * creation in our tree when the project IDs are the same; else | 2549 | * creation in our tree when the project IDs are the same; else |
2562 | * the tree quota mechanism could be circumvented. | 2550 | * the tree quota mechanism could be circumvented. |
2563 | */ | 2551 | */ |
2564 | if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && | 2552 | if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && |
2565 | (tdp->i_d.di_projid != sip->i_d.di_projid))) { | 2553 | (tdp->i_d.di_projid != sip->i_d.di_projid))) { |
2566 | error = XFS_ERROR(EXDEV); | 2554 | error = XFS_ERROR(EXDEV); |
2567 | goto error_return; | 2555 | goto error_return; |
2568 | } | 2556 | } |
2569 | 2557 | ||
2570 | error = xfs_dir_canenter(tp, tdp, target_name, resblks); | 2558 | error = xfs_dir_canenter(tp, tdp, target_name, resblks); |
2571 | if (error) | 2559 | if (error) |
2572 | goto error_return; | 2560 | goto error_return; |
2573 | 2561 | ||
2574 | XFS_BMAP_INIT(&free_list, &first_block); | 2562 | XFS_BMAP_INIT(&free_list, &first_block); |
2575 | 2563 | ||
2576 | error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino, | 2564 | error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino, |
2577 | &first_block, &free_list, resblks); | 2565 | &first_block, &free_list, resblks); |
2578 | if (error) | 2566 | if (error) |
2579 | goto abort_return; | 2567 | goto abort_return; |
2580 | xfs_ichgtime(tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 2568 | xfs_ichgtime(tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
2581 | tdp->i_gen++; | 2569 | tdp->i_gen++; |
2582 | xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE); | 2570 | xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE); |
2583 | 2571 | ||
2584 | error = xfs_bumplink(tp, sip); | 2572 | error = xfs_bumplink(tp, sip); |
2585 | if (error) | 2573 | if (error) |
2586 | goto abort_return; | 2574 | goto abort_return; |
2587 | 2575 | ||
2588 | /* | 2576 | /* |
2589 | * If this is a synchronous mount, make sure that the | 2577 | * If this is a synchronous mount, make sure that the |
2590 | * link transaction goes to disk before returning to | 2578 | * link transaction goes to disk before returning to |
2591 | * the user. | 2579 | * the user. |
2592 | */ | 2580 | */ |
2593 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | 2581 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { |
2594 | xfs_trans_set_sync(tp); | 2582 | xfs_trans_set_sync(tp); |
2595 | } | 2583 | } |
2596 | 2584 | ||
2597 | error = xfs_bmap_finish (&tp, &free_list, &committed); | 2585 | error = xfs_bmap_finish (&tp, &free_list, &committed); |
2598 | if (error) { | 2586 | if (error) { |
2599 | xfs_bmap_cancel(&free_list); | 2587 | xfs_bmap_cancel(&free_list); |
2600 | goto abort_return; | 2588 | goto abort_return; |
2601 | } | 2589 | } |
2602 | 2590 | ||
2603 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 2591 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
2604 | if (error) | 2592 | if (error) |
2605 | goto std_return; | 2593 | goto std_return; |
2606 | 2594 | ||
2607 | /* Fall through to std_return with error = 0. */ | 2595 | /* Fall through to std_return with error = 0. */ |
2608 | std_return: | 2596 | std_return: |
2609 | if (DM_EVENT_ENABLED(sip, DM_EVENT_POSTLINK)) { | 2597 | if (DM_EVENT_ENABLED(sip, DM_EVENT_POSTLINK)) { |
2610 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTLINK, | 2598 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTLINK, |
2611 | tdp, DM_RIGHT_NULL, | 2599 | tdp, DM_RIGHT_NULL, |
2612 | sip, DM_RIGHT_NULL, | 2600 | sip, DM_RIGHT_NULL, |
2613 | target_name->name, NULL, 0, error, 0); | 2601 | target_name->name, NULL, 0, error, 0); |
2614 | } | 2602 | } |
2615 | return error; | 2603 | return error; |
2616 | 2604 | ||
2617 | abort_return: | 2605 | abort_return: |
2618 | cancel_flags |= XFS_TRANS_ABORT; | 2606 | cancel_flags |= XFS_TRANS_ABORT; |
2619 | /* FALLTHROUGH */ | 2607 | /* FALLTHROUGH */ |
2620 | 2608 | ||
2621 | error_return: | 2609 | error_return: |
2622 | xfs_trans_cancel(tp, cancel_flags); | 2610 | xfs_trans_cancel(tp, cancel_flags); |
2623 | goto std_return; | 2611 | goto std_return; |
2624 | } | 2612 | } |
2625 | 2613 | ||
2626 | 2614 | ||
2627 | int | 2615 | int |
2628 | xfs_mkdir( | 2616 | xfs_mkdir( |
2629 | xfs_inode_t *dp, | 2617 | xfs_inode_t *dp, |
2630 | struct xfs_name *dir_name, | 2618 | struct xfs_name *dir_name, |
2631 | mode_t mode, | 2619 | mode_t mode, |
2632 | xfs_inode_t **ipp, | 2620 | xfs_inode_t **ipp, |
2633 | cred_t *credp) | 2621 | cred_t *credp) |
2634 | { | 2622 | { |
2635 | xfs_mount_t *mp = dp->i_mount; | 2623 | xfs_mount_t *mp = dp->i_mount; |
2636 | xfs_inode_t *cdp; /* inode of created dir */ | 2624 | xfs_inode_t *cdp; /* inode of created dir */ |
2637 | xfs_trans_t *tp; | 2625 | xfs_trans_t *tp; |
2638 | int cancel_flags; | 2626 | int cancel_flags; |
2639 | int error; | 2627 | int error; |
2640 | int committed; | 2628 | int committed; |
2641 | xfs_bmap_free_t free_list; | 2629 | xfs_bmap_free_t free_list; |
2642 | xfs_fsblock_t first_block; | 2630 | xfs_fsblock_t first_block; |
2643 | boolean_t unlock_dp_on_error = B_FALSE; | 2631 | boolean_t unlock_dp_on_error = B_FALSE; |
2644 | boolean_t created = B_FALSE; | 2632 | boolean_t created = B_FALSE; |
2645 | int dm_event_sent = 0; | 2633 | int dm_event_sent = 0; |
2646 | xfs_prid_t prid; | 2634 | xfs_prid_t prid; |
2647 | struct xfs_dquot *udqp, *gdqp; | 2635 | struct xfs_dquot *udqp, *gdqp; |
2648 | uint resblks; | 2636 | uint resblks; |
2649 | 2637 | ||
2650 | if (XFS_FORCED_SHUTDOWN(mp)) | 2638 | if (XFS_FORCED_SHUTDOWN(mp)) |
2651 | return XFS_ERROR(EIO); | 2639 | return XFS_ERROR(EIO); |
2652 | 2640 | ||
2653 | tp = NULL; | 2641 | tp = NULL; |
2654 | 2642 | ||
2655 | if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) { | 2643 | if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) { |
2656 | error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE, | 2644 | error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE, |
2657 | dp, DM_RIGHT_NULL, NULL, | 2645 | dp, DM_RIGHT_NULL, NULL, |
2658 | DM_RIGHT_NULL, dir_name->name, NULL, | 2646 | DM_RIGHT_NULL, dir_name->name, NULL, |
2659 | mode, 0, 0); | 2647 | mode, 0, 0); |
2660 | if (error) | 2648 | if (error) |
2661 | return error; | 2649 | return error; |
2662 | dm_event_sent = 1; | 2650 | dm_event_sent = 1; |
2663 | } | 2651 | } |
2664 | 2652 | ||
2665 | /* Return through std_return after this point. */ | 2653 | /* Return through std_return after this point. */ |
2666 | 2654 | ||
2667 | xfs_itrace_entry(dp); | 2655 | xfs_itrace_entry(dp); |
2668 | 2656 | ||
2669 | mp = dp->i_mount; | 2657 | mp = dp->i_mount; |
2670 | udqp = gdqp = NULL; | 2658 | udqp = gdqp = NULL; |
2671 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) | 2659 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) |
2672 | prid = dp->i_d.di_projid; | 2660 | prid = dp->i_d.di_projid; |
2673 | else | 2661 | else |
2674 | prid = (xfs_prid_t)dfltprid; | 2662 | prid = (xfs_prid_t)dfltprid; |
2675 | 2663 | ||
2676 | /* | 2664 | /* |
2677 | * Make sure that we have allocated dquot(s) on disk. | 2665 | * Make sure that we have allocated dquot(s) on disk. |
2678 | */ | 2666 | */ |
2679 | error = XFS_QM_DQVOPALLOC(mp, dp, | 2667 | error = XFS_QM_DQVOPALLOC(mp, dp, |
2680 | current_fsuid(credp), current_fsgid(credp), prid, | 2668 | current_fsuid(credp), current_fsgid(credp), prid, |
2681 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); | 2669 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); |
2682 | if (error) | 2670 | if (error) |
2683 | goto std_return; | 2671 | goto std_return; |
2684 | 2672 | ||
2685 | tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR); | 2673 | tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR); |
2686 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | 2674 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
2687 | resblks = XFS_MKDIR_SPACE_RES(mp, dir_name->len); | 2675 | resblks = XFS_MKDIR_SPACE_RES(mp, dir_name->len); |
2688 | error = xfs_trans_reserve(tp, resblks, XFS_MKDIR_LOG_RES(mp), 0, | 2676 | error = xfs_trans_reserve(tp, resblks, XFS_MKDIR_LOG_RES(mp), 0, |
2689 | XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT); | 2677 | XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT); |
2690 | if (error == ENOSPC) { | 2678 | if (error == ENOSPC) { |
2691 | resblks = 0; | 2679 | resblks = 0; |
2692 | error = xfs_trans_reserve(tp, 0, XFS_MKDIR_LOG_RES(mp), 0, | 2680 | error = xfs_trans_reserve(tp, 0, XFS_MKDIR_LOG_RES(mp), 0, |
2693 | XFS_TRANS_PERM_LOG_RES, | 2681 | XFS_TRANS_PERM_LOG_RES, |
2694 | XFS_MKDIR_LOG_COUNT); | 2682 | XFS_MKDIR_LOG_COUNT); |
2695 | } | 2683 | } |
2696 | if (error) { | 2684 | if (error) { |
2697 | cancel_flags = 0; | 2685 | cancel_flags = 0; |
2698 | goto error_return; | 2686 | goto error_return; |
2699 | } | 2687 | } |
2700 | 2688 | ||
2701 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); | 2689 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); |
2702 | unlock_dp_on_error = B_TRUE; | 2690 | unlock_dp_on_error = B_TRUE; |
2703 | 2691 | ||
2704 | /* | 2692 | /* |
2705 | * Check for directory link count overflow. | 2693 | * Check for directory link count overflow. |
2706 | */ | 2694 | */ |
2707 | if (dp->i_d.di_nlink >= XFS_MAXLINK) { | 2695 | if (dp->i_d.di_nlink >= XFS_MAXLINK) { |
2708 | error = XFS_ERROR(EMLINK); | 2696 | error = XFS_ERROR(EMLINK); |
2709 | goto error_return; | 2697 | goto error_return; |
2710 | } | 2698 | } |
2711 | 2699 | ||
2712 | /* | 2700 | /* |
2713 | * Reserve disk quota and the inode. | 2701 | * Reserve disk quota and the inode. |
2714 | */ | 2702 | */ |
2715 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0); | 2703 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0); |
2716 | if (error) | 2704 | if (error) |
2717 | goto error_return; | 2705 | goto error_return; |
2718 | 2706 | ||
2719 | error = xfs_dir_canenter(tp, dp, dir_name, resblks); | 2707 | error = xfs_dir_canenter(tp, dp, dir_name, resblks); |
2720 | if (error) | 2708 | if (error) |
2721 | goto error_return; | 2709 | goto error_return; |
2722 | /* | 2710 | /* |
2723 | * create the directory inode. | 2711 | * create the directory inode. |
2724 | */ | 2712 | */ |
2725 | error = xfs_dir_ialloc(&tp, dp, mode, 2, | 2713 | error = xfs_dir_ialloc(&tp, dp, mode, 2, |
2726 | 0, credp, prid, resblks > 0, | 2714 | 0, credp, prid, resblks > 0, |
2727 | &cdp, NULL); | 2715 | &cdp, NULL); |
2728 | if (error) { | 2716 | if (error) { |
2729 | if (error == ENOSPC) | 2717 | if (error == ENOSPC) |
2730 | goto error_return; | 2718 | goto error_return; |
2731 | goto abort_return; | 2719 | goto abort_return; |
2732 | } | 2720 | } |
2733 | xfs_itrace_ref(cdp); | 2721 | xfs_itrace_ref(cdp); |
2734 | 2722 | ||
2735 | /* | 2723 | /* |
2736 | * Now we add the directory inode to the transaction. | 2724 | * Now we add the directory inode to the transaction. |
2737 | * We waited until now since xfs_dir_ialloc might start | 2725 | * We waited until now since xfs_dir_ialloc might start |
2738 | * a new transaction. Had we joined the transaction | 2726 | * a new transaction. Had we joined the transaction |
2739 | * earlier, the locks might have gotten released. An error | 2727 | * earlier, the locks might have gotten released. An error |
2740 | * from here on will result in the transaction cancel | 2728 | * from here on will result in the transaction cancel |
2741 | * unlocking dp so don't do it explicitly in the error path. | 2729 | * unlocking dp so don't do it explicitly in the error path. |
2742 | */ | 2730 | */ |
2743 | IHOLD(dp); | 2731 | IHOLD(dp); |
2744 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); | 2732 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); |
2745 | unlock_dp_on_error = B_FALSE; | 2733 | unlock_dp_on_error = B_FALSE; |
2746 | 2734 | ||
2747 | XFS_BMAP_INIT(&free_list, &first_block); | 2735 | XFS_BMAP_INIT(&free_list, &first_block); |
2748 | 2736 | ||
2749 | error = xfs_dir_createname(tp, dp, dir_name, cdp->i_ino, | 2737 | error = xfs_dir_createname(tp, dp, dir_name, cdp->i_ino, |
2750 | &first_block, &free_list, resblks ? | 2738 | &first_block, &free_list, resblks ? |
2751 | resblks - XFS_IALLOC_SPACE_RES(mp) : 0); | 2739 | resblks - XFS_IALLOC_SPACE_RES(mp) : 0); |
2752 | if (error) { | 2740 | if (error) { |
2753 | ASSERT(error != ENOSPC); | 2741 | ASSERT(error != ENOSPC); |
2754 | goto error1; | 2742 | goto error1; |
2755 | } | 2743 | } |
2756 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 2744 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
2757 | 2745 | ||
2758 | /* | 2746 | /* |
2759 | * Bump the in memory version number of the parent directory | 2747 | * Bump the in memory version number of the parent directory |
2760 | * so that other processes accessing it will recognize that | 2748 | * so that other processes accessing it will recognize that |
2761 | * the directory has changed. | 2749 | * the directory has changed. |
2762 | */ | 2750 | */ |
2763 | dp->i_gen++; | 2751 | dp->i_gen++; |
2764 | 2752 | ||
2765 | error = xfs_dir_init(tp, cdp, dp); | 2753 | error = xfs_dir_init(tp, cdp, dp); |
2766 | if (error) | 2754 | if (error) |
2767 | goto error2; | 2755 | goto error2; |
2768 | 2756 | ||
2769 | cdp->i_gen = 1; | 2757 | cdp->i_gen = 1; |
2770 | error = xfs_bumplink(tp, dp); | 2758 | error = xfs_bumplink(tp, dp); |
2771 | if (error) | 2759 | if (error) |
2772 | goto error2; | 2760 | goto error2; |
2773 | 2761 | ||
2774 | created = B_TRUE; | 2762 | created = B_TRUE; |
2775 | 2763 | ||
2776 | *ipp = cdp; | 2764 | *ipp = cdp; |
2777 | IHOLD(cdp); | 2765 | IHOLD(cdp); |
2778 | 2766 | ||
2779 | /* | 2767 | /* |
2780 | * Attach the dquots to the new inode and modify the icount incore. | 2768 | * Attach the dquots to the new inode and modify the icount incore. |
2781 | */ | 2769 | */ |
2782 | XFS_QM_DQVOPCREATE(mp, tp, cdp, udqp, gdqp); | 2770 | XFS_QM_DQVOPCREATE(mp, tp, cdp, udqp, gdqp); |
2783 | 2771 | ||
2784 | /* | 2772 | /* |
2785 | * If this is a synchronous mount, make sure that the | 2773 | * If this is a synchronous mount, make sure that the |
2786 | * mkdir transaction goes to disk before returning to | 2774 | * mkdir transaction goes to disk before returning to |
2787 | * the user. | 2775 | * the user. |
2788 | */ | 2776 | */ |
2789 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | 2777 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { |
2790 | xfs_trans_set_sync(tp); | 2778 | xfs_trans_set_sync(tp); |
2791 | } | 2779 | } |
2792 | 2780 | ||
2793 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 2781 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
2794 | if (error) { | 2782 | if (error) { |
2795 | IRELE(cdp); | 2783 | IRELE(cdp); |
2796 | goto error2; | 2784 | goto error2; |
2797 | } | 2785 | } |
2798 | 2786 | ||
2799 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 2787 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
2800 | XFS_QM_DQRELE(mp, udqp); | 2788 | XFS_QM_DQRELE(mp, udqp); |
2801 | XFS_QM_DQRELE(mp, gdqp); | 2789 | XFS_QM_DQRELE(mp, gdqp); |
2802 | if (error) { | 2790 | if (error) { |
2803 | IRELE(cdp); | 2791 | IRELE(cdp); |
2804 | } | 2792 | } |
2805 | 2793 | ||
2806 | /* Fall through to std_return with error = 0 or errno from | 2794 | /* Fall through to std_return with error = 0 or errno from |
2807 | * xfs_trans_commit. */ | 2795 | * xfs_trans_commit. */ |
2808 | 2796 | ||
2809 | std_return: | 2797 | std_return: |
2810 | if ((created || (error != 0 && dm_event_sent != 0)) && | 2798 | if ((created || (error != 0 && dm_event_sent != 0)) && |
2811 | DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) { | 2799 | DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) { |
2812 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, | 2800 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, |
2813 | dp, DM_RIGHT_NULL, | 2801 | dp, DM_RIGHT_NULL, |
2814 | created ? cdp : NULL, | 2802 | created ? cdp : NULL, |
2815 | DM_RIGHT_NULL, | 2803 | DM_RIGHT_NULL, |
2816 | dir_name->name, NULL, | 2804 | dir_name->name, NULL, |
2817 | mode, error, 0); | 2805 | mode, error, 0); |
2818 | } | 2806 | } |
2819 | return error; | 2807 | return error; |
2820 | 2808 | ||
2821 | error2: | 2809 | error2: |
2822 | error1: | 2810 | error1: |
2823 | xfs_bmap_cancel(&free_list); | 2811 | xfs_bmap_cancel(&free_list); |
2824 | abort_return: | 2812 | abort_return: |
2825 | cancel_flags |= XFS_TRANS_ABORT; | 2813 | cancel_flags |= XFS_TRANS_ABORT; |
2826 | error_return: | 2814 | error_return: |
2827 | xfs_trans_cancel(tp, cancel_flags); | 2815 | xfs_trans_cancel(tp, cancel_flags); |
2828 | XFS_QM_DQRELE(mp, udqp); | 2816 | XFS_QM_DQRELE(mp, udqp); |
2829 | XFS_QM_DQRELE(mp, gdqp); | 2817 | XFS_QM_DQRELE(mp, gdqp); |
2830 | 2818 | ||
2831 | if (unlock_dp_on_error) | 2819 | if (unlock_dp_on_error) |
2832 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 2820 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
2833 | 2821 | ||
2834 | goto std_return; | 2822 | goto std_return; |
2835 | } | 2823 | } |
2836 | 2824 | ||
2837 | int | 2825 | int |
2838 | xfs_rmdir( | 2826 | xfs_rmdir( |
2839 | xfs_inode_t *dp, | 2827 | xfs_inode_t *dp, |
2840 | struct xfs_name *name, | 2828 | struct xfs_name *name, |
2841 | xfs_inode_t *cdp) | 2829 | xfs_inode_t *cdp) |
2842 | { | 2830 | { |
2843 | bhv_vnode_t *dir_vp = XFS_ITOV(dp); | 2831 | bhv_vnode_t *dir_vp = XFS_ITOV(dp); |
2844 | xfs_mount_t *mp = dp->i_mount; | 2832 | xfs_mount_t *mp = dp->i_mount; |
2845 | xfs_trans_t *tp; | 2833 | xfs_trans_t *tp; |
2846 | int error; | 2834 | int error; |
2847 | xfs_bmap_free_t free_list; | 2835 | xfs_bmap_free_t free_list; |
2848 | xfs_fsblock_t first_block; | 2836 | xfs_fsblock_t first_block; |
2849 | int cancel_flags; | 2837 | int cancel_flags; |
2850 | int committed; | 2838 | int committed; |
2851 | int last_cdp_link; | 2839 | int last_cdp_link; |
2852 | uint resblks; | 2840 | uint resblks; |
2853 | 2841 | ||
2854 | xfs_itrace_entry(dp); | 2842 | xfs_itrace_entry(dp); |
2855 | 2843 | ||
2856 | if (XFS_FORCED_SHUTDOWN(mp)) | 2844 | if (XFS_FORCED_SHUTDOWN(mp)) |
2857 | return XFS_ERROR(EIO); | 2845 | return XFS_ERROR(EIO); |
2858 | 2846 | ||
2859 | if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) { | 2847 | if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) { |
2860 | error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, | 2848 | error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, |
2861 | dp, DM_RIGHT_NULL, | 2849 | dp, DM_RIGHT_NULL, |
2862 | NULL, DM_RIGHT_NULL, name->name, | 2850 | NULL, DM_RIGHT_NULL, name->name, |
2863 | NULL, cdp->i_d.di_mode, 0, 0); | 2851 | NULL, cdp->i_d.di_mode, 0, 0); |
2864 | if (error) | 2852 | if (error) |
2865 | return XFS_ERROR(error); | 2853 | return XFS_ERROR(error); |
2866 | } | 2854 | } |
2867 | 2855 | ||
2868 | /* | 2856 | /* |
2869 | * We need to get a reference to cdp before we get our log | 2857 | * We need to get a reference to cdp before we get our log |
2870 | * reservation. The reason for this is that we cannot call | 2858 | * reservation. The reason for this is that we cannot call |
2871 | * xfs_iget for an inode for which we do not have a reference | 2859 | * xfs_iget for an inode for which we do not have a reference |
2872 | * once we've acquired a log reservation. This is because the | 2860 | * once we've acquired a log reservation. This is because the |
2873 | * inode we are trying to get might be in xfs_inactive going | 2861 | * inode we are trying to get might be in xfs_inactive going |
2874 | * for a log reservation. Since we'll have to wait for the | 2862 | * for a log reservation. Since we'll have to wait for the |
2875 | * inactive code to complete before returning from xfs_iget, | 2863 | * inactive code to complete before returning from xfs_iget, |
2876 | * we need to make sure that we don't have log space reserved | 2864 | * we need to make sure that we don't have log space reserved |
2877 | * when we call xfs_iget. Instead we get an unlocked reference | 2865 | * when we call xfs_iget. Instead we get an unlocked reference |
2878 | * to the inode before getting our log reservation. | 2866 | * to the inode before getting our log reservation. |
2879 | */ | 2867 | */ |
2880 | IHOLD(cdp); | 2868 | IHOLD(cdp); |
2881 | 2869 | ||
2882 | /* | 2870 | /* |
2883 | * Get the dquots for the inodes. | 2871 | * Get the dquots for the inodes. |
2884 | */ | 2872 | */ |
2885 | error = XFS_QM_DQATTACH(mp, dp, 0); | 2873 | error = XFS_QM_DQATTACH(mp, dp, 0); |
2886 | if (!error && dp != cdp) | 2874 | if (!error && dp != cdp) |
2887 | error = XFS_QM_DQATTACH(mp, cdp, 0); | 2875 | error = XFS_QM_DQATTACH(mp, cdp, 0); |
2888 | if (error) { | 2876 | if (error) { |
2889 | IRELE(cdp); | 2877 | IRELE(cdp); |
2890 | REMOVE_DEBUG_TRACE(__LINE__); | 2878 | REMOVE_DEBUG_TRACE(__LINE__); |
2891 | goto std_return; | 2879 | goto std_return; |
2892 | } | 2880 | } |
2893 | 2881 | ||
2894 | tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR); | 2882 | tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR); |
2895 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | 2883 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
2896 | /* | 2884 | /* |
2897 | * We try to get the real space reservation first, | 2885 | * We try to get the real space reservation first, |
2898 | * allowing for directory btree deletion(s) implying | 2886 | * allowing for directory btree deletion(s) implying |
2899 | * possible bmap insert(s). If we can't get the space | 2887 | * possible bmap insert(s). If we can't get the space |
2900 | * reservation then we use 0 instead, and avoid the bmap | 2888 | * reservation then we use 0 instead, and avoid the bmap |
2901 | * btree insert(s) in the directory code by, if the bmap | 2889 | * btree insert(s) in the directory code by, if the bmap |
2902 | * insert tries to happen, instead trimming the LAST | 2890 | * insert tries to happen, instead trimming the LAST |
2903 | * block from the directory. | 2891 | * block from the directory. |
2904 | */ | 2892 | */ |
2905 | resblks = XFS_REMOVE_SPACE_RES(mp); | 2893 | resblks = XFS_REMOVE_SPACE_RES(mp); |
2906 | error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, | 2894 | error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, |
2907 | XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); | 2895 | XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); |
2908 | if (error == ENOSPC) { | 2896 | if (error == ENOSPC) { |
2909 | resblks = 0; | 2897 | resblks = 0; |
2910 | error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, | 2898 | error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, |
2911 | XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); | 2899 | XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); |
2912 | } | 2900 | } |
2913 | if (error) { | 2901 | if (error) { |
2914 | ASSERT(error != ENOSPC); | 2902 | ASSERT(error != ENOSPC); |
2915 | cancel_flags = 0; | 2903 | cancel_flags = 0; |
2916 | IRELE(cdp); | 2904 | IRELE(cdp); |
2917 | goto error_return; | 2905 | goto error_return; |
2918 | } | 2906 | } |
2919 | XFS_BMAP_INIT(&free_list, &first_block); | 2907 | XFS_BMAP_INIT(&free_list, &first_block); |
2920 | 2908 | ||
2921 | /* | 2909 | /* |
2922 | * Now lock the child directory inode and the parent directory | 2910 | * Now lock the child directory inode and the parent directory |
2923 | * inode in the proper order. This will take care of validating | 2911 | * inode in the proper order. This will take care of validating |
2924 | * that the directory entry for the child directory inode has | 2912 | * that the directory entry for the child directory inode has |
2925 | * not changed while we were obtaining a log reservation. | 2913 | * not changed while we were obtaining a log reservation. |
2926 | */ | 2914 | */ |
2927 | error = xfs_lock_dir_and_entry(dp, cdp); | 2915 | error = xfs_lock_dir_and_entry(dp, cdp); |
2928 | if (error) { | 2916 | if (error) { |
2929 | xfs_trans_cancel(tp, cancel_flags); | 2917 | xfs_trans_cancel(tp, cancel_flags); |
2930 | IRELE(cdp); | 2918 | IRELE(cdp); |
2931 | goto std_return; | 2919 | goto std_return; |
2932 | } | 2920 | } |
2933 | 2921 | ||
2934 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); | 2922 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); |
2935 | if (dp != cdp) { | 2923 | if (dp != cdp) { |
2936 | /* | 2924 | /* |
2937 | * Only increment the parent directory vnode count if | 2925 | * Only increment the parent directory vnode count if |
2938 | * we didn't bump it in looking up cdp. The only time | 2926 | * we didn't bump it in looking up cdp. The only time |
2939 | * we don't bump it is when we're looking up ".". | 2927 | * we don't bump it is when we're looking up ".". |
2940 | */ | 2928 | */ |
2941 | VN_HOLD(dir_vp); | 2929 | VN_HOLD(dir_vp); |
2942 | } | 2930 | } |
2943 | 2931 | ||
2944 | xfs_itrace_ref(cdp); | 2932 | xfs_itrace_ref(cdp); |
2945 | xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL); | 2933 | xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL); |
2946 | 2934 | ||
2947 | ASSERT(cdp->i_d.di_nlink >= 2); | 2935 | ASSERT(cdp->i_d.di_nlink >= 2); |
2948 | if (cdp->i_d.di_nlink != 2) { | 2936 | if (cdp->i_d.di_nlink != 2) { |
2949 | error = XFS_ERROR(ENOTEMPTY); | 2937 | error = XFS_ERROR(ENOTEMPTY); |
2950 | goto error_return; | 2938 | goto error_return; |
2951 | } | 2939 | } |
2952 | if (!xfs_dir_isempty(cdp)) { | 2940 | if (!xfs_dir_isempty(cdp)) { |
2953 | error = XFS_ERROR(ENOTEMPTY); | 2941 | error = XFS_ERROR(ENOTEMPTY); |
2954 | goto error_return; | 2942 | goto error_return; |
2955 | } | 2943 | } |
2956 | 2944 | ||
2957 | error = xfs_dir_removename(tp, dp, name, cdp->i_ino, | 2945 | error = xfs_dir_removename(tp, dp, name, cdp->i_ino, |
2958 | &first_block, &free_list, resblks); | 2946 | &first_block, &free_list, resblks); |
2959 | if (error) | 2947 | if (error) |
2960 | goto error1; | 2948 | goto error1; |
2961 | 2949 | ||
2962 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 2950 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
2963 | 2951 | ||
2964 | /* | 2952 | /* |
2965 | * Bump the in memory generation count on the parent | 2953 | * Bump the in memory generation count on the parent |
2966 | * directory so that other can know that it has changed. | 2954 | * directory so that other can know that it has changed. |
2967 | */ | 2955 | */ |
2968 | dp->i_gen++; | 2956 | dp->i_gen++; |
2969 | 2957 | ||
2970 | /* | 2958 | /* |
2971 | * Drop the link from cdp's "..". | 2959 | * Drop the link from cdp's "..". |
2972 | */ | 2960 | */ |
2973 | error = xfs_droplink(tp, dp); | 2961 | error = xfs_droplink(tp, dp); |
2974 | if (error) { | 2962 | if (error) { |
2975 | goto error1; | 2963 | goto error1; |
2976 | } | 2964 | } |
2977 | 2965 | ||
2978 | /* | 2966 | /* |
2979 | * Drop the link from dp to cdp. | 2967 | * Drop the link from dp to cdp. |
2980 | */ | 2968 | */ |
2981 | error = xfs_droplink(tp, cdp); | 2969 | error = xfs_droplink(tp, cdp); |
2982 | if (error) { | 2970 | if (error) { |
2983 | goto error1; | 2971 | goto error1; |
2984 | } | 2972 | } |
2985 | 2973 | ||
2986 | /* | 2974 | /* |
2987 | * Drop the "." link from cdp to self. | 2975 | * Drop the "." link from cdp to self. |
2988 | */ | 2976 | */ |
2989 | error = xfs_droplink(tp, cdp); | 2977 | error = xfs_droplink(tp, cdp); |
2990 | if (error) { | 2978 | if (error) { |
2991 | goto error1; | 2979 | goto error1; |
2992 | } | 2980 | } |
2993 | 2981 | ||
2994 | /* Determine these before committing transaction */ | 2982 | /* Determine these before committing transaction */ |
2995 | last_cdp_link = (cdp)->i_d.di_nlink==0; | 2983 | last_cdp_link = (cdp)->i_d.di_nlink==0; |
2996 | 2984 | ||
2997 | /* | 2985 | /* |
2998 | * Take an extra ref on the child vnode so that it | 2986 | * Take an extra ref on the child vnode so that it |
2999 | * does not go to xfs_inactive() from within the commit. | 2987 | * does not go to xfs_inactive() from within the commit. |
3000 | */ | 2988 | */ |
3001 | IHOLD(cdp); | 2989 | IHOLD(cdp); |
3002 | 2990 | ||
3003 | /* | 2991 | /* |
3004 | * If this is a synchronous mount, make sure that the | 2992 | * If this is a synchronous mount, make sure that the |
3005 | * rmdir transaction goes to disk before returning to | 2993 | * rmdir transaction goes to disk before returning to |
3006 | * the user. | 2994 | * the user. |
3007 | */ | 2995 | */ |
3008 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | 2996 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { |
3009 | xfs_trans_set_sync(tp); | 2997 | xfs_trans_set_sync(tp); |
3010 | } | 2998 | } |
3011 | 2999 | ||
3012 | error = xfs_bmap_finish (&tp, &free_list, &committed); | 3000 | error = xfs_bmap_finish (&tp, &free_list, &committed); |
3013 | if (error) { | 3001 | if (error) { |
3014 | xfs_bmap_cancel(&free_list); | 3002 | xfs_bmap_cancel(&free_list); |
3015 | xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | | 3003 | xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | |
3016 | XFS_TRANS_ABORT)); | 3004 | XFS_TRANS_ABORT)); |
3017 | IRELE(cdp); | 3005 | IRELE(cdp); |
3018 | goto std_return; | 3006 | goto std_return; |
3019 | } | 3007 | } |
3020 | 3008 | ||
3021 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 3009 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
3022 | if (error) { | 3010 | if (error) { |
3023 | IRELE(cdp); | 3011 | IRELE(cdp); |
3024 | goto std_return; | 3012 | goto std_return; |
3025 | } | 3013 | } |
3026 | 3014 | ||
3027 | 3015 | ||
3028 | IRELE(cdp); | 3016 | IRELE(cdp); |
3029 | 3017 | ||
3030 | /* Fall through to std_return with error = 0 or the errno | 3018 | /* Fall through to std_return with error = 0 or the errno |
3031 | * from xfs_trans_commit. */ | 3019 | * from xfs_trans_commit. */ |
3032 | std_return: | 3020 | std_return: |
3033 | if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { | 3021 | if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { |
3034 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, | 3022 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, |
3035 | dp, DM_RIGHT_NULL, | 3023 | dp, DM_RIGHT_NULL, |
3036 | NULL, DM_RIGHT_NULL, | 3024 | NULL, DM_RIGHT_NULL, |
3037 | name->name, NULL, cdp->i_d.di_mode, | 3025 | name->name, NULL, cdp->i_d.di_mode, |
3038 | error, 0); | 3026 | error, 0); |
3039 | } | 3027 | } |
3040 | return error; | 3028 | return error; |
3041 | 3029 | ||
3042 | error1: | 3030 | error1: |
3043 | xfs_bmap_cancel(&free_list); | 3031 | xfs_bmap_cancel(&free_list); |
3044 | cancel_flags |= XFS_TRANS_ABORT; | 3032 | cancel_flags |= XFS_TRANS_ABORT; |
3045 | /* FALLTHROUGH */ | 3033 | /* FALLTHROUGH */ |
3046 | 3034 | ||
3047 | error_return: | 3035 | error_return: |
3048 | xfs_trans_cancel(tp, cancel_flags); | 3036 | xfs_trans_cancel(tp, cancel_flags); |
3049 | goto std_return; | 3037 | goto std_return; |
3050 | } | 3038 | } |
3051 | 3039 | ||
3052 | int | 3040 | int |
3053 | xfs_symlink( | 3041 | xfs_symlink( |
3054 | xfs_inode_t *dp, | 3042 | xfs_inode_t *dp, |
3055 | struct xfs_name *link_name, | 3043 | struct xfs_name *link_name, |
3056 | const char *target_path, | 3044 | const char *target_path, |
3057 | mode_t mode, | 3045 | mode_t mode, |
3058 | xfs_inode_t **ipp, | 3046 | xfs_inode_t **ipp, |
3059 | cred_t *credp) | 3047 | cred_t *credp) |
3060 | { | 3048 | { |
3061 | xfs_mount_t *mp = dp->i_mount; | 3049 | xfs_mount_t *mp = dp->i_mount; |
3062 | xfs_trans_t *tp; | 3050 | xfs_trans_t *tp; |
3063 | xfs_inode_t *ip; | 3051 | xfs_inode_t *ip; |
3064 | int error; | 3052 | int error; |
3065 | int pathlen; | 3053 | int pathlen; |
3066 | xfs_bmap_free_t free_list; | 3054 | xfs_bmap_free_t free_list; |
3067 | xfs_fsblock_t first_block; | 3055 | xfs_fsblock_t first_block; |
3068 | boolean_t unlock_dp_on_error = B_FALSE; | 3056 | boolean_t unlock_dp_on_error = B_FALSE; |
3069 | uint cancel_flags; | 3057 | uint cancel_flags; |
3070 | int committed; | 3058 | int committed; |
3071 | xfs_fileoff_t first_fsb; | 3059 | xfs_fileoff_t first_fsb; |
3072 | xfs_filblks_t fs_blocks; | 3060 | xfs_filblks_t fs_blocks; |
3073 | int nmaps; | 3061 | int nmaps; |
3074 | xfs_bmbt_irec_t mval[SYMLINK_MAPS]; | 3062 | xfs_bmbt_irec_t mval[SYMLINK_MAPS]; |
3075 | xfs_daddr_t d; | 3063 | xfs_daddr_t d; |
3076 | const char *cur_chunk; | 3064 | const char *cur_chunk; |
3077 | int byte_cnt; | 3065 | int byte_cnt; |
3078 | int n; | 3066 | int n; |
3079 | xfs_buf_t *bp; | 3067 | xfs_buf_t *bp; |
3080 | xfs_prid_t prid; | 3068 | xfs_prid_t prid; |
3081 | struct xfs_dquot *udqp, *gdqp; | 3069 | struct xfs_dquot *udqp, *gdqp; |
3082 | uint resblks; | 3070 | uint resblks; |
3083 | 3071 | ||
3084 | *ipp = NULL; | 3072 | *ipp = NULL; |
3085 | error = 0; | 3073 | error = 0; |
3086 | ip = NULL; | 3074 | ip = NULL; |
3087 | tp = NULL; | 3075 | tp = NULL; |
3088 | 3076 | ||
3089 | xfs_itrace_entry(dp); | 3077 | xfs_itrace_entry(dp); |
3090 | 3078 | ||
3091 | if (XFS_FORCED_SHUTDOWN(mp)) | 3079 | if (XFS_FORCED_SHUTDOWN(mp)) |
3092 | return XFS_ERROR(EIO); | 3080 | return XFS_ERROR(EIO); |
3093 | 3081 | ||
3094 | /* | 3082 | /* |
3095 | * Check component lengths of the target path name. | 3083 | * Check component lengths of the target path name. |
3096 | */ | 3084 | */ |
3097 | pathlen = strlen(target_path); | 3085 | pathlen = strlen(target_path); |
3098 | if (pathlen >= MAXPATHLEN) /* total string too long */ | 3086 | if (pathlen >= MAXPATHLEN) /* total string too long */ |
3099 | return XFS_ERROR(ENAMETOOLONG); | 3087 | return XFS_ERROR(ENAMETOOLONG); |
3100 | 3088 | ||
3101 | if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) { | 3089 | if (DM_EVENT_ENABLED(dp, DM_EVENT_SYMLINK)) { |
3102 | error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dp, | 3090 | error = XFS_SEND_NAMESP(mp, DM_EVENT_SYMLINK, dp, |
3103 | DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, | 3091 | DM_RIGHT_NULL, NULL, DM_RIGHT_NULL, |
3104 | link_name->name, target_path, 0, 0, 0); | 3092 | link_name->name, target_path, 0, 0, 0); |
3105 | if (error) | 3093 | if (error) |
3106 | return error; | 3094 | return error; |
3107 | } | 3095 | } |
3108 | 3096 | ||
3109 | /* Return through std_return after this point. */ | 3097 | /* Return through std_return after this point. */ |
3110 | 3098 | ||
3111 | udqp = gdqp = NULL; | 3099 | udqp = gdqp = NULL; |
3112 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) | 3100 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) |
3113 | prid = dp->i_d.di_projid; | 3101 | prid = dp->i_d.di_projid; |
3114 | else | 3102 | else |
3115 | prid = (xfs_prid_t)dfltprid; | 3103 | prid = (xfs_prid_t)dfltprid; |
3116 | 3104 | ||
3117 | /* | 3105 | /* |
3118 | * Make sure that we have allocated dquot(s) on disk. | 3106 | * Make sure that we have allocated dquot(s) on disk. |
3119 | */ | 3107 | */ |
3120 | error = XFS_QM_DQVOPALLOC(mp, dp, | 3108 | error = XFS_QM_DQVOPALLOC(mp, dp, |
3121 | current_fsuid(credp), current_fsgid(credp), prid, | 3109 | current_fsuid(credp), current_fsgid(credp), prid, |
3122 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); | 3110 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); |
3123 | if (error) | 3111 | if (error) |
3124 | goto std_return; | 3112 | goto std_return; |
3125 | 3113 | ||
3126 | tp = xfs_trans_alloc(mp, XFS_TRANS_SYMLINK); | 3114 | tp = xfs_trans_alloc(mp, XFS_TRANS_SYMLINK); |
3127 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | 3115 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
3128 | /* | 3116 | /* |
3129 | * The symlink will fit into the inode data fork? | 3117 | * The symlink will fit into the inode data fork? |
3130 | * There can't be any attributes so we get the whole variable part. | 3118 | * There can't be any attributes so we get the whole variable part. |
3131 | */ | 3119 | */ |
3132 | if (pathlen <= XFS_LITINO(mp)) | 3120 | if (pathlen <= XFS_LITINO(mp)) |
3133 | fs_blocks = 0; | 3121 | fs_blocks = 0; |
3134 | else | 3122 | else |
3135 | fs_blocks = XFS_B_TO_FSB(mp, pathlen); | 3123 | fs_blocks = XFS_B_TO_FSB(mp, pathlen); |
3136 | resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks); | 3124 | resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks); |
3137 | error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0, | 3125 | error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0, |
3138 | XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT); | 3126 | XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT); |
3139 | if (error == ENOSPC && fs_blocks == 0) { | 3127 | if (error == ENOSPC && fs_blocks == 0) { |
3140 | resblks = 0; | 3128 | resblks = 0; |
3141 | error = xfs_trans_reserve(tp, 0, XFS_SYMLINK_LOG_RES(mp), 0, | 3129 | error = xfs_trans_reserve(tp, 0, XFS_SYMLINK_LOG_RES(mp), 0, |
3142 | XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT); | 3130 | XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT); |
3143 | } | 3131 | } |
3144 | if (error) { | 3132 | if (error) { |
3145 | cancel_flags = 0; | 3133 | cancel_flags = 0; |
3146 | goto error_return; | 3134 | goto error_return; |
3147 | } | 3135 | } |
3148 | 3136 | ||
3149 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); | 3137 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); |
3150 | unlock_dp_on_error = B_TRUE; | 3138 | unlock_dp_on_error = B_TRUE; |
3151 | 3139 | ||
3152 | /* | 3140 | /* |
3153 | * Check whether the directory allows new symlinks or not. | 3141 | * Check whether the directory allows new symlinks or not. |
3154 | */ | 3142 | */ |
3155 | if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) { | 3143 | if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) { |
3156 | error = XFS_ERROR(EPERM); | 3144 | error = XFS_ERROR(EPERM); |
3157 | goto error_return; | 3145 | goto error_return; |
3158 | } | 3146 | } |
3159 | 3147 | ||
3160 | /* | 3148 | /* |
3161 | * Reserve disk quota : blocks and inode. | 3149 | * Reserve disk quota : blocks and inode. |
3162 | */ | 3150 | */ |
3163 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0); | 3151 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0); |
3164 | if (error) | 3152 | if (error) |
3165 | goto error_return; | 3153 | goto error_return; |
3166 | 3154 | ||
3167 | /* | 3155 | /* |
3168 | * Check for ability to enter directory entry, if no space reserved. | 3156 | * Check for ability to enter directory entry, if no space reserved. |
3169 | */ | 3157 | */ |
3170 | error = xfs_dir_canenter(tp, dp, link_name, resblks); | 3158 | error = xfs_dir_canenter(tp, dp, link_name, resblks); |
3171 | if (error) | 3159 | if (error) |
3172 | goto error_return; | 3160 | goto error_return; |
3173 | /* | 3161 | /* |
3174 | * Initialize the bmap freelist prior to calling either | 3162 | * Initialize the bmap freelist prior to calling either |
3175 | * bmapi or the directory create code. | 3163 | * bmapi or the directory create code. |
3176 | */ | 3164 | */ |
3177 | XFS_BMAP_INIT(&free_list, &first_block); | 3165 | XFS_BMAP_INIT(&free_list, &first_block); |
3178 | 3166 | ||
3179 | /* | 3167 | /* |
3180 | * Allocate an inode for the symlink. | 3168 | * Allocate an inode for the symlink. |
3181 | */ | 3169 | */ |
3182 | error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), | 3170 | error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), |
3183 | 1, 0, credp, prid, resblks > 0, &ip, NULL); | 3171 | 1, 0, credp, prid, resblks > 0, &ip, NULL); |
3184 | if (error) { | 3172 | if (error) { |
3185 | if (error == ENOSPC) | 3173 | if (error == ENOSPC) |
3186 | goto error_return; | 3174 | goto error_return; |
3187 | goto error1; | 3175 | goto error1; |
3188 | } | 3176 | } |
3189 | xfs_itrace_ref(ip); | 3177 | xfs_itrace_ref(ip); |
3190 | 3178 | ||
3191 | /* | 3179 | /* |
3192 | * An error after we've joined dp to the transaction will result in the | 3180 | * An error after we've joined dp to the transaction will result in the |
3193 | * transaction cancel unlocking dp so don't do it explicitly in the | 3181 | * transaction cancel unlocking dp so don't do it explicitly in the |
3194 | * error path. | 3182 | * error path. |
3195 | */ | 3183 | */ |
3196 | IHOLD(dp); | 3184 | IHOLD(dp); |
3197 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); | 3185 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); |
3198 | unlock_dp_on_error = B_FALSE; | 3186 | unlock_dp_on_error = B_FALSE; |
3199 | 3187 | ||
3200 | /* | 3188 | /* |
3201 | * Also attach the dquot(s) to it, if applicable. | 3189 | * Also attach the dquot(s) to it, if applicable. |
3202 | */ | 3190 | */ |
3203 | XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp); | 3191 | XFS_QM_DQVOPCREATE(mp, tp, ip, udqp, gdqp); |
3204 | 3192 | ||
3205 | if (resblks) | 3193 | if (resblks) |
3206 | resblks -= XFS_IALLOC_SPACE_RES(mp); | 3194 | resblks -= XFS_IALLOC_SPACE_RES(mp); |
3207 | /* | 3195 | /* |
3208 | * If the symlink will fit into the inode, write it inline. | 3196 | * If the symlink will fit into the inode, write it inline. |
3209 | */ | 3197 | */ |
3210 | if (pathlen <= XFS_IFORK_DSIZE(ip)) { | 3198 | if (pathlen <= XFS_IFORK_DSIZE(ip)) { |
3211 | xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK); | 3199 | xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK); |
3212 | memcpy(ip->i_df.if_u1.if_data, target_path, pathlen); | 3200 | memcpy(ip->i_df.if_u1.if_data, target_path, pathlen); |
3213 | ip->i_d.di_size = pathlen; | 3201 | ip->i_d.di_size = pathlen; |
3214 | 3202 | ||
3215 | /* | 3203 | /* |
3216 | * The inode was initially created in extent format. | 3204 | * The inode was initially created in extent format. |
3217 | */ | 3205 | */ |
3218 | ip->i_df.if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT); | 3206 | ip->i_df.if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT); |
3219 | ip->i_df.if_flags |= XFS_IFINLINE; | 3207 | ip->i_df.if_flags |= XFS_IFINLINE; |
3220 | 3208 | ||
3221 | ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; | 3209 | ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; |
3222 | xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE); | 3210 | xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE); |
3223 | 3211 | ||
3224 | } else { | 3212 | } else { |
3225 | first_fsb = 0; | 3213 | first_fsb = 0; |
3226 | nmaps = SYMLINK_MAPS; | 3214 | nmaps = SYMLINK_MAPS; |
3227 | 3215 | ||
3228 | error = xfs_bmapi(tp, ip, first_fsb, fs_blocks, | 3216 | error = xfs_bmapi(tp, ip, first_fsb, fs_blocks, |
3229 | XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, | 3217 | XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, |
3230 | &first_block, resblks, mval, &nmaps, | 3218 | &first_block, resblks, mval, &nmaps, |
3231 | &free_list, NULL); | 3219 | &free_list, NULL); |
3232 | if (error) { | 3220 | if (error) { |
3233 | goto error1; | 3221 | goto error1; |
3234 | } | 3222 | } |
3235 | 3223 | ||
3236 | if (resblks) | 3224 | if (resblks) |
3237 | resblks -= fs_blocks; | 3225 | resblks -= fs_blocks; |
3238 | ip->i_d.di_size = pathlen; | 3226 | ip->i_d.di_size = pathlen; |
3239 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 3227 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
3240 | 3228 | ||
3241 | cur_chunk = target_path; | 3229 | cur_chunk = target_path; |
3242 | for (n = 0; n < nmaps; n++) { | 3230 | for (n = 0; n < nmaps; n++) { |
3243 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); | 3231 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); |
3244 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); | 3232 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); |
3245 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, | 3233 | bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, |
3246 | BTOBB(byte_cnt), 0); | 3234 | BTOBB(byte_cnt), 0); |
3247 | ASSERT(bp && !XFS_BUF_GETERROR(bp)); | 3235 | ASSERT(bp && !XFS_BUF_GETERROR(bp)); |
3248 | if (pathlen < byte_cnt) { | 3236 | if (pathlen < byte_cnt) { |
3249 | byte_cnt = pathlen; | 3237 | byte_cnt = pathlen; |
3250 | } | 3238 | } |
3251 | pathlen -= byte_cnt; | 3239 | pathlen -= byte_cnt; |
3252 | 3240 | ||
3253 | memcpy(XFS_BUF_PTR(bp), cur_chunk, byte_cnt); | 3241 | memcpy(XFS_BUF_PTR(bp), cur_chunk, byte_cnt); |
3254 | cur_chunk += byte_cnt; | 3242 | cur_chunk += byte_cnt; |
3255 | 3243 | ||
3256 | xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1); | 3244 | xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1); |
3257 | } | 3245 | } |
3258 | } | 3246 | } |
3259 | 3247 | ||
3260 | /* | 3248 | /* |
3261 | * Create the directory entry for the symlink. | 3249 | * Create the directory entry for the symlink. |
3262 | */ | 3250 | */ |
3263 | error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, | 3251 | error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, |
3264 | &first_block, &free_list, resblks); | 3252 | &first_block, &free_list, resblks); |
3265 | if (error) | 3253 | if (error) |
3266 | goto error1; | 3254 | goto error1; |
3267 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 3255 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
3268 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | 3256 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); |
3269 | 3257 | ||
3270 | /* | 3258 | /* |
3271 | * Bump the in memory version number of the parent directory | 3259 | * Bump the in memory version number of the parent directory |
3272 | * so that other processes accessing it will recognize that | 3260 | * so that other processes accessing it will recognize that |
3273 | * the directory has changed. | 3261 | * the directory has changed. |
3274 | */ | 3262 | */ |
3275 | dp->i_gen++; | 3263 | dp->i_gen++; |
3276 | 3264 | ||
3277 | /* | 3265 | /* |
3278 | * If this is a synchronous mount, make sure that the | 3266 | * If this is a synchronous mount, make sure that the |
3279 | * symlink transaction goes to disk before returning to | 3267 | * symlink transaction goes to disk before returning to |
3280 | * the user. | 3268 | * the user. |
3281 | */ | 3269 | */ |
3282 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | 3270 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { |
3283 | xfs_trans_set_sync(tp); | 3271 | xfs_trans_set_sync(tp); |
3284 | } | 3272 | } |
3285 | 3273 | ||
3286 | /* | 3274 | /* |
3287 | * xfs_trans_commit normally decrements the vnode ref count | 3275 | * xfs_trans_commit normally decrements the vnode ref count |
3288 | * when it unlocks the inode. Since we want to return the | 3276 | * when it unlocks the inode. Since we want to return the |
3289 | * vnode to the caller, we bump the vnode ref count now. | 3277 | * vnode to the caller, we bump the vnode ref count now. |
3290 | */ | 3278 | */ |
3291 | IHOLD(ip); | 3279 | IHOLD(ip); |
3292 | 3280 | ||
3293 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 3281 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
3294 | if (error) { | 3282 | if (error) { |
3295 | goto error2; | 3283 | goto error2; |
3296 | } | 3284 | } |
3297 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 3285 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
3298 | XFS_QM_DQRELE(mp, udqp); | 3286 | XFS_QM_DQRELE(mp, udqp); |
3299 | XFS_QM_DQRELE(mp, gdqp); | 3287 | XFS_QM_DQRELE(mp, gdqp); |
3300 | 3288 | ||
3301 | /* Fall through to std_return with error = 0 or errno from | 3289 | /* Fall through to std_return with error = 0 or errno from |
3302 | * xfs_trans_commit */ | 3290 | * xfs_trans_commit */ |
3303 | std_return: | 3291 | std_return: |
3304 | if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTSYMLINK)) { | 3292 | if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTSYMLINK)) { |
3305 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTSYMLINK, | 3293 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTSYMLINK, |
3306 | dp, DM_RIGHT_NULL, | 3294 | dp, DM_RIGHT_NULL, |
3307 | error ? NULL : ip, | 3295 | error ? NULL : ip, |
3308 | DM_RIGHT_NULL, link_name->name, | 3296 | DM_RIGHT_NULL, link_name->name, |
3309 | target_path, 0, error, 0); | 3297 | target_path, 0, error, 0); |
3310 | } | 3298 | } |
3311 | 3299 | ||
3312 | if (!error) | 3300 | if (!error) |
3313 | *ipp = ip; | 3301 | *ipp = ip; |
3314 | return error; | 3302 | return error; |
3315 | 3303 | ||
3316 | error2: | 3304 | error2: |
3317 | IRELE(ip); | 3305 | IRELE(ip); |
3318 | error1: | 3306 | error1: |
3319 | xfs_bmap_cancel(&free_list); | 3307 | xfs_bmap_cancel(&free_list); |
3320 | cancel_flags |= XFS_TRANS_ABORT; | 3308 | cancel_flags |= XFS_TRANS_ABORT; |
3321 | error_return: | 3309 | error_return: |
3322 | xfs_trans_cancel(tp, cancel_flags); | 3310 | xfs_trans_cancel(tp, cancel_flags); |
3323 | XFS_QM_DQRELE(mp, udqp); | 3311 | XFS_QM_DQRELE(mp, udqp); |
3324 | XFS_QM_DQRELE(mp, gdqp); | 3312 | XFS_QM_DQRELE(mp, gdqp); |
3325 | 3313 | ||
3326 | if (unlock_dp_on_error) | 3314 | if (unlock_dp_on_error) |
3327 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 3315 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
3328 | 3316 | ||
3329 | goto std_return; | 3317 | goto std_return; |
3330 | } | 3318 | } |
3331 | 3319 | ||
3332 | int | 3320 | int |
3333 | xfs_inode_flush( | 3321 | xfs_inode_flush( |
3334 | xfs_inode_t *ip, | 3322 | xfs_inode_t *ip, |
3335 | int flags) | 3323 | int flags) |
3336 | { | 3324 | { |
3337 | xfs_mount_t *mp = ip->i_mount; | 3325 | xfs_mount_t *mp = ip->i_mount; |
3338 | int error = 0; | 3326 | int error = 0; |
3339 | 3327 | ||
3340 | if (XFS_FORCED_SHUTDOWN(mp)) | 3328 | if (XFS_FORCED_SHUTDOWN(mp)) |
3341 | return XFS_ERROR(EIO); | 3329 | return XFS_ERROR(EIO); |
3342 | 3330 | ||
3343 | /* | 3331 | /* |
3344 | * Bypass inodes which have already been cleaned by | 3332 | * Bypass inodes which have already been cleaned by |
3345 | * the inode flush clustering code inside xfs_iflush | 3333 | * the inode flush clustering code inside xfs_iflush |
3346 | */ | 3334 | */ |
3347 | if (xfs_inode_clean(ip)) | 3335 | if (xfs_inode_clean(ip)) |
3348 | return 0; | 3336 | return 0; |
3349 | 3337 | ||
3350 | /* | 3338 | /* |
3351 | * We make this non-blocking if the inode is contended, | 3339 | * We make this non-blocking if the inode is contended, |
3352 | * return EAGAIN to indicate to the caller that they | 3340 | * return EAGAIN to indicate to the caller that they |
3353 | * did not succeed. This prevents the flush path from | 3341 | * did not succeed. This prevents the flush path from |
3354 | * blocking on inodes inside another operation right | 3342 | * blocking on inodes inside another operation right |
3355 | * now, they get caught later by xfs_sync. | 3343 | * now, they get caught later by xfs_sync. |
3356 | */ | 3344 | */ |
3357 | if (flags & FLUSH_SYNC) { | 3345 | if (flags & FLUSH_SYNC) { |
3358 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 3346 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
3359 | xfs_iflock(ip); | 3347 | xfs_iflock(ip); |
3360 | } else if (xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) { | 3348 | } else if (xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) { |
3361 | if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip)) { | 3349 | if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip)) { |
3362 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 3350 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
3363 | return EAGAIN; | 3351 | return EAGAIN; |
3364 | } | 3352 | } |
3365 | } else { | 3353 | } else { |
3366 | return EAGAIN; | 3354 | return EAGAIN; |
3367 | } | 3355 | } |
3368 | 3356 | ||
3369 | error = xfs_iflush(ip, (flags & FLUSH_SYNC) ? XFS_IFLUSH_SYNC | 3357 | error = xfs_iflush(ip, (flags & FLUSH_SYNC) ? XFS_IFLUSH_SYNC |
3370 | : XFS_IFLUSH_ASYNC_NOBLOCK); | 3358 | : XFS_IFLUSH_ASYNC_NOBLOCK); |
3371 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 3359 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
3372 | 3360 | ||
3373 | return error; | 3361 | return error; |
3374 | } | 3362 | } |
3375 | 3363 | ||
3376 | 3364 | ||
3377 | int | 3365 | int |
3378 | xfs_set_dmattrs( | 3366 | xfs_set_dmattrs( |
3379 | xfs_inode_t *ip, | 3367 | xfs_inode_t *ip, |
3380 | u_int evmask, | 3368 | u_int evmask, |
3381 | u_int16_t state) | 3369 | u_int16_t state) |
3382 | { | 3370 | { |
3383 | xfs_mount_t *mp = ip->i_mount; | 3371 | xfs_mount_t *mp = ip->i_mount; |
3384 | xfs_trans_t *tp; | 3372 | xfs_trans_t *tp; |
3385 | int error; | 3373 | int error; |
3386 | 3374 | ||
3387 | if (!capable(CAP_SYS_ADMIN)) | 3375 | if (!capable(CAP_SYS_ADMIN)) |
3388 | return XFS_ERROR(EPERM); | 3376 | return XFS_ERROR(EPERM); |
3389 | 3377 | ||
3390 | if (XFS_FORCED_SHUTDOWN(mp)) | 3378 | if (XFS_FORCED_SHUTDOWN(mp)) |
3391 | return XFS_ERROR(EIO); | 3379 | return XFS_ERROR(EIO); |
3392 | 3380 | ||
3393 | tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); | 3381 | tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); |
3394 | error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0); | 3382 | error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0); |
3395 | if (error) { | 3383 | if (error) { |
3396 | xfs_trans_cancel(tp, 0); | 3384 | xfs_trans_cancel(tp, 0); |
3397 | return error; | 3385 | return error; |
3398 | } | 3386 | } |
3399 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 3387 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
3400 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 3388 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
3401 | 3389 | ||
3402 | ip->i_d.di_dmevmask = evmask; | 3390 | ip->i_d.di_dmevmask = evmask; |
3403 | ip->i_d.di_dmstate = state; | 3391 | ip->i_d.di_dmstate = state; |
3404 | 3392 | ||
3405 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 3393 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
3406 | IHOLD(ip); | 3394 | IHOLD(ip); |
3407 | error = xfs_trans_commit(tp, 0); | 3395 | error = xfs_trans_commit(tp, 0); |
3408 | 3396 | ||
3409 | return error; | 3397 | return error; |
3410 | } | 3398 | } |
3411 | 3399 | ||
3412 | int | 3400 | int |
3413 | xfs_reclaim( | 3401 | xfs_reclaim( |
3414 | xfs_inode_t *ip) | 3402 | xfs_inode_t *ip) |
3415 | { | 3403 | { |
3416 | bhv_vnode_t *vp = XFS_ITOV(ip); | 3404 | bhv_vnode_t *vp = XFS_ITOV(ip); |
3417 | 3405 | ||
3418 | xfs_itrace_entry(ip); | 3406 | xfs_itrace_entry(ip); |
3419 | 3407 | ||
3420 | ASSERT(!VN_MAPPED(vp)); | 3408 | ASSERT(!VN_MAPPED(vp)); |
3421 | 3409 | ||
3422 | /* bad inode, get out here ASAP */ | 3410 | /* bad inode, get out here ASAP */ |
3423 | if (VN_BAD(vp)) { | 3411 | if (VN_BAD(vp)) { |
3424 | xfs_ireclaim(ip); | 3412 | xfs_ireclaim(ip); |
3425 | return 0; | 3413 | return 0; |
3426 | } | 3414 | } |
3427 | 3415 | ||
3428 | vn_iowait(ip); | 3416 | vn_iowait(ip); |
3429 | 3417 | ||
3430 | ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0); | 3418 | ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0); |
3431 | 3419 | ||
3432 | /* | 3420 | /* |
3433 | * Make sure the atime in the XFS inode is correct before freeing the | 3421 | * Make sure the atime in the XFS inode is correct before freeing the |
3434 | * Linux inode. | 3422 | * Linux inode. |
3435 | */ | 3423 | */ |
3436 | xfs_synchronize_atime(ip); | 3424 | xfs_synchronize_atime(ip); |
3437 | 3425 | ||
3438 | /* | 3426 | /* |
3439 | * If we have nothing to flush with this inode then complete the | 3427 | * If we have nothing to flush with this inode then complete the |
3440 | * teardown now, otherwise break the link between the xfs inode and the | 3428 | * teardown now, otherwise break the link between the xfs inode and the |
3441 | * linux inode and clean up the xfs inode later. This avoids flushing | 3429 | * linux inode and clean up the xfs inode later. This avoids flushing |
3442 | * the inode to disk during the delete operation itself. | 3430 | * the inode to disk during the delete operation itself. |
3443 | * | 3431 | * |
3444 | * When breaking the link, we need to set the XFS_IRECLAIMABLE flag | 3432 | * When breaking the link, we need to set the XFS_IRECLAIMABLE flag |
3445 | * first to ensure that xfs_iunpin() will never see an xfs inode | 3433 | * first to ensure that xfs_iunpin() will never see an xfs inode |
3446 | * that has a linux inode being reclaimed. Synchronisation is provided | 3434 | * that has a linux inode being reclaimed. Synchronisation is provided |
3447 | * by the i_flags_lock. | 3435 | * by the i_flags_lock. |
3448 | */ | 3436 | */ |
3449 | if (!ip->i_update_core && (ip->i_itemp == NULL)) { | 3437 | if (!ip->i_update_core && (ip->i_itemp == NULL)) { |
3450 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 3438 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
3451 | xfs_iflock(ip); | 3439 | xfs_iflock(ip); |
3452 | return xfs_finish_reclaim(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC); | 3440 | return xfs_finish_reclaim(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC); |
3453 | } else { | 3441 | } else { |
3454 | xfs_mount_t *mp = ip->i_mount; | 3442 | xfs_mount_t *mp = ip->i_mount; |
3455 | 3443 | ||
3456 | /* Protect sync and unpin from us */ | 3444 | /* Protect sync and unpin from us */ |
3457 | XFS_MOUNT_ILOCK(mp); | 3445 | XFS_MOUNT_ILOCK(mp); |
3458 | spin_lock(&ip->i_flags_lock); | 3446 | spin_lock(&ip->i_flags_lock); |
3459 | __xfs_iflags_set(ip, XFS_IRECLAIMABLE); | 3447 | __xfs_iflags_set(ip, XFS_IRECLAIMABLE); |
3460 | vn_to_inode(vp)->i_private = NULL; | 3448 | vn_to_inode(vp)->i_private = NULL; |
3461 | ip->i_vnode = NULL; | 3449 | ip->i_vnode = NULL; |
3462 | spin_unlock(&ip->i_flags_lock); | 3450 | spin_unlock(&ip->i_flags_lock); |
3463 | list_add_tail(&ip->i_reclaim, &mp->m_del_inodes); | 3451 | list_add_tail(&ip->i_reclaim, &mp->m_del_inodes); |
3464 | XFS_MOUNT_IUNLOCK(mp); | 3452 | XFS_MOUNT_IUNLOCK(mp); |
3465 | } | 3453 | } |
3466 | return 0; | 3454 | return 0; |
3467 | } | 3455 | } |
3468 | 3456 | ||
3469 | int | 3457 | int |
3470 | xfs_finish_reclaim( | 3458 | xfs_finish_reclaim( |
3471 | xfs_inode_t *ip, | 3459 | xfs_inode_t *ip, |
3472 | int locked, | 3460 | int locked, |
3473 | int sync_mode) | 3461 | int sync_mode) |
3474 | { | 3462 | { |
3475 | xfs_perag_t *pag = xfs_get_perag(ip->i_mount, ip->i_ino); | 3463 | xfs_perag_t *pag = xfs_get_perag(ip->i_mount, ip->i_ino); |
3476 | bhv_vnode_t *vp = XFS_ITOV_NULL(ip); | 3464 | bhv_vnode_t *vp = XFS_ITOV_NULL(ip); |
3477 | int error; | 3465 | int error; |
3478 | 3466 | ||
3479 | if (vp && VN_BAD(vp)) | 3467 | if (vp && VN_BAD(vp)) |
3480 | goto reclaim; | 3468 | goto reclaim; |
3481 | 3469 | ||
3482 | /* The hash lock here protects a thread in xfs_iget_core from | 3470 | /* The hash lock here protects a thread in xfs_iget_core from |
3483 | * racing with us on linking the inode back with a vnode. | 3471 | * racing with us on linking the inode back with a vnode. |
3484 | * Once we have the XFS_IRECLAIM flag set it will not touch | 3472 | * Once we have the XFS_IRECLAIM flag set it will not touch |
3485 | * us. | 3473 | * us. |
3486 | */ | 3474 | */ |
3487 | write_lock(&pag->pag_ici_lock); | 3475 | write_lock(&pag->pag_ici_lock); |
3488 | spin_lock(&ip->i_flags_lock); | 3476 | spin_lock(&ip->i_flags_lock); |
3489 | if (__xfs_iflags_test(ip, XFS_IRECLAIM) || | 3477 | if (__xfs_iflags_test(ip, XFS_IRECLAIM) || |
3490 | (!__xfs_iflags_test(ip, XFS_IRECLAIMABLE) && vp == NULL)) { | 3478 | (!__xfs_iflags_test(ip, XFS_IRECLAIMABLE) && vp == NULL)) { |
3491 | spin_unlock(&ip->i_flags_lock); | 3479 | spin_unlock(&ip->i_flags_lock); |
3492 | write_unlock(&pag->pag_ici_lock); | 3480 | write_unlock(&pag->pag_ici_lock); |
3493 | if (locked) { | 3481 | if (locked) { |
3494 | xfs_ifunlock(ip); | 3482 | xfs_ifunlock(ip); |
3495 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 3483 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
3496 | } | 3484 | } |
3497 | return 1; | 3485 | return 1; |
3498 | } | 3486 | } |
3499 | __xfs_iflags_set(ip, XFS_IRECLAIM); | 3487 | __xfs_iflags_set(ip, XFS_IRECLAIM); |
3500 | spin_unlock(&ip->i_flags_lock); | 3488 | spin_unlock(&ip->i_flags_lock); |
3501 | write_unlock(&pag->pag_ici_lock); | 3489 | write_unlock(&pag->pag_ici_lock); |
3502 | xfs_put_perag(ip->i_mount, pag); | 3490 | xfs_put_perag(ip->i_mount, pag); |
3503 | 3491 | ||
3504 | /* | 3492 | /* |
3505 | * If the inode is still dirty, then flush it out. If the inode | 3493 | * If the inode is still dirty, then flush it out. If the inode |
3506 | * is not in the AIL, then it will be OK to flush it delwri as | 3494 | * is not in the AIL, then it will be OK to flush it delwri as |
3507 | * long as xfs_iflush() does not keep any references to the inode. | 3495 | * long as xfs_iflush() does not keep any references to the inode. |
3508 | * We leave that decision up to xfs_iflush() since it has the | 3496 | * We leave that decision up to xfs_iflush() since it has the |
3509 | * knowledge of whether it's OK to simply do a delwri flush of | 3497 | * knowledge of whether it's OK to simply do a delwri flush of |
3510 | * the inode or whether we need to wait until the inode is | 3498 | * the inode or whether we need to wait until the inode is |
3511 | * pulled from the AIL. | 3499 | * pulled from the AIL. |
3512 | * We get the flush lock regardless, though, just to make sure | 3500 | * We get the flush lock regardless, though, just to make sure |
3513 | * we don't free it while it is being flushed. | 3501 | * we don't free it while it is being flushed. |
3514 | */ | 3502 | */ |
3515 | if (!locked) { | 3503 | if (!locked) { |
3516 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 3504 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
3517 | xfs_iflock(ip); | 3505 | xfs_iflock(ip); |
3518 | } | 3506 | } |
3519 | 3507 | ||
3520 | if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { | 3508 | if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { |
3521 | if (ip->i_update_core || | 3509 | if (ip->i_update_core || |
3522 | ((ip->i_itemp != NULL) && | 3510 | ((ip->i_itemp != NULL) && |
3523 | (ip->i_itemp->ili_format.ilf_fields != 0))) { | 3511 | (ip->i_itemp->ili_format.ilf_fields != 0))) { |
3524 | error = xfs_iflush(ip, sync_mode); | 3512 | error = xfs_iflush(ip, sync_mode); |
3525 | /* | 3513 | /* |
3526 | * If we hit an error, typically because of filesystem | 3514 | * If we hit an error, typically because of filesystem |
3527 | * shutdown, we don't need to let vn_reclaim to know | 3515 | * shutdown, we don't need to let vn_reclaim to know |
3528 | * because we're gonna reclaim the inode anyway. | 3516 | * because we're gonna reclaim the inode anyway. |
3529 | */ | 3517 | */ |
3530 | if (error) { | 3518 | if (error) { |
3531 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 3519 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
3532 | goto reclaim; | 3520 | goto reclaim; |
3533 | } | 3521 | } |
3534 | xfs_iflock(ip); /* synchronize with xfs_iflush_done */ | 3522 | xfs_iflock(ip); /* synchronize with xfs_iflush_done */ |
3535 | } | 3523 | } |
3536 | 3524 | ||
3537 | ASSERT(ip->i_update_core == 0); | 3525 | ASSERT(ip->i_update_core == 0); |
3538 | ASSERT(ip->i_itemp == NULL || | 3526 | ASSERT(ip->i_itemp == NULL || |
3539 | ip->i_itemp->ili_format.ilf_fields == 0); | 3527 | ip->i_itemp->ili_format.ilf_fields == 0); |
3540 | } | 3528 | } |
3541 | 3529 | ||
3542 | xfs_ifunlock(ip); | 3530 | xfs_ifunlock(ip); |
3543 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 3531 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
3544 | 3532 | ||
3545 | reclaim: | 3533 | reclaim: |
3546 | xfs_ireclaim(ip); | 3534 | xfs_ireclaim(ip); |
3547 | return 0; | 3535 | return 0; |
3548 | } | 3536 | } |
3549 | 3537 | ||
3550 | int | 3538 | int |
3551 | xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock) | 3539 | xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock) |
3552 | { | 3540 | { |
3553 | int purged; | 3541 | int purged; |
3554 | xfs_inode_t *ip, *n; | 3542 | xfs_inode_t *ip, *n; |
3555 | int done = 0; | 3543 | int done = 0; |
3556 | 3544 | ||
3557 | while (!done) { | 3545 | while (!done) { |
3558 | purged = 0; | 3546 | purged = 0; |
3559 | XFS_MOUNT_ILOCK(mp); | 3547 | XFS_MOUNT_ILOCK(mp); |
3560 | list_for_each_entry_safe(ip, n, &mp->m_del_inodes, i_reclaim) { | 3548 | list_for_each_entry_safe(ip, n, &mp->m_del_inodes, i_reclaim) { |
3561 | if (noblock) { | 3549 | if (noblock) { |
3562 | if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) | 3550 | if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) |
3563 | continue; | 3551 | continue; |
3564 | if (xfs_ipincount(ip) || | 3552 | if (xfs_ipincount(ip) || |
3565 | !xfs_iflock_nowait(ip)) { | 3553 | !xfs_iflock_nowait(ip)) { |
3566 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 3554 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
3567 | continue; | 3555 | continue; |
3568 | } | 3556 | } |
3569 | } | 3557 | } |
3570 | XFS_MOUNT_IUNLOCK(mp); | 3558 | XFS_MOUNT_IUNLOCK(mp); |
3571 | if (xfs_finish_reclaim(ip, noblock, | 3559 | if (xfs_finish_reclaim(ip, noblock, |
3572 | XFS_IFLUSH_DELWRI_ELSE_ASYNC)) | 3560 | XFS_IFLUSH_DELWRI_ELSE_ASYNC)) |
3573 | delay(1); | 3561 | delay(1); |
3574 | purged = 1; | 3562 | purged = 1; |
3575 | break; | 3563 | break; |
3576 | } | 3564 | } |
3577 | 3565 | ||
3578 | done = !purged; | 3566 | done = !purged; |
3579 | } | 3567 | } |
3580 | 3568 | ||
3581 | XFS_MOUNT_IUNLOCK(mp); | 3569 | XFS_MOUNT_IUNLOCK(mp); |
3582 | return 0; | 3570 | return 0; |
3583 | } | 3571 | } |
3584 | 3572 | ||
3585 | /* | 3573 | /* |
3586 | * xfs_alloc_file_space() | 3574 | * xfs_alloc_file_space() |
3587 | * This routine allocates disk space for the given file. | 3575 | * This routine allocates disk space for the given file. |
3588 | * | 3576 | * |
3589 | * If alloc_type == 0, this request is for an ALLOCSP type | 3577 | * If alloc_type == 0, this request is for an ALLOCSP type |
3590 | * request which will change the file size. In this case, no | 3578 | * request which will change the file size. In this case, no |
3591 | * DMAPI event will be generated by the call. A TRUNCATE event | 3579 | * DMAPI event will be generated by the call. A TRUNCATE event |
3592 | * will be generated later by xfs_setattr. | 3580 | * will be generated later by xfs_setattr. |
3593 | * | 3581 | * |
3594 | * If alloc_type != 0, this request is for a RESVSP type | 3582 | * If alloc_type != 0, this request is for a RESVSP type |
3595 | * request, and a DMAPI DM_EVENT_WRITE will be generated if the | 3583 | * request, and a DMAPI DM_EVENT_WRITE will be generated if the |
3596 | * lower block boundary byte address is less than the file's | 3584 | * lower block boundary byte address is less than the file's |
3597 | * length. | 3585 | * length. |
3598 | * | 3586 | * |
3599 | * RETURNS: | 3587 | * RETURNS: |
3600 | * 0 on success | 3588 | * 0 on success |
3601 | * errno on error | 3589 | * errno on error |
3602 | * | 3590 | * |
3603 | */ | 3591 | */ |
3604 | STATIC int | 3592 | STATIC int |
3605 | xfs_alloc_file_space( | 3593 | xfs_alloc_file_space( |
3606 | xfs_inode_t *ip, | 3594 | xfs_inode_t *ip, |
3607 | xfs_off_t offset, | 3595 | xfs_off_t offset, |
3608 | xfs_off_t len, | 3596 | xfs_off_t len, |
3609 | int alloc_type, | 3597 | int alloc_type, |
3610 | int attr_flags) | 3598 | int attr_flags) |
3611 | { | 3599 | { |
3612 | xfs_mount_t *mp = ip->i_mount; | 3600 | xfs_mount_t *mp = ip->i_mount; |
3613 | xfs_off_t count; | 3601 | xfs_off_t count; |
3614 | xfs_filblks_t allocated_fsb; | 3602 | xfs_filblks_t allocated_fsb; |
3615 | xfs_filblks_t allocatesize_fsb; | 3603 | xfs_filblks_t allocatesize_fsb; |
3616 | xfs_extlen_t extsz, temp; | 3604 | xfs_extlen_t extsz, temp; |
3617 | xfs_fileoff_t startoffset_fsb; | 3605 | xfs_fileoff_t startoffset_fsb; |
3618 | xfs_fsblock_t firstfsb; | 3606 | xfs_fsblock_t firstfsb; |
3619 | int nimaps; | 3607 | int nimaps; |
3620 | int bmapi_flag; | 3608 | int bmapi_flag; |
3621 | int quota_flag; | 3609 | int quota_flag; |
3622 | int rt; | 3610 | int rt; |
3623 | xfs_trans_t *tp; | 3611 | xfs_trans_t *tp; |
3624 | xfs_bmbt_irec_t imaps[1], *imapp; | 3612 | xfs_bmbt_irec_t imaps[1], *imapp; |
3625 | xfs_bmap_free_t free_list; | 3613 | xfs_bmap_free_t free_list; |
3626 | uint qblocks, resblks, resrtextents; | 3614 | uint qblocks, resblks, resrtextents; |
3627 | int committed; | 3615 | int committed; |
3628 | int error; | 3616 | int error; |
3629 | 3617 | ||
3630 | xfs_itrace_entry(ip); | 3618 | xfs_itrace_entry(ip); |
3631 | 3619 | ||
3632 | if (XFS_FORCED_SHUTDOWN(mp)) | 3620 | if (XFS_FORCED_SHUTDOWN(mp)) |
3633 | return XFS_ERROR(EIO); | 3621 | return XFS_ERROR(EIO); |
3634 | 3622 | ||
3635 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) | 3623 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) |
3636 | return error; | 3624 | return error; |
3637 | 3625 | ||
3638 | if (len <= 0) | 3626 | if (len <= 0) |
3639 | return XFS_ERROR(EINVAL); | 3627 | return XFS_ERROR(EINVAL); |
3640 | 3628 | ||
3641 | rt = XFS_IS_REALTIME_INODE(ip); | 3629 | rt = XFS_IS_REALTIME_INODE(ip); |
3642 | extsz = xfs_get_extsz_hint(ip); | 3630 | extsz = xfs_get_extsz_hint(ip); |
3643 | 3631 | ||
3644 | count = len; | 3632 | count = len; |
3645 | imapp = &imaps[0]; | 3633 | imapp = &imaps[0]; |
3646 | nimaps = 1; | 3634 | nimaps = 1; |
3647 | bmapi_flag = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0); | 3635 | bmapi_flag = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0); |
3648 | startoffset_fsb = XFS_B_TO_FSBT(mp, offset); | 3636 | startoffset_fsb = XFS_B_TO_FSBT(mp, offset); |
3649 | allocatesize_fsb = XFS_B_TO_FSB(mp, count); | 3637 | allocatesize_fsb = XFS_B_TO_FSB(mp, count); |
3650 | 3638 | ||
3651 | /* Generate a DMAPI event if needed. */ | 3639 | /* Generate a DMAPI event if needed. */ |
3652 | if (alloc_type != 0 && offset < ip->i_size && | 3640 | if (alloc_type != 0 && offset < ip->i_size && |
3653 | (attr_flags&ATTR_DMI) == 0 && | 3641 | (attr_flags&ATTR_DMI) == 0 && |
3654 | DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { | 3642 | DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { |
3655 | xfs_off_t end_dmi_offset; | 3643 | xfs_off_t end_dmi_offset; |
3656 | 3644 | ||
3657 | end_dmi_offset = offset+len; | 3645 | end_dmi_offset = offset+len; |
3658 | if (end_dmi_offset > ip->i_size) | 3646 | if (end_dmi_offset > ip->i_size) |
3659 | end_dmi_offset = ip->i_size; | 3647 | end_dmi_offset = ip->i_size; |
3660 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip, offset, | 3648 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip, offset, |
3661 | end_dmi_offset - offset, 0, NULL); | 3649 | end_dmi_offset - offset, 0, NULL); |
3662 | if (error) | 3650 | if (error) |
3663 | return error; | 3651 | return error; |
3664 | } | 3652 | } |
3665 | 3653 | ||
3666 | /* | 3654 | /* |
3667 | * Allocate file space until done or until there is an error | 3655 | * Allocate file space until done or until there is an error |
3668 | */ | 3656 | */ |
3669 | retry: | 3657 | retry: |
3670 | while (allocatesize_fsb && !error) { | 3658 | while (allocatesize_fsb && !error) { |
3671 | xfs_fileoff_t s, e; | 3659 | xfs_fileoff_t s, e; |
3672 | 3660 | ||
3673 | /* | 3661 | /* |
3674 | * Determine space reservations for data/realtime. | 3662 | * Determine space reservations for data/realtime. |
3675 | */ | 3663 | */ |
3676 | if (unlikely(extsz)) { | 3664 | if (unlikely(extsz)) { |
3677 | s = startoffset_fsb; | 3665 | s = startoffset_fsb; |
3678 | do_div(s, extsz); | 3666 | do_div(s, extsz); |
3679 | s *= extsz; | 3667 | s *= extsz; |
3680 | e = startoffset_fsb + allocatesize_fsb; | 3668 | e = startoffset_fsb + allocatesize_fsb; |
3681 | if ((temp = do_mod(startoffset_fsb, extsz))) | 3669 | if ((temp = do_mod(startoffset_fsb, extsz))) |
3682 | e += temp; | 3670 | e += temp; |
3683 | if ((temp = do_mod(e, extsz))) | 3671 | if ((temp = do_mod(e, extsz))) |
3684 | e += extsz - temp; | 3672 | e += extsz - temp; |
3685 | } else { | 3673 | } else { |
3686 | s = 0; | 3674 | s = 0; |
3687 | e = allocatesize_fsb; | 3675 | e = allocatesize_fsb; |
3688 | } | 3676 | } |
3689 | 3677 | ||
3690 | if (unlikely(rt)) { | 3678 | if (unlikely(rt)) { |
3691 | resrtextents = qblocks = (uint)(e - s); | 3679 | resrtextents = qblocks = (uint)(e - s); |
3692 | resrtextents /= mp->m_sb.sb_rextsize; | 3680 | resrtextents /= mp->m_sb.sb_rextsize; |
3693 | resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); | 3681 | resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); |
3694 | quota_flag = XFS_QMOPT_RES_RTBLKS; | 3682 | quota_flag = XFS_QMOPT_RES_RTBLKS; |
3695 | } else { | 3683 | } else { |
3696 | resrtextents = 0; | 3684 | resrtextents = 0; |
3697 | resblks = qblocks = \ | 3685 | resblks = qblocks = \ |
3698 | XFS_DIOSTRAT_SPACE_RES(mp, (uint)(e - s)); | 3686 | XFS_DIOSTRAT_SPACE_RES(mp, (uint)(e - s)); |
3699 | quota_flag = XFS_QMOPT_RES_REGBLKS; | 3687 | quota_flag = XFS_QMOPT_RES_REGBLKS; |
3700 | } | 3688 | } |
3701 | 3689 | ||
3702 | /* | 3690 | /* |
3703 | * Allocate and setup the transaction. | 3691 | * Allocate and setup the transaction. |
3704 | */ | 3692 | */ |
3705 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); | 3693 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); |
3706 | error = xfs_trans_reserve(tp, resblks, | 3694 | error = xfs_trans_reserve(tp, resblks, |
3707 | XFS_WRITE_LOG_RES(mp), resrtextents, | 3695 | XFS_WRITE_LOG_RES(mp), resrtextents, |
3708 | XFS_TRANS_PERM_LOG_RES, | 3696 | XFS_TRANS_PERM_LOG_RES, |
3709 | XFS_WRITE_LOG_COUNT); | 3697 | XFS_WRITE_LOG_COUNT); |
3710 | /* | 3698 | /* |
3711 | * Check for running out of space | 3699 | * Check for running out of space |
3712 | */ | 3700 | */ |
3713 | if (error) { | 3701 | if (error) { |
3714 | /* | 3702 | /* |
3715 | * Free the transaction structure. | 3703 | * Free the transaction structure. |
3716 | */ | 3704 | */ |
3717 | ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); | 3705 | ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); |
3718 | xfs_trans_cancel(tp, 0); | 3706 | xfs_trans_cancel(tp, 0); |
3719 | break; | 3707 | break; |
3720 | } | 3708 | } |
3721 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 3709 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
3722 | error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, | 3710 | error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, tp, ip, |
3723 | qblocks, 0, quota_flag); | 3711 | qblocks, 0, quota_flag); |
3724 | if (error) | 3712 | if (error) |
3725 | goto error1; | 3713 | goto error1; |
3726 | 3714 | ||
3727 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 3715 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
3728 | xfs_trans_ihold(tp, ip); | 3716 | xfs_trans_ihold(tp, ip); |
3729 | 3717 | ||
3730 | /* | 3718 | /* |
3731 | * Issue the xfs_bmapi() call to allocate the blocks | 3719 | * Issue the xfs_bmapi() call to allocate the blocks |
3732 | */ | 3720 | */ |
3733 | XFS_BMAP_INIT(&free_list, &firstfsb); | 3721 | XFS_BMAP_INIT(&free_list, &firstfsb); |
3734 | error = xfs_bmapi(tp, ip, startoffset_fsb, | 3722 | error = xfs_bmapi(tp, ip, startoffset_fsb, |
3735 | allocatesize_fsb, bmapi_flag, | 3723 | allocatesize_fsb, bmapi_flag, |
3736 | &firstfsb, 0, imapp, &nimaps, | 3724 | &firstfsb, 0, imapp, &nimaps, |
3737 | &free_list, NULL); | 3725 | &free_list, NULL); |
3738 | if (error) { | 3726 | if (error) { |
3739 | goto error0; | 3727 | goto error0; |
3740 | } | 3728 | } |
3741 | 3729 | ||
3742 | /* | 3730 | /* |
3743 | * Complete the transaction | 3731 | * Complete the transaction |
3744 | */ | 3732 | */ |
3745 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 3733 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
3746 | if (error) { | 3734 | if (error) { |
3747 | goto error0; | 3735 | goto error0; |
3748 | } | 3736 | } |
3749 | 3737 | ||
3750 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 3738 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
3751 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 3739 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
3752 | if (error) { | 3740 | if (error) { |
3753 | break; | 3741 | break; |
3754 | } | 3742 | } |
3755 | 3743 | ||
3756 | allocated_fsb = imapp->br_blockcount; | 3744 | allocated_fsb = imapp->br_blockcount; |
3757 | 3745 | ||
3758 | if (nimaps == 0) { | 3746 | if (nimaps == 0) { |
3759 | error = XFS_ERROR(ENOSPC); | 3747 | error = XFS_ERROR(ENOSPC); |
3760 | break; | 3748 | break; |
3761 | } | 3749 | } |
3762 | 3750 | ||
3763 | startoffset_fsb += allocated_fsb; | 3751 | startoffset_fsb += allocated_fsb; |
3764 | allocatesize_fsb -= allocated_fsb; | 3752 | allocatesize_fsb -= allocated_fsb; |
3765 | } | 3753 | } |
3766 | dmapi_enospc_check: | 3754 | dmapi_enospc_check: |
3767 | if (error == ENOSPC && (attr_flags & ATTR_DMI) == 0 && | 3755 | if (error == ENOSPC && (attr_flags & ATTR_DMI) == 0 && |
3768 | DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE)) { | 3756 | DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE)) { |
3769 | error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE, | 3757 | error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE, |
3770 | ip, DM_RIGHT_NULL, | 3758 | ip, DM_RIGHT_NULL, |
3771 | ip, DM_RIGHT_NULL, | 3759 | ip, DM_RIGHT_NULL, |
3772 | NULL, NULL, 0, 0, 0); /* Delay flag intentionally unused */ | 3760 | NULL, NULL, 0, 0, 0); /* Delay flag intentionally unused */ |
3773 | if (error == 0) | 3761 | if (error == 0) |
3774 | goto retry; /* Maybe DMAPI app. has made space */ | 3762 | goto retry; /* Maybe DMAPI app. has made space */ |
3775 | /* else fall through with error from XFS_SEND_DATA */ | 3763 | /* else fall through with error from XFS_SEND_DATA */ |
3776 | } | 3764 | } |
3777 | 3765 | ||
3778 | return error; | 3766 | return error; |
3779 | 3767 | ||
3780 | error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */ | 3768 | error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */ |
3781 | xfs_bmap_cancel(&free_list); | 3769 | xfs_bmap_cancel(&free_list); |
3782 | XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag); | 3770 | XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp, tp, ip, qblocks, 0, quota_flag); |
3783 | 3771 | ||
3784 | error1: /* Just cancel transaction */ | 3772 | error1: /* Just cancel transaction */ |
3785 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | 3773 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); |
3786 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 3774 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
3787 | goto dmapi_enospc_check; | 3775 | goto dmapi_enospc_check; |
3788 | } | 3776 | } |
3789 | 3777 | ||
3790 | /* | 3778 | /* |
3791 | * Zero file bytes between startoff and endoff inclusive. | 3779 | * Zero file bytes between startoff and endoff inclusive. |
3792 | * The iolock is held exclusive and no blocks are buffered. | 3780 | * The iolock is held exclusive and no blocks are buffered. |
3793 | */ | 3781 | */ |
3794 | STATIC int | 3782 | STATIC int |
3795 | xfs_zero_remaining_bytes( | 3783 | xfs_zero_remaining_bytes( |
3796 | xfs_inode_t *ip, | 3784 | xfs_inode_t *ip, |
3797 | xfs_off_t startoff, | 3785 | xfs_off_t startoff, |
3798 | xfs_off_t endoff) | 3786 | xfs_off_t endoff) |
3799 | { | 3787 | { |
3800 | xfs_bmbt_irec_t imap; | 3788 | xfs_bmbt_irec_t imap; |
3801 | xfs_fileoff_t offset_fsb; | 3789 | xfs_fileoff_t offset_fsb; |
3802 | xfs_off_t lastoffset; | 3790 | xfs_off_t lastoffset; |
3803 | xfs_off_t offset; | 3791 | xfs_off_t offset; |
3804 | xfs_buf_t *bp; | 3792 | xfs_buf_t *bp; |
3805 | xfs_mount_t *mp = ip->i_mount; | 3793 | xfs_mount_t *mp = ip->i_mount; |
3806 | int nimap; | 3794 | int nimap; |
3807 | int error = 0; | 3795 | int error = 0; |
3808 | 3796 | ||
3809 | bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize, | 3797 | bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize, |
3810 | XFS_IS_REALTIME_INODE(ip) ? | 3798 | XFS_IS_REALTIME_INODE(ip) ? |
3811 | mp->m_rtdev_targp : mp->m_ddev_targp); | 3799 | mp->m_rtdev_targp : mp->m_ddev_targp); |
3812 | 3800 | ||
3813 | for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { | 3801 | for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { |
3814 | offset_fsb = XFS_B_TO_FSBT(mp, offset); | 3802 | offset_fsb = XFS_B_TO_FSBT(mp, offset); |
3815 | nimap = 1; | 3803 | nimap = 1; |
3816 | error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0, | 3804 | error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0, |
3817 | NULL, 0, &imap, &nimap, NULL, NULL); | 3805 | NULL, 0, &imap, &nimap, NULL, NULL); |
3818 | if (error || nimap < 1) | 3806 | if (error || nimap < 1) |
3819 | break; | 3807 | break; |
3820 | ASSERT(imap.br_blockcount >= 1); | 3808 | ASSERT(imap.br_blockcount >= 1); |
3821 | ASSERT(imap.br_startoff == offset_fsb); | 3809 | ASSERT(imap.br_startoff == offset_fsb); |
3822 | lastoffset = XFS_FSB_TO_B(mp, imap.br_startoff + 1) - 1; | 3810 | lastoffset = XFS_FSB_TO_B(mp, imap.br_startoff + 1) - 1; |
3823 | if (lastoffset > endoff) | 3811 | if (lastoffset > endoff) |
3824 | lastoffset = endoff; | 3812 | lastoffset = endoff; |
3825 | if (imap.br_startblock == HOLESTARTBLOCK) | 3813 | if (imap.br_startblock == HOLESTARTBLOCK) |
3826 | continue; | 3814 | continue; |
3827 | ASSERT(imap.br_startblock != DELAYSTARTBLOCK); | 3815 | ASSERT(imap.br_startblock != DELAYSTARTBLOCK); |
3828 | if (imap.br_state == XFS_EXT_UNWRITTEN) | 3816 | if (imap.br_state == XFS_EXT_UNWRITTEN) |
3829 | continue; | 3817 | continue; |
3830 | XFS_BUF_UNDONE(bp); | 3818 | XFS_BUF_UNDONE(bp); |
3831 | XFS_BUF_UNWRITE(bp); | 3819 | XFS_BUF_UNWRITE(bp); |
3832 | XFS_BUF_READ(bp); | 3820 | XFS_BUF_READ(bp); |
3833 | XFS_BUF_SET_ADDR(bp, XFS_FSB_TO_DB(ip, imap.br_startblock)); | 3821 | XFS_BUF_SET_ADDR(bp, XFS_FSB_TO_DB(ip, imap.br_startblock)); |
3834 | xfsbdstrat(mp, bp); | 3822 | xfsbdstrat(mp, bp); |
3835 | error = xfs_iowait(bp); | 3823 | error = xfs_iowait(bp); |
3836 | if (error) { | 3824 | if (error) { |
3837 | xfs_ioerror_alert("xfs_zero_remaining_bytes(read)", | 3825 | xfs_ioerror_alert("xfs_zero_remaining_bytes(read)", |
3838 | mp, bp, XFS_BUF_ADDR(bp)); | 3826 | mp, bp, XFS_BUF_ADDR(bp)); |
3839 | break; | 3827 | break; |
3840 | } | 3828 | } |
3841 | memset(XFS_BUF_PTR(bp) + | 3829 | memset(XFS_BUF_PTR(bp) + |
3842 | (offset - XFS_FSB_TO_B(mp, imap.br_startoff)), | 3830 | (offset - XFS_FSB_TO_B(mp, imap.br_startoff)), |
3843 | 0, lastoffset - offset + 1); | 3831 | 0, lastoffset - offset + 1); |
3844 | XFS_BUF_UNDONE(bp); | 3832 | XFS_BUF_UNDONE(bp); |
3845 | XFS_BUF_UNREAD(bp); | 3833 | XFS_BUF_UNREAD(bp); |
3846 | XFS_BUF_WRITE(bp); | 3834 | XFS_BUF_WRITE(bp); |
3847 | xfsbdstrat(mp, bp); | 3835 | xfsbdstrat(mp, bp); |
3848 | error = xfs_iowait(bp); | 3836 | error = xfs_iowait(bp); |
3849 | if (error) { | 3837 | if (error) { |
3850 | xfs_ioerror_alert("xfs_zero_remaining_bytes(write)", | 3838 | xfs_ioerror_alert("xfs_zero_remaining_bytes(write)", |
3851 | mp, bp, XFS_BUF_ADDR(bp)); | 3839 | mp, bp, XFS_BUF_ADDR(bp)); |
3852 | break; | 3840 | break; |
3853 | } | 3841 | } |
3854 | } | 3842 | } |
3855 | xfs_buf_free(bp); | 3843 | xfs_buf_free(bp); |
3856 | return error; | 3844 | return error; |
3857 | } | 3845 | } |
3858 | 3846 | ||
3859 | /* | 3847 | /* |
3860 | * xfs_free_file_space() | 3848 | * xfs_free_file_space() |
3861 | * This routine frees disk space for the given file. | 3849 | * This routine frees disk space for the given file. |
3862 | * | 3850 | * |
3863 | * This routine is only called by xfs_change_file_space | 3851 | * This routine is only called by xfs_change_file_space |
3864 | * for an UNRESVSP type call. | 3852 | * for an UNRESVSP type call. |
3865 | * | 3853 | * |
3866 | * RETURNS: | 3854 | * RETURNS: |
3867 | * 0 on success | 3855 | * 0 on success |
3868 | * errno on error | 3856 | * errno on error |
3869 | * | 3857 | * |
3870 | */ | 3858 | */ |
3871 | STATIC int | 3859 | STATIC int |
3872 | xfs_free_file_space( | 3860 | xfs_free_file_space( |
3873 | xfs_inode_t *ip, | 3861 | xfs_inode_t *ip, |
3874 | xfs_off_t offset, | 3862 | xfs_off_t offset, |
3875 | xfs_off_t len, | 3863 | xfs_off_t len, |
3876 | int attr_flags) | 3864 | int attr_flags) |
3877 | { | 3865 | { |
3878 | bhv_vnode_t *vp; | 3866 | bhv_vnode_t *vp; |
3879 | int committed; | 3867 | int committed; |
3880 | int done; | 3868 | int done; |
3881 | xfs_off_t end_dmi_offset; | 3869 | xfs_off_t end_dmi_offset; |
3882 | xfs_fileoff_t endoffset_fsb; | 3870 | xfs_fileoff_t endoffset_fsb; |
3883 | int error; | 3871 | int error; |
3884 | xfs_fsblock_t firstfsb; | 3872 | xfs_fsblock_t firstfsb; |
3885 | xfs_bmap_free_t free_list; | 3873 | xfs_bmap_free_t free_list; |
3886 | xfs_bmbt_irec_t imap; | 3874 | xfs_bmbt_irec_t imap; |
3887 | xfs_off_t ioffset; | 3875 | xfs_off_t ioffset; |
3888 | xfs_extlen_t mod=0; | 3876 | xfs_extlen_t mod=0; |
3889 | xfs_mount_t *mp; | 3877 | xfs_mount_t *mp; |
3890 | int nimap; | 3878 | int nimap; |
3891 | uint resblks; | 3879 | uint resblks; |
3892 | uint rounding; | 3880 | uint rounding; |
3893 | int rt; | 3881 | int rt; |
3894 | xfs_fileoff_t startoffset_fsb; | 3882 | xfs_fileoff_t startoffset_fsb; |
3895 | xfs_trans_t *tp; | 3883 | xfs_trans_t *tp; |
3896 | int need_iolock = 1; | 3884 | int need_iolock = 1; |
3897 | 3885 | ||
3898 | vp = XFS_ITOV(ip); | 3886 | vp = XFS_ITOV(ip); |
3899 | mp = ip->i_mount; | 3887 | mp = ip->i_mount; |
3900 | 3888 | ||
3901 | xfs_itrace_entry(ip); | 3889 | xfs_itrace_entry(ip); |
3902 | 3890 | ||
3903 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) | 3891 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) |
3904 | return error; | 3892 | return error; |
3905 | 3893 | ||
3906 | error = 0; | 3894 | error = 0; |
3907 | if (len <= 0) /* if nothing being freed */ | 3895 | if (len <= 0) /* if nothing being freed */ |
3908 | return error; | 3896 | return error; |
3909 | rt = XFS_IS_REALTIME_INODE(ip); | 3897 | rt = XFS_IS_REALTIME_INODE(ip); |
3910 | startoffset_fsb = XFS_B_TO_FSB(mp, offset); | 3898 | startoffset_fsb = XFS_B_TO_FSB(mp, offset); |
3911 | end_dmi_offset = offset + len; | 3899 | end_dmi_offset = offset + len; |
3912 | endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); | 3900 | endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); |
3913 | 3901 | ||
3914 | if (offset < ip->i_size && (attr_flags & ATTR_DMI) == 0 && | 3902 | if (offset < ip->i_size && (attr_flags & ATTR_DMI) == 0 && |
3915 | DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { | 3903 | DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { |
3916 | if (end_dmi_offset > ip->i_size) | 3904 | if (end_dmi_offset > ip->i_size) |
3917 | end_dmi_offset = ip->i_size; | 3905 | end_dmi_offset = ip->i_size; |
3918 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip, | 3906 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, ip, |
3919 | offset, end_dmi_offset - offset, | 3907 | offset, end_dmi_offset - offset, |
3920 | AT_DELAY_FLAG(attr_flags), NULL); | 3908 | AT_DELAY_FLAG(attr_flags), NULL); |
3921 | if (error) | 3909 | if (error) |
3922 | return error; | 3910 | return error; |
3923 | } | 3911 | } |
3924 | 3912 | ||
3925 | if (attr_flags & ATTR_NOLOCK) | 3913 | if (attr_flags & ATTR_NOLOCK) |
3926 | need_iolock = 0; | 3914 | need_iolock = 0; |
3927 | if (need_iolock) { | 3915 | if (need_iolock) { |
3928 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 3916 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
3929 | vn_iowait(ip); /* wait for the completion of any pending DIOs */ | 3917 | vn_iowait(ip); /* wait for the completion of any pending DIOs */ |
3930 | } | 3918 | } |
3931 | 3919 | ||
3932 | rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); | 3920 | rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); |
3933 | ioffset = offset & ~(rounding - 1); | 3921 | ioffset = offset & ~(rounding - 1); |
3934 | 3922 | ||
3935 | if (VN_CACHED(vp) != 0) { | 3923 | if (VN_CACHED(vp) != 0) { |
3936 | xfs_inval_cached_trace(ip, ioffset, -1, ioffset, -1); | 3924 | xfs_inval_cached_trace(ip, ioffset, -1, ioffset, -1); |
3937 | error = xfs_flushinval_pages(ip, ioffset, -1, FI_REMAPF_LOCKED); | 3925 | error = xfs_flushinval_pages(ip, ioffset, -1, FI_REMAPF_LOCKED); |
3938 | if (error) | 3926 | if (error) |
3939 | goto out_unlock_iolock; | 3927 | goto out_unlock_iolock; |
3940 | } | 3928 | } |
3941 | 3929 | ||
3942 | /* | 3930 | /* |
3943 | * Need to zero the stuff we're not freeing, on disk. | 3931 | * Need to zero the stuff we're not freeing, on disk. |
3944 | * If its a realtime file & can't use unwritten extents then we | 3932 | * If its a realtime file & can't use unwritten extents then we |
3945 | * actually need to zero the extent edges. Otherwise xfs_bunmapi | 3933 | * actually need to zero the extent edges. Otherwise xfs_bunmapi |
3946 | * will take care of it for us. | 3934 | * will take care of it for us. |
3947 | */ | 3935 | */ |
3948 | if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) { | 3936 | if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) { |
3949 | nimap = 1; | 3937 | nimap = 1; |
3950 | error = xfs_bmapi(NULL, ip, startoffset_fsb, | 3938 | error = xfs_bmapi(NULL, ip, startoffset_fsb, |
3951 | 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); | 3939 | 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); |
3952 | if (error) | 3940 | if (error) |
3953 | goto out_unlock_iolock; | 3941 | goto out_unlock_iolock; |
3954 | ASSERT(nimap == 0 || nimap == 1); | 3942 | ASSERT(nimap == 0 || nimap == 1); |
3955 | if (nimap && imap.br_startblock != HOLESTARTBLOCK) { | 3943 | if (nimap && imap.br_startblock != HOLESTARTBLOCK) { |
3956 | xfs_daddr_t block; | 3944 | xfs_daddr_t block; |
3957 | 3945 | ||
3958 | ASSERT(imap.br_startblock != DELAYSTARTBLOCK); | 3946 | ASSERT(imap.br_startblock != DELAYSTARTBLOCK); |
3959 | block = imap.br_startblock; | 3947 | block = imap.br_startblock; |
3960 | mod = do_div(block, mp->m_sb.sb_rextsize); | 3948 | mod = do_div(block, mp->m_sb.sb_rextsize); |
3961 | if (mod) | 3949 | if (mod) |
3962 | startoffset_fsb += mp->m_sb.sb_rextsize - mod; | 3950 | startoffset_fsb += mp->m_sb.sb_rextsize - mod; |
3963 | } | 3951 | } |
3964 | nimap = 1; | 3952 | nimap = 1; |
3965 | error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, | 3953 | error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, |
3966 | 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); | 3954 | 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); |
3967 | if (error) | 3955 | if (error) |
3968 | goto out_unlock_iolock; | 3956 | goto out_unlock_iolock; |
3969 | ASSERT(nimap == 0 || nimap == 1); | 3957 | ASSERT(nimap == 0 || nimap == 1); |
3970 | if (nimap && imap.br_startblock != HOLESTARTBLOCK) { | 3958 | if (nimap && imap.br_startblock != HOLESTARTBLOCK) { |
3971 | ASSERT(imap.br_startblock != DELAYSTARTBLOCK); | 3959 | ASSERT(imap.br_startblock != DELAYSTARTBLOCK); |
3972 | mod++; | 3960 | mod++; |
3973 | if (mod && (mod != mp->m_sb.sb_rextsize)) | 3961 | if (mod && (mod != mp->m_sb.sb_rextsize)) |
3974 | endoffset_fsb -= mod; | 3962 | endoffset_fsb -= mod; |
3975 | } | 3963 | } |
3976 | } | 3964 | } |
3977 | if ((done = (endoffset_fsb <= startoffset_fsb))) | 3965 | if ((done = (endoffset_fsb <= startoffset_fsb))) |
3978 | /* | 3966 | /* |
3979 | * One contiguous piece to clear | 3967 | * One contiguous piece to clear |
3980 | */ | 3968 | */ |
3981 | error = xfs_zero_remaining_bytes(ip, offset, offset + len - 1); | 3969 | error = xfs_zero_remaining_bytes(ip, offset, offset + len - 1); |
3982 | else { | 3970 | else { |
3983 | /* | 3971 | /* |
3984 | * Some full blocks, possibly two pieces to clear | 3972 | * Some full blocks, possibly two pieces to clear |
3985 | */ | 3973 | */ |
3986 | if (offset < XFS_FSB_TO_B(mp, startoffset_fsb)) | 3974 | if (offset < XFS_FSB_TO_B(mp, startoffset_fsb)) |
3987 | error = xfs_zero_remaining_bytes(ip, offset, | 3975 | error = xfs_zero_remaining_bytes(ip, offset, |
3988 | XFS_FSB_TO_B(mp, startoffset_fsb) - 1); | 3976 | XFS_FSB_TO_B(mp, startoffset_fsb) - 1); |
3989 | if (!error && | 3977 | if (!error && |
3990 | XFS_FSB_TO_B(mp, endoffset_fsb) < offset + len) | 3978 | XFS_FSB_TO_B(mp, endoffset_fsb) < offset + len) |
3991 | error = xfs_zero_remaining_bytes(ip, | 3979 | error = xfs_zero_remaining_bytes(ip, |
3992 | XFS_FSB_TO_B(mp, endoffset_fsb), | 3980 | XFS_FSB_TO_B(mp, endoffset_fsb), |
3993 | offset + len - 1); | 3981 | offset + len - 1); |
3994 | } | 3982 | } |
3995 | 3983 | ||
3996 | /* | 3984 | /* |
3997 | * free file space until done or until there is an error | 3985 | * free file space until done or until there is an error |
3998 | */ | 3986 | */ |
3999 | resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); | 3987 | resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); |
4000 | while (!error && !done) { | 3988 | while (!error && !done) { |
4001 | 3989 | ||
4002 | /* | 3990 | /* |
4003 | * allocate and setup the transaction. Allow this | 3991 | * allocate and setup the transaction. Allow this |
4004 | * transaction to dip into the reserve blocks to ensure | 3992 | * transaction to dip into the reserve blocks to ensure |
4005 | * the freeing of the space succeeds at ENOSPC. | 3993 | * the freeing of the space succeeds at ENOSPC. |
4006 | */ | 3994 | */ |
4007 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); | 3995 | tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); |
4008 | tp->t_flags |= XFS_TRANS_RESERVE; | 3996 | tp->t_flags |= XFS_TRANS_RESERVE; |
4009 | error = xfs_trans_reserve(tp, | 3997 | error = xfs_trans_reserve(tp, |
4010 | resblks, | 3998 | resblks, |
4011 | XFS_WRITE_LOG_RES(mp), | 3999 | XFS_WRITE_LOG_RES(mp), |
4012 | 0, | 4000 | 0, |
4013 | XFS_TRANS_PERM_LOG_RES, | 4001 | XFS_TRANS_PERM_LOG_RES, |
4014 | XFS_WRITE_LOG_COUNT); | 4002 | XFS_WRITE_LOG_COUNT); |
4015 | 4003 | ||
4016 | /* | 4004 | /* |
4017 | * check for running out of space | 4005 | * check for running out of space |
4018 | */ | 4006 | */ |
4019 | if (error) { | 4007 | if (error) { |
4020 | /* | 4008 | /* |
4021 | * Free the transaction structure. | 4009 | * Free the transaction structure. |
4022 | */ | 4010 | */ |
4023 | ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); | 4011 | ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); |
4024 | xfs_trans_cancel(tp, 0); | 4012 | xfs_trans_cancel(tp, 0); |
4025 | break; | 4013 | break; |
4026 | } | 4014 | } |
4027 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 4015 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
4028 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, | 4016 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, |
4029 | ip->i_udquot, ip->i_gdquot, resblks, 0, | 4017 | ip->i_udquot, ip->i_gdquot, resblks, 0, |
4030 | XFS_QMOPT_RES_REGBLKS); | 4018 | XFS_QMOPT_RES_REGBLKS); |
4031 | if (error) | 4019 | if (error) |
4032 | goto error1; | 4020 | goto error1; |
4033 | 4021 | ||
4034 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 4022 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
4035 | xfs_trans_ihold(tp, ip); | 4023 | xfs_trans_ihold(tp, ip); |
4036 | 4024 | ||
4037 | /* | 4025 | /* |
4038 | * issue the bunmapi() call to free the blocks | 4026 | * issue the bunmapi() call to free the blocks |
4039 | */ | 4027 | */ |
4040 | XFS_BMAP_INIT(&free_list, &firstfsb); | 4028 | XFS_BMAP_INIT(&free_list, &firstfsb); |
4041 | error = xfs_bunmapi(tp, ip, startoffset_fsb, | 4029 | error = xfs_bunmapi(tp, ip, startoffset_fsb, |
4042 | endoffset_fsb - startoffset_fsb, | 4030 | endoffset_fsb - startoffset_fsb, |
4043 | 0, 2, &firstfsb, &free_list, NULL, &done); | 4031 | 0, 2, &firstfsb, &free_list, NULL, &done); |
4044 | if (error) { | 4032 | if (error) { |
4045 | goto error0; | 4033 | goto error0; |
4046 | } | 4034 | } |
4047 | 4035 | ||
4048 | /* | 4036 | /* |
4049 | * complete the transaction | 4037 | * complete the transaction |
4050 | */ | 4038 | */ |
4051 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 4039 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
4052 | if (error) { | 4040 | if (error) { |
4053 | goto error0; | 4041 | goto error0; |
4054 | } | 4042 | } |
4055 | 4043 | ||
4056 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 4044 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
4057 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 4045 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
4058 | } | 4046 | } |
4059 | 4047 | ||
4060 | out_unlock_iolock: | 4048 | out_unlock_iolock: |
4061 | if (need_iolock) | 4049 | if (need_iolock) |
4062 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 4050 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
4063 | return error; | 4051 | return error; |
4064 | 4052 | ||
4065 | error0: | 4053 | error0: |
4066 | xfs_bmap_cancel(&free_list); | 4054 | xfs_bmap_cancel(&free_list); |
4067 | error1: | 4055 | error1: |
4068 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | 4056 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); |
4069 | xfs_iunlock(ip, need_iolock ? (XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL) : | 4057 | xfs_iunlock(ip, need_iolock ? (XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL) : |
4070 | XFS_ILOCK_EXCL); | 4058 | XFS_ILOCK_EXCL); |
4071 | return error; | 4059 | return error; |
4072 | } | 4060 | } |
4073 | 4061 | ||
4074 | /* | 4062 | /* |
4075 | * xfs_change_file_space() | 4063 | * xfs_change_file_space() |
4076 | * This routine allocates or frees disk space for the given file. | 4064 | * This routine allocates or frees disk space for the given file. |
4077 | * The user specified parameters are checked for alignment and size | 4065 | * The user specified parameters are checked for alignment and size |
4078 | * limitations. | 4066 | * limitations. |
4079 | * | 4067 | * |
4080 | * RETURNS: | 4068 | * RETURNS: |
4081 | * 0 on success | 4069 | * 0 on success |
4082 | * errno on error | 4070 | * errno on error |
4083 | * | 4071 | * |
4084 | */ | 4072 | */ |
4085 | int | 4073 | int |
4086 | xfs_change_file_space( | 4074 | xfs_change_file_space( |
4087 | xfs_inode_t *ip, | 4075 | xfs_inode_t *ip, |
4088 | int cmd, | 4076 | int cmd, |
4089 | xfs_flock64_t *bf, | 4077 | xfs_flock64_t *bf, |
4090 | xfs_off_t offset, | 4078 | xfs_off_t offset, |
4091 | cred_t *credp, | 4079 | cred_t *credp, |
4092 | int attr_flags) | 4080 | int attr_flags) |
4093 | { | 4081 | { |
4094 | xfs_mount_t *mp = ip->i_mount; | 4082 | xfs_mount_t *mp = ip->i_mount; |
4095 | int clrprealloc; | 4083 | int clrprealloc; |
4096 | int error; | 4084 | int error; |
4097 | xfs_fsize_t fsize; | 4085 | xfs_fsize_t fsize; |
4098 | int setprealloc; | 4086 | int setprealloc; |
4099 | xfs_off_t startoffset; | 4087 | xfs_off_t startoffset; |
4100 | xfs_off_t llen; | 4088 | xfs_off_t llen; |
4101 | xfs_trans_t *tp; | 4089 | xfs_trans_t *tp; |
4102 | bhv_vattr_t va; | 4090 | bhv_vattr_t va; |
4103 | 4091 | ||
4104 | xfs_itrace_entry(ip); | 4092 | xfs_itrace_entry(ip); |
4105 | 4093 | ||
4106 | if (!S_ISREG(ip->i_d.di_mode)) | 4094 | if (!S_ISREG(ip->i_d.di_mode)) |
4107 | return XFS_ERROR(EINVAL); | 4095 | return XFS_ERROR(EINVAL); |
4108 | 4096 | ||
4109 | switch (bf->l_whence) { | 4097 | switch (bf->l_whence) { |
4110 | case 0: /*SEEK_SET*/ | 4098 | case 0: /*SEEK_SET*/ |
4111 | break; | 4099 | break; |
4112 | case 1: /*SEEK_CUR*/ | 4100 | case 1: /*SEEK_CUR*/ |
4113 | bf->l_start += offset; | 4101 | bf->l_start += offset; |
4114 | break; | 4102 | break; |
4115 | case 2: /*SEEK_END*/ | 4103 | case 2: /*SEEK_END*/ |
4116 | bf->l_start += ip->i_size; | 4104 | bf->l_start += ip->i_size; |
4117 | break; | 4105 | break; |
4118 | default: | 4106 | default: |
4119 | return XFS_ERROR(EINVAL); | 4107 | return XFS_ERROR(EINVAL); |
4120 | } | 4108 | } |
4121 | 4109 | ||
4122 | llen = bf->l_len > 0 ? bf->l_len - 1 : bf->l_len; | 4110 | llen = bf->l_len > 0 ? bf->l_len - 1 : bf->l_len; |
4123 | 4111 | ||
4124 | if ( (bf->l_start < 0) | 4112 | if ( (bf->l_start < 0) |
4125 | || (bf->l_start > XFS_MAXIOFFSET(mp)) | 4113 | || (bf->l_start > XFS_MAXIOFFSET(mp)) |
4126 | || (bf->l_start + llen < 0) | 4114 | || (bf->l_start + llen < 0) |
4127 | || (bf->l_start + llen > XFS_MAXIOFFSET(mp))) | 4115 | || (bf->l_start + llen > XFS_MAXIOFFSET(mp))) |
4128 | return XFS_ERROR(EINVAL); | 4116 | return XFS_ERROR(EINVAL); |
4129 | 4117 | ||
4130 | bf->l_whence = 0; | 4118 | bf->l_whence = 0; |
4131 | 4119 | ||
4132 | startoffset = bf->l_start; | 4120 | startoffset = bf->l_start; |
4133 | fsize = ip->i_size; | 4121 | fsize = ip->i_size; |
4134 | 4122 | ||
4135 | /* | 4123 | /* |
4136 | * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve | 4124 | * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve |
4137 | * file space. | 4125 | * file space. |
4138 | * These calls do NOT zero the data space allocated to the file, | 4126 | * These calls do NOT zero the data space allocated to the file, |
4139 | * nor do they change the file size. | 4127 | * nor do they change the file size. |
4140 | * | 4128 | * |
4141 | * XFS_IOC_ALLOCSP and XFS_IOC_FREESP will allocate and free file | 4129 | * XFS_IOC_ALLOCSP and XFS_IOC_FREESP will allocate and free file |
4142 | * space. | 4130 | * space. |
4143 | * These calls cause the new file data to be zeroed and the file | 4131 | * These calls cause the new file data to be zeroed and the file |
4144 | * size to be changed. | 4132 | * size to be changed. |
4145 | */ | 4133 | */ |
4146 | setprealloc = clrprealloc = 0; | 4134 | setprealloc = clrprealloc = 0; |
4147 | 4135 | ||
4148 | switch (cmd) { | 4136 | switch (cmd) { |
4149 | case XFS_IOC_RESVSP: | 4137 | case XFS_IOC_RESVSP: |
4150 | case XFS_IOC_RESVSP64: | 4138 | case XFS_IOC_RESVSP64: |
4151 | error = xfs_alloc_file_space(ip, startoffset, bf->l_len, | 4139 | error = xfs_alloc_file_space(ip, startoffset, bf->l_len, |
4152 | 1, attr_flags); | 4140 | 1, attr_flags); |
4153 | if (error) | 4141 | if (error) |
4154 | return error; | 4142 | return error; |
4155 | setprealloc = 1; | 4143 | setprealloc = 1; |
4156 | break; | 4144 | break; |
4157 | 4145 | ||
4158 | case XFS_IOC_UNRESVSP: | 4146 | case XFS_IOC_UNRESVSP: |
4159 | case XFS_IOC_UNRESVSP64: | 4147 | case XFS_IOC_UNRESVSP64: |
4160 | if ((error = xfs_free_file_space(ip, startoffset, bf->l_len, | 4148 | if ((error = xfs_free_file_space(ip, startoffset, bf->l_len, |
4161 | attr_flags))) | 4149 | attr_flags))) |
4162 | return error; | 4150 | return error; |
4163 | break; | 4151 | break; |
4164 | 4152 | ||
4165 | case XFS_IOC_ALLOCSP: | 4153 | case XFS_IOC_ALLOCSP: |
4166 | case XFS_IOC_ALLOCSP64: | 4154 | case XFS_IOC_ALLOCSP64: |
4167 | case XFS_IOC_FREESP: | 4155 | case XFS_IOC_FREESP: |
4168 | case XFS_IOC_FREESP64: | 4156 | case XFS_IOC_FREESP64: |
4169 | if (startoffset > fsize) { | 4157 | if (startoffset > fsize) { |
4170 | error = xfs_alloc_file_space(ip, fsize, | 4158 | error = xfs_alloc_file_space(ip, fsize, |
4171 | startoffset - fsize, 0, attr_flags); | 4159 | startoffset - fsize, 0, attr_flags); |
4172 | if (error) | 4160 | if (error) |
4173 | break; | 4161 | break; |
4174 | } | 4162 | } |
4175 | 4163 | ||
4176 | va.va_mask = XFS_AT_SIZE; | 4164 | va.va_mask = XFS_AT_SIZE; |
4177 | va.va_size = startoffset; | 4165 | va.va_size = startoffset; |
4178 | 4166 | ||
4179 | error = xfs_setattr(ip, &va, attr_flags, credp); | 4167 | error = xfs_setattr(ip, &va, attr_flags, credp); |
4180 | 4168 | ||
4181 | if (error) | 4169 | if (error) |
4182 | return error; | 4170 | return error; |
4183 | 4171 | ||
4184 | clrprealloc = 1; | 4172 | clrprealloc = 1; |
4185 | break; | 4173 | break; |
4186 | 4174 | ||
4187 | default: | 4175 | default: |
4188 | ASSERT(0); | 4176 | ASSERT(0); |
4189 | return XFS_ERROR(EINVAL); | 4177 | return XFS_ERROR(EINVAL); |
4190 | } | 4178 | } |
4191 | 4179 | ||
4192 | /* | 4180 | /* |
4193 | * update the inode timestamp, mode, and prealloc flag bits | 4181 | * update the inode timestamp, mode, and prealloc flag bits |
4194 | */ | 4182 | */ |
4195 | tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID); | 4183 | tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID); |
4196 | 4184 | ||
4197 | if ((error = xfs_trans_reserve(tp, 0, XFS_WRITEID_LOG_RES(mp), | 4185 | if ((error = xfs_trans_reserve(tp, 0, XFS_WRITEID_LOG_RES(mp), |
4198 | 0, 0, 0))) { | 4186 | 0, 0, 0))) { |
4199 | /* ASSERT(0); */ | 4187 | /* ASSERT(0); */ |
4200 | xfs_trans_cancel(tp, 0); | 4188 | xfs_trans_cancel(tp, 0); |
4201 | return error; | 4189 | return error; |
4202 | } | 4190 | } |
4203 | 4191 | ||
4204 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 4192 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
4205 | 4193 | ||
4206 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 4194 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
4207 | xfs_trans_ihold(tp, ip); | 4195 | xfs_trans_ihold(tp, ip); |
4208 | 4196 | ||
4209 | if ((attr_flags & ATTR_DMI) == 0) { | 4197 | if ((attr_flags & ATTR_DMI) == 0) { |
4210 | ip->i_d.di_mode &= ~S_ISUID; | 4198 | ip->i_d.di_mode &= ~S_ISUID; |
4211 | 4199 | ||
4212 | /* | 4200 | /* |
4213 | * Note that we don't have to worry about mandatory | 4201 | * Note that we don't have to worry about mandatory |
4214 | * file locking being disabled here because we only | 4202 | * file locking being disabled here because we only |
4215 | * clear the S_ISGID bit if the Group execute bit is | 4203 | * clear the S_ISGID bit if the Group execute bit is |
4216 | * on, but if it was on then mandatory locking wouldn't | 4204 | * on, but if it was on then mandatory locking wouldn't |
4217 | * have been enabled. | 4205 | * have been enabled. |
4218 | */ | 4206 | */ |
4219 | if (ip->i_d.di_mode & S_IXGRP) | 4207 | if (ip->i_d.di_mode & S_IXGRP) |
4220 | ip->i_d.di_mode &= ~S_ISGID; | 4208 | ip->i_d.di_mode &= ~S_ISGID; |
4221 | 4209 | ||
4222 | xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 4210 | xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
4223 | } | 4211 | } |
4224 | if (setprealloc) | 4212 | if (setprealloc) |
4225 | ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; | 4213 | ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; |
4226 | else if (clrprealloc) | 4214 | else if (clrprealloc) |
4227 | ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; | 4215 | ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; |
4228 | 4216 | ||
4229 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 4217 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
4230 | xfs_trans_set_sync(tp); | 4218 | xfs_trans_set_sync(tp); |
4231 | 4219 | ||
4232 | error = xfs_trans_commit(tp, 0); | 4220 | error = xfs_trans_commit(tp, 0); |
4233 | 4221 | ||
4234 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 4222 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
4235 | 4223 | ||
4236 | return error; | 4224 | return error; |
4237 | } | 4225 | } |
4238 | 4226 |