Subject: afs/fs/afs proc.c,1.5,1.6 main.c,1.15,1.16 cell.h,1.7,1.8 cell.c,1.16,1.17

From: [email-masked]
Date: Mon, 19 Jan 2004 10:04:51 +0000

Update of /home/cvs/afs/fs/afs
In directory phoenix.infradead.org:/tmp/cvs-serv28491/fs/afs

Modified Files:
	proc.c main.c cell.h cell.c 
Log Message:
handle rootcell being set later if AFS fs compiled into kernel

Index: proc.c
===================================================================
RCS file: /home/cvs/afs/fs/afs/proc.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- proc.c	10 Sep 2003 13:32:37 -0000	1.5
+++ proc.c	19 Jan 2004 10:04:48 -0000	1.6
@@ -45,6 +45,21 @@
 	.release	= seq_release,
 };
 
+static int afs_proc_rootcell_open(struct inode *inode, struct file *file);
+static int afs_proc_rootcell_release(struct inode *inode, struct file *file);
+static ssize_t afs_proc_rootcell_read(struct file *file, char *buf,
+				      size_t size, loff_t *_pos);
+static ssize_t afs_proc_rootcell_write(struct file *file, const char *buf,
+				       size_t size, loff_t *_pos);
+
+static struct file_operations afs_proc_rootcell_fops = {
+	.open		= afs_proc_rootcell_open,
+	.read		= afs_proc_rootcell_read,
+	.write		= afs_proc_rootcell_write,
+	.llseek		= no_llseek,
+	.release	= afs_proc_rootcell_release
+};
+
 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
 static int afs_proc_cell_volumes_release(struct inode *inode,
 					 struct file *file);
@@ -136,9 +151,17 @@
 	p->proc_fops = &afs_proc_cells_fops;
 	p->owner = THIS_MODULE;
 
+	p = create_proc_entry("rootcell", 0, proc_afs);
+	if (!p)
+		goto error_cells;
+	p->proc_fops = &afs_proc_rootcell_fops;
+	p->owner = THIS_MODULE;
+
 	_leave(" = 0");
 	return 0;
 
+ error_cells:
+ 	remove_proc_entry("cells", proc_afs);
  error_proc:
 	remove_proc_entry("fs/afs", NULL);
  error:
@@ -253,7 +276,7 @@
 /*****************************************************************************/
 /*
  * handle writes to /proc/fs/afs/cells
- * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]*
+ * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
  */
 static ssize_t afs_proc_cells_write(struct file *file, const char *buf,
 				    size_t size, loff_t *_pos)
@@ -325,6 +348,70 @@
 	printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
 	goto done;
 } /* end afs_proc_cells_write() */
+
+/*****************************************************************************/
+/*
+ * Stubs for /proc/fs/afs/rootcell
+ */
+static int afs_proc_rootcell_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int afs_proc_rootcell_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t afs_proc_rootcell_read(struct file *file, char *buf,
+				      size_t size, loff_t *_pos)
+{
+	return 0;
+}
+
+/*****************************************************************************/
+/*
+ * handle writes to /proc/fs/afs/rootcell
+ * - to initialize rootcell: echo "cell.name:192.168.231.14"
+ */
+static ssize_t afs_proc_rootcell_write(struct file *file, const char *buf,
+				       size_t size, loff_t *_pos)
+{
+	char *kbuf, *s;
+	int ret;
+
+	/* start by dragging the command into memory */
+	if (size <= 1 || size >= PAGE_SIZE)
+		return -EINVAL;
+
+	ret = -ENOMEM;
+	kbuf = kmalloc(size + 1, GFP_KERNEL);
+	if (!kbuf)
+		goto nomem;
+
+	ret = -EFAULT;
+	if (copy_from_user(kbuf, buf, size) != 0)
+		goto infault;
+	kbuf[size] = 0;
+
+	/* trim to first NL */
+	s = memchr(kbuf, '\n', size);
+	if (s)
+		*s = 0;
+
+	/* determine command to perform */
+	_debug("rootcell=%s", kbuf);
+
+	ret = afs_cell_init(kbuf);
+	if (ret >= 0)
+		ret = size;	/* consume everything, always */
+
+ infault:
+	kfree(kbuf);
+ nomem:
+	_leave(" = %d", ret);
+	return ret;
+} /* end afs_proc_rootcell_write() */
 
 /*****************************************************************************/
 /*

Index: main.c
===================================================================
RCS file: /home/cvs/afs/fs/afs/main.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- main.c	10 Sep 2003 13:32:37 -0000	1.15
+++ main.c	19 Jan 2004 10:04:48 -0000	1.16
@@ -33,13 +33,24 @@
 static int afs_adding_peer(struct rxrpc_peer *peer);
 static void afs_discarding_peer(struct rxrpc_peer *peer);
 
-module_init(afs_init);
+/* XXX late_initcall is kludgy, but the only alternative seems to create
+ * a transport upon the first mount, which is worse. Or is it?
+ */
+/* module_init(afs_init); */
+late_initcall(afs_init);	/* must be called after net/ to create socket */
+
 module_exit(afs_exit);
 
 MODULE_DESCRIPTION("AFS Client File System");
 MODULE_AUTHOR("Red Hat, Inc.");
 MODULE_LICENSE("GPL");
 
+static char *rootcell;
+
+MODULE_PARM(rootcell, "s");
+MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
+
+
 static struct rxrpc_peer_ops afs_peer_ops = {
 	.adding		= afs_adding_peer,
 	.discarding	= afs_discarding_peer,
@@ -95,7 +106,7 @@
 #endif
 
 	/* initialise the cell DB */
-	ret = afs_cell_init();
+	ret = afs_cell_init(rootcell);
 	if (ret < 0)
 		goto error_keys;

Index: cell.h
===================================================================
RCS file: /home/cvs/afs/fs/afs/cell.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- cell.h	19 Aug 2003 13:37:08 -0000	1.7
+++ cell.h	19 Jan 2004 10:04:48 -0000	1.8
@@ -61,7 +61,7 @@
 	char			name[0];	/* cell name - must go last */
 };
 
-extern int afs_cell_init(void);
+extern int afs_cell_init(char *rootcell);
 
 extern int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell);

Index: cell.c
===================================================================
RCS file: /home/cvs/afs/fs/afs/cell.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- cell.c	24 Sep 2003 07:09:18 -0000	1.16
+++ cell.c	19 Jan 2004 10:04:48 -0000	1.17
@@ -31,11 +31,6 @@
 static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
 static struct afs_cell *afs_cell_root;
 
-static char *rootcell;
-
-MODULE_PARM(rootcell, "s");
-MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
-
 #ifdef AFS_CACHING_SUPPORT
 static cachefs_match_val_t afs_cell_cache_match(void *target,
 						const void *entry);
@@ -66,8 +61,6 @@
 
 	BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
 
-	down_write(&afs_cells_sem);
-
 	/* allocate and initialise a cell record */
 	cell = kmalloc(sizeof(struct afs_cell) + strlen(name) + 1, GFP_KERNEL);
 	if (!cell) {
@@ -75,6 +68,8 @@
 		return -ENOMEM;
 	}
 
+	down_write(&afs_cells_sem);
+
 	memset(cell, 0, sizeof(struct afs_cell));
 	atomic_set(&cell->usage, 0);
 
@@ -144,10 +139,11 @@
 	return 0;
 
  badaddr:
-	printk("kAFS: bad VL server IP address: '%s'\n", vllist);
+	printk(KERN_ERR "kAFS: bad VL server IP address: '%s'\n", vllist);
  error:
 	up_write(&afs_cells_sem);
 	kfree(cell);
+	_leave(" = %d", ret);
 	return ret;
 } /* end afs_cell_create() */
 
@@ -155,29 +151,52 @@
 /*
  * initialise the cell database from module parameters
  */
-int afs_cell_init(void)
+int afs_cell_init(char *rootcell)
 {
+	struct afs_cell *old_root, *new_root;
 	char *cp;
 	int ret;
 
 	_enter("");
 
 	if (!rootcell) {
-		printk("kAFS: no root cell specified\n");
-		return -EINVAL;
+		/* module is loaded with no parameters, or built statically.
+		 * - in the future we might initialize cell DB here.
+		 */
+		_leave(" = 0 (but no root)");
+		return 0;
 	}
 
 	cp = strchr(rootcell, ':');
 	if (!cp) {
-		printk("kAFS: no VL server IP addresses specified\n");
+		printk(KERN_ERR "kAFS: no VL server IP addresses specified\n");
+		_leave(" = %d (no colon)", -EINVAL);
 		return -EINVAL;
 	}
 
 	/* allocate a cell record for the root cell */
 	*cp++ = 0;
-	ret = afs_cell_create(rootcell, cp, &afs_cell_root);
-	if (ret == 0)
-		afs_get_cell(afs_cell_root);
+	ret = afs_cell_create(rootcell, cp, &new_root);
+	if (ret < 0) {
+		_leave(" = %d", ret);
+		return ret;
+	}
+
+	/* as afs_put_cell() takes locks by itself, we have to do
+	 * a little gymnastics to be race-free.
+	 */
+	afs_get_cell(new_root);
+
+	write_lock(&afs_cells_lock);
+	while (afs_cell_root) {
+		old_root = afs_cell_root;
+		afs_cell_root = NULL;
+		write_unlock(&afs_cells_lock);
+		afs_put_cell(old_root);
+		write_lock(&afs_cells_lock);
+	}
+	afs_cell_root = new_root;
+	write_unlock(&afs_cells_lock);
 
 	_leave(" = %d", ret);
 	return ret;
@@ -218,9 +237,24 @@
 			ret = 0;
 	}
 	else {
+		read_lock(&afs_cells_lock);
+
 		cell = afs_cell_root;
-		afs_get_cell(cell);
-		ret = 0;
+		if (!cell) {
+			/* this should not happen unless user tries to mount
+			 * when root cell is not set. Return an impossibly
+			 * bizzare errno to alert the user. Things like
+			 * ENOENT might be "more appropriate" but they happen
+			 * for other reasons.
+			 */
+			ret = -EDESTADDRREQ;
+		}
+		else {
+			afs_get_cell(cell);
+			ret = 0;
+		}
+
+		read_unlock(&afs_cells_lock);
 	}
 
 	*_cell = cell;
@@ -402,7 +436,7 @@
 
 /*****************************************************************************/
 /*
- * purge in-memory cell database on module unload
+ * purge in-memory cell database on module unload or afs_init() failure
  * - the timeout daemon is stopped before calling this
  */
 void afs_cell_purge(void)