xref: /linux/fs/btrfs/super.c (revision 7f5c15160e1436a53d01f9190db11c2a3a4d788a)
12e635a27SChris Mason #include <linux/module.h>
2e20d96d6SChris Mason #include <linux/buffer_head.h>
32e635a27SChris Mason #include <linux/fs.h>
42e635a27SChris Mason #include <linux/pagemap.h>
52e635a27SChris Mason #include <linux/highmem.h>
62e635a27SChris Mason #include <linux/time.h>
72e635a27SChris Mason #include <linux/init.h>
82e635a27SChris Mason #include <linux/string.h>
92e635a27SChris Mason #include <linux/smp_lock.h>
102e635a27SChris Mason #include <linux/backing-dev.h>
112e635a27SChris Mason #include "ctree.h"
12e20d96d6SChris Mason #include "disk-io.h"
13d5719762SChris Mason #include "transaction.h"
142e635a27SChris Mason 
152e635a27SChris Mason #define BTRFS_SUPER_MAGIC 0x9123682E
16e20d96d6SChris Mason 
17e20d96d6SChris Mason static struct inode_operations btrfs_dir_inode_operations;
18e20d96d6SChris Mason static struct super_operations btrfs_super_ops;
19e20d96d6SChris Mason static struct file_operations btrfs_dir_file_operations;
20e20d96d6SChris Mason 
212e635a27SChris Mason #if 0
222e635a27SChris Mason /* some random number */
232e635a27SChris Mason 
242e635a27SChris Mason static struct super_operations ramfs_ops;
252e635a27SChris Mason 
262e635a27SChris Mason static struct backing_dev_info ramfs_backing_dev_info = {
272e635a27SChris Mason 	.ra_pages	= 0,	/* No readahead */
282e635a27SChris Mason 	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK |
292e635a27SChris Mason 			  BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
302e635a27SChris Mason 			  BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
312e635a27SChris Mason };
322e635a27SChris Mason 
332e635a27SChris Mason struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
342e635a27SChris Mason {
352e635a27SChris Mason 	struct inode * inode = new_inode(sb);
362e635a27SChris Mason 
372e635a27SChris Mason 	if (inode) {
382e635a27SChris Mason 		inode->i_mode = mode;
392e635a27SChris Mason 		inode->i_uid = current->fsuid;
402e635a27SChris Mason 		inode->i_gid = current->fsgid;
412e635a27SChris Mason 		inode->i_blocks = 0;
422e635a27SChris Mason 		inode->i_mapping->a_ops = &ramfs_aops;
432e635a27SChris Mason 		inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
442e635a27SChris Mason 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
452e635a27SChris Mason 		switch (mode & S_IFMT) {
462e635a27SChris Mason 		default:
472e635a27SChris Mason 			init_special_inode(inode, mode, dev);
482e635a27SChris Mason 			break;
492e635a27SChris Mason 		case S_IFREG:
502e635a27SChris Mason 			inode->i_op = &ramfs_file_inode_operations;
512e635a27SChris Mason 			inode->i_fop = &ramfs_file_operations;
522e635a27SChris Mason 			break;
532e635a27SChris Mason 		case S_IFDIR:
542e635a27SChris Mason 			inode->i_op = &ramfs_dir_inode_operations;
552e635a27SChris Mason 			inode->i_fop = &simple_dir_operations;
562e635a27SChris Mason 
572e635a27SChris Mason 			/* directory inodes start off with i_nlink == 2 (for "." entry) */
582e635a27SChris Mason 			inc_nlink(inode);
592e635a27SChris Mason 			break;
602e635a27SChris Mason 		case S_IFLNK:
612e635a27SChris Mason 			inode->i_op = &page_symlink_inode_operations;
622e635a27SChris Mason 			break;
632e635a27SChris Mason 		}
642e635a27SChris Mason 	}
652e635a27SChris Mason 	return inode;
662e635a27SChris Mason }
672e635a27SChris Mason 
682e635a27SChris Mason /*
692e635a27SChris Mason  * File creation. Allocate an inode, and we're done..
702e635a27SChris Mason  */
712e635a27SChris Mason /* SMP-safe */
722e635a27SChris Mason static int
732e635a27SChris Mason ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
742e635a27SChris Mason {
752e635a27SChris Mason 	struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev);
762e635a27SChris Mason 	int error = -ENOSPC;
772e635a27SChris Mason 
782e635a27SChris Mason 	if (inode) {
792e635a27SChris Mason 		if (dir->i_mode & S_ISGID) {
802e635a27SChris Mason 			inode->i_gid = dir->i_gid;
812e635a27SChris Mason 			if (S_ISDIR(mode))
822e635a27SChris Mason 				inode->i_mode |= S_ISGID;
832e635a27SChris Mason 		}
842e635a27SChris Mason 		d_instantiate(dentry, inode);
852e635a27SChris Mason 		dget(dentry);	/* Extra count - pin the dentry in core */
862e635a27SChris Mason 		error = 0;
872e635a27SChris Mason 		dir->i_mtime = dir->i_ctime = CURRENT_TIME;
882e635a27SChris Mason 	}
892e635a27SChris Mason 	return error;
902e635a27SChris Mason }
912e635a27SChris Mason 
922e635a27SChris Mason static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
932e635a27SChris Mason {
942e635a27SChris Mason 	int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
952e635a27SChris Mason 	if (!retval)
962e635a27SChris Mason 		inc_nlink(dir);
972e635a27SChris Mason 	return retval;
982e635a27SChris Mason }
992e635a27SChris Mason 
1002e635a27SChris Mason static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
1012e635a27SChris Mason {
1022e635a27SChris Mason 	return ramfs_mknod(dir, dentry, mode | S_IFREG, 0);
1032e635a27SChris Mason }
1042e635a27SChris Mason 
1052e635a27SChris Mason static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
1062e635a27SChris Mason {
1072e635a27SChris Mason 	struct inode *inode;
1082e635a27SChris Mason 	int error = -ENOSPC;
1092e635a27SChris Mason 
1102e635a27SChris Mason 	inode = ramfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
1112e635a27SChris Mason 	if (inode) {
1122e635a27SChris Mason 		int l = strlen(symname)+1;
1132e635a27SChris Mason 		error = page_symlink(inode, symname, l);
1142e635a27SChris Mason 		if (!error) {
1152e635a27SChris Mason 			if (dir->i_mode & S_ISGID)
1162e635a27SChris Mason 				inode->i_gid = dir->i_gid;
1172e635a27SChris Mason 			d_instantiate(dentry, inode);
1182e635a27SChris Mason 			dget(dentry);
1192e635a27SChris Mason 			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
1202e635a27SChris Mason 		} else
1212e635a27SChris Mason 			iput(inode);
1222e635a27SChris Mason 	}
1232e635a27SChris Mason 	return error;
1242e635a27SChris Mason }
1252e635a27SChris Mason 
1262e635a27SChris Mason static struct inode_operations ramfs_dir_inode_operations = {
1272e635a27SChris Mason 	.create		= ramfs_create,
1282e635a27SChris Mason 	.lookup		= simple_lookup,
1292e635a27SChris Mason 	.link		= simple_link,
1302e635a27SChris Mason 	.unlink		= simple_unlink,
1312e635a27SChris Mason 	.symlink	= ramfs_symlink,
1322e635a27SChris Mason 	.mkdir		= ramfs_mkdir,
1332e635a27SChris Mason 	.rmdir		= simple_rmdir,
1342e635a27SChris Mason 	.mknod		= ramfs_mknod,
1352e635a27SChris Mason 	.rename		= simple_rename,
1362e635a27SChris Mason };
1372e635a27SChris Mason #endif
1382e635a27SChris Mason 
139e20d96d6SChris Mason static void btrfs_read_locked_inode(struct inode *inode)
1402e635a27SChris Mason {
141e20d96d6SChris Mason 	struct btrfs_path path;
142e20d96d6SChris Mason 	struct btrfs_inode_item *inode_item;
143e20d96d6SChris Mason 	struct btrfs_root *root = btrfs_sb(inode->i_sb);
144e20d96d6SChris Mason 	int ret;
145e20d96d6SChris Mason 	btrfs_init_path(&path);
146e20d96d6SChris Mason 	ret = btrfs_lookup_inode(NULL, root, &path, inode->i_ino, 0);
147e20d96d6SChris Mason 	if (ret) {
148e20d96d6SChris Mason 		make_bad_inode(inode);
149e20d96d6SChris Mason 		return;
1502e635a27SChris Mason 	}
151e20d96d6SChris Mason 	inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
152e20d96d6SChris Mason 				  path.slots[0],
153e20d96d6SChris Mason 				  struct btrfs_inode_item);
154e20d96d6SChris Mason 
155e20d96d6SChris Mason 	inode->i_mode = btrfs_inode_mode(inode_item);
156e20d96d6SChris Mason 	inode->i_nlink = btrfs_inode_nlink(inode_item);
157e20d96d6SChris Mason 	inode->i_uid = btrfs_inode_uid(inode_item);
158e20d96d6SChris Mason 	inode->i_gid = btrfs_inode_gid(inode_item);
159e20d96d6SChris Mason 	inode->i_size = btrfs_inode_size(inode_item);
160e20d96d6SChris Mason 	inode->i_atime.tv_sec = btrfs_timespec_sec(&inode_item->atime);
161e20d96d6SChris Mason 	inode->i_atime.tv_nsec = btrfs_timespec_nsec(&inode_item->atime);
162e20d96d6SChris Mason 	inode->i_mtime.tv_sec = btrfs_timespec_sec(&inode_item->mtime);
163e20d96d6SChris Mason 	inode->i_mtime.tv_nsec = btrfs_timespec_nsec(&inode_item->mtime);
164e20d96d6SChris Mason 	inode->i_ctime.tv_sec = btrfs_timespec_sec(&inode_item->ctime);
165e20d96d6SChris Mason 	inode->i_ctime.tv_nsec = btrfs_timespec_nsec(&inode_item->ctime);
166e20d96d6SChris Mason 	inode->i_blocks = btrfs_inode_nblocks(inode_item);
167e20d96d6SChris Mason 	inode->i_generation = btrfs_inode_generation(inode_item);
168e20d96d6SChris Mason 	btrfs_release_path(root, &path);
169e20d96d6SChris Mason 	switch (inode->i_mode & S_IFMT) {
170e20d96d6SChris Mason #if 0
171e20d96d6SChris Mason 	default:
172e20d96d6SChris Mason 		init_special_inode(inode, inode->i_mode,
173e20d96d6SChris Mason 				   btrfs_inode_rdev(inode_item));
174e20d96d6SChris Mason 		break;
175e20d96d6SChris Mason #endif
176e20d96d6SChris Mason 	case S_IFREG:
177e20d96d6SChris Mason 		break;
178e20d96d6SChris Mason 	case S_IFDIR:
179e20d96d6SChris Mason 		inode->i_op = &btrfs_dir_inode_operations;
180e20d96d6SChris Mason 		inode->i_fop = &btrfs_dir_file_operations;
181e20d96d6SChris Mason 		break;
182e20d96d6SChris Mason 	case S_IFLNK:
183e20d96d6SChris Mason 		// inode->i_op = &page_symlink_inode_operations;
184e20d96d6SChris Mason 		break;
185e20d96d6SChris Mason 	}
186e20d96d6SChris Mason 	return;
1872e635a27SChris Mason }
1882e635a27SChris Mason 
189e20d96d6SChris Mason static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
190e20d96d6SChris Mason 			      ino_t *ino)
191e20d96d6SChris Mason {
192e20d96d6SChris Mason 	const char *name = dentry->d_name.name;
193e20d96d6SChris Mason 	int namelen = dentry->d_name.len;
194e20d96d6SChris Mason 	struct btrfs_dir_item *di;
195e20d96d6SChris Mason 	struct btrfs_path path;
196e20d96d6SChris Mason 	struct btrfs_root *root = btrfs_sb(dir->i_sb);
197e20d96d6SChris Mason 	int ret;
198e20d96d6SChris Mason 
199e20d96d6SChris Mason 	btrfs_init_path(&path);
200e20d96d6SChris Mason 	ret = btrfs_lookup_dir_item(NULL, root, &path, dir->i_ino, name,
201e20d96d6SChris Mason 				    namelen, 0);
202*7f5c1516SChris Mason 	if (ret || !btrfs_match_dir_item_name(root, &path, name, namelen)) {
203e20d96d6SChris Mason 		*ino = 0;
204e20d96d6SChris Mason 		goto out;
205e20d96d6SChris Mason 	}
206e20d96d6SChris Mason 	di = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
207e20d96d6SChris Mason 			    struct btrfs_dir_item);
208e20d96d6SChris Mason 	*ino = btrfs_dir_objectid(di);
209e20d96d6SChris Mason out:
210e20d96d6SChris Mason 	btrfs_release_path(root, &path);
211e20d96d6SChris Mason 	return ret;
212e20d96d6SChris Mason }
213e20d96d6SChris Mason 
214e20d96d6SChris Mason static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
215e20d96d6SChris Mason 				   struct nameidata *nd)
216e20d96d6SChris Mason {
217e20d96d6SChris Mason 	struct inode * inode;
218e20d96d6SChris Mason 	ino_t ino;
219e20d96d6SChris Mason 	int ret;
220e20d96d6SChris Mason 
221e20d96d6SChris Mason 	if (dentry->d_name.len > BTRFS_NAME_LEN)
222e20d96d6SChris Mason 		return ERR_PTR(-ENAMETOOLONG);
223e20d96d6SChris Mason 
224e20d96d6SChris Mason 	ret = btrfs_inode_by_name(dir, dentry, &ino);
225e20d96d6SChris Mason 	if (ret < 0)
226e20d96d6SChris Mason 		return ERR_PTR(ret);
227e20d96d6SChris Mason 	inode = NULL;
228e20d96d6SChris Mason 	if (ino) {
229e20d96d6SChris Mason 		inode = iget(dir->i_sb, ino);
230e20d96d6SChris Mason 		if (!inode)
231e20d96d6SChris Mason 			return ERR_PTR(-EACCES);
232e20d96d6SChris Mason 	}
233e20d96d6SChris Mason 	return d_splice_alias(inode, dentry);
234e20d96d6SChris Mason }
235e20d96d6SChris Mason 
236e20d96d6SChris Mason static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
237e20d96d6SChris Mason {
238e20d96d6SChris Mason 	struct inode *inode = filp->f_path.dentry->d_inode;
239e20d96d6SChris Mason 	struct btrfs_root *root = btrfs_sb(inode->i_sb);
240e20d96d6SChris Mason 	struct btrfs_item *item;
241e20d96d6SChris Mason 	struct btrfs_dir_item *di;
242e20d96d6SChris Mason 	struct btrfs_key key;
243e20d96d6SChris Mason 	struct btrfs_path path;
244e20d96d6SChris Mason 	int ret;
245e20d96d6SChris Mason 	u32 nritems;
246e20d96d6SChris Mason 	struct btrfs_leaf *leaf;
247e20d96d6SChris Mason 	int slot;
248e20d96d6SChris Mason 	int advance;
249e20d96d6SChris Mason 	unsigned char d_type = DT_UNKNOWN;
250*7f5c1516SChris Mason 	int over = 0;
251e20d96d6SChris Mason 
252e20d96d6SChris Mason 	key.objectid = inode->i_ino;
253e20d96d6SChris Mason 	key.flags = 0;
254e20d96d6SChris Mason 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
255e20d96d6SChris Mason 	key.offset = filp->f_pos;
256e20d96d6SChris Mason 	btrfs_init_path(&path);
257e20d96d6SChris Mason 	ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
258e20d96d6SChris Mason 	if (ret < 0) {
259e20d96d6SChris Mason 		goto err;
260e20d96d6SChris Mason 	}
261*7f5c1516SChris Mason 	advance = 0;
262e20d96d6SChris Mason 	while(1) {
263e20d96d6SChris Mason 		leaf = btrfs_buffer_leaf(path.nodes[0]);
264e20d96d6SChris Mason 		nritems = btrfs_header_nritems(&leaf->header);
265e20d96d6SChris Mason 		slot = path.slots[0];
266e20d96d6SChris Mason 		if (advance) {
267e20d96d6SChris Mason 			if (slot == nritems -1) {
268e20d96d6SChris Mason 				ret = btrfs_next_leaf(root, &path);
269e20d96d6SChris Mason 				if (ret)
270e20d96d6SChris Mason 					break;
271e20d96d6SChris Mason 				leaf = btrfs_buffer_leaf(path.nodes[0]);
272e20d96d6SChris Mason 				nritems = btrfs_header_nritems(&leaf->header);
273e20d96d6SChris Mason 				slot = path.slots[0];
274e20d96d6SChris Mason 			} else {
275e20d96d6SChris Mason 				slot++;
276e20d96d6SChris Mason 				path.slots[0]++;
277e20d96d6SChris Mason 			}
278e20d96d6SChris Mason 		}
279e20d96d6SChris Mason 		advance = 1;
280e20d96d6SChris Mason 		item = leaf->items + slot;
281e20d96d6SChris Mason 		if (btrfs_disk_key_objectid(&item->key) != key.objectid)
282e20d96d6SChris Mason 			break;
283e20d96d6SChris Mason 		if (btrfs_disk_key_type(&item->key) != BTRFS_DIR_ITEM_KEY)
284e20d96d6SChris Mason 			continue;
285*7f5c1516SChris Mason 		if (btrfs_disk_key_offset(&item->key) < filp->f_pos)
286*7f5c1516SChris Mason 			continue;
287e20d96d6SChris Mason 		di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
288e20d96d6SChris Mason 		over = filldir(dirent, (const char *)(di + 1),
289e20d96d6SChris Mason 			       btrfs_dir_name_len(di),
290e20d96d6SChris Mason 			       btrfs_disk_key_offset(&item->key),
291e20d96d6SChris Mason 			       btrfs_dir_objectid(di), d_type);
292*7f5c1516SChris Mason 		if (over) {
293*7f5c1516SChris Mason 			filp->f_pos = btrfs_disk_key_offset(&item->key);
294e20d96d6SChris Mason 			break;
295*7f5c1516SChris Mason 		}
296e20d96d6SChris Mason 		filp->f_pos = btrfs_disk_key_offset(&item->key) + 1;
297e20d96d6SChris Mason 	}
298e20d96d6SChris Mason 	ret = 0;
299e20d96d6SChris Mason err:
300e20d96d6SChris Mason 	btrfs_release_path(root, &path);
301e20d96d6SChris Mason 	return ret;
302e20d96d6SChris Mason }
303e20d96d6SChris Mason 
304e20d96d6SChris Mason static void btrfs_put_super (struct super_block * sb)
305e20d96d6SChris Mason {
306e20d96d6SChris Mason 	struct btrfs_root *root = btrfs_sb(sb);
307e20d96d6SChris Mason 	int ret;
308e20d96d6SChris Mason 
309e20d96d6SChris Mason 	ret = close_ctree(root);
310e20d96d6SChris Mason 	if (ret) {
311e20d96d6SChris Mason 		printk("close ctree returns %d\n", ret);
312e20d96d6SChris Mason 	}
313e20d96d6SChris Mason 	sb->s_fs_info = NULL;
314e20d96d6SChris Mason }
3152e635a27SChris Mason 
3162e635a27SChris Mason static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
3172e635a27SChris Mason {
3182e635a27SChris Mason 	struct inode * inode;
319e20d96d6SChris Mason 	struct dentry * root_dentry;
320e20d96d6SChris Mason 	struct btrfs_super_block *disk_super;
321e20d96d6SChris Mason 	struct buffer_head *bh;
322e20d96d6SChris Mason 	struct btrfs_root *root;
3232e635a27SChris Mason 
3242e635a27SChris Mason 	sb->s_maxbytes = MAX_LFS_FILESIZE;
3252e635a27SChris Mason 	sb->s_blocksize = PAGE_CACHE_SIZE;
3262e635a27SChris Mason 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
3272e635a27SChris Mason 	sb->s_magic = BTRFS_SUPER_MAGIC;
328e20d96d6SChris Mason 	sb->s_op = &btrfs_super_ops;
3292e635a27SChris Mason 	sb->s_time_gran = 1;
330e20d96d6SChris Mason 
331e20d96d6SChris Mason 	bh = sb_bread(sb, BTRFS_SUPER_INFO_OFFSET / sb->s_blocksize);
332e20d96d6SChris Mason 	if (!bh) {
333e20d96d6SChris Mason 		printk("btrfs: unable to read on disk super\n");
334e20d96d6SChris Mason 		return -EIO;
335e20d96d6SChris Mason 	}
336e20d96d6SChris Mason 	disk_super = (struct btrfs_super_block *)bh->b_data;
337e20d96d6SChris Mason 	root = open_ctree(sb, bh, disk_super);
338e20d96d6SChris Mason 	sb->s_fs_info = root;
339e20d96d6SChris Mason 	if (!root) {
340e20d96d6SChris Mason 		printk("btrfs: open_ctree failed\n");
341e20d96d6SChris Mason 		return -EIO;
342e20d96d6SChris Mason 	}
343e20d96d6SChris Mason 	printk("read in super total blocks %Lu root %Lu\n",
344e20d96d6SChris Mason 	       btrfs_super_total_blocks(disk_super),
345e20d96d6SChris Mason 	       btrfs_super_root_dir(disk_super));
346e20d96d6SChris Mason 
347e20d96d6SChris Mason 	inode = iget_locked(sb, btrfs_super_root_dir(disk_super));
3482e635a27SChris Mason 	if (!inode)
3492e635a27SChris Mason 		return -ENOMEM;
350e20d96d6SChris Mason 	if (inode->i_state & I_NEW) {
351e20d96d6SChris Mason 		btrfs_read_locked_inode(inode);
352e20d96d6SChris Mason 		unlock_new_inode(inode);
353e20d96d6SChris Mason 	}
3542e635a27SChris Mason 
355e20d96d6SChris Mason 	root_dentry = d_alloc_root(inode);
356e20d96d6SChris Mason 	if (!root_dentry) {
3572e635a27SChris Mason 		iput(inode);
3582e635a27SChris Mason 		return -ENOMEM;
3592e635a27SChris Mason 	}
360e20d96d6SChris Mason 	sb->s_root = root_dentry;
361e20d96d6SChris Mason 
3622e635a27SChris Mason 	return 0;
3632e635a27SChris Mason }
3642e635a27SChris Mason 
365d5719762SChris Mason static void fill_inode_item(struct btrfs_inode_item *item,
366d5719762SChris Mason 			    struct inode *inode)
367d5719762SChris Mason {
368d5719762SChris Mason 	btrfs_set_inode_uid(item, inode->i_uid);
369d5719762SChris Mason 	btrfs_set_inode_gid(item, inode->i_gid);
370d5719762SChris Mason 	btrfs_set_inode_size(item, inode->i_size);
371d5719762SChris Mason 	btrfs_set_inode_mode(item, inode->i_mode);
372d5719762SChris Mason 	btrfs_set_inode_nlink(item, inode->i_nlink);
373d5719762SChris Mason 	btrfs_set_timespec_sec(&item->atime, inode->i_atime.tv_sec);
374d5719762SChris Mason 	btrfs_set_timespec_nsec(&item->atime, inode->i_atime.tv_nsec);
375d5719762SChris Mason 	btrfs_set_timespec_sec(&item->mtime, inode->i_mtime.tv_sec);
376d5719762SChris Mason 	btrfs_set_timespec_nsec(&item->mtime, inode->i_mtime.tv_nsec);
377d5719762SChris Mason 	btrfs_set_timespec_sec(&item->ctime, inode->i_ctime.tv_sec);
378d5719762SChris Mason 	btrfs_set_timespec_nsec(&item->ctime, inode->i_ctime.tv_nsec);
379d5719762SChris Mason 	btrfs_set_inode_nblocks(item, inode->i_blocks);
380d5719762SChris Mason 	btrfs_set_inode_generation(item, inode->i_generation);
381d5719762SChris Mason }
382d5719762SChris Mason 
383d5719762SChris Mason static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
384d5719762SChris Mason 				     struct inode *dir, int mode)
385d5719762SChris Mason {
386d5719762SChris Mason 	struct inode *inode;
387d5719762SChris Mason 	struct btrfs_inode_item inode_item;
388d5719762SChris Mason 	struct btrfs_root *root = btrfs_sb(dir->i_sb);
389d5719762SChris Mason 	struct btrfs_key key;
390d5719762SChris Mason 	int ret;
391d5719762SChris Mason 	u64 objectid;
392d5719762SChris Mason 
393d5719762SChris Mason 	inode = new_inode(dir->i_sb);
394d5719762SChris Mason 	if (!inode)
395d5719762SChris Mason 		return ERR_PTR(-ENOMEM);
396d5719762SChris Mason 
397d5719762SChris Mason 	ret = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
398d5719762SChris Mason 	BUG_ON(ret);
399d5719762SChris Mason 
400d5719762SChris Mason 	inode->i_uid = current->fsuid;
401d5719762SChris Mason 	inode->i_gid = current->fsgid;
402d5719762SChris Mason 	inode->i_mode = mode;
403d5719762SChris Mason 	inode->i_ino = objectid;
404d5719762SChris Mason 	inode->i_blocks = 0;
405d5719762SChris Mason 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
406d5719762SChris Mason 	fill_inode_item(&inode_item, inode);
407d5719762SChris Mason 
408d5719762SChris Mason 
409d5719762SChris Mason 	key.objectid = objectid;
410d5719762SChris Mason 	key.flags = 0;
411d5719762SChris Mason 	key.offset = 0;
412d5719762SChris Mason 	btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
413d5719762SChris Mason 	ret = btrfs_insert_inode_map(trans, root, objectid, &key);
414d5719762SChris Mason 	BUG_ON(ret);
415d5719762SChris Mason 
416d5719762SChris Mason 	ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
417d5719762SChris Mason 	BUG_ON(ret);
418d5719762SChris Mason 
419d5719762SChris Mason 	insert_inode_hash(inode);
420d5719762SChris Mason 	// FIXME mark_inode_dirty(inode)
421d5719762SChris Mason 	return inode;
422d5719762SChris Mason }
423d5719762SChris Mason 
424d5719762SChris Mason static int btrfs_add_link(struct btrfs_trans_handle *trans,
425d5719762SChris Mason 			    struct dentry *dentry, struct inode *inode)
426d5719762SChris Mason {
427d5719762SChris Mason 	int ret;
428d5719762SChris Mason 	ret = btrfs_insert_dir_item(trans, btrfs_sb(inode->i_sb),
429d5719762SChris Mason 				    dentry->d_name.name, dentry->d_name.len,
430d5719762SChris Mason 				    dentry->d_parent->d_inode->i_ino,
431d5719762SChris Mason 				    inode->i_ino, 0);
432d5719762SChris Mason 	return ret;
433d5719762SChris Mason }
434d5719762SChris Mason 
435d5719762SChris Mason static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
436d5719762SChris Mason 			    struct dentry *dentry, struct inode *inode)
437d5719762SChris Mason {
438d5719762SChris Mason 	int err = btrfs_add_link(trans, dentry, inode);
439d5719762SChris Mason 	if (!err) {
440d5719762SChris Mason 		d_instantiate(dentry, inode);
441d5719762SChris Mason 		return 0;
442d5719762SChris Mason 	}
443d5719762SChris Mason 	inode_dec_link_count(inode);
444d5719762SChris Mason 	iput(inode);
445d5719762SChris Mason 	return err;
446d5719762SChris Mason }
447d5719762SChris Mason 
448d5719762SChris Mason static int btrfs_create(struct inode *dir, struct dentry *dentry,
449d5719762SChris Mason 			int mode, struct nameidata *nd)
450d5719762SChris Mason {
451d5719762SChris Mason 	struct btrfs_trans_handle *trans;
452d5719762SChris Mason 	struct btrfs_root *root = btrfs_sb(dir->i_sb);
453d5719762SChris Mason 	struct inode *inode;
454d5719762SChris Mason 	int err;
455d5719762SChris Mason 
456d5719762SChris Mason 	trans = btrfs_start_transaction(root, 1);
457d5719762SChris Mason 	inode = btrfs_new_inode(trans, dir, mode);
458d5719762SChris Mason 	err = PTR_ERR(inode);
459d5719762SChris Mason 	if (IS_ERR(inode))
460d5719762SChris Mason 		return err;
461d5719762SChris Mason 	// FIXME mark the inode dirty
462d5719762SChris Mason 	err = btrfs_add_nondir(trans, dentry, inode);
463d5719762SChris Mason 	dir->i_sb->s_dirt = 1;
464d5719762SChris Mason 	btrfs_end_transaction(trans, root);
465d5719762SChris Mason 	return err;
466d5719762SChris Mason }
467d5719762SChris Mason 
468d5719762SChris Mason static void btrfs_write_super(struct super_block *sb)
469d5719762SChris Mason {
470d5719762SChris Mason 	sb->s_dirt = 0;
471d5719762SChris Mason printk("btrfs write_super!\n");
472*7f5c1516SChris Mason 	filemap_flush(sb->s_bdev->bd_inode->i_mapping);
473d5719762SChris Mason }
474d5719762SChris Mason 
475d5719762SChris Mason static int btrfs_sync_fs(struct super_block *sb, int wait)
476d5719762SChris Mason {
477d5719762SChris Mason 	struct btrfs_trans_handle *trans;
478d5719762SChris Mason 	struct btrfs_root *root;
479d5719762SChris Mason 	int ret;
480df2ce34cSChris Mason 
481d5719762SChris Mason 	sb->s_dirt = 0;
482df2ce34cSChris Mason 	return 0;
483df2ce34cSChris Mason 
484d5719762SChris Mason 	root = btrfs_sb(sb);
485d5719762SChris Mason 	trans = btrfs_start_transaction(root, 1);
486d5719762SChris Mason 	ret = btrfs_commit_transaction(trans, root);
487d5719762SChris Mason 	sb->s_dirt = 0;
488d5719762SChris Mason 	BUG_ON(ret);
489d5719762SChris Mason printk("btrfs sync_fs\n");
490d5719762SChris Mason 	return 0;
491d5719762SChris Mason }
492d5719762SChris Mason 
4932e635a27SChris Mason static int btrfs_get_sb(struct file_system_type *fs_type,
4942e635a27SChris Mason 	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
4952e635a27SChris Mason {
4962e635a27SChris Mason 	return get_sb_bdev(fs_type, flags, dev_name, data,
4972e635a27SChris Mason 			   btrfs_fill_super, mnt);
4982e635a27SChris Mason }
4992e635a27SChris Mason 
5002e635a27SChris Mason static struct file_system_type btrfs_fs_type = {
5012e635a27SChris Mason 	.owner		= THIS_MODULE,
5022e635a27SChris Mason 	.name		= "btrfs",
5032e635a27SChris Mason 	.get_sb		= btrfs_get_sb,
5042e635a27SChris Mason 	.kill_sb	= kill_block_super,
5052e635a27SChris Mason 	.fs_flags	= FS_REQUIRES_DEV,
5062e635a27SChris Mason };
5072e635a27SChris Mason 
508e20d96d6SChris Mason static struct super_operations btrfs_super_ops = {
509e20d96d6SChris Mason 	.statfs		= simple_statfs,
510e20d96d6SChris Mason 	.drop_inode	= generic_delete_inode,
511e20d96d6SChris Mason 	.put_super	= btrfs_put_super,
512e20d96d6SChris Mason 	.read_inode	= btrfs_read_locked_inode,
513d5719762SChris Mason 	.write_super	= btrfs_write_super,
514d5719762SChris Mason 	.sync_fs	= btrfs_sync_fs,
515e20d96d6SChris Mason };
516e20d96d6SChris Mason 
517e20d96d6SChris Mason static struct inode_operations btrfs_dir_inode_operations = {
518e20d96d6SChris Mason 	.lookup		= btrfs_lookup,
519d5719762SChris Mason 	.create		= btrfs_create,
520e20d96d6SChris Mason };
521e20d96d6SChris Mason 
522e20d96d6SChris Mason static struct file_operations btrfs_dir_file_operations = {
523e20d96d6SChris Mason 	.llseek		= generic_file_llseek,
524e20d96d6SChris Mason 	.read		= generic_read_dir,
525e20d96d6SChris Mason 	.readdir	= btrfs_readdir,
526e20d96d6SChris Mason };
527e20d96d6SChris Mason 
528e20d96d6SChris Mason 
5292e635a27SChris Mason static int __init init_btrfs_fs(void)
5302e635a27SChris Mason {
5312e635a27SChris Mason 	printk("btrfs loaded!\n");
5322e635a27SChris Mason 	return register_filesystem(&btrfs_fs_type);
5332e635a27SChris Mason }
5342e635a27SChris Mason 
5352e635a27SChris Mason static void __exit exit_btrfs_fs(void)
5362e635a27SChris Mason {
5372e635a27SChris Mason 	unregister_filesystem(&btrfs_fs_type);
5382e635a27SChris Mason 	printk("btrfs unloaded\n");
5392e635a27SChris Mason }
5402e635a27SChris Mason 
5412e635a27SChris Mason module_init(init_btrfs_fs)
5422e635a27SChris Mason module_exit(exit_btrfs_fs)
5432e635a27SChris Mason 
5442e635a27SChris Mason MODULE_LICENSE("GPL");
545