diff options
| -rw-r--r-- | Documentation/filesystems/gfs2-uevents.txt | 100 | ||||
| -rw-r--r-- | fs/gfs2/Makefile | 2 | ||||
| -rw-r--r-- | fs/gfs2/acl.c | 106 | ||||
| -rw-r--r-- | fs/gfs2/dentry.c | 18 | ||||
| -rw-r--r-- | fs/gfs2/eaops.c | 157 | ||||
| -rw-r--r-- | fs/gfs2/eaops.h | 30 | ||||
| -rw-r--r-- | fs/gfs2/export.c | 36 | ||||
| -rw-r--r-- | fs/gfs2/file.c | 1 | ||||
| -rw-r--r-- | fs/gfs2/incore.h | 15 | ||||
| -rw-r--r-- | fs/gfs2/inode.c | 159 | ||||
| -rw-r--r-- | fs/gfs2/ops_fstype.c | 66 | ||||
| -rw-r--r-- | fs/gfs2/ops_inode.c | 82 | ||||
| -rw-r--r-- | fs/gfs2/rgrp.c | 82 | ||||
| -rw-r--r-- | fs/gfs2/rgrp.h | 6 | ||||
| -rw-r--r-- | fs/gfs2/super.c | 46 | ||||
| -rw-r--r-- | fs/gfs2/super.h | 5 | ||||
| -rw-r--r-- | fs/gfs2/sys.c | 31 | ||||
| -rw-r--r-- | fs/gfs2/util.c | 41 | ||||
| -rw-r--r-- | fs/gfs2/xattr.c (renamed from fs/gfs2/eattr.c) | 425 | ||||
| -rw-r--r-- | fs/gfs2/xattr.h (renamed from fs/gfs2/eattr.h) | 54 | ||||
| -rw-r--r-- | include/linux/gfs2_ondisk.h | 22 |
21 files changed, 678 insertions, 806 deletions
diff --git a/Documentation/filesystems/gfs2-uevents.txt b/Documentation/filesystems/gfs2-uevents.txt new file mode 100644 index 000000000000..fd966dc9979a --- /dev/null +++ b/Documentation/filesystems/gfs2-uevents.txt | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | uevents and GFS2 | ||
| 2 | ================== | ||
| 3 | |||
| 4 | During the lifetime of a GFS2 mount, a number of uevents are generated. | ||
| 5 | This document explains what the events are and what they are used | ||
| 6 | for (by gfs_controld in gfs2-utils). | ||
| 7 | |||
| 8 | A list of GFS2 uevents | ||
| 9 | ----------------------- | ||
| 10 | |||
| 11 | 1. ADD | ||
| 12 | |||
| 13 | The ADD event occurs at mount time. It will always be the first | ||
| 14 | uevent generated by the newly created filesystem. If the mount | ||
| 15 | is successful, an ONLINE uevent will follow. If it is not successful | ||
| 16 | then a REMOVE uevent will follow. | ||
| 17 | |||
| 18 | The ADD uevent has two environment variables: SPECTATOR=[0|1] | ||
| 19 | and RDONLY=[0|1] that specify the spectator status (a read-only mount | ||
| 20 | with no journal assigned), and read-only (with journal assigned) status | ||
| 21 | of the filesystem respectively. | ||
| 22 | |||
| 23 | 2. ONLINE | ||
| 24 | |||
| 25 | The ONLINE uevent is generated after a successful mount or remount. It | ||
| 26 | has the same environment variables as the ADD uevent. The ONLINE | ||
| 27 | uevent, along with the two environment variables for spectator and | ||
| 28 | RDONLY are a relatively recent addition (2.6.32-rc+) and will not | ||
| 29 | be generated by older kernels. | ||
| 30 | |||
| 31 | 3. CHANGE | ||
| 32 | |||
| 33 | The CHANGE uevent is used in two places. One is when reporting the | ||
| 34 | successful mount of the filesystem by the first node (FIRSTMOUNT=Done). | ||
| 35 | This is used as a signal by gfs_controld that it is then ok for other | ||
| 36 | nodes in the cluster to mount the filesystem. | ||
| 37 | |||
| 38 | The other CHANGE uevent is used to inform of the completion | ||
| 39 | of journal recovery for one of the filesystems journals. It has | ||
| 40 | two environment variables, JID= which specifies the journal id which | ||
| 41 | has just been recovered, and RECOVERY=[Done|Failed] to indicate the | ||
| 42 | success (or otherwise) of the operation. These uevents are generated | ||
| 43 | for every journal recovered, whether it is during the initial mount | ||
| 44 | process or as the result of gfs_controld requesting a specific journal | ||
| 45 | recovery via the /sys/fs/gfs2/<fsname>/lock_module/recovery file. | ||
| 46 | |||
| 47 | Because the CHANGE uevent was used (in early versions of gfs_controld) | ||
| 48 | without checking the environment variables to discover the state, we | ||
| 49 | cannot add any more functions to it without running the risk of | ||
| 50 | someone using an older version of the user tools and breaking their | ||
| 51 | cluster. For this reason the ONLINE uevent was used when adding a new | ||
| 52 | uevent for a successful mount or remount. | ||
| 53 | |||
| 54 | 4. OFFLINE | ||
| 55 | |||
| 56 | The OFFLINE uevent is only generated due to filesystem errors and is used | ||
| 57 | as part of the "withdraw" mechanism. Currently this doesn't give any | ||
| 58 | information about what the error is, which is something that needs to | ||
| 59 | be fixed. | ||
| 60 | |||
| 61 | 5. REMOVE | ||
| 62 | |||
| 63 | The REMOVE uevent is generated at the end of an unsuccessful mount | ||
| 64 | or at the end of a umount of the filesystem. All REMOVE uevents will | ||
| 65 | have been preceeded by at least an ADD uevent for the same fileystem, | ||
| 66 | and unlike the other uevents is generated automatically by the kernel's | ||
| 67 | kobject subsystem. | ||
| 68 | |||
| 69 | |||
| 70 | Information common to all GFS2 uevents (uevent environment variables) | ||
| 71 | ---------------------------------------------------------------------- | ||
| 72 | |||
| 73 | 1. LOCKTABLE= | ||
| 74 | |||
| 75 | The LOCKTABLE is a string, as supplied on the mount command | ||
| 76 | line (locktable=) or via fstab. It is used as a filesystem label | ||
| 77 | as well as providing the information for a lock_dlm mount to be | ||
| 78 | able to join the cluster. | ||
| 79 | |||
| 80 | 2. LOCKPROTO= | ||
| 81 | |||
| 82 | The LOCKPROTO is a string, and its value depends on what is set | ||
| 83 | on the mount command line, or via fstab. It will be either | ||
| 84 | lock_nolock or lock_dlm. In the future other lock managers | ||
| 85 | may be supported. | ||
| 86 | |||
| 87 | 3. JOURNALID= | ||
| 88 | |||
| 89 | If a journal is in use by the filesystem (journals are not | ||
| 90 | assigned for spectator mounts) then this will give the | ||
| 91 | numeric journal id in all GFS2 uevents. | ||
| 92 | |||
| 93 | 4. UUID= | ||
| 94 | |||
| 95 | With recent versions of gfs2-utils, mkfs.gfs2 writes a UUID | ||
| 96 | into the filesystem superblock. If it exists, this will | ||
| 97 | be included in every uevent relating to the filesystem. | ||
| 98 | |||
| 99 | |||
| 100 | |||
diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 3da2f1f4f738..21f7e46da4c0 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | EXTRA_CFLAGS := -I$(src) | 1 | EXTRA_CFLAGS := -I$(src) |
| 2 | obj-$(CONFIG_GFS2_FS) += gfs2.o | 2 | obj-$(CONFIG_GFS2_FS) += gfs2.o |
| 3 | gfs2-y := acl.o bmap.o dir.o eaops.o eattr.o glock.o \ | 3 | gfs2-y := acl.o bmap.o dir.o xattr.o glock.o \ |
| 4 | glops.o inode.o log.o lops.o main.o meta_io.o \ | 4 | glops.o inode.o log.o lops.o main.o meta_io.o \ |
| 5 | aops.o dentry.o export.o file.o \ | 5 | aops.o dentry.o export.o file.o \ |
| 6 | ops_fstype.o ops_inode.o quota.o \ | 6 | ops_fstype.o ops_inode.o quota.o \ |
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index fa881bdc3d85..3fc4e3ac7d84 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c | |||
| @@ -19,8 +19,7 @@ | |||
| 19 | #include "gfs2.h" | 19 | #include "gfs2.h" |
| 20 | #include "incore.h" | 20 | #include "incore.h" |
| 21 | #include "acl.h" | 21 | #include "acl.h" |
| 22 | #include "eaops.h" | 22 | #include "xattr.h" |
| 23 | #include "eattr.h" | ||
| 24 | #include "glock.h" | 23 | #include "glock.h" |
| 25 | #include "inode.h" | 24 | #include "inode.h" |
| 26 | #include "meta_io.h" | 25 | #include "meta_io.h" |
| @@ -31,8 +30,7 @@ | |||
| 31 | #define ACL_DEFAULT 0 | 30 | #define ACL_DEFAULT 0 |
| 32 | 31 | ||
| 33 | int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, | 32 | int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, |
| 34 | struct gfs2_ea_request *er, | 33 | struct gfs2_ea_request *er, int *remove, mode_t *mode) |
| 35 | int *remove, mode_t *mode) | ||
| 36 | { | 34 | { |
| 37 | struct posix_acl *acl; | 35 | struct posix_acl *acl; |
| 38 | int error; | 36 | int error; |
| @@ -83,30 +81,20 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) | |||
| 83 | return 0; | 81 | return 0; |
| 84 | } | 82 | } |
| 85 | 83 | ||
| 86 | static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, | 84 | static int acl_get(struct gfs2_inode *ip, const char *name, |
| 87 | struct gfs2_ea_location *el, char **data, unsigned int *len) | 85 | struct posix_acl **acl, struct gfs2_ea_location *el, |
| 86 | char **datap, unsigned int *lenp) | ||
| 88 | { | 87 | { |
| 89 | struct gfs2_ea_request er; | 88 | char *data; |
| 90 | struct gfs2_ea_location el_this; | 89 | unsigned int len; |
| 91 | int error; | 90 | int error; |
| 92 | 91 | ||
| 92 | el->el_bh = NULL; | ||
| 93 | |||
| 93 | if (!ip->i_eattr) | 94 | if (!ip->i_eattr) |
| 94 | return 0; | 95 | return 0; |
| 95 | 96 | ||
| 96 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 97 | error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, el); |
| 97 | if (access) { | ||
| 98 | er.er_name = GFS2_POSIX_ACL_ACCESS; | ||
| 99 | er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN; | ||
| 100 | } else { | ||
| 101 | er.er_name = GFS2_POSIX_ACL_DEFAULT; | ||
| 102 | er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; | ||
| 103 | } | ||
| 104 | er.er_type = GFS2_EATYPE_SYS; | ||
| 105 | |||
| 106 | if (!el) | ||
| 107 | el = &el_this; | ||
| 108 | |||
| 109 | error = gfs2_ea_find(ip, &er, el); | ||
| 110 | if (error) | 98 | if (error) |
| 111 | return error; | 99 | return error; |
| 112 | if (!el->el_ea) | 100 | if (!el->el_ea) |
| @@ -114,32 +102,31 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, | |||
| 114 | if (!GFS2_EA_DATA_LEN(el->el_ea)) | 102 | if (!GFS2_EA_DATA_LEN(el->el_ea)) |
| 115 | goto out; | 103 | goto out; |
| 116 | 104 | ||
| 117 | er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea); | 105 | len = GFS2_EA_DATA_LEN(el->el_ea); |
| 118 | er.er_data = kmalloc(er.er_data_len, GFP_NOFS); | 106 | data = kmalloc(len, GFP_NOFS); |
| 119 | error = -ENOMEM; | 107 | error = -ENOMEM; |
| 120 | if (!er.er_data) | 108 | if (!data) |
| 121 | goto out; | 109 | goto out; |
| 122 | 110 | ||
| 123 | error = gfs2_ea_get_copy(ip, el, er.er_data); | 111 | error = gfs2_ea_get_copy(ip, el, data, len); |
| 124 | if (error) | 112 | if (error < 0) |
| 125 | goto out_kfree; | 113 | goto out_kfree; |
| 114 | error = 0; | ||
| 126 | 115 | ||
| 127 | if (acl) { | 116 | if (acl) { |
| 128 | *acl = posix_acl_from_xattr(er.er_data, er.er_data_len); | 117 | *acl = posix_acl_from_xattr(data, len); |
| 129 | if (IS_ERR(*acl)) | 118 | if (IS_ERR(*acl)) |
| 130 | error = PTR_ERR(*acl); | 119 | error = PTR_ERR(*acl); |
| 131 | } | 120 | } |
| 132 | 121 | ||
| 133 | out_kfree: | 122 | out_kfree: |
| 134 | if (error || !data) | 123 | if (error || !datap) { |
| 135 | kfree(er.er_data); | 124 | kfree(data); |
| 136 | else { | 125 | } else { |
| 137 | *data = er.er_data; | 126 | *datap = data; |
| 138 | *len = er.er_data_len; | 127 | *lenp = len; |
| 139 | } | 128 | } |
| 140 | out: | 129 | out: |
| 141 | if (error || el == &el_this) | ||
| 142 | brelse(el->el_bh); | ||
| 143 | return error; | 130 | return error; |
| 144 | } | 131 | } |
| 145 | 132 | ||
| @@ -153,10 +140,12 @@ out: | |||
| 153 | 140 | ||
| 154 | int gfs2_check_acl(struct inode *inode, int mask) | 141 | int gfs2_check_acl(struct inode *inode, int mask) |
| 155 | { | 142 | { |
| 143 | struct gfs2_ea_location el; | ||
| 156 | struct posix_acl *acl = NULL; | 144 | struct posix_acl *acl = NULL; |
| 157 | int error; | 145 | int error; |
| 158 | 146 | ||
| 159 | error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL); | 147 | error = acl_get(GFS2_I(inode), GFS2_POSIX_ACL_ACCESS, &acl, &el, NULL, NULL); |
| 148 | brelse(el.el_bh); | ||
| 160 | if (error) | 149 | if (error) |
| 161 | return error; | 150 | return error; |
| 162 | 151 | ||
| @@ -196,10 +185,12 @@ static int munge_mode(struct gfs2_inode *ip, mode_t mode) | |||
| 196 | 185 | ||
| 197 | int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | 186 | int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) |
| 198 | { | 187 | { |
| 188 | struct gfs2_ea_location el; | ||
| 199 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 189 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
| 200 | struct posix_acl *acl = NULL, *clone; | 190 | struct posix_acl *acl = NULL, *clone; |
| 201 | struct gfs2_ea_request er; | ||
| 202 | mode_t mode = ip->i_inode.i_mode; | 191 | mode_t mode = ip->i_inode.i_mode; |
| 192 | char *data = NULL; | ||
| 193 | unsigned int len; | ||
| 203 | int error; | 194 | int error; |
| 204 | 195 | ||
| 205 | if (!sdp->sd_args.ar_posix_acl) | 196 | if (!sdp->sd_args.ar_posix_acl) |
| @@ -207,11 +198,8 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
| 207 | if (S_ISLNK(ip->i_inode.i_mode)) | 198 | if (S_ISLNK(ip->i_inode.i_mode)) |
| 208 | return 0; | 199 | return 0; |
| 209 | 200 | ||
| 210 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 201 | error = acl_get(dip, GFS2_POSIX_ACL_DEFAULT, &acl, &el, &data, &len); |
| 211 | er.er_type = GFS2_EATYPE_SYS; | 202 | brelse(el.el_bh); |
| 212 | |||
| 213 | error = acl_get(dip, ACL_DEFAULT, &acl, NULL, | ||
| 214 | &er.er_data, &er.er_data_len); | ||
| 215 | if (error) | 203 | if (error) |
| 216 | return error; | 204 | return error; |
| 217 | if (!acl) { | 205 | if (!acl) { |
| @@ -229,9 +217,8 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
| 229 | acl = clone; | 217 | acl = clone; |
| 230 | 218 | ||
| 231 | if (S_ISDIR(ip->i_inode.i_mode)) { | 219 | if (S_ISDIR(ip->i_inode.i_mode)) { |
| 232 | er.er_name = GFS2_POSIX_ACL_DEFAULT; | 220 | error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS, |
| 233 | er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN; | 221 | GFS2_POSIX_ACL_DEFAULT, data, len, 0); |
| 234 | error = gfs2_system_eaops.eo_set(ip, &er); | ||
| 235 | if (error) | 222 | if (error) |
| 236 | goto out; | 223 | goto out; |
| 237 | } | 224 | } |
| @@ -239,21 +226,19 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
| 239 | error = posix_acl_create_masq(acl, &mode); | 226 | error = posix_acl_create_masq(acl, &mode); |
| 240 | if (error < 0) | 227 | if (error < 0) |
| 241 | goto out; | 228 | goto out; |
| 242 | if (error > 0) { | 229 | if (error == 0) |
| 243 | er.er_name = GFS2_POSIX_ACL_ACCESS; | 230 | goto munge; |
| 244 | er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN; | ||
| 245 | posix_acl_to_xattr(acl, er.er_data, er.er_data_len); | ||
| 246 | er.er_mode = mode; | ||
| 247 | er.er_flags = GFS2_ERF_MODE; | ||
| 248 | error = gfs2_system_eaops.eo_set(ip, &er); | ||
| 249 | if (error) | ||
| 250 | goto out; | ||
| 251 | } else | ||
| 252 | munge_mode(ip, mode); | ||
| 253 | 231 | ||
| 232 | posix_acl_to_xattr(acl, data, len); | ||
| 233 | error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS, | ||
| 234 | GFS2_POSIX_ACL_ACCESS, data, len, 0); | ||
| 235 | if (error) | ||
| 236 | goto out; | ||
| 237 | munge: | ||
| 238 | error = munge_mode(ip, mode); | ||
| 254 | out: | 239 | out: |
| 255 | posix_acl_release(acl); | 240 | posix_acl_release(acl); |
| 256 | kfree(er.er_data); | 241 | kfree(data); |
| 257 | return error; | 242 | return error; |
| 258 | } | 243 | } |
| 259 | 244 | ||
| @@ -265,9 +250,9 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) | |||
| 265 | unsigned int len; | 250 | unsigned int len; |
| 266 | int error; | 251 | int error; |
| 267 | 252 | ||
| 268 | error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len); | 253 | error = acl_get(ip, GFS2_POSIX_ACL_ACCESS, &acl, &el, &data, &len); |
| 269 | if (error) | 254 | if (error) |
| 270 | return error; | 255 | goto out_brelse; |
| 271 | if (!acl) | 256 | if (!acl) |
| 272 | return gfs2_setattr_simple(ip, attr); | 257 | return gfs2_setattr_simple(ip, attr); |
| 273 | 258 | ||
| @@ -286,8 +271,9 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) | |||
| 286 | 271 | ||
| 287 | out: | 272 | out: |
| 288 | posix_acl_release(acl); | 273 | posix_acl_release(acl); |
| 289 | brelse(el.el_bh); | ||
| 290 | kfree(data); | 274 | kfree(data); |
| 275 | out_brelse: | ||
| 276 | brelse(el.el_bh); | ||
| 291 | return error; | 277 | return error; |
| 292 | } | 278 | } |
| 293 | 279 | ||
diff --git a/fs/gfs2/dentry.c b/fs/gfs2/dentry.c index 022c66cd5606..91beddadd388 100644 --- a/fs/gfs2/dentry.c +++ b/fs/gfs2/dentry.c | |||
| @@ -107,8 +107,26 @@ static int gfs2_dhash(struct dentry *dentry, struct qstr *str) | |||
| 107 | return 0; | 107 | return 0; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static int gfs2_dentry_delete(struct dentry *dentry) | ||
| 111 | { | ||
| 112 | struct gfs2_inode *ginode; | ||
| 113 | |||
| 114 | if (!dentry->d_inode) | ||
| 115 | return 0; | ||
| 116 | |||
| 117 | ginode = GFS2_I(dentry->d_inode); | ||
| 118 | if (!ginode->i_iopen_gh.gh_gl) | ||
| 119 | return 0; | ||
| 120 | |||
| 121 | if (test_bit(GLF_DEMOTE, &ginode->i_iopen_gh.gh_gl->gl_flags)) | ||
| 122 | return 1; | ||
| 123 | |||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 110 | const struct dentry_operations gfs2_dops = { | 127 | const struct dentry_operations gfs2_dops = { |
| 111 | .d_revalidate = gfs2_drevalidate, | 128 | .d_revalidate = gfs2_drevalidate, |
| 112 | .d_hash = gfs2_dhash, | 129 | .d_hash = gfs2_dhash, |
| 130 | .d_delete = gfs2_dentry_delete, | ||
| 113 | }; | 131 | }; |
| 114 | 132 | ||
diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c deleted file mode 100644 index dee9b03e5b37..000000000000 --- a/fs/gfs2/eaops.c +++ /dev/null | |||
| @@ -1,157 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
| 3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||
| 4 | * | ||
| 5 | * This copyrighted material is made available to anyone wishing to use, | ||
| 6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
| 7 | * of the GNU General Public License version 2. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/slab.h> | ||
| 11 | #include <linux/spinlock.h> | ||
| 12 | #include <linux/completion.h> | ||
| 13 | #include <linux/buffer_head.h> | ||
| 14 | #include <linux/capability.h> | ||
| 15 | #include <linux/xattr.h> | ||
| 16 | #include <linux/gfs2_ondisk.h> | ||
| 17 | #include <asm/uaccess.h> | ||
| 18 | |||
| 19 | #include "gfs2.h" | ||
| 20 | #include "incore.h" | ||
| 21 | #include "acl.h" | ||
| 22 | #include "eaops.h" | ||
| 23 | #include "eattr.h" | ||
| 24 | #include "util.h" | ||
| 25 | |||
| 26 | /** | ||
| 27 | * gfs2_ea_name2type - get the type of the ea, and truncate type from the name | ||
| 28 | * @namep: ea name, possibly with type appended | ||
| 29 | * | ||
| 30 | * Returns: GFS2_EATYPE_XXX | ||
| 31 | */ | ||
| 32 | |||
| 33 | unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name) | ||
| 34 | { | ||
| 35 | unsigned int type; | ||
| 36 | |||
| 37 | if (strncmp(name, "system.", 7) == 0) { | ||
| 38 | type = GFS2_EATYPE_SYS; | ||
| 39 | if (truncated_name) | ||
| 40 | *truncated_name = name + sizeof("system.") - 1; | ||
| 41 | } else if (strncmp(name, "user.", 5) == 0) { | ||
| 42 | type = GFS2_EATYPE_USR; | ||
| 43 | if (truncated_name) | ||
| 44 | *truncated_name = name + sizeof("user.") - 1; | ||
| 45 | } else if (strncmp(name, "security.", 9) == 0) { | ||
| 46 | type = GFS2_EATYPE_SECURITY; | ||
| 47 | if (truncated_name) | ||
| 48 | *truncated_name = name + sizeof("security.") - 1; | ||
| 49 | } else { | ||
| 50 | type = GFS2_EATYPE_UNUSED; | ||
| 51 | if (truncated_name) | ||
| 52 | *truncated_name = NULL; | ||
| 53 | } | ||
| 54 | |||
| 55 | return type; | ||
| 56 | } | ||
| 57 | |||
| 58 | static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 59 | { | ||
| 60 | if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) && | ||
| 61 | !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) && | ||
| 62 | !capable(CAP_SYS_ADMIN)) | ||
| 63 | return -EPERM; | ||
| 64 | |||
| 65 | if (GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl == 0 && | ||
| 66 | (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) || | ||
| 67 | GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len))) | ||
| 68 | return -EOPNOTSUPP; | ||
| 69 | |||
| 70 | return gfs2_ea_get_i(ip, er); | ||
| 71 | } | ||
| 72 | |||
| 73 | static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 74 | { | ||
| 75 | int remove = 0; | ||
| 76 | int error; | ||
| 77 | |||
| 78 | if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { | ||
| 79 | if (!(er->er_flags & GFS2_ERF_MODE)) { | ||
| 80 | er->er_mode = ip->i_inode.i_mode; | ||
| 81 | er->er_flags |= GFS2_ERF_MODE; | ||
| 82 | } | ||
| 83 | error = gfs2_acl_validate_set(ip, 1, er, | ||
| 84 | &remove, &er->er_mode); | ||
| 85 | if (error) | ||
| 86 | return error; | ||
| 87 | error = gfs2_ea_set_i(ip, er); | ||
| 88 | if (error) | ||
| 89 | return error; | ||
| 90 | if (remove) | ||
| 91 | gfs2_ea_remove_i(ip, er); | ||
| 92 | return 0; | ||
| 93 | |||
| 94 | } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) { | ||
| 95 | error = gfs2_acl_validate_set(ip, 0, er, | ||
| 96 | &remove, NULL); | ||
| 97 | if (error) | ||
| 98 | return error; | ||
| 99 | if (!remove) | ||
| 100 | error = gfs2_ea_set_i(ip, er); | ||
| 101 | else { | ||
| 102 | error = gfs2_ea_remove_i(ip, er); | ||
| 103 | if (error == -ENODATA) | ||
| 104 | error = 0; | ||
| 105 | } | ||
| 106 | return error; | ||
| 107 | } | ||
| 108 | |||
| 109 | return -EPERM; | ||
| 110 | } | ||
| 111 | |||
| 112 | static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 113 | { | ||
| 114 | if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) { | ||
| 115 | int error = gfs2_acl_validate_remove(ip, 1); | ||
| 116 | if (error) | ||
| 117 | return error; | ||
| 118 | |||
| 119 | } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) { | ||
| 120 | int error = gfs2_acl_validate_remove(ip, 0); | ||
| 121 | if (error) | ||
| 122 | return error; | ||
| 123 | |||
| 124 | } else | ||
| 125 | return -EPERM; | ||
| 126 | |||
| 127 | return gfs2_ea_remove_i(ip, er); | ||
| 128 | } | ||
| 129 | |||
| 130 | static const struct gfs2_eattr_operations gfs2_user_eaops = { | ||
| 131 | .eo_get = gfs2_ea_get_i, | ||
| 132 | .eo_set = gfs2_ea_set_i, | ||
| 133 | .eo_remove = gfs2_ea_remove_i, | ||
| 134 | .eo_name = "user", | ||
| 135 | }; | ||
| 136 | |||
| 137 | const struct gfs2_eattr_operations gfs2_system_eaops = { | ||
| 138 | .eo_get = system_eo_get, | ||
| 139 | .eo_set = system_eo_set, | ||
| 140 | .eo_remove = system_eo_remove, | ||
| 141 | .eo_name = "system", | ||
| 142 | }; | ||
| 143 | |||
| 144 | static const struct gfs2_eattr_operations gfs2_security_eaops = { | ||
| 145 | .eo_get = gfs2_ea_get_i, | ||
| 146 | .eo_set = gfs2_ea_set_i, | ||
| 147 | .eo_remove = gfs2_ea_remove_i, | ||
| 148 | .eo_name = "security", | ||
| 149 | }; | ||
| 150 | |||
| 151 | const struct gfs2_eattr_operations *gfs2_ea_ops[] = { | ||
| 152 | NULL, | ||
| 153 | &gfs2_user_eaops, | ||
| 154 | &gfs2_system_eaops, | ||
| 155 | &gfs2_security_eaops, | ||
| 156 | }; | ||
| 157 | |||
diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h deleted file mode 100644 index da2f7fbbb40d..000000000000 --- a/fs/gfs2/eaops.h +++ /dev/null | |||
| @@ -1,30 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
| 3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||
| 4 | * | ||
| 5 | * This copyrighted material is made available to anyone wishing to use, | ||
| 6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
| 7 | * of the GNU General Public License version 2. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __EAOPS_DOT_H__ | ||
| 11 | #define __EAOPS_DOT_H__ | ||
| 12 | |||
| 13 | struct gfs2_ea_request; | ||
| 14 | struct gfs2_inode; | ||
| 15 | |||
| 16 | struct gfs2_eattr_operations { | ||
| 17 | int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
| 18 | int (*eo_set) (struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
| 19 | int (*eo_remove) (struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
| 20 | char *eo_name; | ||
| 21 | }; | ||
| 22 | |||
| 23 | unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name); | ||
| 24 | |||
| 25 | extern const struct gfs2_eattr_operations gfs2_system_eaops; | ||
| 26 | |||
| 27 | extern const struct gfs2_eattr_operations *gfs2_ea_ops[]; | ||
| 28 | |||
| 29 | #endif /* __EAOPS_DOT_H__ */ | ||
| 30 | |||
diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index 9200ef221716..d15876e9aa26 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c | |||
| @@ -143,17 +143,14 @@ static struct dentry *gfs2_get_parent(struct dentry *child) | |||
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | static struct dentry *gfs2_get_dentry(struct super_block *sb, | 145 | static struct dentry *gfs2_get_dentry(struct super_block *sb, |
| 146 | struct gfs2_inum_host *inum) | 146 | struct gfs2_inum_host *inum) |
| 147 | { | 147 | { |
| 148 | struct gfs2_sbd *sdp = sb->s_fs_info; | 148 | struct gfs2_sbd *sdp = sb->s_fs_info; |
| 149 | struct gfs2_holder i_gh, ri_gh, rgd_gh; | 149 | struct gfs2_holder i_gh; |
| 150 | struct gfs2_rgrpd *rgd; | ||
| 151 | struct inode *inode; | 150 | struct inode *inode; |
| 152 | struct dentry *dentry; | 151 | struct dentry *dentry; |
| 153 | int error; | 152 | int error; |
| 154 | 153 | ||
| 155 | /* System files? */ | ||
| 156 | |||
| 157 | inode = gfs2_ilookup(sb, inum->no_addr); | 154 | inode = gfs2_ilookup(sb, inum->no_addr); |
| 158 | if (inode) { | 155 | if (inode) { |
| 159 | if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) { | 156 | if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) { |
| @@ -168,29 +165,11 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, | |||
| 168 | if (error) | 165 | if (error) |
| 169 | return ERR_PTR(error); | 166 | return ERR_PTR(error); |
| 170 | 167 | ||
| 171 | error = gfs2_rindex_hold(sdp, &ri_gh); | 168 | error = gfs2_check_blk_type(sdp, inum->no_addr, GFS2_BLKST_DINODE); |
| 172 | if (error) | 169 | if (error) |
| 173 | goto fail; | 170 | goto fail; |
| 174 | 171 | ||
| 175 | error = -EINVAL; | 172 | inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, 0, 0); |
| 176 | rgd = gfs2_blk2rgrpd(sdp, inum->no_addr); | ||
| 177 | if (!rgd) | ||
| 178 | goto fail_rindex; | ||
| 179 | |||
| 180 | error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh); | ||
| 181 | if (error) | ||
| 182 | goto fail_rindex; | ||
| 183 | |||
| 184 | error = -ESTALE; | ||
| 185 | if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE) | ||
| 186 | goto fail_rgd; | ||
| 187 | |||
| 188 | gfs2_glock_dq_uninit(&rgd_gh); | ||
| 189 | gfs2_glock_dq_uninit(&ri_gh); | ||
| 190 | |||
| 191 | inode = gfs2_inode_lookup(sb, DT_UNKNOWN, | ||
| 192 | inum->no_addr, | ||
| 193 | 0, 0); | ||
| 194 | if (IS_ERR(inode)) { | 173 | if (IS_ERR(inode)) { |
| 195 | error = PTR_ERR(inode); | 174 | error = PTR_ERR(inode); |
| 196 | goto fail; | 175 | goto fail; |
| @@ -224,13 +203,6 @@ out_inode: | |||
| 224 | if (!IS_ERR(dentry)) | 203 | if (!IS_ERR(dentry)) |
| 225 | dentry->d_op = &gfs2_dops; | 204 | dentry->d_op = &gfs2_dops; |
| 226 | return dentry; | 205 | return dentry; |
| 227 | |||
| 228 | fail_rgd: | ||
| 229 | gfs2_glock_dq_uninit(&rgd_gh); | ||
| 230 | |||
| 231 | fail_rindex: | ||
| 232 | gfs2_glock_dq_uninit(&ri_gh); | ||
| 233 | |||
| 234 | fail: | 206 | fail: |
| 235 | gfs2_glock_dq_uninit(&i_gh); | 207 | gfs2_glock_dq_uninit(&i_gh); |
| 236 | return ERR_PTR(error); | 208 | return ERR_PTR(error); |
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 73318a3ce6f1..166f38fbd246 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
| @@ -38,7 +38,6 @@ | |||
| 38 | #include "rgrp.h" | 38 | #include "rgrp.h" |
| 39 | #include "trans.h" | 39 | #include "trans.h" |
| 40 | #include "util.h" | 40 | #include "util.h" |
| 41 | #include "eaops.h" | ||
| 42 | 41 | ||
| 43 | /** | 42 | /** |
| 44 | * gfs2_llseek - seek to a location in a file | 43 | * gfs2_llseek - seek to a location in a file |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 61801ada36f0..6edb423f90b3 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
| @@ -406,6 +406,12 @@ struct gfs2_statfs_change_host { | |||
| 406 | #define GFS2_DATA_WRITEBACK 1 | 406 | #define GFS2_DATA_WRITEBACK 1 |
| 407 | #define GFS2_DATA_ORDERED 2 | 407 | #define GFS2_DATA_ORDERED 2 |
| 408 | 408 | ||
| 409 | #define GFS2_ERRORS_DEFAULT GFS2_ERRORS_WITHDRAW | ||
| 410 | #define GFS2_ERRORS_WITHDRAW 0 | ||
| 411 | #define GFS2_ERRORS_CONTINUE 1 /* place holder for future feature */ | ||
| 412 | #define GFS2_ERRORS_RO 2 /* place holder for future feature */ | ||
| 413 | #define GFS2_ERRORS_PANIC 3 | ||
| 414 | |||
| 409 | struct gfs2_args { | 415 | struct gfs2_args { |
| 410 | char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */ | 416 | char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */ |
| 411 | char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */ | 417 | char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */ |
| @@ -422,6 +428,7 @@ struct gfs2_args { | |||
| 422 | unsigned int ar_data:2; /* ordered/writeback */ | 428 | unsigned int ar_data:2; /* ordered/writeback */ |
| 423 | unsigned int ar_meta:1; /* mount metafs */ | 429 | unsigned int ar_meta:1; /* mount metafs */ |
| 424 | unsigned int ar_discard:1; /* discard requests */ | 430 | unsigned int ar_discard:1; /* discard requests */ |
| 431 | unsigned int ar_errors:2; /* errors=withdraw | panic */ | ||
| 425 | int ar_commit; /* Commit interval */ | 432 | int ar_commit; /* Commit interval */ |
| 426 | }; | 433 | }; |
| 427 | 434 | ||
| @@ -489,7 +496,6 @@ struct gfs2_sb_host { | |||
| 489 | */ | 496 | */ |
| 490 | 497 | ||
| 491 | struct lm_lockstruct { | 498 | struct lm_lockstruct { |
| 492 | u32 ls_id; | ||
| 493 | unsigned int ls_jid; | 499 | unsigned int ls_jid; |
| 494 | unsigned int ls_first; | 500 | unsigned int ls_first; |
| 495 | unsigned int ls_first_done; | 501 | unsigned int ls_first_done; |
| @@ -541,18 +547,12 @@ struct gfs2_sbd { | |||
| 541 | struct dentry *sd_root_dir; | 547 | struct dentry *sd_root_dir; |
| 542 | 548 | ||
| 543 | struct inode *sd_jindex; | 549 | struct inode *sd_jindex; |
| 544 | struct inode *sd_inum_inode; | ||
| 545 | struct inode *sd_statfs_inode; | 550 | struct inode *sd_statfs_inode; |
| 546 | struct inode *sd_ir_inode; | ||
| 547 | struct inode *sd_sc_inode; | 551 | struct inode *sd_sc_inode; |
| 548 | struct inode *sd_qc_inode; | 552 | struct inode *sd_qc_inode; |
| 549 | struct inode *sd_rindex; | 553 | struct inode *sd_rindex; |
| 550 | struct inode *sd_quota_inode; | 554 | struct inode *sd_quota_inode; |
| 551 | 555 | ||
| 552 | /* Inum stuff */ | ||
| 553 | |||
| 554 | struct mutex sd_inum_mutex; | ||
| 555 | |||
| 556 | /* StatFS stuff */ | 556 | /* StatFS stuff */ |
| 557 | 557 | ||
| 558 | spinlock_t sd_statfs_spin; | 558 | spinlock_t sd_statfs_spin; |
| @@ -580,7 +580,6 @@ struct gfs2_sbd { | |||
| 580 | struct gfs2_holder sd_journal_gh; | 580 | struct gfs2_holder sd_journal_gh; |
| 581 | struct gfs2_holder sd_jinode_gh; | 581 | struct gfs2_holder sd_jinode_gh; |
| 582 | 582 | ||
| 583 | struct gfs2_holder sd_ir_gh; | ||
| 584 | struct gfs2_holder sd_sc_gh; | 583 | struct gfs2_holder sd_sc_gh; |
| 585 | struct gfs2_holder sd_qc_gh; | 584 | struct gfs2_holder sd_qc_gh; |
| 586 | 585 | ||
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 2f94bd723698..fb15d3b1f409 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | #include "acl.h" | 24 | #include "acl.h" |
| 25 | #include "bmap.h" | 25 | #include "bmap.h" |
| 26 | #include "dir.h" | 26 | #include "dir.h" |
| 27 | #include "eattr.h" | 27 | #include "xattr.h" |
| 28 | #include "glock.h" | 28 | #include "glock.h" |
| 29 | #include "glops.h" | 29 | #include "glops.h" |
| 30 | #include "inode.h" | 30 | #include "inode.h" |
| @@ -519,139 +519,6 @@ out: | |||
| 519 | return inode ? inode : ERR_PTR(error); | 519 | return inode ? inode : ERR_PTR(error); |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | static void gfs2_inum_range_in(struct gfs2_inum_range_host *ir, const void *buf) | ||
| 523 | { | ||
| 524 | const struct gfs2_inum_range *str = buf; | ||
| 525 | |||
| 526 | ir->ir_start = be64_to_cpu(str->ir_start); | ||
| 527 | ir->ir_length = be64_to_cpu(str->ir_length); | ||
| 528 | } | ||
| 529 | |||
| 530 | static void gfs2_inum_range_out(const struct gfs2_inum_range_host *ir, void *buf) | ||
| 531 | { | ||
| 532 | struct gfs2_inum_range *str = buf; | ||
| 533 | |||
| 534 | str->ir_start = cpu_to_be64(ir->ir_start); | ||
| 535 | str->ir_length = cpu_to_be64(ir->ir_length); | ||
| 536 | } | ||
| 537 | |||
| 538 | static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino) | ||
| 539 | { | ||
| 540 | struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode); | ||
| 541 | struct buffer_head *bh; | ||
| 542 | struct gfs2_inum_range_host ir; | ||
| 543 | int error; | ||
| 544 | |||
| 545 | error = gfs2_trans_begin(sdp, RES_DINODE, 0); | ||
| 546 | if (error) | ||
| 547 | return error; | ||
| 548 | mutex_lock(&sdp->sd_inum_mutex); | ||
| 549 | |||
| 550 | error = gfs2_meta_inode_buffer(ip, &bh); | ||
| 551 | if (error) { | ||
| 552 | mutex_unlock(&sdp->sd_inum_mutex); | ||
| 553 | gfs2_trans_end(sdp); | ||
| 554 | return error; | ||
| 555 | } | ||
| 556 | |||
| 557 | gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode)); | ||
| 558 | |||
| 559 | if (ir.ir_length) { | ||
| 560 | *formal_ino = ir.ir_start++; | ||
| 561 | ir.ir_length--; | ||
| 562 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | ||
| 563 | gfs2_inum_range_out(&ir, | ||
| 564 | bh->b_data + sizeof(struct gfs2_dinode)); | ||
| 565 | brelse(bh); | ||
| 566 | mutex_unlock(&sdp->sd_inum_mutex); | ||
| 567 | gfs2_trans_end(sdp); | ||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | brelse(bh); | ||
| 572 | |||
| 573 | mutex_unlock(&sdp->sd_inum_mutex); | ||
| 574 | gfs2_trans_end(sdp); | ||
| 575 | |||
| 576 | return 1; | ||
| 577 | } | ||
| 578 | |||
| 579 | static int pick_formal_ino_2(struct gfs2_sbd *sdp, u64 *formal_ino) | ||
| 580 | { | ||
| 581 | struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode); | ||
| 582 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_inum_inode); | ||
| 583 | struct gfs2_holder gh; | ||
| 584 | struct buffer_head *bh; | ||
| 585 | struct gfs2_inum_range_host ir; | ||
| 586 | int error; | ||
| 587 | |||
| 588 | error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | ||
| 589 | if (error) | ||
| 590 | return error; | ||
| 591 | |||
| 592 | error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0); | ||
| 593 | if (error) | ||
| 594 | goto out; | ||
| 595 | mutex_lock(&sdp->sd_inum_mutex); | ||
| 596 | |||
| 597 | error = gfs2_meta_inode_buffer(ip, &bh); | ||
| 598 | if (error) | ||
| 599 | goto out_end_trans; | ||
| 600 | |||
| 601 | gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode)); | ||
| 602 | |||
| 603 | if (!ir.ir_length) { | ||
| 604 | struct buffer_head *m_bh; | ||
| 605 | u64 x, y; | ||
| 606 | __be64 z; | ||
| 607 | |||
| 608 | error = gfs2_meta_inode_buffer(m_ip, &m_bh); | ||
| 609 | if (error) | ||
| 610 | goto out_brelse; | ||
| 611 | |||
| 612 | z = *(__be64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)); | ||
| 613 | x = y = be64_to_cpu(z); | ||
| 614 | ir.ir_start = x; | ||
| 615 | ir.ir_length = GFS2_INUM_QUANTUM; | ||
| 616 | x += GFS2_INUM_QUANTUM; | ||
| 617 | if (x < y) | ||
| 618 | gfs2_consist_inode(m_ip); | ||
| 619 | z = cpu_to_be64(x); | ||
| 620 | gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); | ||
| 621 | *(__be64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = z; | ||
| 622 | |||
| 623 | brelse(m_bh); | ||
| 624 | } | ||
| 625 | |||
| 626 | *formal_ino = ir.ir_start++; | ||
| 627 | ir.ir_length--; | ||
| 628 | |||
| 629 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | ||
| 630 | gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode)); | ||
| 631 | |||
| 632 | out_brelse: | ||
| 633 | brelse(bh); | ||
| 634 | out_end_trans: | ||
| 635 | mutex_unlock(&sdp->sd_inum_mutex); | ||
| 636 | gfs2_trans_end(sdp); | ||
| 637 | out: | ||
| 638 | gfs2_glock_dq_uninit(&gh); | ||
| 639 | return error; | ||
| 640 | } | ||
| 641 | |||
| 642 | static int pick_formal_ino(struct gfs2_sbd *sdp, u64 *inum) | ||
| 643 | { | ||
| 644 | int error; | ||
| 645 | |||
| 646 | error = pick_formal_ino_1(sdp, inum); | ||
| 647 | if (error <= 0) | ||
| 648 | return error; | ||
| 649 | |||
| 650 | error = pick_formal_ino_2(sdp, inum); | ||
| 651 | |||
| 652 | return error; | ||
| 653 | } | ||
| 654 | |||
| 655 | /** | 522 | /** |
| 656 | * create_ok - OK to create a new on-disk inode here? | 523 | * create_ok - OK to create a new on-disk inode here? |
| 657 | * @dip: Directory in which dinode is to be created | 524 | * @dip: Directory in which dinode is to be created |
| @@ -731,7 +598,7 @@ static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) | |||
| 731 | if (error) | 598 | if (error) |
| 732 | goto out_ipreserv; | 599 | goto out_ipreserv; |
| 733 | 600 | ||
| 734 | *no_addr = gfs2_alloc_di(dip, generation); | 601 | error = gfs2_alloc_di(dip, no_addr, generation); |
| 735 | 602 | ||
| 736 | gfs2_trans_end(sdp); | 603 | gfs2_trans_end(sdp); |
| 737 | 604 | ||
| @@ -924,7 +791,6 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
| 924 | size_t len; | 791 | size_t len; |
| 925 | void *value; | 792 | void *value; |
| 926 | char *name; | 793 | char *name; |
| 927 | struct gfs2_ea_request er; | ||
| 928 | 794 | ||
| 929 | err = security_inode_init_security(&ip->i_inode, &dip->i_inode, | 795 | err = security_inode_init_security(&ip->i_inode, &dip->i_inode, |
| 930 | &name, &value, &len); | 796 | &name, &value, &len); |
| @@ -935,16 +801,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip) | |||
| 935 | return err; | 801 | return err; |
| 936 | } | 802 | } |
| 937 | 803 | ||
| 938 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 804 | err = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SECURITY, name, value, len, 0); |
| 939 | |||
| 940 | er.er_type = GFS2_EATYPE_SECURITY; | ||
| 941 | er.er_name = name; | ||
| 942 | er.er_data = value; | ||
| 943 | er.er_name_len = strlen(name); | ||
| 944 | er.er_data_len = len; | ||
| 945 | |||
| 946 | err = gfs2_ea_set_i(ip, &er); | ||
| 947 | |||
| 948 | kfree(value); | 805 | kfree(value); |
| 949 | kfree(name); | 806 | kfree(name); |
| 950 | 807 | ||
| @@ -991,13 +848,10 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
| 991 | if (error) | 848 | if (error) |
| 992 | goto fail_gunlock; | 849 | goto fail_gunlock; |
| 993 | 850 | ||
| 994 | error = pick_formal_ino(sdp, &inum.no_formal_ino); | ||
| 995 | if (error) | ||
| 996 | goto fail_gunlock; | ||
| 997 | |||
| 998 | error = alloc_dinode(dip, &inum.no_addr, &generation); | 851 | error = alloc_dinode(dip, &inum.no_addr, &generation); |
| 999 | if (error) | 852 | if (error) |
| 1000 | goto fail_gunlock; | 853 | goto fail_gunlock; |
| 854 | inum.no_formal_ino = generation; | ||
| 1001 | 855 | ||
| 1002 | error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, | 856 | error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, |
| 1003 | LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); | 857 | LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); |
| @@ -1008,9 +862,8 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | |||
| 1008 | if (error) | 862 | if (error) |
| 1009 | goto fail_gunlock2; | 863 | goto fail_gunlock2; |
| 1010 | 864 | ||
| 1011 | inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), | 865 | inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, |
| 1012 | inum.no_addr, | 866 | inum.no_formal_ino, 0); |
| 1013 | inum.no_formal_ino, 0); | ||
| 1014 | if (IS_ERR(inode)) | 867 | if (IS_ERR(inode)) |
| 1015 | goto fail_gunlock2; | 868 | goto fail_gunlock2; |
| 1016 | 869 | ||
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 7bc3c45cd676..52fb6c048981 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
| @@ -84,7 +84,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) | |||
| 84 | 84 | ||
| 85 | gfs2_tune_init(&sdp->sd_tune); | 85 | gfs2_tune_init(&sdp->sd_tune); |
| 86 | 86 | ||
| 87 | mutex_init(&sdp->sd_inum_mutex); | ||
| 88 | spin_lock_init(&sdp->sd_statfs_spin); | 87 | spin_lock_init(&sdp->sd_statfs_spin); |
| 89 | 88 | ||
| 90 | spin_lock_init(&sdp->sd_rindex_spin); | 89 | spin_lock_init(&sdp->sd_rindex_spin); |
| @@ -833,21 +832,12 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) | |||
| 833 | if (error) | 832 | if (error) |
| 834 | goto fail; | 833 | goto fail; |
| 835 | 834 | ||
| 836 | /* Read in the master inode number inode */ | ||
| 837 | sdp->sd_inum_inode = gfs2_lookup_simple(master, "inum"); | ||
| 838 | if (IS_ERR(sdp->sd_inum_inode)) { | ||
| 839 | error = PTR_ERR(sdp->sd_inum_inode); | ||
| 840 | fs_err(sdp, "can't read in inum inode: %d\n", error); | ||
| 841 | goto fail_journal; | ||
| 842 | } | ||
| 843 | |||
| 844 | |||
| 845 | /* Read in the master statfs inode */ | 835 | /* Read in the master statfs inode */ |
| 846 | sdp->sd_statfs_inode = gfs2_lookup_simple(master, "statfs"); | 836 | sdp->sd_statfs_inode = gfs2_lookup_simple(master, "statfs"); |
| 847 | if (IS_ERR(sdp->sd_statfs_inode)) { | 837 | if (IS_ERR(sdp->sd_statfs_inode)) { |
| 848 | error = PTR_ERR(sdp->sd_statfs_inode); | 838 | error = PTR_ERR(sdp->sd_statfs_inode); |
| 849 | fs_err(sdp, "can't read in statfs inode: %d\n", error); | 839 | fs_err(sdp, "can't read in statfs inode: %d\n", error); |
| 850 | goto fail_inum; | 840 | goto fail_journal; |
| 851 | } | 841 | } |
| 852 | 842 | ||
| 853 | /* Read in the resource index inode */ | 843 | /* Read in the resource index inode */ |
| @@ -876,8 +866,6 @@ fail_rindex: | |||
| 876 | iput(sdp->sd_rindex); | 866 | iput(sdp->sd_rindex); |
| 877 | fail_statfs: | 867 | fail_statfs: |
| 878 | iput(sdp->sd_statfs_inode); | 868 | iput(sdp->sd_statfs_inode); |
| 879 | fail_inum: | ||
| 880 | iput(sdp->sd_inum_inode); | ||
| 881 | fail_journal: | 869 | fail_journal: |
| 882 | init_journal(sdp, UNDO); | 870 | init_journal(sdp, UNDO); |
| 883 | fail: | 871 | fail: |
| @@ -905,20 +893,12 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) | |||
| 905 | return error; | 893 | return error; |
| 906 | } | 894 | } |
| 907 | 895 | ||
| 908 | sprintf(buf, "inum_range%u", sdp->sd_jdesc->jd_jid); | ||
| 909 | sdp->sd_ir_inode = gfs2_lookup_simple(pn, buf); | ||
| 910 | if (IS_ERR(sdp->sd_ir_inode)) { | ||
| 911 | error = PTR_ERR(sdp->sd_ir_inode); | ||
| 912 | fs_err(sdp, "can't find local \"ir\" file: %d\n", error); | ||
| 913 | goto fail; | ||
| 914 | } | ||
| 915 | |||
| 916 | sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid); | 896 | sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid); |
| 917 | sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf); | 897 | sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf); |
| 918 | if (IS_ERR(sdp->sd_sc_inode)) { | 898 | if (IS_ERR(sdp->sd_sc_inode)) { |
| 919 | error = PTR_ERR(sdp->sd_sc_inode); | 899 | error = PTR_ERR(sdp->sd_sc_inode); |
| 920 | fs_err(sdp, "can't find local \"sc\" file: %d\n", error); | 900 | fs_err(sdp, "can't find local \"sc\" file: %d\n", error); |
| 921 | goto fail_ir_i; | 901 | goto fail; |
| 922 | } | 902 | } |
| 923 | 903 | ||
| 924 | sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid); | 904 | sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid); |
| @@ -932,27 +912,16 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo) | |||
| 932 | iput(pn); | 912 | iput(pn); |
| 933 | pn = NULL; | 913 | pn = NULL; |
| 934 | 914 | ||
| 935 | ip = GFS2_I(sdp->sd_ir_inode); | ||
| 936 | error = gfs2_glock_nq_init(ip->i_gl, | ||
| 937 | LM_ST_EXCLUSIVE, 0, | ||
| 938 | &sdp->sd_ir_gh); | ||
| 939 | if (error) { | ||
| 940 | fs_err(sdp, "can't lock local \"ir\" file: %d\n", error); | ||
| 941 | goto fail_qc_i; | ||
| 942 | } | ||
| 943 | |||
| 944 | ip = GFS2_I(sdp->sd_sc_inode); | 915 | ip = GFS2_I(sdp->sd_sc_inode); |
| 945 | error = gfs2_glock_nq_init(ip->i_gl, | 916 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, |
| 946 | LM_ST_EXCLUSIVE, 0, | ||
| 947 | &sdp->sd_sc_gh); | 917 | &sdp->sd_sc_gh); |
| 948 | if (error) { | 918 | if (error) { |
| 949 | fs_err(sdp, "can't lock local \"sc\" file: %d\n", error); | 919 | fs_err(sdp, "can't lock local \"sc\" file: %d\n", error); |
| 950 | goto fail_ir_gh; | 920 | goto fail_qc_i; |
| 951 | } | 921 | } |
| 952 | 922 | ||
| 953 | ip = GFS2_I(sdp->sd_qc_inode); | 923 | ip = GFS2_I(sdp->sd_qc_inode); |
| 954 | error = gfs2_glock_nq_init(ip->i_gl, | 924 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, |
| 955 | LM_ST_EXCLUSIVE, 0, | ||
| 956 | &sdp->sd_qc_gh); | 925 | &sdp->sd_qc_gh); |
| 957 | if (error) { | 926 | if (error) { |
| 958 | fs_err(sdp, "can't lock local \"qc\" file: %d\n", error); | 927 | fs_err(sdp, "can't lock local \"qc\" file: %d\n", error); |
| @@ -965,14 +934,10 @@ fail_qc_gh: | |||
| 965 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); | 934 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); |
| 966 | fail_ut_gh: | 935 | fail_ut_gh: |
| 967 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); | 936 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); |
| 968 | fail_ir_gh: | ||
| 969 | gfs2_glock_dq_uninit(&sdp->sd_ir_gh); | ||
| 970 | fail_qc_i: | 937 | fail_qc_i: |
| 971 | iput(sdp->sd_qc_inode); | 938 | iput(sdp->sd_qc_inode); |
| 972 | fail_ut_i: | 939 | fail_ut_i: |
| 973 | iput(sdp->sd_sc_inode); | 940 | iput(sdp->sd_sc_inode); |
| 974 | fail_ir_i: | ||
| 975 | iput(sdp->sd_ir_inode); | ||
| 976 | fail: | 941 | fail: |
| 977 | if (pn) | 942 | if (pn) |
| 978 | iput(pn); | 943 | iput(pn); |
| @@ -1063,7 +1028,6 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) | |||
| 1063 | 1028 | ||
| 1064 | ls->ls_ops = lm; | 1029 | ls->ls_ops = lm; |
| 1065 | ls->ls_first = 1; | 1030 | ls->ls_first = 1; |
| 1066 | ls->ls_id = 0; | ||
| 1067 | 1031 | ||
| 1068 | for (options = args->ar_hostdata; (o = strsep(&options, ":")); ) { | 1032 | for (options = args->ar_hostdata; (o = strsep(&options, ":")); ) { |
| 1069 | substring_t tmp[MAX_OPT_ARGS]; | 1033 | substring_t tmp[MAX_OPT_ARGS]; |
| @@ -1081,10 +1045,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) | |||
| 1081 | ls->ls_jid = option; | 1045 | ls->ls_jid = option; |
| 1082 | break; | 1046 | break; |
| 1083 | case Opt_id: | 1047 | case Opt_id: |
| 1084 | ret = match_int(&tmp[0], &option); | 1048 | /* Obsolete, but left for backward compat purposes */ |
| 1085 | if (ret) | ||
| 1086 | goto hostdata_error; | ||
| 1087 | ls->ls_id = option; | ||
| 1088 | break; | 1049 | break; |
| 1089 | case Opt_first: | 1050 | case Opt_first: |
| 1090 | ret = match_int(&tmp[0], &option); | 1051 | ret = match_int(&tmp[0], &option); |
| @@ -1133,6 +1094,17 @@ void gfs2_lm_unmount(struct gfs2_sbd *sdp) | |||
| 1133 | lm->lm_unmount(sdp); | 1094 | lm->lm_unmount(sdp); |
| 1134 | } | 1095 | } |
| 1135 | 1096 | ||
| 1097 | void gfs2_online_uevent(struct gfs2_sbd *sdp) | ||
| 1098 | { | ||
| 1099 | struct super_block *sb = sdp->sd_vfs; | ||
| 1100 | char ro[20]; | ||
| 1101 | char spectator[20]; | ||
| 1102 | char *envp[] = { ro, spectator, NULL }; | ||
| 1103 | sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0); | ||
| 1104 | sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0); | ||
| 1105 | kobject_uevent_env(&sdp->sd_kobj, KOBJ_ONLINE, envp); | ||
| 1106 | } | ||
| 1107 | |||
| 1136 | /** | 1108 | /** |
| 1137 | * fill_super - Read in superblock | 1109 | * fill_super - Read in superblock |
| 1138 | * @sb: The VFS superblock | 1110 | * @sb: The VFS superblock |
| @@ -1157,6 +1129,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
| 1157 | sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT; | 1129 | sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT; |
| 1158 | sdp->sd_args.ar_data = GFS2_DATA_DEFAULT; | 1130 | sdp->sd_args.ar_data = GFS2_DATA_DEFAULT; |
| 1159 | sdp->sd_args.ar_commit = 60; | 1131 | sdp->sd_args.ar_commit = 60; |
| 1132 | sdp->sd_args.ar_errors = GFS2_ERRORS_DEFAULT; | ||
| 1160 | 1133 | ||
| 1161 | error = gfs2_mount_args(sdp, &sdp->sd_args, data); | 1134 | error = gfs2_mount_args(sdp, &sdp->sd_args, data); |
| 1162 | if (error) { | 1135 | if (error) { |
| @@ -1174,6 +1147,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
| 1174 | sb->s_magic = GFS2_MAGIC; | 1147 | sb->s_magic = GFS2_MAGIC; |
| 1175 | sb->s_op = &gfs2_super_ops; | 1148 | sb->s_op = &gfs2_super_ops; |
| 1176 | sb->s_export_op = &gfs2_export_ops; | 1149 | sb->s_export_op = &gfs2_export_ops; |
| 1150 | sb->s_xattr = gfs2_xattr_handlers; | ||
| 1177 | sb->s_time_gran = 1; | 1151 | sb->s_time_gran = 1; |
| 1178 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 1152 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
| 1179 | 1153 | ||
| @@ -1236,7 +1210,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
| 1236 | } | 1210 | } |
| 1237 | 1211 | ||
| 1238 | gfs2_glock_dq_uninit(&mount_gh); | 1212 | gfs2_glock_dq_uninit(&mount_gh); |
| 1239 | 1213 | gfs2_online_uevent(sdp); | |
| 1240 | return 0; | 1214 | return 0; |
| 1241 | 1215 | ||
| 1242 | fail_threads: | 1216 | fail_threads: |
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index f8bd20baf99c..c3ac18054057 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
| @@ -26,8 +26,7 @@ | |||
| 26 | #include "acl.h" | 26 | #include "acl.h" |
| 27 | #include "bmap.h" | 27 | #include "bmap.h" |
| 28 | #include "dir.h" | 28 | #include "dir.h" |
| 29 | #include "eaops.h" | 29 | #include "xattr.h" |
| 30 | #include "eattr.h" | ||
| 31 | #include "glock.h" | 30 | #include "glock.h" |
| 32 | #include "inode.h" | 31 | #include "inode.h" |
| 33 | #include "meta_io.h" | 32 | #include "meta_io.h" |
| @@ -349,7 +348,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) | |||
| 349 | 348 | ||
| 350 | error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); | 349 | error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); |
| 351 | if (error) | 350 | if (error) |
| 352 | goto out_rgrp; | 351 | goto out_gunlock; |
| 353 | 352 | ||
| 354 | error = gfs2_dir_del(dip, &dentry->d_name); | 353 | error = gfs2_dir_del(dip, &dentry->d_name); |
| 355 | if (error) | 354 | if (error) |
| @@ -1302,60 +1301,53 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name, | |||
| 1302 | const void *data, size_t size, int flags) | 1301 | const void *data, size_t size, int flags) |
| 1303 | { | 1302 | { |
| 1304 | struct inode *inode = dentry->d_inode; | 1303 | struct inode *inode = dentry->d_inode; |
| 1305 | struct gfs2_ea_request er; | 1304 | struct gfs2_inode *ip = GFS2_I(inode); |
| 1306 | 1305 | struct gfs2_holder gh; | |
| 1307 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 1306 | int ret; |
| 1308 | er.er_type = gfs2_ea_name2type(name, &er.er_name); | ||
| 1309 | if (er.er_type == GFS2_EATYPE_UNUSED) | ||
| 1310 | return -EOPNOTSUPP; | ||
| 1311 | er.er_data = (char *)data; | ||
| 1312 | er.er_name_len = strlen(er.er_name); | ||
| 1313 | er.er_data_len = size; | ||
| 1314 | er.er_flags = flags; | ||
| 1315 | |||
| 1316 | gfs2_assert_warn(GFS2_SB(inode), !(er.er_flags & GFS2_ERF_MODE)); | ||
| 1317 | 1307 | ||
| 1318 | return gfs2_ea_set(GFS2_I(inode), &er); | 1308 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); |
| 1309 | ret = gfs2_glock_nq(&gh); | ||
| 1310 | if (ret == 0) { | ||
| 1311 | ret = generic_setxattr(dentry, name, data, size, flags); | ||
| 1312 | gfs2_glock_dq(&gh); | ||
| 1313 | } | ||
| 1314 | gfs2_holder_uninit(&gh); | ||
| 1315 | return ret; | ||
| 1319 | } | 1316 | } |
| 1320 | 1317 | ||
| 1321 | static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, | 1318 | static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, |
| 1322 | void *data, size_t size) | 1319 | void *data, size_t size) |
| 1323 | { | 1320 | { |
| 1324 | struct gfs2_ea_request er; | 1321 | struct inode *inode = dentry->d_inode; |
| 1325 | 1322 | struct gfs2_inode *ip = GFS2_I(inode); | |
| 1326 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 1323 | struct gfs2_holder gh; |
| 1327 | er.er_type = gfs2_ea_name2type(name, &er.er_name); | 1324 | int ret; |
| 1328 | if (er.er_type == GFS2_EATYPE_UNUSED) | ||
| 1329 | return -EOPNOTSUPP; | ||
| 1330 | er.er_data = data; | ||
| 1331 | er.er_name_len = strlen(er.er_name); | ||
| 1332 | er.er_data_len = size; | ||
| 1333 | |||
| 1334 | return gfs2_ea_get(GFS2_I(dentry->d_inode), &er); | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
| 1338 | { | ||
| 1339 | struct gfs2_ea_request er; | ||
| 1340 | |||
| 1341 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | ||
| 1342 | er.er_data = (size) ? buffer : NULL; | ||
| 1343 | er.er_data_len = size; | ||
| 1344 | 1325 | ||
| 1345 | return gfs2_ea_list(GFS2_I(dentry->d_inode), &er); | 1326 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); |
| 1327 | ret = gfs2_glock_nq(&gh); | ||
| 1328 | if (ret == 0) { | ||
| 1329 | ret = generic_getxattr(dentry, name, data, size); | ||
| 1330 | gfs2_glock_dq(&gh); | ||
| 1331 | } | ||
| 1332 | gfs2_holder_uninit(&gh); | ||
| 1333 | return ret; | ||
| 1346 | } | 1334 | } |
| 1347 | 1335 | ||
| 1348 | static int gfs2_removexattr(struct dentry *dentry, const char *name) | 1336 | static int gfs2_removexattr(struct dentry *dentry, const char *name) |
| 1349 | { | 1337 | { |
| 1350 | struct gfs2_ea_request er; | 1338 | struct inode *inode = dentry->d_inode; |
| 1351 | 1339 | struct gfs2_inode *ip = GFS2_I(inode); | |
| 1352 | memset(&er, 0, sizeof(struct gfs2_ea_request)); | 1340 | struct gfs2_holder gh; |
| 1353 | er.er_type = gfs2_ea_name2type(name, &er.er_name); | 1341 | int ret; |
| 1354 | if (er.er_type == GFS2_EATYPE_UNUSED) | ||
| 1355 | return -EOPNOTSUPP; | ||
| 1356 | er.er_name_len = strlen(er.er_name); | ||
| 1357 | 1342 | ||
| 1358 | return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er); | 1343 | gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); |
| 1344 | ret = gfs2_glock_nq(&gh); | ||
| 1345 | if (ret == 0) { | ||
| 1346 | ret = generic_removexattr(dentry, name); | ||
| 1347 | gfs2_glock_dq(&gh); | ||
| 1348 | } | ||
| 1349 | gfs2_holder_uninit(&gh); | ||
| 1350 | return ret; | ||
| 1359 | } | 1351 | } |
| 1360 | 1352 | ||
| 1361 | static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 1353 | static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index fba795798d3a..18d3a28554ac 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
| @@ -1256,7 +1256,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip) | |||
| 1256 | * Returns: The block type (GFS2_BLKST_*) | 1256 | * Returns: The block type (GFS2_BLKST_*) |
| 1257 | */ | 1257 | */ |
| 1258 | 1258 | ||
| 1259 | unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) | 1259 | static unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) |
| 1260 | { | 1260 | { |
| 1261 | struct gfs2_bitmap *bi = NULL; | 1261 | struct gfs2_bitmap *bi = NULL; |
| 1262 | u32 length, rgrp_block, buf_block; | 1262 | u32 length, rgrp_block, buf_block; |
| @@ -1459,6 +1459,16 @@ int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl) | |||
| 1459 | return 0; | 1459 | return 0; |
| 1460 | } | 1460 | } |
| 1461 | 1461 | ||
| 1462 | static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd) | ||
| 1463 | { | ||
| 1464 | struct gfs2_sbd *sdp = rgd->rd_sbd; | ||
| 1465 | fs_warn(sdp, "rgrp %llu has an error, marking it readonly until umount\n", | ||
| 1466 | (unsigned long long)rgd->rd_addr); | ||
| 1467 | fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n"); | ||
| 1468 | gfs2_rgrp_dump(NULL, rgd->rd_gl); | ||
| 1469 | rgd->rd_flags |= GFS2_RDF_ERROR; | ||
| 1470 | } | ||
| 1471 | |||
| 1462 | /** | 1472 | /** |
| 1463 | * gfs2_alloc_block - Allocate one or more blocks | 1473 | * gfs2_alloc_block - Allocate one or more blocks |
| 1464 | * @ip: the inode to allocate the block for | 1474 | * @ip: the inode to allocate the block for |
| @@ -1520,22 +1530,20 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n) | |||
| 1520 | return 0; | 1530 | return 0; |
| 1521 | 1531 | ||
| 1522 | rgrp_error: | 1532 | rgrp_error: |
| 1523 | fs_warn(sdp, "rgrp %llu has an error, marking it readonly until umount\n", | 1533 | gfs2_rgrp_error(rgd); |
| 1524 | (unsigned long long)rgd->rd_addr); | ||
| 1525 | fs_warn(sdp, "umount on all nodes and run fsck.gfs2 to fix the error\n"); | ||
| 1526 | gfs2_rgrp_dump(NULL, rgd->rd_gl); | ||
| 1527 | rgd->rd_flags |= GFS2_RDF_ERROR; | ||
| 1528 | return -EIO; | 1534 | return -EIO; |
| 1529 | } | 1535 | } |
| 1530 | 1536 | ||
| 1531 | /** | 1537 | /** |
| 1532 | * gfs2_alloc_di - Allocate a dinode | 1538 | * gfs2_alloc_di - Allocate a dinode |
| 1533 | * @dip: the directory that the inode is going in | 1539 | * @dip: the directory that the inode is going in |
| 1540 | * @bn: the block number which is allocated | ||
| 1541 | * @generation: the generation number of the inode | ||
| 1534 | * | 1542 | * |
| 1535 | * Returns: the block allocated | 1543 | * Returns: 0 on success or error |
| 1536 | */ | 1544 | */ |
| 1537 | 1545 | ||
| 1538 | u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) | 1546 | int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation) |
| 1539 | { | 1547 | { |
| 1540 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 1548 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
| 1541 | struct gfs2_alloc *al = dip->i_alloc; | 1549 | struct gfs2_alloc *al = dip->i_alloc; |
| @@ -1546,16 +1554,21 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) | |||
| 1546 | 1554 | ||
| 1547 | blk = rgblk_search(rgd, rgd->rd_last_alloc, | 1555 | blk = rgblk_search(rgd, rgd->rd_last_alloc, |
| 1548 | GFS2_BLKST_FREE, GFS2_BLKST_DINODE, &n); | 1556 | GFS2_BLKST_FREE, GFS2_BLKST_DINODE, &n); |
| 1549 | BUG_ON(blk == BFITNOENT); | ||
| 1550 | 1557 | ||
| 1551 | rgd->rd_last_alloc = blk; | 1558 | /* Since all blocks are reserved in advance, this shouldn't happen */ |
| 1559 | if (blk == BFITNOENT) | ||
| 1560 | goto rgrp_error; | ||
| 1552 | 1561 | ||
| 1562 | rgd->rd_last_alloc = blk; | ||
| 1553 | block = rgd->rd_data0 + blk; | 1563 | block = rgd->rd_data0 + blk; |
| 1564 | if (rgd->rd_free == 0) | ||
| 1565 | goto rgrp_error; | ||
| 1554 | 1566 | ||
| 1555 | gfs2_assert_withdraw(sdp, rgd->rd_free); | ||
| 1556 | rgd->rd_free--; | 1567 | rgd->rd_free--; |
| 1557 | rgd->rd_dinodes++; | 1568 | rgd->rd_dinodes++; |
| 1558 | *generation = rgd->rd_igeneration++; | 1569 | *generation = rgd->rd_igeneration++; |
| 1570 | if (*generation == 0) | ||
| 1571 | *generation = rgd->rd_igeneration++; | ||
| 1559 | gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); | 1572 | gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); |
| 1560 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); | 1573 | gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); |
| 1561 | 1574 | ||
| @@ -1568,7 +1581,12 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) | |||
| 1568 | rgd->rd_free_clone--; | 1581 | rgd->rd_free_clone--; |
| 1569 | spin_unlock(&sdp->sd_rindex_spin); | 1582 | spin_unlock(&sdp->sd_rindex_spin); |
| 1570 | trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE); | 1583 | trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE); |
| 1571 | return block; | 1584 | *bn = block; |
| 1585 | return 0; | ||
| 1586 | |||
| 1587 | rgrp_error: | ||
| 1588 | gfs2_rgrp_error(rgd); | ||
| 1589 | return -EIO; | ||
| 1572 | } | 1590 | } |
| 1573 | 1591 | ||
| 1574 | /** | 1592 | /** |
| @@ -1676,6 +1694,46 @@ void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip) | |||
| 1676 | } | 1694 | } |
| 1677 | 1695 | ||
| 1678 | /** | 1696 | /** |
| 1697 | * gfs2_check_blk_type - Check the type of a block | ||
| 1698 | * @sdp: The superblock | ||
| 1699 | * @no_addr: The block number to check | ||
| 1700 | * @type: The block type we are looking for | ||
| 1701 | * | ||
| 1702 | * Returns: 0 if the block type matches the expected type | ||
| 1703 | * -ESTALE if it doesn't match | ||
| 1704 | * or -ve errno if something went wrong while checking | ||
| 1705 | */ | ||
| 1706 | |||
| 1707 | int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) | ||
| 1708 | { | ||
| 1709 | struct gfs2_rgrpd *rgd; | ||
| 1710 | struct gfs2_holder ri_gh, rgd_gh; | ||
| 1711 | int error; | ||
| 1712 | |||
| 1713 | error = gfs2_rindex_hold(sdp, &ri_gh); | ||
| 1714 | if (error) | ||
| 1715 | goto fail; | ||
| 1716 | |||
| 1717 | error = -EINVAL; | ||
| 1718 | rgd = gfs2_blk2rgrpd(sdp, no_addr); | ||
| 1719 | if (!rgd) | ||
| 1720 | goto fail_rindex; | ||
| 1721 | |||
| 1722 | error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh); | ||
| 1723 | if (error) | ||
| 1724 | goto fail_rindex; | ||
| 1725 | |||
| 1726 | if (gfs2_get_block_type(rgd, no_addr) != type) | ||
| 1727 | error = -ESTALE; | ||
| 1728 | |||
| 1729 | gfs2_glock_dq_uninit(&rgd_gh); | ||
| 1730 | fail_rindex: | ||
| 1731 | gfs2_glock_dq_uninit(&ri_gh); | ||
| 1732 | fail: | ||
| 1733 | return error; | ||
| 1734 | } | ||
| 1735 | |||
| 1736 | /** | ||
| 1679 | * gfs2_rlist_add - add a RG to a list of RGs | 1737 | * gfs2_rlist_add - add a RG to a list of RGs |
| 1680 | * @sdp: the filesystem | 1738 | * @sdp: the filesystem |
| 1681 | * @rlist: the list of resource groups | 1739 | * @rlist: the list of resource groups |
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 1e76ff0f3e00..b4106ddaaa98 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h | |||
| @@ -44,15 +44,15 @@ gfs2_inplace_reserve_i((ip), __FILE__, __LINE__) | |||
| 44 | 44 | ||
| 45 | extern void gfs2_inplace_release(struct gfs2_inode *ip); | 45 | extern void gfs2_inplace_release(struct gfs2_inode *ip); |
| 46 | 46 | ||
| 47 | extern unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block); | ||
| 48 | |||
| 49 | extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n); | 47 | extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n); |
| 50 | extern u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation); | 48 | extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation); |
| 51 | 49 | ||
| 52 | extern void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); | 50 | extern void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); |
| 53 | extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); | 51 | extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen); |
| 54 | extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); | 52 | extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip); |
| 55 | extern void gfs2_unlink_di(struct inode *inode); | 53 | extern void gfs2_unlink_di(struct inode *inode); |
| 54 | extern int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, | ||
| 55 | unsigned int type); | ||
| 56 | 56 | ||
| 57 | struct gfs2_rgrp_list { | 57 | struct gfs2_rgrp_list { |
| 58 | unsigned int rl_rgrps; | 58 | unsigned int rl_rgrps; |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index f522bb017973..0ec3ec672de1 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
| @@ -38,7 +38,7 @@ | |||
| 38 | #include "trans.h" | 38 | #include "trans.h" |
| 39 | #include "util.h" | 39 | #include "util.h" |
| 40 | #include "sys.h" | 40 | #include "sys.h" |
| 41 | #include "eattr.h" | 41 | #include "xattr.h" |
| 42 | 42 | ||
| 43 | #define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x) | 43 | #define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x) |
| 44 | 44 | ||
| @@ -68,6 +68,8 @@ enum { | |||
| 68 | Opt_discard, | 68 | Opt_discard, |
| 69 | Opt_nodiscard, | 69 | Opt_nodiscard, |
| 70 | Opt_commit, | 70 | Opt_commit, |
| 71 | Opt_err_withdraw, | ||
| 72 | Opt_err_panic, | ||
| 71 | Opt_error, | 73 | Opt_error, |
| 72 | }; | 74 | }; |
| 73 | 75 | ||
| @@ -97,6 +99,8 @@ static const match_table_t tokens = { | |||
| 97 | {Opt_discard, "discard"}, | 99 | {Opt_discard, "discard"}, |
| 98 | {Opt_nodiscard, "nodiscard"}, | 100 | {Opt_nodiscard, "nodiscard"}, |
| 99 | {Opt_commit, "commit=%d"}, | 101 | {Opt_commit, "commit=%d"}, |
| 102 | {Opt_err_withdraw, "errors=withdraw"}, | ||
| 103 | {Opt_err_panic, "errors=panic"}, | ||
| 100 | {Opt_error, NULL} | 104 | {Opt_error, NULL} |
| 101 | }; | 105 | }; |
| 102 | 106 | ||
| @@ -152,6 +156,11 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | |||
| 152 | args->ar_localcaching = 1; | 156 | args->ar_localcaching = 1; |
| 153 | break; | 157 | break; |
| 154 | case Opt_debug: | 158 | case Opt_debug: |
| 159 | if (args->ar_errors == GFS2_ERRORS_PANIC) { | ||
| 160 | fs_info(sdp, "-o debug and -o errors=panic " | ||
| 161 | "are mutually exclusive.\n"); | ||
| 162 | return -EINVAL; | ||
| 163 | } | ||
| 155 | args->ar_debug = 1; | 164 | args->ar_debug = 1; |
| 156 | break; | 165 | break; |
| 157 | case Opt_nodebug: | 166 | case Opt_nodebug: |
| @@ -205,6 +214,17 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | |||
| 205 | return rv ? rv : -EINVAL; | 214 | return rv ? rv : -EINVAL; |
| 206 | } | 215 | } |
| 207 | break; | 216 | break; |
| 217 | case Opt_err_withdraw: | ||
| 218 | args->ar_errors = GFS2_ERRORS_WITHDRAW; | ||
| 219 | break; | ||
| 220 | case Opt_err_panic: | ||
| 221 | if (args->ar_debug) { | ||
| 222 | fs_info(sdp, "-o debug and -o errors=panic " | ||
| 223 | "are mutually exclusive.\n"); | ||
| 224 | return -EINVAL; | ||
| 225 | } | ||
| 226 | args->ar_errors = GFS2_ERRORS_PANIC; | ||
| 227 | break; | ||
| 208 | case Opt_error: | 228 | case Opt_error: |
| 209 | default: | 229 | default: |
| 210 | fs_info(sdp, "invalid mount option: %s\n", o); | 230 | fs_info(sdp, "invalid mount option: %s\n", o); |
| @@ -768,7 +788,6 @@ restart: | |||
| 768 | /* Release stuff */ | 788 | /* Release stuff */ |
| 769 | 789 | ||
| 770 | iput(sdp->sd_jindex); | 790 | iput(sdp->sd_jindex); |
| 771 | iput(sdp->sd_inum_inode); | ||
| 772 | iput(sdp->sd_statfs_inode); | 791 | iput(sdp->sd_statfs_inode); |
| 773 | iput(sdp->sd_rindex); | 792 | iput(sdp->sd_rindex); |
| 774 | iput(sdp->sd_quota_inode); | 793 | iput(sdp->sd_quota_inode); |
| @@ -779,10 +798,8 @@ restart: | |||
| 779 | if (!sdp->sd_args.ar_spectator) { | 798 | if (!sdp->sd_args.ar_spectator) { |
| 780 | gfs2_glock_dq_uninit(&sdp->sd_journal_gh); | 799 | gfs2_glock_dq_uninit(&sdp->sd_journal_gh); |
| 781 | gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); | 800 | gfs2_glock_dq_uninit(&sdp->sd_jinode_gh); |
| 782 | gfs2_glock_dq_uninit(&sdp->sd_ir_gh); | ||
| 783 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); | 801 | gfs2_glock_dq_uninit(&sdp->sd_sc_gh); |
| 784 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); | 802 | gfs2_glock_dq_uninit(&sdp->sd_qc_gh); |
| 785 | iput(sdp->sd_ir_inode); | ||
| 786 | iput(sdp->sd_sc_inode); | 803 | iput(sdp->sd_sc_inode); |
| 787 | iput(sdp->sd_qc_inode); | 804 | iput(sdp->sd_qc_inode); |
| 788 | } | 805 | } |
| @@ -1084,6 +1101,7 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) | |||
| 1084 | gt->gt_log_flush_secs = args.ar_commit; | 1101 | gt->gt_log_flush_secs = args.ar_commit; |
| 1085 | spin_unlock(>->gt_spin); | 1102 | spin_unlock(>->gt_spin); |
| 1086 | 1103 | ||
| 1104 | gfs2_online_uevent(sdp); | ||
| 1087 | return 0; | 1105 | return 0; |
| 1088 | } | 1106 | } |
| 1089 | 1107 | ||
| @@ -1225,6 +1243,22 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
| 1225 | lfsecs = sdp->sd_tune.gt_log_flush_secs; | 1243 | lfsecs = sdp->sd_tune.gt_log_flush_secs; |
| 1226 | if (lfsecs != 60) | 1244 | if (lfsecs != 60) |
| 1227 | seq_printf(s, ",commit=%d", lfsecs); | 1245 | seq_printf(s, ",commit=%d", lfsecs); |
| 1246 | if (args->ar_errors != GFS2_ERRORS_DEFAULT) { | ||
| 1247 | const char *state; | ||
| 1248 | |||
| 1249 | switch (args->ar_errors) { | ||
| 1250 | case GFS2_ERRORS_WITHDRAW: | ||
| 1251 | state = "withdraw"; | ||
| 1252 | break; | ||
| 1253 | case GFS2_ERRORS_PANIC: | ||
| 1254 | state = "panic"; | ||
| 1255 | break; | ||
| 1256 | default: | ||
| 1257 | state = "unknown"; | ||
| 1258 | break; | ||
| 1259 | } | ||
| 1260 | seq_printf(s, ",errors=%s", state); | ||
| 1261 | } | ||
| 1228 | return 0; | 1262 | return 0; |
| 1229 | } | 1263 | } |
| 1230 | 1264 | ||
| @@ -1252,6 +1286,10 @@ static void gfs2_delete_inode(struct inode *inode) | |||
| 1252 | goto out; | 1286 | goto out; |
| 1253 | } | 1287 | } |
| 1254 | 1288 | ||
| 1289 | error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED); | ||
| 1290 | if (error) | ||
| 1291 | goto out_truncate; | ||
| 1292 | |||
| 1255 | gfs2_glock_dq_wait(&ip->i_iopen_gh); | 1293 | gfs2_glock_dq_wait(&ip->i_iopen_gh); |
| 1256 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); | 1294 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); |
| 1257 | error = gfs2_glock_nq(&ip->i_iopen_gh); | 1295 | error = gfs2_glock_nq(&ip->i_iopen_gh); |
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 22e0417ed996..235db3682885 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h | |||
| @@ -25,7 +25,7 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) | |||
| 25 | return x; | 25 | return x; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | void gfs2_jindex_free(struct gfs2_sbd *sdp); | 28 | extern void gfs2_jindex_free(struct gfs2_sbd *sdp); |
| 29 | 29 | ||
| 30 | extern int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *data); | 30 | extern int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *data); |
| 31 | 31 | ||
| @@ -36,7 +36,7 @@ extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename, | |||
| 36 | struct gfs2_inode **ipp); | 36 | struct gfs2_inode **ipp); |
| 37 | 37 | ||
| 38 | extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp); | 38 | extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp); |
| 39 | 39 | extern void gfs2_online_uevent(struct gfs2_sbd *sdp); | |
| 40 | extern int gfs2_statfs_init(struct gfs2_sbd *sdp); | 40 | extern int gfs2_statfs_init(struct gfs2_sbd *sdp); |
| 41 | extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, | 41 | extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, |
| 42 | s64 dinodes); | 42 | s64 dinodes); |
| @@ -54,6 +54,7 @@ extern struct file_system_type gfs2meta_fs_type; | |||
| 54 | extern const struct export_operations gfs2_export_ops; | 54 | extern const struct export_operations gfs2_export_ops; |
| 55 | extern const struct super_operations gfs2_super_ops; | 55 | extern const struct super_operations gfs2_super_ops; |
| 56 | extern const struct dentry_operations gfs2_dops; | 56 | extern const struct dentry_operations gfs2_dops; |
| 57 | extern struct xattr_handler *gfs2_xattr_handlers[]; | ||
| 57 | 58 | ||
| 58 | #endif /* __SUPER_DOT_H__ */ | 59 | #endif /* __SUPER_DOT_H__ */ |
| 59 | 60 | ||
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index a7cbfbd340c7..446329728d52 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/kobject.h> | 16 | #include <linux/kobject.h> |
| 17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
| 18 | #include <linux/gfs2_ondisk.h> | 18 | #include <linux/gfs2_ondisk.h> |
| 19 | #include <linux/genhd.h> | ||
| 19 | 20 | ||
| 20 | #include "gfs2.h" | 21 | #include "gfs2.h" |
| 21 | #include "incore.h" | 22 | #include "incore.h" |
| @@ -319,12 +320,6 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len) | |||
| 319 | return ret; | 320 | return ret; |
| 320 | } | 321 | } |
| 321 | 322 | ||
| 322 | static ssize_t lkid_show(struct gfs2_sbd *sdp, char *buf) | ||
| 323 | { | ||
| 324 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; | ||
| 325 | return sprintf(buf, "%u\n", ls->ls_id); | ||
| 326 | } | ||
| 327 | |||
| 328 | static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf) | 323 | static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf) |
| 329 | { | 324 | { |
| 330 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; | 325 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; |
| @@ -389,7 +384,6 @@ static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) | |||
| 389 | GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); | 384 | GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); |
| 390 | GDLM_ATTR(block, 0644, block_show, block_store); | 385 | GDLM_ATTR(block, 0644, block_show, block_store); |
| 391 | GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); | 386 | GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); |
| 392 | GDLM_ATTR(id, 0444, lkid_show, NULL); | ||
| 393 | GDLM_ATTR(jid, 0444, jid_show, NULL); | 387 | GDLM_ATTR(jid, 0444, jid_show, NULL); |
| 394 | GDLM_ATTR(first, 0444, lkfirst_show, NULL); | 388 | GDLM_ATTR(first, 0444, lkfirst_show, NULL); |
| 395 | GDLM_ATTR(first_done, 0444, first_done_show, NULL); | 389 | GDLM_ATTR(first_done, 0444, first_done_show, NULL); |
| @@ -401,7 +395,6 @@ static struct attribute *lock_module_attrs[] = { | |||
| 401 | &gdlm_attr_proto_name.attr, | 395 | &gdlm_attr_proto_name.attr, |
| 402 | &gdlm_attr_block.attr, | 396 | &gdlm_attr_block.attr, |
| 403 | &gdlm_attr_withdraw.attr, | 397 | &gdlm_attr_withdraw.attr, |
| 404 | &gdlm_attr_id.attr, | ||
| 405 | &gdlm_attr_jid.attr, | 398 | &gdlm_attr_jid.attr, |
| 406 | &gdlm_attr_first.attr, | 399 | &gdlm_attr_first.attr, |
| 407 | &gdlm_attr_first_done.attr, | 400 | &gdlm_attr_first_done.attr, |
| @@ -519,7 +512,14 @@ static struct attribute_group lock_module_group = { | |||
| 519 | 512 | ||
| 520 | int gfs2_sys_fs_add(struct gfs2_sbd *sdp) | 513 | int gfs2_sys_fs_add(struct gfs2_sbd *sdp) |
| 521 | { | 514 | { |
| 515 | struct super_block *sb = sdp->sd_vfs; | ||
| 522 | int error; | 516 | int error; |
| 517 | char ro[20]; | ||
| 518 | char spectator[20]; | ||
| 519 | char *envp[] = { ro, spectator, NULL }; | ||
| 520 | |||
| 521 | sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0); | ||
| 522 | sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0); | ||
| 523 | 523 | ||
| 524 | sdp->sd_kobj.kset = gfs2_kset; | 524 | sdp->sd_kobj.kset = gfs2_kset; |
| 525 | error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL, | 525 | error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL, |
| @@ -535,9 +535,17 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp) | |||
| 535 | if (error) | 535 | if (error) |
| 536 | goto fail_tune; | 536 | goto fail_tune; |
| 537 | 537 | ||
| 538 | kobject_uevent(&sdp->sd_kobj, KOBJ_ADD); | 538 | error = sysfs_create_link(&sdp->sd_kobj, |
| 539 | &disk_to_dev(sb->s_bdev->bd_disk)->kobj, | ||
| 540 | "device"); | ||
| 541 | if (error) | ||
| 542 | goto fail_lock_module; | ||
| 543 | |||
| 544 | kobject_uevent_env(&sdp->sd_kobj, KOBJ_ADD, envp); | ||
| 539 | return 0; | 545 | return 0; |
| 540 | 546 | ||
| 547 | fail_lock_module: | ||
| 548 | sysfs_remove_group(&sdp->sd_kobj, &lock_module_group); | ||
| 541 | fail_tune: | 549 | fail_tune: |
| 542 | sysfs_remove_group(&sdp->sd_kobj, &tune_group); | 550 | sysfs_remove_group(&sdp->sd_kobj, &tune_group); |
| 543 | fail_reg: | 551 | fail_reg: |
| @@ -549,12 +557,12 @@ fail: | |||
| 549 | 557 | ||
| 550 | void gfs2_sys_fs_del(struct gfs2_sbd *sdp) | 558 | void gfs2_sys_fs_del(struct gfs2_sbd *sdp) |
| 551 | { | 559 | { |
| 560 | sysfs_remove_link(&sdp->sd_kobj, "device"); | ||
| 552 | sysfs_remove_group(&sdp->sd_kobj, &tune_group); | 561 | sysfs_remove_group(&sdp->sd_kobj, &tune_group); |
| 553 | sysfs_remove_group(&sdp->sd_kobj, &lock_module_group); | 562 | sysfs_remove_group(&sdp->sd_kobj, &lock_module_group); |
| 554 | kobject_put(&sdp->sd_kobj); | 563 | kobject_put(&sdp->sd_kobj); |
| 555 | } | 564 | } |
| 556 | 565 | ||
| 557 | |||
| 558 | static int gfs2_uevent(struct kset *kset, struct kobject *kobj, | 566 | static int gfs2_uevent(struct kset *kset, struct kobject *kobj, |
| 559 | struct kobj_uevent_env *env) | 567 | struct kobj_uevent_env *env) |
| 560 | { | 568 | { |
| @@ -563,6 +571,8 @@ static int gfs2_uevent(struct kset *kset, struct kobject *kobj, | |||
| 563 | 571 | ||
| 564 | add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name); | 572 | add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name); |
| 565 | add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name); | 573 | add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name); |
| 574 | if (!sdp->sd_args.ar_spectator) | ||
| 575 | add_uevent_var(env, "JOURNALID=%u", sdp->sd_lockstruct.ls_jid); | ||
| 566 | if (gfs2_uuid_valid(uuid)) { | 576 | if (gfs2_uuid_valid(uuid)) { |
| 567 | add_uevent_var(env, "UUID=%02X%02X%02X%02X-%02X%02X-%02X%02X-" | 577 | add_uevent_var(env, "UUID=%02X%02X%02X%02X-%02X%02X-%02X%02X-" |
| 568 | "%02X%02X-%02X%02X%02X%02X%02X%02X", | 578 | "%02X%02X-%02X%02X%02X%02X%02X%02X", |
| @@ -578,7 +588,6 @@ static struct kset_uevent_ops gfs2_uevent_ops = { | |||
| 578 | .uevent = gfs2_uevent, | 588 | .uevent = gfs2_uevent, |
| 579 | }; | 589 | }; |
| 580 | 590 | ||
| 581 | |||
| 582 | int gfs2_sys_init(void) | 591 | int gfs2_sys_init(void) |
| 583 | { | 592 | { |
| 584 | gfs2_kset = kset_create_and_add("gfs2", &gfs2_uevent_ops, fs_kobj); | 593 | gfs2_kset = kset_create_and_add("gfs2", &gfs2_uevent_ops, fs_kobj); |
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 9d12b1118ba0..f6a7efa34eb9 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c | |||
| @@ -38,24 +38,30 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) | |||
| 38 | const struct lm_lockops *lm = ls->ls_ops; | 38 | const struct lm_lockops *lm = ls->ls_ops; |
| 39 | va_list args; | 39 | va_list args; |
| 40 | 40 | ||
| 41 | if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) | 41 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW && |
| 42 | test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) | ||
| 42 | return 0; | 43 | return 0; |
| 43 | 44 | ||
| 44 | va_start(args, fmt); | 45 | va_start(args, fmt); |
| 45 | vprintk(fmt, args); | 46 | vprintk(fmt, args); |
| 46 | va_end(args); | 47 | va_end(args); |
| 47 | 48 | ||
| 48 | fs_err(sdp, "about to withdraw this file system\n"); | 49 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) { |
| 49 | BUG_ON(sdp->sd_args.ar_debug); | 50 | fs_err(sdp, "about to withdraw this file system\n"); |
| 51 | BUG_ON(sdp->sd_args.ar_debug); | ||
| 50 | 52 | ||
| 51 | kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE); | 53 | kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE); |
| 52 | 54 | ||
| 53 | if (lm->lm_unmount) { | 55 | if (lm->lm_unmount) { |
| 54 | fs_err(sdp, "telling LM to unmount\n"); | 56 | fs_err(sdp, "telling LM to unmount\n"); |
| 55 | lm->lm_unmount(sdp); | 57 | lm->lm_unmount(sdp); |
| 58 | } | ||
| 59 | fs_err(sdp, "withdrawn\n"); | ||
| 60 | dump_stack(); | ||
| 56 | } | 61 | } |
| 57 | fs_err(sdp, "withdrawn\n"); | 62 | |
| 58 | dump_stack(); | 63 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) |
| 64 | panic("GFS2: fsid=%s: panic requested.\n", sdp->sd_fsname); | ||
| 59 | 65 | ||
| 60 | return -1; | 66 | return -1; |
| 61 | } | 67 | } |
| @@ -93,17 +99,24 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, | |||
| 93 | gfs2_tune_get(sdp, gt_complain_secs) * HZ)) | 99 | gfs2_tune_get(sdp, gt_complain_secs) * HZ)) |
| 94 | return -2; | 100 | return -2; |
| 95 | 101 | ||
| 96 | printk(KERN_WARNING | 102 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) |
| 97 | "GFS2: fsid=%s: warning: assertion \"%s\" failed\n" | 103 | printk(KERN_WARNING |
| 98 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", | 104 | "GFS2: fsid=%s: warning: assertion \"%s\" failed\n" |
| 99 | sdp->sd_fsname, assertion, | 105 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", |
| 100 | sdp->sd_fsname, function, file, line); | 106 | sdp->sd_fsname, assertion, |
| 107 | sdp->sd_fsname, function, file, line); | ||
| 101 | 108 | ||
| 102 | if (sdp->sd_args.ar_debug) | 109 | if (sdp->sd_args.ar_debug) |
| 103 | BUG(); | 110 | BUG(); |
| 104 | else | 111 | else |
| 105 | dump_stack(); | 112 | dump_stack(); |
| 106 | 113 | ||
| 114 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) | ||
| 115 | panic("GFS2: fsid=%s: warning: assertion \"%s\" failed\n" | ||
| 116 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", | ||
| 117 | sdp->sd_fsname, assertion, | ||
| 118 | sdp->sd_fsname, function, file, line); | ||
| 119 | |||
| 107 | sdp->sd_last_warning = jiffies; | 120 | sdp->sd_last_warning = jiffies; |
| 108 | 121 | ||
| 109 | return -1; | 122 | return -1; |
diff --git a/fs/gfs2/eattr.c b/fs/gfs2/xattr.c index 07ea9529adda..8a0f8ef6ee27 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/xattr.c | |||
| @@ -18,8 +18,7 @@ | |||
| 18 | #include "gfs2.h" | 18 | #include "gfs2.h" |
| 19 | #include "incore.h" | 19 | #include "incore.h" |
| 20 | #include "acl.h" | 20 | #include "acl.h" |
| 21 | #include "eaops.h" | 21 | #include "xattr.h" |
| 22 | #include "eattr.h" | ||
| 23 | #include "glock.h" | 22 | #include "glock.h" |
| 24 | #include "inode.h" | 23 | #include "inode.h" |
| 25 | #include "meta_io.h" | 24 | #include "meta_io.h" |
| @@ -38,26 +37,32 @@ | |||
| 38 | * Returns: 1 if the EA should be stuffed | 37 | * Returns: 1 if the EA should be stuffed |
| 39 | */ | 38 | */ |
| 40 | 39 | ||
| 41 | static int ea_calc_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er, | 40 | static int ea_calc_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize, |
| 42 | unsigned int *size) | 41 | unsigned int *size) |
| 43 | { | 42 | { |
| 44 | *size = GFS2_EAREQ_SIZE_STUFFED(er); | 43 | unsigned int jbsize = sdp->sd_jbsize; |
| 45 | if (*size <= sdp->sd_jbsize) | 44 | |
| 45 | /* Stuffed */ | ||
| 46 | *size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + dsize, 8); | ||
| 47 | |||
| 48 | if (*size <= jbsize) | ||
| 46 | return 1; | 49 | return 1; |
| 47 | 50 | ||
| 48 | *size = GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er); | 51 | /* Unstuffed */ |
| 52 | *size = ALIGN(sizeof(struct gfs2_ea_header) + nsize + | ||
| 53 | (sizeof(__be64) * DIV_ROUND_UP(dsize, jbsize)), 8); | ||
| 49 | 54 | ||
| 50 | return 0; | 55 | return 0; |
| 51 | } | 56 | } |
| 52 | 57 | ||
| 53 | static int ea_check_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er) | 58 | static int ea_check_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize) |
| 54 | { | 59 | { |
| 55 | unsigned int size; | 60 | unsigned int size; |
| 56 | 61 | ||
| 57 | if (er->er_data_len > GFS2_EA_MAX_DATA_LEN) | 62 | if (dsize > GFS2_EA_MAX_DATA_LEN) |
| 58 | return -ERANGE; | 63 | return -ERANGE; |
| 59 | 64 | ||
| 60 | ea_calc_size(sdp, er, &size); | 65 | ea_calc_size(sdp, nsize, dsize, &size); |
| 61 | 66 | ||
| 62 | /* This can only happen with 512 byte blocks */ | 67 | /* This can only happen with 512 byte blocks */ |
| 63 | if (size > sdp->sd_jbsize) | 68 | if (size > sdp->sd_jbsize) |
| @@ -151,7 +156,9 @@ out: | |||
| 151 | } | 156 | } |
| 152 | 157 | ||
| 153 | struct ea_find { | 158 | struct ea_find { |
| 154 | struct gfs2_ea_request *ef_er; | 159 | int type; |
| 160 | const char *name; | ||
| 161 | size_t namel; | ||
| 155 | struct gfs2_ea_location *ef_el; | 162 | struct gfs2_ea_location *ef_el; |
| 156 | }; | 163 | }; |
| 157 | 164 | ||
| @@ -160,14 +167,13 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 160 | void *private) | 167 | void *private) |
| 161 | { | 168 | { |
| 162 | struct ea_find *ef = private; | 169 | struct ea_find *ef = private; |
| 163 | struct gfs2_ea_request *er = ef->ef_er; | ||
| 164 | 170 | ||
| 165 | if (ea->ea_type == GFS2_EATYPE_UNUSED) | 171 | if (ea->ea_type == GFS2_EATYPE_UNUSED) |
| 166 | return 0; | 172 | return 0; |
| 167 | 173 | ||
| 168 | if (ea->ea_type == er->er_type) { | 174 | if (ea->ea_type == ef->type) { |
| 169 | if (ea->ea_name_len == er->er_name_len && | 175 | if (ea->ea_name_len == ef->namel && |
| 170 | !memcmp(GFS2_EA2NAME(ea), er->er_name, ea->ea_name_len)) { | 176 | !memcmp(GFS2_EA2NAME(ea), ef->name, ea->ea_name_len)) { |
| 171 | struct gfs2_ea_location *el = ef->ef_el; | 177 | struct gfs2_ea_location *el = ef->ef_el; |
| 172 | get_bh(bh); | 178 | get_bh(bh); |
| 173 | el->el_bh = bh; | 179 | el->el_bh = bh; |
| @@ -180,13 +186,15 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 180 | return 0; | 186 | return 0; |
| 181 | } | 187 | } |
| 182 | 188 | ||
| 183 | int gfs2_ea_find(struct gfs2_inode *ip, struct gfs2_ea_request *er, | 189 | int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, |
| 184 | struct gfs2_ea_location *el) | 190 | struct gfs2_ea_location *el) |
| 185 | { | 191 | { |
| 186 | struct ea_find ef; | 192 | struct ea_find ef; |
| 187 | int error; | 193 | int error; |
| 188 | 194 | ||
| 189 | ef.ef_er = er; | 195 | ef.type = type; |
| 196 | ef.name = name; | ||
| 197 | ef.namel = strlen(name); | ||
| 190 | ef.ef_el = el; | 198 | ef.ef_el = el; |
| 191 | 199 | ||
| 192 | memset(el, 0, sizeof(struct gfs2_ea_location)); | 200 | memset(el, 0, sizeof(struct gfs2_ea_location)); |
| @@ -344,6 +352,20 @@ struct ea_list { | |||
| 344 | unsigned int ei_size; | 352 | unsigned int ei_size; |
| 345 | }; | 353 | }; |
| 346 | 354 | ||
| 355 | static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea) | ||
| 356 | { | ||
| 357 | switch (ea->ea_type) { | ||
| 358 | case GFS2_EATYPE_USR: | ||
| 359 | return 5 + ea->ea_name_len + 1; | ||
| 360 | case GFS2_EATYPE_SYS: | ||
| 361 | return 7 + ea->ea_name_len + 1; | ||
| 362 | case GFS2_EATYPE_SECURITY: | ||
| 363 | return 9 + ea->ea_name_len + 1; | ||
| 364 | default: | ||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 347 | static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, | 369 | static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, |
| 348 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, | 370 | struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, |
| 349 | void *private) | 371 | void *private) |
| @@ -392,21 +414,25 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 392 | } | 414 | } |
| 393 | 415 | ||
| 394 | /** | 416 | /** |
| 395 | * gfs2_ea_list - | 417 | * gfs2_listxattr - List gfs2 extended attributes |
| 396 | * @ip: | 418 | * @dentry: The dentry whose inode we are interested in |
| 397 | * @er: | 419 | * @buffer: The buffer to write the results |
| 420 | * @size: The size of the buffer | ||
| 398 | * | 421 | * |
| 399 | * Returns: actual size of data on success, -errno on error | 422 | * Returns: actual size of data on success, -errno on error |
| 400 | */ | 423 | */ |
| 401 | 424 | ||
| 402 | int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 425 | ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size) |
| 403 | { | 426 | { |
| 427 | struct gfs2_inode *ip = GFS2_I(dentry->d_inode); | ||
| 428 | struct gfs2_ea_request er; | ||
| 404 | struct gfs2_holder i_gh; | 429 | struct gfs2_holder i_gh; |
| 405 | int error; | 430 | int error; |
| 406 | 431 | ||
| 407 | if (!er->er_data || !er->er_data_len) { | 432 | memset(&er, 0, sizeof(struct gfs2_ea_request)); |
| 408 | er->er_data = NULL; | 433 | if (size) { |
| 409 | er->er_data_len = 0; | 434 | er.er_data = buffer; |
| 435 | er.er_data_len = size; | ||
| 410 | } | 436 | } |
| 411 | 437 | ||
| 412 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | 438 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); |
| @@ -414,7 +440,7 @@ int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
| 414 | return error; | 440 | return error; |
| 415 | 441 | ||
| 416 | if (ip->i_eattr) { | 442 | if (ip->i_eattr) { |
| 417 | struct ea_list ei = { .ei_er = er, .ei_size = 0 }; | 443 | struct ea_list ei = { .ei_er = &er, .ei_size = 0 }; |
| 418 | 444 | ||
| 419 | error = ea_foreach(ip, ea_list_i, &ei); | 445 | error = ea_foreach(ip, ea_list_i, &ei); |
| 420 | if (!error) | 446 | if (!error) |
| @@ -491,84 +517,61 @@ out: | |||
| 491 | } | 517 | } |
| 492 | 518 | ||
| 493 | int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, | 519 | int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
| 494 | char *data) | 520 | char *data, size_t size) |
| 495 | { | 521 | { |
| 522 | int ret; | ||
| 523 | size_t len = GFS2_EA_DATA_LEN(el->el_ea); | ||
| 524 | if (len > size) | ||
| 525 | return -ERANGE; | ||
| 526 | |||
| 496 | if (GFS2_EA_IS_STUFFED(el->el_ea)) { | 527 | if (GFS2_EA_IS_STUFFED(el->el_ea)) { |
| 497 | memcpy(data, GFS2_EA2DATA(el->el_ea), GFS2_EA_DATA_LEN(el->el_ea)); | 528 | memcpy(data, GFS2_EA2DATA(el->el_ea), len); |
| 498 | return 0; | 529 | return len; |
| 499 | } else | 530 | } |
| 500 | return ea_get_unstuffed(ip, el->el_ea, data); | 531 | ret = ea_get_unstuffed(ip, el->el_ea, data); |
| 532 | if (ret < 0) | ||
| 533 | return ret; | ||
| 534 | return len; | ||
| 501 | } | 535 | } |
| 502 | 536 | ||
| 503 | /** | 537 | /** |
| 504 | * gfs2_ea_get_i - | 538 | * gfs2_xattr_get - Get a GFS2 extended attribute |
| 505 | * @ip: The GFS2 inode | 539 | * @inode: The inode |
| 506 | * @er: The request structure | 540 | * @type: The type of extended attribute |
| 541 | * @name: The name of the extended attribute | ||
| 542 | * @buffer: The buffer to write the result into | ||
| 543 | * @size: The size of the buffer | ||
| 507 | * | 544 | * |
| 508 | * Returns: actual size of data on success, -errno on error | 545 | * Returns: actual size of data on success, -errno on error |
| 509 | */ | 546 | */ |
| 510 | 547 | ||
| 511 | int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 548 | int gfs2_xattr_get(struct inode *inode, int type, const char *name, |
| 549 | void *buffer, size_t size) | ||
| 512 | { | 550 | { |
| 551 | struct gfs2_inode *ip = GFS2_I(inode); | ||
| 513 | struct gfs2_ea_location el; | 552 | struct gfs2_ea_location el; |
| 514 | int error; | 553 | int error; |
| 515 | 554 | ||
| 516 | if (!ip->i_eattr) | 555 | if (!ip->i_eattr) |
| 517 | return -ENODATA; | 556 | return -ENODATA; |
| 557 | if (strlen(name) > GFS2_EA_MAX_NAME_LEN) | ||
| 558 | return -EINVAL; | ||
| 518 | 559 | ||
| 519 | error = gfs2_ea_find(ip, er, &el); | 560 | error = gfs2_ea_find(ip, type, name, &el); |
| 520 | if (error) | 561 | if (error) |
| 521 | return error; | 562 | return error; |
| 522 | if (!el.el_ea) | 563 | if (!el.el_ea) |
| 523 | return -ENODATA; | 564 | return -ENODATA; |
| 524 | 565 | if (size) | |
| 525 | if (er->er_data_len) { | 566 | error = gfs2_ea_get_copy(ip, &el, buffer, size); |
| 526 | if (GFS2_EA_DATA_LEN(el.el_ea) > er->er_data_len) | 567 | else |
| 527 | error = -ERANGE; | ||
| 528 | else | ||
| 529 | error = gfs2_ea_get_copy(ip, &el, er->er_data); | ||
| 530 | } | ||
| 531 | if (!error) | ||
| 532 | error = GFS2_EA_DATA_LEN(el.el_ea); | 568 | error = GFS2_EA_DATA_LEN(el.el_ea); |
| 533 | |||
| 534 | brelse(el.el_bh); | 569 | brelse(el.el_bh); |
| 535 | 570 | ||
| 536 | return error; | 571 | return error; |
| 537 | } | 572 | } |
| 538 | 573 | ||
| 539 | /** | 574 | /** |
| 540 | * gfs2_ea_get - | ||
| 541 | * @ip: The GFS2 inode | ||
| 542 | * @er: The request structure | ||
| 543 | * | ||
| 544 | * Returns: actual size of data on success, -errno on error | ||
| 545 | */ | ||
| 546 | |||
| 547 | int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 548 | { | ||
| 549 | struct gfs2_holder i_gh; | ||
| 550 | int error; | ||
| 551 | |||
| 552 | if (!er->er_name_len || | ||
| 553 | er->er_name_len > GFS2_EA_MAX_NAME_LEN) | ||
| 554 | return -EINVAL; | ||
| 555 | if (!er->er_data || !er->er_data_len) { | ||
| 556 | er->er_data = NULL; | ||
| 557 | er->er_data_len = 0; | ||
| 558 | } | ||
| 559 | |||
| 560 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | ||
| 561 | if (error) | ||
| 562 | return error; | ||
| 563 | |||
| 564 | error = gfs2_ea_ops[er->er_type]->eo_get(ip, er); | ||
| 565 | |||
| 566 | gfs2_glock_dq_uninit(&i_gh); | ||
| 567 | |||
| 568 | return error; | ||
| 569 | } | ||
| 570 | |||
| 571 | /** | ||
| 572 | * ea_alloc_blk - allocates a new block for extended attributes. | 575 | * ea_alloc_blk - allocates a new block for extended attributes. |
| 573 | * @ip: A pointer to the inode that's getting extended attributes | 576 | * @ip: A pointer to the inode that's getting extended attributes |
| 574 | * @bhp: Pointer to pointer to a struct buffer_head | 577 | * @bhp: Pointer to pointer to a struct buffer_head |
| @@ -713,12 +716,6 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
| 713 | 716 | ||
| 714 | error = gfs2_meta_inode_buffer(ip, &dibh); | 717 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 715 | if (!error) { | 718 | if (!error) { |
| 716 | if (er->er_flags & GFS2_ERF_MODE) { | ||
| 717 | gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), | ||
| 718 | (ip->i_inode.i_mode & S_IFMT) == | ||
| 719 | (er->er_mode & S_IFMT)); | ||
| 720 | ip->i_inode.i_mode = er->er_mode; | ||
| 721 | } | ||
| 722 | ip->i_inode.i_ctime = CURRENT_TIME; | 719 | ip->i_inode.i_ctime = CURRENT_TIME; |
| 723 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 720 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
| 724 | gfs2_dinode_out(ip, dibh->b_data); | 721 | gfs2_dinode_out(ip, dibh->b_data); |
| @@ -762,15 +759,23 @@ static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
| 762 | * Returns: errno | 759 | * Returns: errno |
| 763 | */ | 760 | */ |
| 764 | 761 | ||
| 765 | static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 762 | static int ea_init(struct gfs2_inode *ip, int type, const char *name, |
| 763 | const void *data, size_t size) | ||
| 766 | { | 764 | { |
| 765 | struct gfs2_ea_request er; | ||
| 767 | unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; | 766 | unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; |
| 768 | unsigned int blks = 1; | 767 | unsigned int blks = 1; |
| 769 | 768 | ||
| 770 | if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize) | 769 | er.er_type = type; |
| 771 | blks += DIV_ROUND_UP(er->er_data_len, jbsize); | 770 | er.er_name = name; |
| 771 | er.er_name_len = strlen(name); | ||
| 772 | er.er_data = (void *)data; | ||
| 773 | er.er_data_len = size; | ||
| 774 | |||
| 775 | if (GFS2_EAREQ_SIZE_STUFFED(&er) > jbsize) | ||
| 776 | blks += DIV_ROUND_UP(er.er_data_len, jbsize); | ||
| 772 | 777 | ||
| 773 | return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL); | 778 | return ea_alloc_skeleton(ip, &er, blks, ea_init_i, NULL); |
| 774 | } | 779 | } |
| 775 | 780 | ||
| 776 | static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) | 781 | static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea) |
| @@ -848,12 +853,6 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 848 | error = gfs2_meta_inode_buffer(ip, &dibh); | 853 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 849 | if (error) | 854 | if (error) |
| 850 | goto out; | 855 | goto out; |
| 851 | |||
| 852 | if (er->er_flags & GFS2_ERF_MODE) { | ||
| 853 | gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), | ||
| 854 | (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT)); | ||
| 855 | ip->i_inode.i_mode = er->er_mode; | ||
| 856 | } | ||
| 857 | ip->i_inode.i_ctime = CURRENT_TIME; | 856 | ip->i_inode.i_ctime = CURRENT_TIME; |
| 858 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 857 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
| 859 | gfs2_dinode_out(ip, dibh->b_data); | 858 | gfs2_dinode_out(ip, dibh->b_data); |
| @@ -894,7 +893,8 @@ static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, | |||
| 894 | int stuffed; | 893 | int stuffed; |
| 895 | int error; | 894 | int error; |
| 896 | 895 | ||
| 897 | stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er, &size); | 896 | stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er->er_name_len, |
| 897 | es->es_er->er_data_len, &size); | ||
| 898 | 898 | ||
| 899 | if (ea->ea_type == GFS2_EATYPE_UNUSED) { | 899 | if (ea->ea_type == GFS2_EATYPE_UNUSED) { |
| 900 | if (GFS2_EA_REC_LEN(ea) < size) | 900 | if (GFS2_EA_REC_LEN(ea) < size) |
| @@ -1005,15 +1005,22 @@ out: | |||
| 1005 | return error; | 1005 | return error; |
| 1006 | } | 1006 | } |
| 1007 | 1007 | ||
| 1008 | static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | 1008 | static int ea_set_i(struct gfs2_inode *ip, int type, const char *name, |
| 1009 | struct gfs2_ea_location *el) | 1009 | const void *value, size_t size, struct gfs2_ea_location *el) |
| 1010 | { | 1010 | { |
| 1011 | struct gfs2_ea_request er; | ||
| 1011 | struct ea_set es; | 1012 | struct ea_set es; |
| 1012 | unsigned int blks = 2; | 1013 | unsigned int blks = 2; |
| 1013 | int error; | 1014 | int error; |
| 1014 | 1015 | ||
| 1016 | er.er_type = type; | ||
| 1017 | er.er_name = name; | ||
| 1018 | er.er_data = (void *)value; | ||
| 1019 | er.er_name_len = strlen(name); | ||
| 1020 | er.er_data_len = size; | ||
| 1021 | |||
| 1015 | memset(&es, 0, sizeof(struct ea_set)); | 1022 | memset(&es, 0, sizeof(struct ea_set)); |
| 1016 | es.es_er = er; | 1023 | es.es_er = &er; |
| 1017 | es.es_el = el; | 1024 | es.es_el = el; |
| 1018 | 1025 | ||
| 1019 | error = ea_foreach(ip, ea_set_simple, &es); | 1026 | error = ea_foreach(ip, ea_set_simple, &es); |
| @@ -1024,10 +1031,10 @@ static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, | |||
| 1024 | 1031 | ||
| 1025 | if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) | 1032 | if (!(ip->i_diskflags & GFS2_DIF_EA_INDIRECT)) |
| 1026 | blks++; | 1033 | blks++; |
| 1027 | if (GFS2_EAREQ_SIZE_STUFFED(er) > GFS2_SB(&ip->i_inode)->sd_jbsize) | 1034 | if (GFS2_EAREQ_SIZE_STUFFED(&er) > GFS2_SB(&ip->i_inode)->sd_jbsize) |
| 1028 | blks += DIV_ROUND_UP(er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); | 1035 | blks += DIV_ROUND_UP(er.er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); |
| 1029 | 1036 | ||
| 1030 | return ea_alloc_skeleton(ip, er, blks, ea_set_block, el); | 1037 | return ea_alloc_skeleton(ip, &er, blks, ea_set_block, el); |
| 1031 | } | 1038 | } |
| 1032 | 1039 | ||
| 1033 | static int ea_set_remove_unstuffed(struct gfs2_inode *ip, | 1040 | static int ea_set_remove_unstuffed(struct gfs2_inode *ip, |
| @@ -1039,75 +1046,7 @@ static int ea_set_remove_unstuffed(struct gfs2_inode *ip, | |||
| 1039 | GFS2_EA2NEXT(el->el_prev) == el->el_ea); | 1046 | GFS2_EA2NEXT(el->el_prev) == el->el_ea); |
| 1040 | } | 1047 | } |
| 1041 | 1048 | ||
| 1042 | return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0); | 1049 | return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev, 0); |
| 1043 | } | ||
| 1044 | |||
| 1045 | int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 1046 | { | ||
| 1047 | struct gfs2_ea_location el; | ||
| 1048 | int error; | ||
| 1049 | |||
| 1050 | if (!ip->i_eattr) { | ||
| 1051 | if (er->er_flags & XATTR_REPLACE) | ||
| 1052 | return -ENODATA; | ||
| 1053 | return ea_init(ip, er); | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | error = gfs2_ea_find(ip, er, &el); | ||
| 1057 | if (error) | ||
| 1058 | return error; | ||
| 1059 | |||
| 1060 | if (el.el_ea) { | ||
| 1061 | if (ip->i_diskflags & GFS2_DIF_APPENDONLY) { | ||
| 1062 | brelse(el.el_bh); | ||
| 1063 | return -EPERM; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | error = -EEXIST; | ||
| 1067 | if (!(er->er_flags & XATTR_CREATE)) { | ||
| 1068 | int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); | ||
| 1069 | error = ea_set_i(ip, er, &el); | ||
| 1070 | if (!error && unstuffed) | ||
| 1071 | ea_set_remove_unstuffed(ip, &el); | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | brelse(el.el_bh); | ||
| 1075 | } else { | ||
| 1076 | error = -ENODATA; | ||
| 1077 | if (!(er->er_flags & XATTR_REPLACE)) | ||
| 1078 | error = ea_set_i(ip, er, NULL); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | return error; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er) | ||
| 1085 | { | ||
| 1086 | struct gfs2_holder i_gh; | ||
| 1087 | int error; | ||
| 1088 | |||
| 1089 | if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) | ||
| 1090 | return -EINVAL; | ||
| 1091 | if (!er->er_data || !er->er_data_len) { | ||
| 1092 | er->er_data = NULL; | ||
| 1093 | er->er_data_len = 0; | ||
| 1094 | } | ||
| 1095 | error = ea_check_size(GFS2_SB(&ip->i_inode), er); | ||
| 1096 | if (error) | ||
| 1097 | return error; | ||
| 1098 | |||
| 1099 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | ||
| 1100 | if (error) | ||
| 1101 | return error; | ||
| 1102 | |||
| 1103 | if (IS_IMMUTABLE(&ip->i_inode)) | ||
| 1104 | error = -EPERM; | ||
| 1105 | else | ||
| 1106 | error = gfs2_ea_ops[er->er_type]->eo_set(ip, er); | ||
| 1107 | |||
| 1108 | gfs2_glock_dq_uninit(&i_gh); | ||
| 1109 | |||
| 1110 | return error; | ||
| 1111 | } | 1050 | } |
| 1112 | 1051 | ||
| 1113 | static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | 1052 | static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) |
| @@ -1131,8 +1070,9 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | |||
| 1131 | 1070 | ||
| 1132 | if (GFS2_EA_IS_LAST(ea)) | 1071 | if (GFS2_EA_IS_LAST(ea)) |
| 1133 | prev->ea_flags |= GFS2_EAFLAG_LAST; | 1072 | prev->ea_flags |= GFS2_EAFLAG_LAST; |
| 1134 | } else | 1073 | } else { |
| 1135 | ea->ea_type = GFS2_EATYPE_UNUSED; | 1074 | ea->ea_type = GFS2_EATYPE_UNUSED; |
| 1075 | } | ||
| 1136 | 1076 | ||
| 1137 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1077 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 1138 | if (!error) { | 1078 | if (!error) { |
| @@ -1147,15 +1087,29 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) | |||
| 1147 | return error; | 1087 | return error; |
| 1148 | } | 1088 | } |
| 1149 | 1089 | ||
| 1150 | int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 1090 | /** |
| 1091 | * gfs2_xattr_remove - Remove a GFS2 extended attribute | ||
| 1092 | * @inode: The inode | ||
| 1093 | * @type: The type of the extended attribute | ||
| 1094 | * @name: The name of the extended attribute | ||
| 1095 | * | ||
| 1096 | * This is not called directly by the VFS since we use the (common) | ||
| 1097 | * scheme of making a "set with NULL data" mean a remove request. Note | ||
| 1098 | * that this is different from a set with zero length data. | ||
| 1099 | * | ||
| 1100 | * Returns: 0, or errno on failure | ||
| 1101 | */ | ||
| 1102 | |||
| 1103 | static int gfs2_xattr_remove(struct inode *inode, int type, const char *name) | ||
| 1151 | { | 1104 | { |
| 1105 | struct gfs2_inode *ip = GFS2_I(inode); | ||
| 1152 | struct gfs2_ea_location el; | 1106 | struct gfs2_ea_location el; |
| 1153 | int error; | 1107 | int error; |
| 1154 | 1108 | ||
| 1155 | if (!ip->i_eattr) | 1109 | if (!ip->i_eattr) |
| 1156 | return -ENODATA; | 1110 | return -ENODATA; |
| 1157 | 1111 | ||
| 1158 | error = gfs2_ea_find(ip, er, &el); | 1112 | error = gfs2_ea_find(ip, type, name, &el); |
| 1159 | if (error) | 1113 | if (error) |
| 1160 | return error; | 1114 | return error; |
| 1161 | if (!el.el_ea) | 1115 | if (!el.el_ea) |
| @@ -1164,8 +1118,7 @@ int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
| 1164 | if (GFS2_EA_IS_STUFFED(el.el_ea)) | 1118 | if (GFS2_EA_IS_STUFFED(el.el_ea)) |
| 1165 | error = ea_remove_stuffed(ip, &el); | 1119 | error = ea_remove_stuffed(ip, &el); |
| 1166 | else | 1120 | else |
| 1167 | error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, | 1121 | error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, 0); |
| 1168 | 0); | ||
| 1169 | 1122 | ||
| 1170 | brelse(el.el_bh); | 1123 | brelse(el.el_bh); |
| 1171 | 1124 | ||
| @@ -1173,31 +1126,70 @@ int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er) | |||
| 1173 | } | 1126 | } |
| 1174 | 1127 | ||
| 1175 | /** | 1128 | /** |
| 1176 | * gfs2_ea_remove - sets (or creates or replaces) an extended attribute | 1129 | * gfs2_xattr_set - Set (or remove) a GFS2 extended attribute |
| 1177 | * @ip: pointer to the inode of the target file | 1130 | * @inode: The inode |
| 1178 | * @er: request information | 1131 | * @type: The type of the extended attribute |
| 1132 | * @name: The name of the extended attribute | ||
| 1133 | * @value: The value of the extended attribute (NULL for remove) | ||
| 1134 | * @size: The size of the @value argument | ||
| 1135 | * @flags: Create or Replace | ||
| 1179 | * | 1136 | * |
| 1180 | * Returns: errno | 1137 | * See gfs2_xattr_remove() for details of the removal of xattrs. |
| 1138 | * | ||
| 1139 | * Returns: 0 or errno on failure | ||
| 1181 | */ | 1140 | */ |
| 1182 | 1141 | ||
| 1183 | int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er) | 1142 | int gfs2_xattr_set(struct inode *inode, int type, const char *name, |
| 1143 | const void *value, size_t size, int flags) | ||
| 1184 | { | 1144 | { |
| 1185 | struct gfs2_holder i_gh; | 1145 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
| 1146 | struct gfs2_inode *ip = GFS2_I(inode); | ||
| 1147 | struct gfs2_ea_location el; | ||
| 1148 | unsigned int namel = strlen(name); | ||
| 1186 | int error; | 1149 | int error; |
| 1187 | 1150 | ||
| 1188 | if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) | 1151 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
| 1189 | return -EINVAL; | 1152 | return -EPERM; |
| 1153 | if (namel > GFS2_EA_MAX_NAME_LEN) | ||
| 1154 | return -ERANGE; | ||
| 1190 | 1155 | ||
| 1191 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); | 1156 | if (value == NULL) |
| 1157 | return gfs2_xattr_remove(inode, type, name); | ||
| 1158 | |||
| 1159 | if (ea_check_size(sdp, namel, size)) | ||
| 1160 | return -ERANGE; | ||
| 1161 | |||
| 1162 | if (!ip->i_eattr) { | ||
| 1163 | if (flags & XATTR_REPLACE) | ||
| 1164 | return -ENODATA; | ||
| 1165 | return ea_init(ip, type, name, value, size); | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | error = gfs2_ea_find(ip, type, name, &el); | ||
| 1192 | if (error) | 1169 | if (error) |
| 1193 | return error; | 1170 | return error; |
| 1194 | 1171 | ||
| 1195 | if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) | 1172 | if (el.el_ea) { |
| 1196 | error = -EPERM; | 1173 | if (ip->i_diskflags & GFS2_DIF_APPENDONLY) { |
| 1197 | else | 1174 | brelse(el.el_bh); |
| 1198 | error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er); | 1175 | return -EPERM; |
| 1176 | } | ||
| 1199 | 1177 | ||
| 1200 | gfs2_glock_dq_uninit(&i_gh); | 1178 | error = -EEXIST; |
| 1179 | if (!(flags & XATTR_CREATE)) { | ||
| 1180 | int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); | ||
| 1181 | error = ea_set_i(ip, type, name, value, size, &el); | ||
| 1182 | if (!error && unstuffed) | ||
| 1183 | ea_set_remove_unstuffed(ip, &el); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | brelse(el.el_bh); | ||
| 1187 | return error; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | error = -ENODATA; | ||
| 1191 | if (!(flags & XATTR_REPLACE)) | ||
| 1192 | error = ea_set_i(ip, type, name, value, size, NULL); | ||
| 1201 | 1193 | ||
| 1202 | return error; | 1194 | return error; |
| 1203 | } | 1195 | } |
| @@ -1503,3 +1495,64 @@ out_alloc: | |||
| 1503 | return error; | 1495 | return error; |
| 1504 | } | 1496 | } |
| 1505 | 1497 | ||
| 1498 | static int gfs2_xattr_user_get(struct inode *inode, const char *name, | ||
| 1499 | void *buffer, size_t size) | ||
| 1500 | { | ||
| 1501 | return gfs2_xattr_get(inode, GFS2_EATYPE_USR, name, buffer, size); | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | static int gfs2_xattr_user_set(struct inode *inode, const char *name, | ||
| 1505 | const void *value, size_t size, int flags) | ||
| 1506 | { | ||
| 1507 | return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags); | ||
| 1508 | } | ||
| 1509 | |||
| 1510 | static int gfs2_xattr_system_get(struct inode *inode, const char *name, | ||
| 1511 | void *buffer, size_t size) | ||
| 1512 | { | ||
| 1513 | return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size); | ||
| 1514 | } | ||
| 1515 | |||
| 1516 | static int gfs2_xattr_system_set(struct inode *inode, const char *name, | ||
| 1517 | const void *value, size_t size, int flags) | ||
| 1518 | { | ||
| 1519 | return gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, flags); | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | static int gfs2_xattr_security_get(struct inode *inode, const char *name, | ||
| 1523 | void *buffer, size_t size) | ||
| 1524 | { | ||
| 1525 | return gfs2_xattr_get(inode, GFS2_EATYPE_SECURITY, name, buffer, size); | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | static int gfs2_xattr_security_set(struct inode *inode, const char *name, | ||
| 1529 | const void *value, size_t size, int flags) | ||
| 1530 | { | ||
| 1531 | return gfs2_xattr_set(inode, GFS2_EATYPE_SECURITY, name, value, size, flags); | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | static struct xattr_handler gfs2_xattr_user_handler = { | ||
| 1535 | .prefix = XATTR_USER_PREFIX, | ||
| 1536 | .get = gfs2_xattr_user_get, | ||
| 1537 | .set = gfs2_xattr_user_set, | ||
| 1538 | }; | ||
| 1539 | |||
| 1540 | static struct xattr_handler gfs2_xattr_security_handler = { | ||
| 1541 | .prefix = XATTR_SECURITY_PREFIX, | ||
| 1542 | .get = gfs2_xattr_security_get, | ||
| 1543 | .set = gfs2_xattr_security_set, | ||
| 1544 | }; | ||
| 1545 | |||
| 1546 | static struct xattr_handler gfs2_xattr_system_handler = { | ||
| 1547 | .prefix = XATTR_SYSTEM_PREFIX, | ||
| 1548 | .get = gfs2_xattr_system_get, | ||
| 1549 | .set = gfs2_xattr_system_set, | ||
| 1550 | }; | ||
| 1551 | |||
| 1552 | struct xattr_handler *gfs2_xattr_handlers[] = { | ||
| 1553 | &gfs2_xattr_user_handler, | ||
| 1554 | &gfs2_xattr_security_handler, | ||
| 1555 | &gfs2_xattr_system_handler, | ||
| 1556 | NULL, | ||
| 1557 | }; | ||
| 1558 | |||
diff --git a/fs/gfs2/eattr.h b/fs/gfs2/xattr.h index c82dbe01d713..cbdfd7743733 100644 --- a/fs/gfs2/eattr.h +++ b/fs/gfs2/xattr.h | |||
| @@ -19,7 +19,7 @@ struct iattr; | |||
| 19 | #define GFS2_EA_SIZE(ea) \ | 19 | #define GFS2_EA_SIZE(ea) \ |
| 20 | ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \ | 20 | ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \ |
| 21 | ((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \ | 21 | ((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \ |
| 22 | (sizeof(__be64) * (ea)->ea_num_ptrs)), 8) | 22 | (sizeof(__be64) * (ea)->ea_num_ptrs)), 8) |
| 23 | 23 | ||
| 24 | #define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs) | 24 | #define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs) |
| 25 | #define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST) | 25 | #define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST) |
| @@ -27,10 +27,6 @@ ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \ | |||
| 27 | #define GFS2_EAREQ_SIZE_STUFFED(er) \ | 27 | #define GFS2_EAREQ_SIZE_STUFFED(er) \ |
| 28 | ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8) | 28 | ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8) |
| 29 | 29 | ||
| 30 | #define GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er) \ | ||
| 31 | ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \ | ||
| 32 | sizeof(__be64) * DIV_ROUND_UP((er)->er_data_len, (sdp)->sd_jbsize), 8) | ||
| 33 | |||
| 34 | #define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1)) | 30 | #define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1)) |
| 35 | #define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len) | 31 | #define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len) |
| 36 | 32 | ||
| @@ -43,16 +39,12 @@ ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \ | |||
| 43 | #define GFS2_EA_BH2FIRST(bh) \ | 39 | #define GFS2_EA_BH2FIRST(bh) \ |
| 44 | ((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header))) | 40 | ((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header))) |
| 45 | 41 | ||
| 46 | #define GFS2_ERF_MODE 0x80000000 | ||
| 47 | |||
| 48 | struct gfs2_ea_request { | 42 | struct gfs2_ea_request { |
| 49 | const char *er_name; | 43 | const char *er_name; |
| 50 | char *er_data; | 44 | char *er_data; |
| 51 | unsigned int er_name_len; | 45 | unsigned int er_name_len; |
| 52 | unsigned int er_data_len; | 46 | unsigned int er_data_len; |
| 53 | unsigned int er_type; /* GFS2_EATYPE_... */ | 47 | unsigned int er_type; /* GFS2_EATYPE_... */ |
| 54 | int er_flags; | ||
| 55 | mode_t er_mode; | ||
| 56 | }; | 48 | }; |
| 57 | 49 | ||
| 58 | struct gfs2_ea_location { | 50 | struct gfs2_ea_location { |
| @@ -61,40 +53,20 @@ struct gfs2_ea_location { | |||
| 61 | struct gfs2_ea_header *el_prev; | 53 | struct gfs2_ea_header *el_prev; |
| 62 | }; | 54 | }; |
| 63 | 55 | ||
| 64 | int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 56 | extern int gfs2_xattr_get(struct inode *inode, int type, const char *name, |
| 65 | int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 57 | void *buffer, size_t size); |
| 66 | int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 58 | extern int gfs2_xattr_set(struct inode *inode, int type, const char *name, |
| 67 | 59 | const void *value, size_t size, int flags); | |
| 68 | int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 60 | extern ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size); |
| 69 | int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er); | 61 | extern int gfs2_ea_dealloc(struct gfs2_inode *ip); |
| 70 | int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
| 71 | int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er); | ||
| 72 | |||
| 73 | int gfs2_ea_dealloc(struct gfs2_inode *ip); | ||
| 74 | 62 | ||
| 75 | /* Exported to acl.c */ | 63 | /* Exported to acl.c */ |
| 76 | 64 | ||
| 77 | int gfs2_ea_find(struct gfs2_inode *ip, | 65 | extern int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, |
| 78 | struct gfs2_ea_request *er, | 66 | struct gfs2_ea_location *el); |
| 79 | struct gfs2_ea_location *el); | 67 | extern int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
| 80 | int gfs2_ea_get_copy(struct gfs2_inode *ip, | 68 | char *data, size_t size); |
| 81 | struct gfs2_ea_location *el, | 69 | extern int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, |
| 82 | char *data); | 70 | struct iattr *attr, char *data); |
| 83 | int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, | ||
| 84 | struct iattr *attr, char *data); | ||
| 85 | |||
| 86 | static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea) | ||
| 87 | { | ||
| 88 | switch (ea->ea_type) { | ||
| 89 | case GFS2_EATYPE_USR: | ||
| 90 | return 5 + ea->ea_name_len + 1; | ||
| 91 | case GFS2_EATYPE_SYS: | ||
| 92 | return 7 + ea->ea_name_len + 1; | ||
| 93 | case GFS2_EATYPE_SECURITY: | ||
| 94 | return 9 + ea->ea_name_len + 1; | ||
| 95 | default: | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | 71 | ||
| 100 | #endif /* __EATTR_DOT_H__ */ | 72 | #endif /* __EATTR_DOT_H__ */ |
diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index c56b4bce56d0..b80c88dedbbb 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h | |||
| @@ -333,6 +333,28 @@ struct gfs2_leaf { | |||
| 333 | 333 | ||
| 334 | /* | 334 | /* |
| 335 | * Extended attribute header format | 335 | * Extended attribute header format |
| 336 | * | ||
| 337 | * This works in a similar way to dirents. There is a fixed size header | ||
| 338 | * followed by a variable length section made up of the name and the | ||
| 339 | * associated data. In the case of a "stuffed" entry, the value is | ||
| 340 | * inline directly after the name, the ea_num_ptrs entry will be | ||
| 341 | * zero in that case. For non-"stuffed" entries, there will be | ||
| 342 | * a set of pointers (aligned to 8 byte boundary) to the block(s) | ||
| 343 | * containing the value. | ||
| 344 | * | ||
| 345 | * The blocks containing the values and the blocks containing the | ||
| 346 | * extended attribute headers themselves all start with the common | ||
| 347 | * metadata header. Each inode, if it has extended attributes, will | ||
| 348 | * have either a single block containing the extended attribute headers | ||
| 349 | * or a single indirect block pointing to blocks containing the | ||
| 350 | * extended attribure headers. | ||
| 351 | * | ||
| 352 | * The maximim size of the data part of an extended attribute is 64k | ||
| 353 | * so the number of blocks required depends upon block size. Since the | ||
| 354 | * block size also determines the number of pointers in an indirect | ||
| 355 | * block, its a fairly complicated calculation to work out the maximum | ||
| 356 | * number of blocks that an inode may have relating to extended attributes. | ||
| 357 | * | ||
| 336 | */ | 358 | */ |
| 337 | 359 | ||
| 338 | #define GFS2_EA_MAX_NAME_LEN 255 | 360 | #define GFS2_EA_MAX_NAME_LEN 255 |
