1/* cnode related routines for the coda kernel code
2   (C) 1996 Peter Braam
3   */
4
5#include <linux/types.h>
6#include <linux/string.h>
7#include <linux/time.h>
8
9#include <linux/coda.h>
10#include <linux/coda_psdev.h>
11#include "coda_linux.h"
12
13static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
14{
15	return memcmp(fid1, fid2, sizeof(*fid1)) == 0;
16}
17
18static const struct inode_operations coda_symlink_inode_operations = {
19	.readlink	= generic_readlink,
20	.follow_link	= page_follow_link_light,
21	.put_link	= page_put_link,
22	.setattr	= coda_setattr,
23};
24
25/* cnode.c */
26static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
27{
28        coda_vattr_to_iattr(inode, attr);
29
30        if (S_ISREG(inode->i_mode)) {
31                inode->i_op = &coda_file_inode_operations;
32                inode->i_fop = &coda_file_operations;
33        } else if (S_ISDIR(inode->i_mode)) {
34                inode->i_op = &coda_dir_inode_operations;
35                inode->i_fop = &coda_dir_operations;
36        } else if (S_ISLNK(inode->i_mode)) {
37		inode->i_op = &coda_symlink_inode_operations;
38		inode->i_data.a_ops = &coda_symlink_aops;
39		inode->i_mapping = &inode->i_data;
40	} else
41                init_special_inode(inode, inode->i_mode, huge_decode_dev(attr->va_rdev));
42}
43
44static int coda_test_inode(struct inode *inode, void *data)
45{
46	struct CodaFid *fid = (struct CodaFid *)data;
47	struct coda_inode_info *cii = ITOC(inode);
48	return coda_fideq(&cii->c_fid, fid);
49}
50
51static int coda_set_inode(struct inode *inode, void *data)
52{
53	struct CodaFid *fid = (struct CodaFid *)data;
54	struct coda_inode_info *cii = ITOC(inode);
55	cii->c_fid = *fid;
56	return 0;
57}
58
59struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
60			 struct coda_vattr * attr)
61{
62	struct inode *inode;
63	struct coda_inode_info *cii;
64	unsigned long hash = coda_f2i(fid);
65
66	inode = iget5_locked(sb, hash, coda_test_inode, coda_set_inode, fid);
67
68	if (!inode)
69		return ERR_PTR(-ENOMEM);
70
71	if (inode->i_state & I_NEW) {
72		cii = ITOC(inode);
73		/* we still need to set i_ino for things like stat(2) */
74		inode->i_ino = hash;
75		/* inode is locked and unique, no need to grab cii->c_lock */
76		cii->c_mapcount = 0;
77		unlock_new_inode(inode);
78	}
79
80	/* always replace the attributes, type might have changed */
81	coda_fill_inode(inode, attr);
82	return inode;
83}
84
85/* this is effectively coda_iget:
86   - get attributes (might be cached)
87   - get the inode for the fid using vfs iget
88   - link the two up if this is needed
89   - fill in the attributes
90*/
91struct inode *coda_cnode_make(struct CodaFid *fid, struct super_block *sb)
92{
93        struct coda_vattr attr;
94	struct inode *inode;
95        int error;
96
97	/* We get inode numbers from Venus -- see venus source */
98	error = venus_getattr(sb, fid, &attr);
99	if (error)
100		return ERR_PTR(error);
101
102	inode = coda_iget(sb, fid, &attr);
103	if (IS_ERR(inode))
104		pr_warn("%s: coda_iget failed\n", __func__);
105	return inode;
106}
107
108
109/* Although we treat Coda file identifiers as immutable, there is one
110 * special case for files created during a disconnection where they may
111 * not be globally unique. When an identifier collision is detected we
112 * first try to flush the cached inode from the kernel and finally
113 * resort to renaming/rehashing in-place. Userspace remembers both old
114 * and new values of the identifier to handle any in-flight upcalls.
115 * The real solution is to use globally unique UUIDs as identifiers, but
116 * retrofitting the existing userspace code for this is non-trivial. */
117void coda_replace_fid(struct inode *inode, struct CodaFid *oldfid,
118		      struct CodaFid *newfid)
119{
120	struct coda_inode_info *cii = ITOC(inode);
121	unsigned long hash = coda_f2i(newfid);
122
123	BUG_ON(!coda_fideq(&cii->c_fid, oldfid));
124
125	/* replace fid and rehash inode */
126	/* XXX we probably need to hold some lock here! */
127	remove_inode_hash(inode);
128	cii->c_fid = *newfid;
129	inode->i_ino = hash;
130	__insert_inode_hash(inode, hash);
131}
132
133/* convert a fid to an inode. */
134struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
135{
136	struct inode *inode;
137	unsigned long hash = coda_f2i(fid);
138
139	if ( !sb ) {
140		pr_warn("%s: no sb!\n", __func__);
141		return NULL;
142	}
143
144	inode = ilookup5(sb, hash, coda_test_inode, fid);
145	if ( !inode )
146		return NULL;
147
148	/* we should never see newly created inodes because we intentionally
149	 * fail in the initialization callback */
150	BUG_ON(inode->i_state & I_NEW);
151
152	return inode;
153}
154
155/* the CONTROL inode is made without asking attributes from Venus */
156struct inode *coda_cnode_makectl(struct super_block *sb)
157{
158	struct inode *inode = new_inode(sb);
159	if (inode) {
160		inode->i_ino = CTL_INO;
161		inode->i_op = &coda_ioctl_inode_operations;
162		inode->i_fop = &coda_ioctl_operations;
163		inode->i_mode = 0444;
164		return inode;
165	}
166	return ERR_PTR(-ENOMEM);
167}
168
169