4 * A snap shot file system.
7 #define DEBUG_SUBSYSTEM S_SNAP
9 #include <linux/kmod.h>
10 #include <linux/init.h>
12 #include <linux/slab.h>
13 #include <linux/string.h>
14 #include <linux/jbd.h>
15 #include <linux/ext3_fs.h>
16 #include <linux/snap.h>
18 #include "snapfs_internal.h"
21 static inline int inode_has_ea(struct inode *inode)
23 return (inode->u.ext2_i.i_file_acl != 0);
26 static int currentfs_readlink(struct dentry * dentry, char * buffer, int buflen)
28 struct snap_cache *cache;
30 struct inode_operations *iops;
31 struct inode * inode = dentry->d_inode;
32 int bpib = inode->i_sb->s_blocksize >> 9;
37 cache = snap_find_cache(inode->i_dev);
43 iops = filter_c2csiops(cache->cache_filter);
50 save_i_blocks = inode->i_blocks;
51 /* If this link has ea and its i_blocks is ea's block,
52 * then we should treate it as a fast symlink
54 if( inode_has_ea(inode) && inode->i_blocks == bpib ) {
57 rc = iops->readlink(dentry, buffer, buflen);
59 if( inode->i_blocks != save_i_blocks ){
60 inode->i_blocks = save_i_blocks;
61 mark_inode_dirty(inode);
69 static int cat_str_ahead(char *buf, int pos, const char* str)
71 int len = strlen(str);
73 if( pos - len -1 < 0 )
77 memcpy(&buf[pos-len], str, len);
82 * Adjust the following path if we are under dotsnap (skip .snap/clonexx...)
83 * in following two case, we just return null and let caller do
84 * the normal follow_link:
85 * (1) we are not lies in .snap
86 * (2) we are already in the root's .snap
88 static int dotsnap_follow_link(struct dentry *dentry,
91 struct super_block *sb = dentry->d_inode->i_sb;
92 struct dentry *de = dentry, *de_save1=NULL, *de_save2=NULL;
94 int pos = D_MAXLEN, rc;
96 SNAP_ALLOC(buf, D_MAXLEN);
101 * iterate upward to construct the path
105 pos = cat_str_ahead(buf, pos, de_save2->d_name.name);
107 if ( de->d_inode && de->d_inode->i_ino & 0xF0000000 )
113 } while (de->d_parent != de);
115 /* we are not under dotsnap */
119 /* See if we already under root's .snap */
121 if( de == sb->s_root )
124 while( (de->d_parent != de) && (de != sb->s_root) ){
125 pos = cat_str_ahead(buf, pos, de->d_name.name);
129 pos = cat_str_ahead(buf, pos, de_save1->d_name.name);
131 pos = cat_str_ahead(buf, pos, ".snap");
133 CDEBUG(D_SNAP, "constructed path: %s\n", &buf[pos]);
135 /* FIXME lookup_dentry will never return NULL ?? */
137 rc = lookup_dentry(&buf[pos], dget(sb->s_root), follow);
139 rc = ERR_PTR(-ENOENT);
140 CDEBUG(D_SNAP, "lookup_dentry return NULL~!@#$^&*\n");
143 if (path_init(&buf[pos], LOOKUP_FOLLOW, nd)) {
144 rc = path_walk(&buf[pos], nd);
150 SNAP_FREE(buf, D_MAXLEN);
154 static int currentfs_follow_link (struct dentry *dentry, struct nameidata *nd)
156 struct snap_cache *cache;
157 struct inode_operations *iops;
158 struct inode * inode = dentry->d_inode;
159 int bpib = inode->i_sb->s_blocksize >> 9;
164 cache = snap_find_cache(inode->i_dev);
169 iops = filter_c2csiops(cache->cache_filter);
171 !iops->follow_link) {
172 GOTO(exit, rc = -EINVAL);
175 if( currentfs_is_under_dotsnap(dentry) ){
176 rc = dotsnap_follow_link(dentry, nd);
181 save_i_blocks = inode->i_blocks;
182 /* If this link has ea and its i_blocks is ea's block,
183 * then we should treate it as a fast symlink
185 if( inode_has_ea(inode) && inode->i_blocks == bpib ) {
188 rc = iops->follow_link(dentry, nd);
190 if( inode->i_blocks != save_i_blocks ){
191 inode->i_blocks = save_i_blocks;
192 mark_inode_dirty(inode);
199 struct inode_operations currentfs_sym_iops = {
200 readlink: currentfs_readlink,
201 follow_link: currentfs_follow_link,
204 struct file_operations currentfs_sym_fops = {