xref: /openbmc/linux/fs/btrfs/super.c (revision df2ce34c)
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);
202e20d96d6SChris Mason 	if (ret) {
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;
250e20d96d6SChris Mason 	int over;
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 	}
261e20d96d6SChris Mason 	advance = filp->f_pos > 0 && ret != 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;
285e20d96d6SChris Mason 		di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
286e20d96d6SChris Mason 		over = filldir(dirent, (const char *)(di + 1),
287e20d96d6SChris Mason 			       btrfs_dir_name_len(di),
288e20d96d6SChris Mason 			       btrfs_disk_key_offset(&item->key),
289e20d96d6SChris Mason 			       btrfs_dir_objectid(di), d_type);
290e20d96d6SChris Mason 		if (over)
291e20d96d6SChris Mason 			break;
292e20d96d6SChris Mason 		filp->f_pos = btrfs_disk_key_offset(&item->key) + 1;
293e20d96d6SChris Mason 	}
294e20d96d6SChris Mason 	ret = 0;
295e20d96d6SChris Mason err:
296e20d96d6SChris Mason 	btrfs_release_path(root, &path);
297e20d96d6SChris Mason 	return ret;
298e20d96d6SChris Mason }
299e20d96d6SChris Mason 
300e20d96d6SChris Mason static void btrfs_put_super (struct super_block * sb)
301e20d96d6SChris Mason {
302e20d96d6SChris Mason 	struct btrfs_root *root = btrfs_sb(sb);
303e20d96d6SChris Mason 	int ret;
304e20d96d6SChris Mason 
305e20d96d6SChris Mason 	ret = close_ctree(root);
306e20d96d6SChris Mason 	if (ret) {
307e20d96d6SChris Mason 		printk("close ctree returns %d\n", ret);
308e20d96d6SChris Mason 	}
309e20d96d6SChris Mason 	sb->s_fs_info = NULL;
310e20d96d6SChris Mason }
3112e635a27SChris Mason 
3122e635a27SChris Mason static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
3132e635a27SChris Mason {
3142e635a27SChris Mason 	struct inode * inode;
315e20d96d6SChris Mason 	struct dentry * root_dentry;
316e20d96d6SChris Mason 	struct btrfs_super_block *disk_super;
317e20d96d6SChris Mason 	struct buffer_head *bh;
318e20d96d6SChris Mason 	struct btrfs_root *root;
3192e635a27SChris Mason 
3202e635a27SChris Mason 	sb->s_maxbytes = MAX_LFS_FILESIZE;
3212e635a27SChris Mason 	sb->s_blocksize = PAGE_CACHE_SIZE;
3222e635a27SChris Mason 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
3232e635a27SChris Mason 	sb->s_magic = BTRFS_SUPER_MAGIC;
324e20d96d6SChris Mason 	sb->s_op = &btrfs_super_ops;
3252e635a27SChris Mason 	sb->s_time_gran = 1;
326e20d96d6SChris Mason 
327e20d96d6SChris Mason 	bh = sb_bread(sb, BTRFS_SUPER_INFO_OFFSET / sb->s_blocksize);
328e20d96d6SChris Mason 	if (!bh) {
329e20d96d6SChris Mason 		printk("btrfs: unable to read on disk super\n");
330e20d96d6SChris Mason 		return -EIO;
331e20d96d6SChris Mason 	}
332e20d96d6SChris Mason 	disk_super = (struct btrfs_super_block *)bh->b_data;
333e20d96d6SChris Mason 	root = open_ctree(sb, bh, disk_super);
334e20d96d6SChris Mason 	sb->s_fs_info = root;
335e20d96d6SChris Mason 	if (!root) {
336e20d96d6SChris Mason 		printk("btrfs: open_ctree failed\n");
337e20d96d6SChris Mason 		return -EIO;
338e20d96d6SChris Mason 	}
339e20d96d6SChris Mason 	printk("read in super total blocks %Lu root %Lu\n",
340e20d96d6SChris Mason 	       btrfs_super_total_blocks(disk_super),
341e20d96d6SChris Mason 	       btrfs_super_root_dir(disk_super));
342e20d96d6SChris Mason 
343e20d96d6SChris Mason 	inode = iget_locked(sb, btrfs_super_root_dir(disk_super));
3442e635a27SChris Mason 	if (!inode)
3452e635a27SChris Mason 		return -ENOMEM;
346e20d96d6SChris Mason 	if (inode->i_state & I_NEW) {
347e20d96d6SChris Mason 		btrfs_read_locked_inode(inode);
348e20d96d6SChris Mason 		unlock_new_inode(inode);
349e20d96d6SChris Mason 	}
3502e635a27SChris Mason 
351e20d96d6SChris Mason 	root_dentry = d_alloc_root(inode);
352e20d96d6SChris Mason 	if (!root_dentry) {
3532e635a27SChris Mason 		iput(inode);
3542e635a27SChris Mason 		return -ENOMEM;
3552e635a27SChris Mason 	}
356e20d96d6SChris Mason 	sb->s_root = root_dentry;
357e20d96d6SChris Mason 
3582e635a27SChris Mason 	return 0;
3592e635a27SChris Mason }
3602e635a27SChris Mason 
361d5719762SChris Mason static void fill_inode_item(struct btrfs_inode_item *item,
362d5719762SChris Mason 			    struct inode *inode)
363d5719762SChris Mason {
364d5719762SChris Mason 	btrfs_set_inode_uid(item, inode->i_uid);
365d5719762SChris Mason 	btrfs_set_inode_gid(item, inode->i_gid);
366d5719762SChris Mason 	btrfs_set_inode_size(item, inode->i_size);
367d5719762SChris Mason 	btrfs_set_inode_mode(item, inode->i_mode);
368d5719762SChris Mason 	btrfs_set_inode_nlink(item, inode->i_nlink);
369d5719762SChris Mason 	btrfs_set_timespec_sec(&item->atime, inode->i_atime.tv_sec);
370d5719762SChris Mason 	btrfs_set_timespec_nsec(&item->atime, inode->i_atime.tv_nsec);
371d5719762SChris Mason 	btrfs_set_timespec_sec(&item->mtime, inode->i_mtime.tv_sec);
372d5719762SChris Mason 	btrfs_set_timespec_nsec(&item->mtime, inode->i_mtime.tv_nsec);
373d5719762SChris Mason 	btrfs_set_timespec_sec(&item->ctime, inode->i_ctime.tv_sec);
374d5719762SChris Mason 	btrfs_set_timespec_nsec(&item->ctime, inode->i_ctime.tv_nsec);
375d5719762SChris Mason 	btrfs_set_inode_nblocks(item, inode->i_blocks);
376d5719762SChris Mason 	btrfs_set_inode_generation(item, inode->i_generation);
377d5719762SChris Mason }
378d5719762SChris Mason 
379d5719762SChris Mason static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
380d5719762SChris Mason 				     struct inode *dir, int mode)
381d5719762SChris Mason {
382d5719762SChris Mason 	struct inode *inode;
383d5719762SChris Mason 	struct btrfs_inode_item inode_item;
384d5719762SChris Mason 	struct btrfs_root *root = btrfs_sb(dir->i_sb);
385d5719762SChris Mason 	struct btrfs_key key;
386d5719762SChris Mason 	int ret;
387d5719762SChris Mason 	u64 objectid;
388d5719762SChris Mason 
389d5719762SChris Mason 	inode = new_inode(dir->i_sb);
390d5719762SChris Mason 	if (!inode)
391d5719762SChris Mason 		return ERR_PTR(-ENOMEM);
392d5719762SChris Mason 
393d5719762SChris Mason 	ret = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
394d5719762SChris Mason 	BUG_ON(ret);
395d5719762SChris Mason 
396d5719762SChris Mason 	inode->i_uid = current->fsuid;
397d5719762SChris Mason 	inode->i_gid = current->fsgid;
398d5719762SChris Mason 	inode->i_mode = mode;
399d5719762SChris Mason 	inode->i_ino = objectid;
400d5719762SChris Mason 	inode->i_blocks = 0;
401d5719762SChris Mason 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
402d5719762SChris Mason 	fill_inode_item(&inode_item, inode);
403d5719762SChris Mason 
404d5719762SChris Mason 
405d5719762SChris Mason 	key.objectid = objectid;
406d5719762SChris Mason 	key.flags = 0;
407d5719762SChris Mason 	key.offset = 0;
408d5719762SChris Mason 	btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
409d5719762SChris Mason 	ret = btrfs_insert_inode_map(trans, root, objectid, &key);
410d5719762SChris Mason 	BUG_ON(ret);
411d5719762SChris Mason 
412d5719762SChris Mason 	ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
413d5719762SChris Mason 	BUG_ON(ret);
414d5719762SChris Mason 
415d5719762SChris Mason 	insert_inode_hash(inode);
416d5719762SChris Mason 	// FIXME mark_inode_dirty(inode)
417d5719762SChris Mason 	return inode;
418d5719762SChris Mason }
419d5719762SChris Mason 
420d5719762SChris Mason static int btrfs_add_link(struct btrfs_trans_handle *trans,
421d5719762SChris Mason 			    struct dentry *dentry, struct inode *inode)
422d5719762SChris Mason {
423d5719762SChris Mason 	int ret;
424d5719762SChris Mason 	ret = btrfs_insert_dir_item(trans, btrfs_sb(inode->i_sb),
425d5719762SChris Mason 				    dentry->d_name.name, dentry->d_name.len,
426d5719762SChris Mason 				    dentry->d_parent->d_inode->i_ino,
427d5719762SChris Mason 				    inode->i_ino, 0);
428d5719762SChris Mason 	BUG_ON(ret);
429d5719762SChris Mason 	return ret;
430d5719762SChris Mason }
431d5719762SChris Mason 
432d5719762SChris Mason static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
433d5719762SChris Mason 			    struct dentry *dentry, struct inode *inode)
434d5719762SChris Mason {
435d5719762SChris Mason 	int err = btrfs_add_link(trans, dentry, inode);
436d5719762SChris Mason 	if (!err) {
437d5719762SChris Mason 		d_instantiate(dentry, inode);
438d5719762SChris Mason 		return 0;
439d5719762SChris Mason 	}
440d5719762SChris Mason 	inode_dec_link_count(inode);
441d5719762SChris Mason 	iput(inode);
442d5719762SChris Mason 	return err;
443d5719762SChris Mason }
444d5719762SChris Mason 
445d5719762SChris Mason static int btrfs_create(struct inode *dir, struct dentry *dentry,
446d5719762SChris Mason 			int mode, struct nameidata *nd)
447d5719762SChris Mason {
448d5719762SChris Mason 	struct btrfs_trans_handle *trans;
449d5719762SChris Mason 	struct btrfs_root *root = btrfs_sb(dir->i_sb);
450d5719762SChris Mason 	struct inode *inode;
451d5719762SChris Mason 	int err;
452d5719762SChris Mason 
453d5719762SChris Mason 	trans = btrfs_start_transaction(root, 1);
454d5719762SChris Mason 	inode = btrfs_new_inode(trans, dir, mode);
455d5719762SChris Mason 	err = PTR_ERR(inode);
456d5719762SChris Mason 	if (IS_ERR(inode))
457d5719762SChris Mason 		return err;
458d5719762SChris Mason 	// FIXME mark the inode dirty
459d5719762SChris Mason 	err = btrfs_add_nondir(trans, dentry, inode);
460d5719762SChris Mason 	dir->i_sb->s_dirt = 1;
461d5719762SChris Mason 	btrfs_end_transaction(trans, root);
462d5719762SChris Mason 	return err;
463d5719762SChris Mason }
464d5719762SChris Mason 
465d5719762SChris Mason static void btrfs_write_super(struct super_block *sb)
466d5719762SChris Mason {
467d5719762SChris Mason 	sb->s_dirt = 0;
468d5719762SChris Mason printk("btrfs write_super!\n");
469d5719762SChris Mason }
470d5719762SChris Mason 
471d5719762SChris Mason static int btrfs_sync_fs(struct super_block *sb, int wait)
472d5719762SChris Mason {
473d5719762SChris Mason 	struct btrfs_trans_handle *trans;
474d5719762SChris Mason 	struct btrfs_root *root;
475d5719762SChris Mason 	int ret;
476*df2ce34cSChris Mason 
477d5719762SChris Mason 	sb->s_dirt = 0;
478*df2ce34cSChris Mason 	return 0;
479*df2ce34cSChris Mason 
480d5719762SChris Mason 	root = btrfs_sb(sb);
481d5719762SChris Mason 	trans = btrfs_start_transaction(root, 1);
482d5719762SChris Mason 	ret = btrfs_commit_transaction(trans, root);
483d5719762SChris Mason 	sb->s_dirt = 0;
484d5719762SChris Mason 	BUG_ON(ret);
485d5719762SChris Mason printk("btrfs sync_fs\n");
486d5719762SChris Mason 	return 0;
487d5719762SChris Mason }
488d5719762SChris Mason 
4892e635a27SChris Mason static int btrfs_get_sb(struct file_system_type *fs_type,
4902e635a27SChris Mason 	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
4912e635a27SChris Mason {
4922e635a27SChris Mason 	return get_sb_bdev(fs_type, flags, dev_name, data,
4932e635a27SChris Mason 			   btrfs_fill_super, mnt);
4942e635a27SChris Mason }
4952e635a27SChris Mason 
4962e635a27SChris Mason static struct file_system_type btrfs_fs_type = {
4972e635a27SChris Mason 	.owner		= THIS_MODULE,
4982e635a27SChris Mason 	.name		= "btrfs",
4992e635a27SChris Mason 	.get_sb		= btrfs_get_sb,
5002e635a27SChris Mason 	.kill_sb	= kill_block_super,
5012e635a27SChris Mason 	.fs_flags	= FS_REQUIRES_DEV,
5022e635a27SChris Mason };
5032e635a27SChris Mason 
504e20d96d6SChris Mason static struct super_operations btrfs_super_ops = {
505e20d96d6SChris Mason 	.statfs		= simple_statfs,
506e20d96d6SChris Mason 	.drop_inode	= generic_delete_inode,
507e20d96d6SChris Mason 	.put_super	= btrfs_put_super,
508e20d96d6SChris Mason 	.read_inode	= btrfs_read_locked_inode,
509d5719762SChris Mason 	.write_super	= btrfs_write_super,
510d5719762SChris Mason 	.sync_fs	= btrfs_sync_fs,
511e20d96d6SChris Mason };
512e20d96d6SChris Mason 
513e20d96d6SChris Mason static struct inode_operations btrfs_dir_inode_operations = {
514e20d96d6SChris Mason 	.lookup		= btrfs_lookup,
515d5719762SChris Mason 	.create		= btrfs_create,
516e20d96d6SChris Mason };
517e20d96d6SChris Mason 
518e20d96d6SChris Mason static struct file_operations btrfs_dir_file_operations = {
519e20d96d6SChris Mason 	.llseek		= generic_file_llseek,
520e20d96d6SChris Mason 	.read		= generic_read_dir,
521e20d96d6SChris Mason 	.readdir	= btrfs_readdir,
522e20d96d6SChris Mason };
523e20d96d6SChris Mason 
524e20d96d6SChris Mason 
5252e635a27SChris Mason static int __init init_btrfs_fs(void)
5262e635a27SChris Mason {
5272e635a27SChris Mason 	printk("btrfs loaded!\n");
5282e635a27SChris Mason 	return register_filesystem(&btrfs_fs_type);
5292e635a27SChris Mason }
5302e635a27SChris Mason 
5312e635a27SChris Mason static void __exit exit_btrfs_fs(void)
5322e635a27SChris Mason {
5332e635a27SChris Mason 	unregister_filesystem(&btrfs_fs_type);
5342e635a27SChris Mason 	printk("btrfs unloaded\n");
5352e635a27SChris Mason }
5362e635a27SChris Mason 
5372e635a27SChris Mason module_init(init_btrfs_fs)
5382e635a27SChris Mason module_exit(exit_btrfs_fs)
5392e635a27SChris Mason 
5402e635a27SChris Mason MODULE_LICENSE("GPL");
541