History

vfs: split up name hashing in link_path_walk() into helper function

The code in link_path_walk() that finds out the length and the hash of the next path component is some of the hottest code in the kernel. And I have a version of it that does things at the full width of the CPU wordsize at a time, but that means that we *really* want to split it up into a separate helper function. So this re-organizes the code a bit and splits the hashing part into a helper function called "hash_name()". It returns the length of the pathname component, while at the same time computing and writing the hash to the appropriate location. The code generation is slightly changed by this patch, but generally for the better - and the added abstraction actually makes the code easier to read too. And the new interface is well suited for replacing just the "hash_name()" function with alternative implementations.

Linus Torvalds committed 14 years ago

Commit 200e9ef1 parent 5707c871 file · +34 −18Browse files

Unified · Split

fs/namei.c+34−18
@@ -1382,6 +1382,25 @@ unsigned int full_name_hash(const unsigned char *name, unsigned int len) · 1381 unmodified lines
13821382 return end_name_hash(hash);
13831383 }
13841384
1385+/*
1386+ * We know there's a real path component here of at least
1387+ * one character.
1388+ */
1389+static inline unsigned long hash_name(const char *name, unsigned int *hashp)
1390+{
1391+ unsigned long hash = init_name_hash();
1392+ unsigned long len = 0, c;
1393+
1394+ c = (unsigned char)*name;
1395+ do {
1396+ len++;
1397+ hash = partial_name_hash(c, hash);
1398+ c = (unsigned char)name[len];
1399+ } while (c && c != '/');
1400+ *hashp = end_name_hash(hash);
1401+ return len;
1402+}
1403+
13851404 /*
13861405 * Name resolution.
13871406 * This is the basic name resolution function, turning a pathname into
@@ -1402,31 +1421,22 @@ static int link_path_walk(const char *name, struct nameidata *nd) · 14 unmodified lines
14021421
14031422 /* At this point we know we have a real path component. */
14041423 for(;;) {
1405− unsigned long hash;
14061424 struct qstr this;
1407− unsigned int c;
1425+ long len;
14081426 int type;
14091427
14101428 err = may_lookup(nd);
14111429 if (err)
14121430 break;
14131431
1432+ len = hash_name(name, &this.hash);
14141433 this.name = name;
1415− c = *(const unsigned char *)name;
1416−
1417− hash = init_name_hash();
1418− do {
1419− name++;
1420− hash = partial_name_hash(c, hash);
1421− c = *(const unsigned char *)name;
1422− } while (c && (c != '/'));
1423− this.len = name - (const char *) this.name;
1424− this.hash = end_name_hash(hash);
1434+ this.len = len;
14251435
14261436 type = LAST_NORM;
1427− if (this.name[0] == '.') switch (this.len) {
1437+ if (name[0] == '.') switch (len) {
14281438 case 2:
1429− if (this.name[1] == '.') {
1439+ if (name[1] == '.') {
14301440 type = LAST_DOTDOT;
14311441 nd->flags |= LOOKUP_JUMPED;
14321442 }
@@ -1445,12 +1455,18 @@ static int link_path_walk(const char *name, struct nameidata *nd) · 12 unmodified lines
14451455 }
14461456 }
14471457
1448− /* remove trailing slashes? */
1449− if (!c)
1458+ if (!name[len])
14501459 goto last_component;
1451− while (*++name == '/');
1452− if (!*name)
1460+ /*
1461+ * If it wasn't NUL, we know it was '/'. Skip that
1462+ * slash, and continue until no more slashes.
1463+ */
1464+ do {
1465+ len++;
1466+ } while (unlikely(name[len] == '/'));
1467+ if (!name[len])
14531468 goto last_component;
1469+ name += len;
14541470
14551471 err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);
14561472 if (err < 0)