Commit ba9e5e98ca2f808fe92b103a8e6ce5271b10cc89
1 parent
e6af00f1d1
Exists in
master
and in
39 other branches
exofs: super_operations and file_system_type
This patch ties all operation vectors into a file system superblock and registers the exofs file_system_type at module's load time. * The file system control block (AKA on-disk superblock) resides in an object with a special ID (defined in common.h). Information included in the file system control block is used to fill the in-memory superblock structure at mount time. This object is created before the file system is used by mkexofs.c It contains information such as: - The file system's magic number - The next inode number to be allocated Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Showing 4 changed files with 720 additions and 1 deletions Side-by-side Diff
fs/exofs/Kbuild
fs/exofs/exofs.h
... | ... | @@ -140,6 +140,8 @@ |
140 | 140 | struct page **pagep, void **fsdata); |
141 | 141 | extern struct inode *exofs_iget(struct super_block *, unsigned long); |
142 | 142 | struct inode *exofs_new_inode(struct inode *, int); |
143 | +extern int exofs_write_inode(struct inode *, int); | |
144 | +extern void exofs_delete_inode(struct inode *); | |
143 | 145 | |
144 | 146 | /* dir.c: */ |
145 | 147 | int exofs_add_link(struct dentry *, struct inode *); |
fs/exofs/inode.c
... | ... | @@ -1115,4 +1115,190 @@ |
1115 | 1115 | |
1116 | 1116 | return inode; |
1117 | 1117 | } |
1118 | + | |
1119 | +/* | |
1120 | + * struct to pass two arguments to update_inode's callback | |
1121 | + */ | |
1122 | +struct updatei_args { | |
1123 | + struct exofs_sb_info *sbi; | |
1124 | + struct exofs_fcb fcb; | |
1125 | +}; | |
1126 | + | |
1127 | +/* | |
1128 | + * Callback function from exofs_update_inode(). | |
1129 | + */ | |
1130 | +static void updatei_done(struct osd_request *or, void *p) | |
1131 | +{ | |
1132 | + struct updatei_args *args = p; | |
1133 | + | |
1134 | + osd_end_request(or); | |
1135 | + | |
1136 | + atomic_dec(&args->sbi->s_curr_pending); | |
1137 | + | |
1138 | + kfree(args); | |
1139 | +} | |
1140 | + | |
1141 | +/* | |
1142 | + * Write the inode to the OSD. Just fill up the struct, and set the attribute | |
1143 | + * synchronously or asynchronously depending on the do_sync flag. | |
1144 | + */ | |
1145 | +static int exofs_update_inode(struct inode *inode, int do_sync) | |
1146 | +{ | |
1147 | + struct exofs_i_info *oi = exofs_i(inode); | |
1148 | + struct super_block *sb = inode->i_sb; | |
1149 | + struct exofs_sb_info *sbi = sb->s_fs_info; | |
1150 | + struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF}; | |
1151 | + struct osd_request *or; | |
1152 | + struct osd_attr attr; | |
1153 | + struct exofs_fcb *fcb; | |
1154 | + struct updatei_args *args; | |
1155 | + int ret; | |
1156 | + | |
1157 | + args = kzalloc(sizeof(*args), GFP_KERNEL); | |
1158 | + if (!args) | |
1159 | + return -ENOMEM; | |
1160 | + | |
1161 | + fcb = &args->fcb; | |
1162 | + | |
1163 | + fcb->i_mode = cpu_to_le16(inode->i_mode); | |
1164 | + fcb->i_uid = cpu_to_le32(inode->i_uid); | |
1165 | + fcb->i_gid = cpu_to_le32(inode->i_gid); | |
1166 | + fcb->i_links_count = cpu_to_le16(inode->i_nlink); | |
1167 | + fcb->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); | |
1168 | + fcb->i_atime = cpu_to_le32(inode->i_atime.tv_sec); | |
1169 | + fcb->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); | |
1170 | + oi->i_commit_size = i_size_read(inode); | |
1171 | + fcb->i_size = cpu_to_le64(oi->i_commit_size); | |
1172 | + fcb->i_generation = cpu_to_le32(inode->i_generation); | |
1173 | + | |
1174 | + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { | |
1175 | + if (old_valid_dev(inode->i_rdev)) { | |
1176 | + fcb->i_data[0] = | |
1177 | + cpu_to_le32(old_encode_dev(inode->i_rdev)); | |
1178 | + fcb->i_data[1] = 0; | |
1179 | + } else { | |
1180 | + fcb->i_data[0] = 0; | |
1181 | + fcb->i_data[1] = | |
1182 | + cpu_to_le32(new_encode_dev(inode->i_rdev)); | |
1183 | + fcb->i_data[2] = 0; | |
1184 | + } | |
1185 | + } else | |
1186 | + memcpy(fcb->i_data, oi->i_data, sizeof(fcb->i_data)); | |
1187 | + | |
1188 | + or = osd_start_request(sbi->s_dev, GFP_KERNEL); | |
1189 | + if (unlikely(!or)) { | |
1190 | + EXOFS_ERR("exofs_update_inode: osd_start_request failed.\n"); | |
1191 | + ret = -ENOMEM; | |
1192 | + goto free_args; | |
1193 | + } | |
1194 | + | |
1195 | + osd_req_set_attributes(or, &obj); | |
1196 | + | |
1197 | + attr = g_attr_inode_data; | |
1198 | + attr.val_ptr = fcb; | |
1199 | + osd_req_add_set_attr_list(or, &attr, 1); | |
1200 | + | |
1201 | + if (!obj_created(oi)) { | |
1202 | + EXOFS_DBGMSG("!obj_created\n"); | |
1203 | + BUG_ON(!obj_2bcreated(oi)); | |
1204 | + wait_event(oi->i_wq, obj_created(oi)); | |
1205 | + EXOFS_DBGMSG("wait_event done\n"); | |
1206 | + } | |
1207 | + | |
1208 | + if (do_sync) { | |
1209 | + ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred); | |
1210 | + osd_end_request(or); | |
1211 | + goto free_args; | |
1212 | + } else { | |
1213 | + args->sbi = sbi; | |
1214 | + | |
1215 | + ret = exofs_async_op(or, updatei_done, args, oi->i_cred); | |
1216 | + if (ret) { | |
1217 | + osd_end_request(or); | |
1218 | + goto free_args; | |
1219 | + } | |
1220 | + atomic_inc(&sbi->s_curr_pending); | |
1221 | + goto out; /* deallocation in updatei_done */ | |
1222 | + } | |
1223 | + | |
1224 | +free_args: | |
1225 | + kfree(args); | |
1226 | +out: | |
1227 | + EXOFS_DBGMSG("ret=>%d\n", ret); | |
1228 | + return ret; | |
1229 | +} | |
1230 | + | |
1231 | +int exofs_write_inode(struct inode *inode, int wait) | |
1232 | +{ | |
1233 | + return exofs_update_inode(inode, wait); | |
1234 | +} | |
1235 | + | |
1236 | +/* | |
1237 | + * Callback function from exofs_delete_inode() - don't have much cleaning up to | |
1238 | + * do. | |
1239 | + */ | |
1240 | +static void delete_done(struct osd_request *or, void *p) | |
1241 | +{ | |
1242 | + struct exofs_sb_info *sbi; | |
1243 | + osd_end_request(or); | |
1244 | + sbi = p; | |
1245 | + atomic_dec(&sbi->s_curr_pending); | |
1246 | +} | |
1247 | + | |
1248 | +/* | |
1249 | + * Called when the refcount of an inode reaches zero. We remove the object | |
1250 | + * from the OSD here. We make sure the object was created before we try and | |
1251 | + * delete it. | |
1252 | + */ | |
1253 | +void exofs_delete_inode(struct inode *inode) | |
1254 | +{ | |
1255 | + struct exofs_i_info *oi = exofs_i(inode); | |
1256 | + struct super_block *sb = inode->i_sb; | |
1257 | + struct exofs_sb_info *sbi = sb->s_fs_info; | |
1258 | + struct osd_obj_id obj = {sbi->s_pid, inode->i_ino + EXOFS_OBJ_OFF}; | |
1259 | + struct osd_request *or; | |
1260 | + int ret; | |
1261 | + | |
1262 | + truncate_inode_pages(&inode->i_data, 0); | |
1263 | + | |
1264 | + if (is_bad_inode(inode)) | |
1265 | + goto no_delete; | |
1266 | + | |
1267 | + mark_inode_dirty(inode); | |
1268 | + exofs_update_inode(inode, inode_needs_sync(inode)); | |
1269 | + | |
1270 | + inode->i_size = 0; | |
1271 | + if (inode->i_blocks) | |
1272 | + exofs_truncate(inode); | |
1273 | + | |
1274 | + clear_inode(inode); | |
1275 | + | |
1276 | + or = osd_start_request(sbi->s_dev, GFP_KERNEL); | |
1277 | + if (unlikely(!or)) { | |
1278 | + EXOFS_ERR("exofs_delete_inode: osd_start_request failed\n"); | |
1279 | + return; | |
1280 | + } | |
1281 | + | |
1282 | + osd_req_remove_object(or, &obj); | |
1283 | + | |
1284 | + /* if we are deleting an obj that hasn't been created yet, wait */ | |
1285 | + if (!obj_created(oi)) { | |
1286 | + BUG_ON(!obj_2bcreated(oi)); | |
1287 | + wait_event(oi->i_wq, obj_created(oi)); | |
1288 | + } | |
1289 | + | |
1290 | + ret = exofs_async_op(or, delete_done, sbi, oi->i_cred); | |
1291 | + if (ret) { | |
1292 | + EXOFS_ERR( | |
1293 | + "ERROR: @exofs_delete_inode exofs_async_op failed\n"); | |
1294 | + osd_end_request(or); | |
1295 | + return; | |
1296 | + } | |
1297 | + atomic_inc(&sbi->s_curr_pending); | |
1298 | + | |
1299 | + return; | |
1300 | + | |
1301 | +no_delete: | |
1302 | + clear_inode(inode); | |
1303 | +} |
fs/exofs/super.c
1 | +/* | |
2 | + * Copyright (C) 2005, 2006 | |
3 | + * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | |
4 | + * Copyright (C) 2005, 2006 | |
5 | + * International Business Machines | |
6 | + * Copyright (C) 2008, 2009 | |
7 | + * Boaz Harrosh <bharrosh@panasas.com> | |
8 | + * | |
9 | + * Copyrights for code taken from ext2: | |
10 | + * Copyright (C) 1992, 1993, 1994, 1995 | |
11 | + * Remy Card (card@masi.ibp.fr) | |
12 | + * Laboratoire MASI - Institut Blaise Pascal | |
13 | + * Universite Pierre et Marie Curie (Paris VI) | |
14 | + * from | |
15 | + * linux/fs/minix/inode.c | |
16 | + * Copyright (C) 1991, 1992 Linus Torvalds | |
17 | + * | |
18 | + * This file is part of exofs. | |
19 | + * | |
20 | + * exofs is free software; you can redistribute it and/or modify | |
21 | + * it under the terms of the GNU General Public License as published by | |
22 | + * the Free Software Foundation. Since it is based on ext2, and the only | |
23 | + * valid version of GPL for the Linux kernel is version 2, the only valid | |
24 | + * version of GPL for exofs is version 2. | |
25 | + * | |
26 | + * exofs is distributed in the hope that it will be useful, | |
27 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
28 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
29 | + * GNU General Public License for more details. | |
30 | + * | |
31 | + * You should have received a copy of the GNU General Public License | |
32 | + * along with exofs; if not, write to the Free Software | |
33 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
34 | + */ | |
35 | + | |
36 | +#include <linux/string.h> | |
37 | +#include <linux/parser.h> | |
38 | +#include <linux/vfs.h> | |
39 | +#include <linux/random.h> | |
40 | + | |
41 | +#include "exofs.h" | |
42 | + | |
43 | +/****************************************************************************** | |
44 | + * MOUNT OPTIONS | |
45 | + *****************************************************************************/ | |
46 | + | |
47 | +/* | |
48 | + * struct to hold what we get from mount options | |
49 | + */ | |
50 | +struct exofs_mountopt { | |
51 | + const char *dev_name; | |
52 | + uint64_t pid; | |
53 | + int timeout; | |
54 | +}; | |
55 | + | |
56 | +/* | |
57 | + * exofs-specific mount-time options. | |
58 | + */ | |
59 | +enum { Opt_pid, Opt_to, Opt_mkfs, Opt_format, Opt_err }; | |
60 | + | |
61 | +/* | |
62 | + * Our mount-time options. These should ideally be 64-bit unsigned, but the | |
63 | + * kernel's parsing functions do not currently support that. 32-bit should be | |
64 | + * sufficient for most applications now. | |
65 | + */ | |
66 | +static match_table_t tokens = { | |
67 | + {Opt_pid, "pid=%u"}, | |
68 | + {Opt_to, "to=%u"}, | |
69 | + {Opt_err, NULL} | |
70 | +}; | |
71 | + | |
72 | +/* | |
73 | + * The main option parsing method. Also makes sure that all of the mandatory | |
74 | + * mount options were set. | |
75 | + */ | |
76 | +static int parse_options(char *options, struct exofs_mountopt *opts) | |
77 | +{ | |
78 | + char *p; | |
79 | + substring_t args[MAX_OPT_ARGS]; | |
80 | + int option; | |
81 | + bool s_pid = false; | |
82 | + | |
83 | + EXOFS_DBGMSG("parse_options %s\n", options); | |
84 | + /* defaults */ | |
85 | + memset(opts, 0, sizeof(*opts)); | |
86 | + opts->timeout = BLK_DEFAULT_SG_TIMEOUT; | |
87 | + | |
88 | + while ((p = strsep(&options, ",")) != NULL) { | |
89 | + int token; | |
90 | + char str[32]; | |
91 | + | |
92 | + if (!*p) | |
93 | + continue; | |
94 | + | |
95 | + token = match_token(p, tokens, args); | |
96 | + switch (token) { | |
97 | + case Opt_pid: | |
98 | + if (0 == match_strlcpy(str, &args[0], sizeof(str))) | |
99 | + return -EINVAL; | |
100 | + opts->pid = simple_strtoull(str, NULL, 0); | |
101 | + if (opts->pid < EXOFS_MIN_PID) { | |
102 | + EXOFS_ERR("Partition ID must be >= %u", | |
103 | + EXOFS_MIN_PID); | |
104 | + return -EINVAL; | |
105 | + } | |
106 | + s_pid = 1; | |
107 | + break; | |
108 | + case Opt_to: | |
109 | + if (match_int(&args[0], &option)) | |
110 | + return -EINVAL; | |
111 | + if (option <= 0) { | |
112 | + EXOFS_ERR("Timout must be > 0"); | |
113 | + return -EINVAL; | |
114 | + } | |
115 | + opts->timeout = option * HZ; | |
116 | + break; | |
117 | + } | |
118 | + } | |
119 | + | |
120 | + if (!s_pid) { | |
121 | + EXOFS_ERR("Need to specify the following options:\n"); | |
122 | + EXOFS_ERR(" -o pid=pid_no_to_use\n"); | |
123 | + return -EINVAL; | |
124 | + } | |
125 | + | |
126 | + return 0; | |
127 | +} | |
128 | + | |
129 | +/****************************************************************************** | |
130 | + * INODE CACHE | |
131 | + *****************************************************************************/ | |
132 | + | |
133 | +/* | |
134 | + * Our inode cache. Isn't it pretty? | |
135 | + */ | |
136 | +static struct kmem_cache *exofs_inode_cachep; | |
137 | + | |
138 | +/* | |
139 | + * Allocate an inode in the cache | |
140 | + */ | |
141 | +static struct inode *exofs_alloc_inode(struct super_block *sb) | |
142 | +{ | |
143 | + struct exofs_i_info *oi; | |
144 | + | |
145 | + oi = kmem_cache_alloc(exofs_inode_cachep, GFP_KERNEL); | |
146 | + if (!oi) | |
147 | + return NULL; | |
148 | + | |
149 | + oi->vfs_inode.i_version = 1; | |
150 | + return &oi->vfs_inode; | |
151 | +} | |
152 | + | |
153 | +/* | |
154 | + * Remove an inode from the cache | |
155 | + */ | |
156 | +static void exofs_destroy_inode(struct inode *inode) | |
157 | +{ | |
158 | + kmem_cache_free(exofs_inode_cachep, exofs_i(inode)); | |
159 | +} | |
160 | + | |
161 | +/* | |
162 | + * Initialize the inode | |
163 | + */ | |
164 | +static void exofs_init_once(void *foo) | |
165 | +{ | |
166 | + struct exofs_i_info *oi = foo; | |
167 | + | |
168 | + inode_init_once(&oi->vfs_inode); | |
169 | +} | |
170 | + | |
171 | +/* | |
172 | + * Create and initialize the inode cache | |
173 | + */ | |
174 | +static int init_inodecache(void) | |
175 | +{ | |
176 | + exofs_inode_cachep = kmem_cache_create("exofs_inode_cache", | |
177 | + sizeof(struct exofs_i_info), 0, | |
178 | + SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, | |
179 | + exofs_init_once); | |
180 | + if (exofs_inode_cachep == NULL) | |
181 | + return -ENOMEM; | |
182 | + return 0; | |
183 | +} | |
184 | + | |
185 | +/* | |
186 | + * Destroy the inode cache | |
187 | + */ | |
188 | +static void destroy_inodecache(void) | |
189 | +{ | |
190 | + kmem_cache_destroy(exofs_inode_cachep); | |
191 | +} | |
192 | + | |
193 | +/****************************************************************************** | |
194 | + * SUPERBLOCK FUNCTIONS | |
195 | + *****************************************************************************/ | |
196 | +static const struct super_operations exofs_sops; | |
197 | + | |
198 | +/* | |
199 | + * Write the superblock to the OSD | |
200 | + */ | |
201 | +static void exofs_write_super(struct super_block *sb) | |
202 | +{ | |
203 | + struct exofs_sb_info *sbi; | |
204 | + struct exofs_fscb *fscb; | |
205 | + struct osd_request *or; | |
206 | + struct osd_obj_id obj; | |
207 | + int ret; | |
208 | + | |
209 | + fscb = kzalloc(sizeof(struct exofs_fscb), GFP_KERNEL); | |
210 | + if (!fscb) { | |
211 | + EXOFS_ERR("exofs_write_super: memory allocation failed.\n"); | |
212 | + return; | |
213 | + } | |
214 | + | |
215 | + lock_kernel(); | |
216 | + sbi = sb->s_fs_info; | |
217 | + fscb->s_nextid = cpu_to_le64(sbi->s_nextid); | |
218 | + fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles); | |
219 | + fscb->s_magic = cpu_to_le16(sb->s_magic); | |
220 | + fscb->s_newfs = 0; | |
221 | + | |
222 | + or = osd_start_request(sbi->s_dev, GFP_KERNEL); | |
223 | + if (unlikely(!or)) { | |
224 | + EXOFS_ERR("exofs_write_super: osd_start_request failed.\n"); | |
225 | + goto out; | |
226 | + } | |
227 | + | |
228 | + obj.partition = sbi->s_pid; | |
229 | + obj.id = EXOFS_SUPER_ID; | |
230 | + ret = osd_req_write_kern(or, &obj, 0, fscb, sizeof(*fscb)); | |
231 | + if (unlikely(ret)) { | |
232 | + EXOFS_ERR("exofs_write_super: osd_req_write_kern failed.\n"); | |
233 | + goto out; | |
234 | + } | |
235 | + | |
236 | + ret = exofs_sync_op(or, sbi->s_timeout, sbi->s_cred); | |
237 | + if (unlikely(ret)) { | |
238 | + EXOFS_ERR("exofs_write_super: exofs_sync_op failed.\n"); | |
239 | + goto out; | |
240 | + } | |
241 | + sb->s_dirt = 0; | |
242 | + | |
243 | +out: | |
244 | + if (or) | |
245 | + osd_end_request(or); | |
246 | + unlock_kernel(); | |
247 | + kfree(fscb); | |
248 | +} | |
249 | + | |
250 | +/* | |
251 | + * This function is called when the vfs is freeing the superblock. We just | |
252 | + * need to free our own part. | |
253 | + */ | |
254 | +static void exofs_put_super(struct super_block *sb) | |
255 | +{ | |
256 | + int num_pend; | |
257 | + struct exofs_sb_info *sbi = sb->s_fs_info; | |
258 | + | |
259 | + /* make sure there are no pending commands */ | |
260 | + for (num_pend = atomic_read(&sbi->s_curr_pending); num_pend > 0; | |
261 | + num_pend = atomic_read(&sbi->s_curr_pending)) { | |
262 | + wait_queue_head_t wq; | |
263 | + init_waitqueue_head(&wq); | |
264 | + wait_event_timeout(wq, | |
265 | + (atomic_read(&sbi->s_curr_pending) == 0), | |
266 | + msecs_to_jiffies(100)); | |
267 | + } | |
268 | + | |
269 | + osduld_put_device(sbi->s_dev); | |
270 | + kfree(sb->s_fs_info); | |
271 | + sb->s_fs_info = NULL; | |
272 | +} | |
273 | + | |
274 | +/* | |
275 | + * Read the superblock from the OSD and fill in the fields | |
276 | + */ | |
277 | +static int exofs_fill_super(struct super_block *sb, void *data, int silent) | |
278 | +{ | |
279 | + struct inode *root; | |
280 | + struct exofs_mountopt *opts = data; | |
281 | + struct exofs_sb_info *sbi; /*extended info */ | |
282 | + struct exofs_fscb fscb; /*on-disk superblock info */ | |
283 | + struct osd_request *or = NULL; | |
284 | + struct osd_obj_id obj; | |
285 | + int ret; | |
286 | + | |
287 | + sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); | |
288 | + if (!sbi) | |
289 | + return -ENOMEM; | |
290 | + sb->s_fs_info = sbi; | |
291 | + | |
292 | + /* use mount options to fill superblock */ | |
293 | + sbi->s_dev = osduld_path_lookup(opts->dev_name); | |
294 | + if (IS_ERR(sbi->s_dev)) { | |
295 | + ret = PTR_ERR(sbi->s_dev); | |
296 | + sbi->s_dev = NULL; | |
297 | + goto free_sbi; | |
298 | + } | |
299 | + | |
300 | + sbi->s_pid = opts->pid; | |
301 | + sbi->s_timeout = opts->timeout; | |
302 | + | |
303 | + /* fill in some other data by hand */ | |
304 | + memset(sb->s_id, 0, sizeof(sb->s_id)); | |
305 | + strcpy(sb->s_id, "exofs"); | |
306 | + sb->s_blocksize = EXOFS_BLKSIZE; | |
307 | + sb->s_blocksize_bits = EXOFS_BLKSHIFT; | |
308 | + sb->s_maxbytes = MAX_LFS_FILESIZE; | |
309 | + atomic_set(&sbi->s_curr_pending, 0); | |
310 | + sb->s_bdev = NULL; | |
311 | + sb->s_dev = 0; | |
312 | + | |
313 | + /* read data from on-disk superblock object */ | |
314 | + obj.partition = sbi->s_pid; | |
315 | + obj.id = EXOFS_SUPER_ID; | |
316 | + exofs_make_credential(sbi->s_cred, &obj); | |
317 | + | |
318 | + or = osd_start_request(sbi->s_dev, GFP_KERNEL); | |
319 | + if (unlikely(!or)) { | |
320 | + if (!silent) | |
321 | + EXOFS_ERR( | |
322 | + "exofs_fill_super: osd_start_request failed.\n"); | |
323 | + ret = -ENOMEM; | |
324 | + goto free_sbi; | |
325 | + } | |
326 | + ret = osd_req_read_kern(or, &obj, 0, &fscb, sizeof(fscb)); | |
327 | + if (unlikely(ret)) { | |
328 | + if (!silent) | |
329 | + EXOFS_ERR( | |
330 | + "exofs_fill_super: osd_req_read_kern failed.\n"); | |
331 | + ret = -ENOMEM; | |
332 | + goto free_sbi; | |
333 | + } | |
334 | + | |
335 | + ret = exofs_sync_op(or, sbi->s_timeout, sbi->s_cred); | |
336 | + if (unlikely(ret)) { | |
337 | + if (!silent) | |
338 | + EXOFS_ERR("exofs_fill_super: exofs_sync_op failed.\n"); | |
339 | + ret = -EIO; | |
340 | + goto free_sbi; | |
341 | + } | |
342 | + | |
343 | + sb->s_magic = le16_to_cpu(fscb.s_magic); | |
344 | + sbi->s_nextid = le64_to_cpu(fscb.s_nextid); | |
345 | + sbi->s_numfiles = le32_to_cpu(fscb.s_numfiles); | |
346 | + | |
347 | + /* make sure what we read from the object store is correct */ | |
348 | + if (sb->s_magic != EXOFS_SUPER_MAGIC) { | |
349 | + if (!silent) | |
350 | + EXOFS_ERR("ERROR: Bad magic value\n"); | |
351 | + ret = -EINVAL; | |
352 | + goto free_sbi; | |
353 | + } | |
354 | + | |
355 | + /* start generation numbers from a random point */ | |
356 | + get_random_bytes(&sbi->s_next_generation, sizeof(u32)); | |
357 | + spin_lock_init(&sbi->s_next_gen_lock); | |
358 | + | |
359 | + /* set up operation vectors */ | |
360 | + sb->s_op = &exofs_sops; | |
361 | + root = exofs_iget(sb, EXOFS_ROOT_ID - EXOFS_OBJ_OFF); | |
362 | + if (IS_ERR(root)) { | |
363 | + EXOFS_ERR("ERROR: exofs_iget failed\n"); | |
364 | + ret = PTR_ERR(root); | |
365 | + goto free_sbi; | |
366 | + } | |
367 | + sb->s_root = d_alloc_root(root); | |
368 | + if (!sb->s_root) { | |
369 | + iput(root); | |
370 | + EXOFS_ERR("ERROR: get root inode failed\n"); | |
371 | + ret = -ENOMEM; | |
372 | + goto free_sbi; | |
373 | + } | |
374 | + | |
375 | + if (!S_ISDIR(root->i_mode)) { | |
376 | + dput(sb->s_root); | |
377 | + sb->s_root = NULL; | |
378 | + EXOFS_ERR("ERROR: corrupt root inode (mode = %hd)\n", | |
379 | + root->i_mode); | |
380 | + ret = -EINVAL; | |
381 | + goto free_sbi; | |
382 | + } | |
383 | + | |
384 | + ret = 0; | |
385 | +out: | |
386 | + if (or) | |
387 | + osd_end_request(or); | |
388 | + return ret; | |
389 | + | |
390 | +free_sbi: | |
391 | + osduld_put_device(sbi->s_dev); /* NULL safe */ | |
392 | + kfree(sbi); | |
393 | + goto out; | |
394 | +} | |
395 | + | |
396 | +/* | |
397 | + * Set up the superblock (calls exofs_fill_super eventually) | |
398 | + */ | |
399 | +static int exofs_get_sb(struct file_system_type *type, | |
400 | + int flags, const char *dev_name, | |
401 | + void *data, struct vfsmount *mnt) | |
402 | +{ | |
403 | + struct exofs_mountopt opts; | |
404 | + int ret; | |
405 | + | |
406 | + ret = parse_options(data, &opts); | |
407 | + if (ret) | |
408 | + return ret; | |
409 | + | |
410 | + opts.dev_name = dev_name; | |
411 | + return get_sb_nodev(type, flags, &opts, exofs_fill_super, mnt); | |
412 | +} | |
413 | + | |
414 | +/* | |
415 | + * Return information about the file system state in the buffer. This is used | |
416 | + * by the 'df' command, for example. | |
417 | + */ | |
418 | +static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf) | |
419 | +{ | |
420 | + struct super_block *sb = dentry->d_sb; | |
421 | + struct exofs_sb_info *sbi = sb->s_fs_info; | |
422 | + struct osd_obj_id obj = {sbi->s_pid, 0}; | |
423 | + struct osd_attr attrs[] = { | |
424 | + ATTR_DEF(OSD_APAGE_PARTITION_QUOTAS, | |
425 | + OSD_ATTR_PQ_CAPACITY_QUOTA, sizeof(__be64)), | |
426 | + ATTR_DEF(OSD_APAGE_PARTITION_INFORMATION, | |
427 | + OSD_ATTR_PI_USED_CAPACITY, sizeof(__be64)), | |
428 | + }; | |
429 | + uint64_t capacity = ULLONG_MAX; | |
430 | + uint64_t used = ULLONG_MAX; | |
431 | + struct osd_request *or; | |
432 | + uint8_t cred_a[OSD_CAP_LEN]; | |
433 | + int ret; | |
434 | + | |
435 | + /* get used/capacity attributes */ | |
436 | + exofs_make_credential(cred_a, &obj); | |
437 | + | |
438 | + or = osd_start_request(sbi->s_dev, GFP_KERNEL); | |
439 | + if (unlikely(!or)) { | |
440 | + EXOFS_DBGMSG("exofs_statfs: osd_start_request failed.\n"); | |
441 | + return -ENOMEM; | |
442 | + } | |
443 | + | |
444 | + osd_req_get_attributes(or, &obj); | |
445 | + osd_req_add_get_attr_list(or, attrs, ARRAY_SIZE(attrs)); | |
446 | + ret = exofs_sync_op(or, sbi->s_timeout, cred_a); | |
447 | + if (unlikely(ret)) | |
448 | + goto out; | |
449 | + | |
450 | + ret = extract_attr_from_req(or, &attrs[0]); | |
451 | + if (likely(!ret)) | |
452 | + capacity = get_unaligned_be64(attrs[0].val_ptr); | |
453 | + else | |
454 | + EXOFS_DBGMSG("exofs_statfs: get capacity failed.\n"); | |
455 | + | |
456 | + ret = extract_attr_from_req(or, &attrs[1]); | |
457 | + if (likely(!ret)) | |
458 | + used = get_unaligned_be64(attrs[1].val_ptr); | |
459 | + else | |
460 | + EXOFS_DBGMSG("exofs_statfs: get used-space failed.\n"); | |
461 | + | |
462 | + /* fill in the stats buffer */ | |
463 | + buf->f_type = EXOFS_SUPER_MAGIC; | |
464 | + buf->f_bsize = EXOFS_BLKSIZE; | |
465 | + buf->f_blocks = (capacity >> EXOFS_BLKSHIFT); | |
466 | + buf->f_bfree = ((capacity - used) >> EXOFS_BLKSHIFT); | |
467 | + buf->f_bavail = buf->f_bfree; | |
468 | + buf->f_files = sbi->s_numfiles; | |
469 | + buf->f_ffree = EXOFS_MAX_ID - sbi->s_numfiles; | |
470 | + buf->f_namelen = EXOFS_NAME_LEN; | |
471 | + | |
472 | +out: | |
473 | + osd_end_request(or); | |
474 | + return ret; | |
475 | +} | |
476 | + | |
477 | +static const struct super_operations exofs_sops = { | |
478 | + .alloc_inode = exofs_alloc_inode, | |
479 | + .destroy_inode = exofs_destroy_inode, | |
480 | + .write_inode = exofs_write_inode, | |
481 | + .delete_inode = exofs_delete_inode, | |
482 | + .put_super = exofs_put_super, | |
483 | + .write_super = exofs_write_super, | |
484 | + .statfs = exofs_statfs, | |
485 | +}; | |
486 | + | |
487 | +/****************************************************************************** | |
488 | + * INSMOD/RMMOD | |
489 | + *****************************************************************************/ | |
490 | + | |
491 | +/* | |
492 | + * struct that describes this file system | |
493 | + */ | |
494 | +static struct file_system_type exofs_type = { | |
495 | + .owner = THIS_MODULE, | |
496 | + .name = "exofs", | |
497 | + .get_sb = exofs_get_sb, | |
498 | + .kill_sb = generic_shutdown_super, | |
499 | +}; | |
500 | + | |
501 | +static int __init init_exofs(void) | |
502 | +{ | |
503 | + int err; | |
504 | + | |
505 | + err = init_inodecache(); | |
506 | + if (err) | |
507 | + goto out; | |
508 | + | |
509 | + err = register_filesystem(&exofs_type); | |
510 | + if (err) | |
511 | + goto out_d; | |
512 | + | |
513 | + return 0; | |
514 | +out_d: | |
515 | + destroy_inodecache(); | |
516 | +out: | |
517 | + return err; | |
518 | +} | |
519 | + | |
520 | +static void __exit exit_exofs(void) | |
521 | +{ | |
522 | + unregister_filesystem(&exofs_type); | |
523 | + destroy_inodecache(); | |
524 | +} | |
525 | + | |
526 | +MODULE_AUTHOR("Avishay Traeger <avishay@gmail.com>"); | |
527 | +MODULE_DESCRIPTION("exofs"); | |
528 | +MODULE_LICENSE("GPL"); | |
529 | + | |
530 | +module_init(init_exofs) | |
531 | +module_exit(exit_exofs) |