* [PATCH/WIP 03/11] t5403: avoid doing "git add foo/bar" where foo/.git exists
From: Nguyễn Thái Ngọc Duy @ 2011-10-24 6:36 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1319438176-7304-1-git-send-email-pclouds@gmail.com>
In this case, "foo" is considered a submodule and bar, if added,
belongs to foo/.git. "git add" should only allow "git add foo" in this
case, but it passes somehow.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
t/t5403-post-checkout-hook.sh | 17 ++++++++++-------
1 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh
index 1753ef2..3b3e2c1 100755
--- a/t/t5403-post-checkout-hook.sh
+++ b/t/t5403-post-checkout-hook.sh
@@ -16,10 +16,13 @@ test_expect_success setup '
git update-ref refs/heads/master $commit0 &&
git clone ./. clone1 &&
git clone ./. clone2 &&
- GIT_DIR=clone2/.git git branch new2 &&
- echo Data for commit1. >clone2/b &&
- GIT_DIR=clone2/.git git add clone2/b &&
- GIT_DIR=clone2/.git git commit -m new2
+ (
+ cd clone2 &&
+ git branch new2 &&
+ echo Data for commit1. >b &&
+ git add b &&
+ git commit -m new2
+ )
'
for clone in 1 2; do
@@ -48,7 +51,7 @@ test_expect_success 'post-checkout runs as expected ' '
'
test_expect_success 'post-checkout args are correct with git checkout -b ' '
- GIT_DIR=clone1/.git git checkout -b new1 &&
+ ( cd clone1 && git checkout -b new1 ) &&
old=$(awk "{print \$1}" clone1/.git/post-checkout.args) &&
new=$(awk "{print \$2}" clone1/.git/post-checkout.args) &&
flag=$(awk "{print \$3}" clone1/.git/post-checkout.args) &&
@@ -56,7 +59,7 @@ test_expect_success 'post-checkout args are correct with git checkout -b ' '
'
test_expect_success 'post-checkout receives the right args with HEAD changed ' '
- GIT_DIR=clone2/.git git checkout new2 &&
+ ( cd clone2 && git checkout new2 ) &&
old=$(awk "{print \$1}" clone2/.git/post-checkout.args) &&
new=$(awk "{print \$2}" clone2/.git/post-checkout.args) &&
flag=$(awk "{print \$3}" clone2/.git/post-checkout.args) &&
@@ -64,7 +67,7 @@ test_expect_success 'post-checkout receives the right args with HEAD changed ' '
'
test_expect_success 'post-checkout receives the right args when not switching branches ' '
- GIT_DIR=clone2/.git git checkout master b &&
+ ( cd clone2 && git checkout master b ) &&
old=$(awk "{print \$1}" clone2/.git/post-checkout.args) &&
new=$(awk "{print \$2}" clone2/.git/post-checkout.args) &&
flag=$(awk "{print \$3}" clone2/.git/post-checkout.args) &&
--
1.7.3.1.256.g2539c.dirty
^ permalink raw reply related
* [PATCH/WIP 04/11] tree-walk.c: do not leak internal structure in tree_entry_len()
From: Nguyễn Thái Ngọc Duy @ 2011-10-24 6:36 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1319438176-7304-1-git-send-email-pclouds@gmail.com>
tree_entry_len() does not simply take two random arguments and return
a tree length. The two pointers must point to a tree item structure,
or struct name_entry. Passing random pointers will return incorrect
value.
Force callers to pass struct name_entry instead of two pointers (with
hope that they don't manually construct struct name_entry themselves)
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin/grep.c | 2 +-
builtin/pack-objects.c | 2 +-
tree-diff.c | 6 +++---
tree-walk.c | 16 ++++++++--------
tree-walk.h | 6 +++---
tree.c | 2 +-
unpack-trees.c | 6 +++---
7 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/builtin/grep.c b/builtin/grep.c
index 7d0779f..2cd0612 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -547,7 +547,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
int old_baselen = base->len;
while (tree_entry(tree, &entry)) {
- int te_len = tree_entry_len(entry.path, entry.sha1);
+ int te_len = tree_entry_len(&entry);
if (match != 2) {
match = tree_entry_interesting(&entry, base, tn_len, pathspec);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 2b18de5..864154b 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -975,7 +975,7 @@ static void add_pbase_object(struct tree_desc *tree,
while (tree_entry(tree,&entry)) {
if (S_ISGITLINK(entry.mode))
continue;
- cmp = tree_entry_len(entry.path, entry.sha1) != cmplen ? 1 :
+ cmp = tree_entry_len(&entry) != cmplen ? 1 :
memcmp(name, entry.path, cmplen);
if (cmp > 0)
continue;
diff --git a/tree-diff.c b/tree-diff.c
index b3cc2e4..6782484 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -21,8 +21,8 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
sha1 = tree_entry_extract(t1, &path1, &mode1);
sha2 = tree_entry_extract(t2, &path2, &mode2);
- pathlen1 = tree_entry_len(path1, sha1);
- pathlen2 = tree_entry_len(path2, sha2);
+ pathlen1 = tree_entry_len(&t1->entry);
+ pathlen2 = tree_entry_len(&t2->entry);
cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);
if (cmp < 0) {
show_entry(opt, "-", t1, base);
@@ -85,7 +85,7 @@ static void show_entry(struct diff_options *opt, const char *prefix,
unsigned mode;
const char *path;
const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);
- int pathlen = tree_entry_len(path, sha1);
+ int pathlen = tree_entry_len(&desc->entry);
int old_baselen = base->len;
strbuf_add(base, path, pathlen);
diff --git a/tree-walk.c b/tree-walk.c
index 418107e..f5d19f9 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -116,7 +116,7 @@ void setup_traverse_info(struct traverse_info *info, const char *base)
char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
{
- int len = tree_entry_len(n->path, n->sha1);
+ int len = tree_entry_len(n);
int pathlen = info->pathlen;
path[pathlen + len] = 0;
@@ -126,7 +126,7 @@ char *make_traverse_path(char *path, const struct traverse_info *info, const str
break;
path[--pathlen] = '/';
n = &info->name;
- len = tree_entry_len(n->path, n->sha1);
+ len = tree_entry_len(n);
info = info->prev;
pathlen -= len;
}
@@ -253,7 +253,7 @@ static void extended_entry_extract(struct tree_desc_x *t,
* The caller wants "first" from this tree, or nothing.
*/
path = a->path;
- len = tree_entry_len(a->path, a->sha1);
+ len = tree_entry_len(a);
switch (check_entry_match(first, first_len, path, len)) {
case -1:
entry_clear(a);
@@ -271,7 +271,7 @@ static void extended_entry_extract(struct tree_desc_x *t,
while (probe.size) {
entry_extract(&probe, a);
path = a->path;
- len = tree_entry_len(a->path, a->sha1);
+ len = tree_entry_len(a);
switch (check_entry_match(first, first_len, path, len)) {
case -1:
entry_clear(a);
@@ -362,7 +362,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
e = entry + i;
if (!e->path)
continue;
- len = tree_entry_len(e->path, e->sha1);
+ len = tree_entry_len(e);
if (!first) {
first = e->path;
first_len = len;
@@ -381,7 +381,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
/* Cull the ones that are not the earliest */
if (!e->path)
continue;
- len = tree_entry_len(e->path, e->sha1);
+ len = tree_entry_len(e);
if (name_compare(e->path, len, first, first_len))
entry_clear(e);
}
@@ -434,8 +434,8 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
int entrylen, cmp;
sha1 = tree_entry_extract(t, &entry, mode);
+ entrylen = tree_entry_len(&t->entry);
update_tree_entry(t);
- entrylen = tree_entry_len(entry, sha1);
if (entrylen > namelen)
continue;
cmp = memcmp(name, entry, entrylen);
@@ -596,7 +596,7 @@ int tree_entry_interesting(const struct name_entry *entry,
ps->max_depth);
}
- pathlen = tree_entry_len(entry->path, entry->sha1);
+ pathlen = tree_entry_len(entry);
for (i = ps->nr - 1; i >= 0; i--) {
const struct pathspec_item *item = ps->items+i;
diff --git a/tree-walk.h b/tree-walk.h
index 0089581..884d01a 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -20,9 +20,9 @@ static inline const unsigned char *tree_entry_extract(struct tree_desc *desc, co
return desc->entry.sha1;
}
-static inline int tree_entry_len(const char *name, const unsigned char *sha1)
+static inline int tree_entry_len(const struct name_entry *ne)
{
- return (const char *)sha1 - name - 1;
+ return (const char *)ne->sha1 - ne->path - 1;
}
void update_tree_entry(struct tree_desc *);
@@ -58,7 +58,7 @@ extern void setup_traverse_info(struct traverse_info *info, const char *base);
static inline int traverse_path_len(const struct traverse_info *info, const struct name_entry *n)
{
- return info->pathlen + tree_entry_len(n->path, n->sha1);
+ return info->pathlen + tree_entry_len(n);
}
extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps);
diff --git a/tree.c b/tree.c
index 698ecf7..e622198 100644
--- a/tree.c
+++ b/tree.c
@@ -99,7 +99,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
else
continue;
- len = tree_entry_len(entry.path, entry.sha1);
+ len = tree_entry_len(&entry);
strbuf_add(base, entry.path, len);
strbuf_addch(base, '/');
retval = read_tree_1(lookup_tree(sha1),
diff --git a/unpack-trees.c b/unpack-trees.c
index 8282f5e..7c9ecf6 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -446,7 +446,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
newinfo.prev = info;
newinfo.pathspec = info->pathspec;
newinfo.name = *p;
- newinfo.pathlen += tree_entry_len(p->path, p->sha1) + 1;
+ newinfo.pathlen += tree_entry_len(p) + 1;
newinfo.conflicts |= df_conflicts;
for (i = 0; i < n; i++, dirmask >>= 1) {
@@ -495,7 +495,7 @@ static int do_compare_entry(const struct cache_entry *ce, const struct traverse_
ce_len -= pathlen;
ce_name = ce->name + pathlen;
- len = tree_entry_len(n->path, n->sha1);
+ len = tree_entry_len(n);
return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
}
@@ -626,7 +626,7 @@ static int find_cache_pos(struct traverse_info *info,
struct unpack_trees_options *o = info->data;
struct index_state *index = o->src_index;
int pfxlen = info->pathlen;
- int p_len = tree_entry_len(p->path, p->sha1);
+ int p_len = tree_entry_len(p);
for (pos = o->cache_bottom; pos < index->cache_nr; pos++) {
struct cache_entry *ce = index->cache[pos];
--
1.7.3.1.256.g2539c.dirty
^ permalink raw reply related
* [PATCH/WIP 05/11] symbolize return values of tree_entry_interesting()
From: Nguyễn Thái Ngọc Duy @ 2011-10-24 6:36 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1319438176-7304-1-git-send-email-pclouds@gmail.com>
This helps extending the value later on for "interesting, but cannot
decide if the entry truely matches yet" (ie. prefix matches)
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin/grep.c | 9 +++++----
list-objects.c | 9 +++++----
tree-diff.c | 13 +++++++------
tree-walk.c | 45 +++++++++++++++++++++------------------------
tree-walk.h | 12 +++++++++++-
tree.c | 9 +++++----
6 files changed, 54 insertions(+), 43 deletions(-)
diff --git a/builtin/grep.c b/builtin/grep.c
index 2cd0612..2fc51fa 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -542,18 +542,19 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
struct tree_desc *tree, struct strbuf *base, int tn_len)
{
- int hit = 0, match = 0;
+ int hit = 0;
+ enum interesting match = entry_not_interesting;
struct name_entry entry;
int old_baselen = base->len;
while (tree_entry(tree, &entry)) {
int te_len = tree_entry_len(&entry);
- if (match != 2) {
+ if (match != all_entries_interesting) {
match = tree_entry_interesting(&entry, base, tn_len, pathspec);
- if (match < 0)
+ if (match == all_entries_not_interesting)
break;
- if (match == 0)
+ if (match == entry_not_interesting)
continue;
}
diff --git a/list-objects.c b/list-objects.c
index 39d80c0..3dd4a96 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -71,7 +71,8 @@ static void process_tree(struct rev_info *revs,
struct tree_desc desc;
struct name_entry entry;
struct name_path me;
- int match = revs->diffopt.pathspec.nr == 0 ? 2 : 0;
+ enum interesting match = revs->diffopt.pathspec.nr == 0 ?
+ all_entries_interesting: entry_not_interesting;
int baselen = base->len;
if (!revs->tree_objects)
@@ -97,12 +98,12 @@ static void process_tree(struct rev_info *revs,
init_tree_desc(&desc, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
- if (match != 2) {
+ if (match != all_entries_interesting) {
match = tree_entry_interesting(&entry, base, 0,
&revs->diffopt.pathspec);
- if (match < 0)
+ if (match == all_entries_not_interesting)
break;
- if (match == 0)
+ if (match == entry_not_interesting)
continue;
}
diff --git a/tree-diff.c b/tree-diff.c
index 6782484..25cc981 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -64,14 +64,14 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
static void show_tree(struct diff_options *opt, const char *prefix,
struct tree_desc *desc, struct strbuf *base)
{
- int match = 0;
+ enum interesting match = entry_not_interesting;
for (; desc->size; update_tree_entry(desc)) {
- if (match != 2) {
+ if (match != all_entries_interesting) {
match = tree_entry_interesting(&desc->entry, base, 0,
&opt->pathspec);
- if (match < 0)
+ if (match == all_entries_not_interesting)
break;
- if (match == 0)
+ if (match == entry_not_interesting)
continue;
}
show_entry(opt, prefix, desc, base);
@@ -114,12 +114,13 @@ static void show_entry(struct diff_options *opt, const char *prefix,
}
static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
- struct diff_options *opt, int *match)
+ struct diff_options *opt,
+ enum interesting *match)
{
while (t->size) {
*match = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
if (*match) {
- if (*match < 0)
+ if (*match == all_entries_not_interesting)
t->size = 0;
break;
}
diff --git a/tree-walk.c b/tree-walk.c
index f5d19f9..fc03262 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -573,27 +573,23 @@ static int match_dir_prefix(const char *base,
*
* Pre-condition: either baselen == base_offset (i.e. empty path)
* or base[baselen-1] == '/' (i.e. with trailing slash).
- *
- * Return:
- * - 2 for "yes, and all subsequent entries will be"
- * - 1 for yes
- * - zero for no
- * - negative for "no, and no subsequent entries will be either"
*/
-int tree_entry_interesting(const struct name_entry *entry,
- struct strbuf *base, int base_offset,
- const struct pathspec *ps)
+enum interesting tree_entry_interesting(const struct name_entry *entry,
+ struct strbuf *base, int base_offset,
+ const struct pathspec *ps)
{
int i;
int pathlen, baselen = base->len - base_offset;
- int never_interesting = ps->has_wildcard ? 0 : -1;
+ int never_interesting = ps->has_wildcard ?
+ entry_not_interesting : all_entries_not_interesting;
if (!ps->nr) {
if (!ps->recursive || ps->max_depth == -1)
- return 2;
- return !!within_depth(base->buf + base_offset, baselen,
- !!S_ISDIR(entry->mode),
- ps->max_depth);
+ return all_entries_interesting;
+ return within_depth(base->buf + base_offset, baselen,
+ !!S_ISDIR(entry->mode),
+ ps->max_depth) ?
+ entry_interesting : entry_not_interesting;
}
pathlen = tree_entry_len(entry);
@@ -610,12 +606,13 @@ int tree_entry_interesting(const struct name_entry *entry,
goto match_wildcards;
if (!ps->recursive || ps->max_depth == -1)
- return 2;
+ return all_entries_interesting;
- return !!within_depth(base_str + matchlen + 1,
- baselen - matchlen - 1,
- !!S_ISDIR(entry->mode),
- ps->max_depth);
+ return within_depth(base_str + matchlen + 1,
+ baselen - matchlen - 1,
+ !!S_ISDIR(entry->mode),
+ ps->max_depth) ?
+ entry_interesting : entry_not_interesting;
}
/* Either there must be no base, or the base must match. */
@@ -623,18 +620,18 @@ int tree_entry_interesting(const struct name_entry *entry,
if (match_entry(entry, pathlen,
match + baselen, matchlen - baselen,
&never_interesting))
- return 1;
+ return entry_interesting;
if (ps->items[i].use_wildcard) {
if (!fnmatch(match + baselen, entry->path, 0))
- return 1;
+ return entry_interesting;
/*
* Match all directories. We'll try to
* match files later on.
*/
if (ps->recursive && S_ISDIR(entry->mode))
- return 1;
+ return entry_interesting;
}
continue;
@@ -653,7 +650,7 @@ match_wildcards:
if (!fnmatch(match, base->buf + base_offset, 0)) {
strbuf_setlen(base, base_offset + baselen);
- return 1;
+ return entry_interesting;
}
strbuf_setlen(base, base_offset + baselen);
@@ -662,7 +659,7 @@ match_wildcards:
* later on.
*/
if (ps->recursive && S_ISDIR(entry->mode))
- return 1;
+ return entry_interesting;
}
return never_interesting; /* No matches */
}
diff --git a/tree-walk.h b/tree-walk.h
index 884d01a..2bf0db9 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -61,6 +61,16 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru
return info->pathlen + tree_entry_len(n);
}
-extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps);
+/* in general, positive means "kind of interesting" */
+enum interesting {
+ all_entries_not_interesting = -1, /* no, and no subsequent entries will be either */
+ entry_not_interesting = 0,
+ entry_interesting = 1,
+ all_entries_interesting = 2 /* yes, and all subsequent entries will be */
+};
+
+extern enum interesting tree_entry_interesting(const struct name_entry *,
+ struct strbuf *, int,
+ const struct pathspec *ps);
#endif
diff --git a/tree.c b/tree.c
index e622198..676e9f7 100644
--- a/tree.c
+++ b/tree.c
@@ -52,7 +52,8 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
struct tree_desc desc;
struct name_entry entry;
unsigned char sha1[20];
- int len, retval = 0, oldlen = base->len;
+ int len, oldlen = base->len;
+ enum interesting retval = entry_not_interesting;
if (parse_tree(tree))
return -1;
@@ -60,11 +61,11 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
init_tree_desc(&desc, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
- if (retval != 2) {
+ if (retval != all_entries_interesting) {
retval = tree_entry_interesting(&entry, base, 0, pathspec);
- if (retval < 0)
+ if (retval == all_entries_not_interesting)
break;
- if (retval == 0)
+ if (retval == entry_not_interesting)
continue;
}
--
1.7.3.1.256.g2539c.dirty
^ permalink raw reply related
* [PATCH/WIP 06/11] read_directory_recursive: reduce one indentation level
From: Nguyễn Thái Ngọc Duy @ 2011-10-24 6:36 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1319438176-7304-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
dir.c | 50 +++++++++++++++++++++++++-------------------------
1 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/dir.c b/dir.c
index 6c0d782..0a78d00 100644
--- a/dir.c
+++ b/dir.c
@@ -968,34 +968,34 @@ static int read_directory_recursive(struct dir_struct *dir,
{
DIR *fdir = opendir(*base ? base : ".");
int contents = 0;
+ struct dirent *de;
+ char path[PATH_MAX + 1];
- if (fdir) {
- struct dirent *de;
- char path[PATH_MAX + 1];
- memcpy(path, base, baselen);
-
- while ((de = readdir(fdir)) != NULL) {
- int len;
- switch (treat_path(dir, de, path, sizeof(path),
- baselen, simplify, &len)) {
- case path_recurse:
- contents += read_directory_recursive
- (dir, path, len, 0, simplify);
- continue;
- case path_ignored:
- continue;
- case path_handled:
- break;
- }
- contents++;
- if (check_only)
- goto exit_early;
- else
- dir_add_name(dir, path, len);
+ if (!fdir)
+ return 0;
+
+ memcpy(path, base, baselen);
+
+ while ((de = readdir(fdir)) != NULL) {
+ int len;
+ switch (treat_path(dir, de, path, sizeof(path),
+ baselen, simplify, &len)) {
+ case path_recurse:
+ contents += read_directory_recursive(dir, path, len, 0, simplify);
+ continue;
+ case path_ignored:
+ continue;
+ case path_handled:
+ break;
}
-exit_early:
- closedir(fdir);
+ contents++;
+ if (check_only)
+ goto exit_early;
+ else
+ dir_add_name(dir, path, len);
}
+exit_early:
+ closedir(fdir);
return contents;
}
--
1.7.3.1.256.g2539c.dirty
^ permalink raw reply related
* [PATCH/WIP 07/11] tree_entry_interesting: make use of local pointer "item"
From: Nguyễn Thái Ngọc Duy @ 2011-10-24 6:36 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1319438176-7304-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
tree-walk.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tree-walk.c b/tree-walk.c
index fc03262..2d9d17a 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -622,7 +622,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
&never_interesting))
return entry_interesting;
- if (ps->items[i].use_wildcard) {
+ if (item->use_wildcard) {
if (!fnmatch(match + baselen, entry->path, 0))
return entry_interesting;
@@ -638,7 +638,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
}
match_wildcards:
- if (!ps->items[i].use_wildcard)
+ if (!item->use_wildcard)
continue;
/*
--
1.7.3.1.256.g2539c.dirty
^ permalink raw reply related
* Re: [PATCH meta-ti 0/3] Update linux-ti33x-psp and beaglebone-tester to latest, add EEPROM patches.
From: Koen Kooi @ 2011-10-24 6:39 UTC (permalink / raw)
To: Joel A Fernandes; +Cc: meta-ti, jdk
In-Reply-To: <1319428763-9677-1-git-send-email-joelagnel@ti.com>
Op 24 okt. 2011, om 05:59 heeft Joel A Fernandes het volgende geschreven:
> Please apply these 3 patches which apart from other things also fixes the kernel build and adds EEPROM support.
>
> All changes have been build and runtime tested.
>
> Thanks!
>
> Joel A Fernandes (3):
> sdcard_image: Copy uEnv.txt once again as the new bonetester also
> checks for GPIO grounding
> linux-ti33x-psp 3.1rc8: Update to latest SRCREV, add EEPROM patches
> beaglebone-tester: Update to latest and bump PR
I did the uEnv change a bit different, but in the end all the above changes are in.
regards,
Koen
^ permalink raw reply
* [PATCH/WIP 08/11] tree-walk: mark useful pathspecs
From: Nguyễn Thái Ngọc Duy @ 2011-10-24 6:36 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1319438176-7304-1-git-send-email-pclouds@gmail.com>
Useful pathspecs are those that help decide whether an item is in or
out, as opposed to useless ones whose existence does not change the
results.
Callers are responsible for cleaning before use, or doing anything
after.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
cache.h | 1 +
tree-walk.c | 13 ++++++++++---
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/cache.h b/cache.h
index be07ec7..946d910 100644
--- a/cache.h
+++ b/cache.h
@@ -532,6 +532,7 @@ struct pathspec {
const char *match;
int len;
unsigned int use_wildcard:1;
+ unsigned int useful:1;
} *items;
};
diff --git a/tree-walk.c b/tree-walk.c
index 2d9d17a..5e9c522 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -595,11 +595,15 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
pathlen = tree_entry_len(entry);
for (i = ps->nr - 1; i >= 0; i--) {
- const struct pathspec_item *item = ps->items+i;
+ struct pathspec_item *item = ps->items+i;
const char *match = item->match;
const char *base_str = base->buf + base_offset;
int matchlen = item->len;
+ /* assume it will be used (which usually means break
+ the loop and return), reset it otherwise */
+ item->useful = 1;
+
if (baselen >= matchlen) {
/* If it doesn't match, move along... */
if (!match_dir_prefix(base_str, match, matchlen))
@@ -634,12 +638,12 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
return entry_interesting;
}
- continue;
+ goto nouse;
}
match_wildcards:
if (!item->use_wildcard)
- continue;
+ goto nouse;
/*
* Concatenate base and entry->path into one and do
@@ -660,6 +664,9 @@ match_wildcards:
*/
if (ps->recursive && S_ISDIR(entry->mode))
return entry_interesting;
+
+nouse:
+ item->useful = 0;
}
return never_interesting; /* No matches */
}
--
1.7.3.1.256.g2539c.dirty
^ permalink raw reply related
* [PATCH/WIP 09/11] tree_entry_interesting: differentiate partial vs full match
From: Nguyễn Thái Ngọc Duy @ 2011-10-24 6:36 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1319438176-7304-1-git-send-email-pclouds@gmail.com>
Up until now, for a/b pathspec, both paths a and a/b would return
entry_interesting. Make it return entry_matched for the latter.
This way if the caller follows up to "a", but decide to stop for some
reason, then it knows that "a" has not really matched the given
pathspec yet.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
tree-walk.c | 13 ++++++++-----
tree-walk.h | 5 +++--
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/tree-walk.c b/tree-walk.c
index 5e9c522..6e12f0f 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -616,19 +616,22 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
baselen - matchlen - 1,
!!S_ISDIR(entry->mode),
ps->max_depth) ?
- entry_interesting : entry_not_interesting;
+ entry_matched : entry_not_interesting;
}
/* Either there must be no base, or the base must match. */
if (baselen == 0 || !strncmp(base_str, match, baselen)) {
if (match_entry(entry, pathlen,
match + baselen, matchlen - baselen,
- &never_interesting))
- return entry_interesting;
+ &never_interesting)) {
+ if (match[baselen + pathlen] == '/')
+ return entry_interesting;
+ return entry_matched;
+ }
if (item->use_wildcard) {
if (!fnmatch(match + baselen, entry->path, 0))
- return entry_interesting;
+ return entry_matched;
/*
* Match all directories. We'll try to
@@ -654,7 +657,7 @@ match_wildcards:
if (!fnmatch(match, base->buf + base_offset, 0)) {
strbuf_setlen(base, base_offset + baselen);
- return entry_interesting;
+ return entry_matched;
}
strbuf_setlen(base, base_offset + baselen);
diff --git a/tree-walk.h b/tree-walk.h
index 2bf0db9..a5f92fa 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -65,8 +65,9 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru
enum interesting {
all_entries_not_interesting = -1, /* no, and no subsequent entries will be either */
entry_not_interesting = 0,
- entry_interesting = 1,
- all_entries_interesting = 2 /* yes, and all subsequent entries will be */
+ entry_interesting = 1, /* a potential match, not not there yet */
+ entry_matched = 2,
+ all_entries_interesting = 3 /* yes, and all subsequent entries will be */
};
extern enum interesting tree_entry_interesting(const struct name_entry *,
--
1.7.3.1.256.g2539c.dirty
^ permalink raw reply related
* [PATCH/WIP 10/11] read-dir: stop using path_simplify code in favor of tree_entry_interesting()
From: Nguyễn Thái Ngọc Duy @ 2011-10-24 6:36 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1319438176-7304-1-git-send-email-pclouds@gmail.com>
Current code tries to find a prefix set of given pathspecs and filter
on the set. Call sites are supposed to do exact pathspec matching
again to remove unmatched entries (but matches the prefix set).
This patch makes read_directory() use tree_entry_interesting()
directly, thus remove the need to filter again by call sites (although
call sites are untouched in this patch).
A less intrusive way would be to use match_pathspec_depth(), but I'd
rather reduce the use of that function and eventually remove it, so we
only have to maintain pathspec matching at one place:
tree_entry_interesting().
In order to make use of tree_entry_interesting(), directory content
from readdir() must be converted to tree object format, which means we
have to read all items of a directory at once and sort it. If the
directory is large, it may become expensive operation. But again,
current code does nothing to stop reading directory early, so nothing
is lost.
ignored_nr and ignored[] are not longer filled. read_directory() users
are supposed to use useful[] instead.
Many functions are left unused in this patch to avoid clutter up the
patch. They will be removed later.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin/add.c | 22 +++--
dir.c | 317 ++++++++++++++++++++++++++++++++++++++-------------------
dir.h | 5 +
tree-walk.c | 2 +
4 files changed, 236 insertions(+), 110 deletions(-)
diff --git a/builtin/add.c b/builtin/add.c
index 23ad4b8..92ba3d4 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -307,7 +307,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
static struct lock_file lock_file;
static const char ignore_error[] =
-N_("The following paths are ignored by one of your .gitignore files:\n");
+N_("The following pathspecs are ignored by one of your .gitignore files:\n");
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
static int ignore_add_errors, addremove, intent_to_add;
@@ -342,12 +342,20 @@ static int add_files(struct dir_struct *dir, int flags)
{
int i, exit_status = 0;
- if (dir->ignored_nr) {
- fprintf(stderr, _(ignore_error));
- for (i = 0; i < dir->ignored_nr; i++)
- fprintf(stderr, "%s\n", dir->ignored[i]->name);
- fprintf(stderr, _("Use -f if you really want to add them.\n"));
- die(_("no files added"));
+ if (dir->useful) {
+ int show_header = 0;
+ for (i = 0; i < dir->ps2.nr; i++)
+ if (!dir->useful[i]) {
+ if (!show_header) {
+ fprintf(stderr, _(ignore_error));
+ show_header = 1;
+ }
+ fprintf(stderr, "%s\n", dir->ps2.items[i].match);
+ }
+ if (show_header) {
+ fprintf(stderr, _("Use -f if you really want to add them.\n"));
+ die(_("no files added"));
+ }
}
for (i = 0; i < dir->nr; i++)
diff --git a/dir.c b/dir.c
index 0a78d00..2946b2d 100644
--- a/dir.c
+++ b/dir.c
@@ -8,14 +8,18 @@
#include "cache.h"
#include "dir.h"
#include "refs.h"
+#include "tree-walk.h"
+#include "string-list.h"
struct path_simplify {
int len;
const char *path;
};
-static int read_directory_recursive(struct dir_struct *dir, const char *path, int len,
- int check_only, const struct path_simplify *simplify);
+static int read_directory_recursive(struct dir_struct *dir,
+ struct strbuf *base,
+ int check_only,
+ enum interesting match);
static int get_dtype(struct dirent *de, const char *path, int len);
/* helper string functions with support for the ignore_case flag */
@@ -609,6 +613,93 @@ struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname,
return dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len);
}
+/* Read and convert directory to tree object (with invalid SHA-1) */
+static void* dir_to_tree(struct strbuf *path, unsigned long *size)
+{
+ int pathlen = path->len;
+ DIR *fdir = opendir(pathlen ? path->buf : ".");
+ struct string_list paths = STRING_LIST_INIT_DUP;
+ struct dirent *de;
+ char *tree, *p;
+ int i,dtype;
+
+ if (!fdir)
+ return NULL;
+
+ *size = 0;
+ while ((de = readdir(fdir)) != NULL) {
+ int namelen = strlen(de->d_name);
+ struct string_list_item *item;
+ const char *mode = NULL;
+
+ if (is_dot_or_dotdot(de->d_name) ||
+ !strcmp(de->d_name, ".git") ||
+ /* Ignore overly long pathnames! */
+ namelen + pathlen + 8 > PATH_MAX)
+ continue;
+
+ strbuf_add(path, de->d_name, namelen);
+ dtype = get_dtype(de, path->buf, path->len);
+ strbuf_setlen(path, pathlen);
+
+ switch (dtype) {
+ case DT_DIR: mode = "040000 "; break;
+ case DT_REG: mode = "100644 "; break;
+ case DT_LNK: mode = "120000 "; break;
+ default: continue;
+ }
+ item = string_list_insert(&paths, de->d_name);
+ item->util = (void*)mode;
+ /* 100644 SPC path NUL SHA-1 */
+ *size += 6 + 1 + namelen + 1 + 20;
+ }
+ closedir(fdir);
+
+ tree = xmalloc(*size);
+ for (i = 0, p = tree;i < paths.nr; i++) {
+ int len = strlen(paths.items[i].string) + 1;
+ if (!paths.items[i].util ||
+ strlen(paths.items[i].util) != 7)
+ die("BUG: util should contain a mode");
+ memcpy(p, paths.items[i].util, 7);
+ p += 7;
+ memcpy(p, paths.items[i].string, len);
+ p += len;
+ /* we don't need valid SHA-1 for tree_entry_interesting() */
+ memcpy(p, "\xbb\xaa\xdd\xbb\xaa\xdd\xbb\xaa\xdd", 9);
+ p += 20;
+ }
+ string_list_clear(&paths, 0);
+ return tree;
+}
+
+static enum interesting match_both_pathspecs(struct dir_struct *dir,
+ struct strbuf *base,
+ const struct name_entry *ne)
+{
+ int i;
+ enum interesting ret1, ret2;
+
+ /* ps1 contains the base path, no need to care about it */
+ for (i = 0; i < dir->ps2.nr; i++)
+ dir->ps2.items[i].useful = 0;
+
+ ret1 = tree_entry_interesting(ne, base, 0, &dir->ps1);
+ if (ret1 <= 0)
+ return ret1;
+ ret2 = tree_entry_interesting(ne, base, 0, &dir->ps2);
+ if (ret2 <= 0)
+ return ret2;
+
+ if (ret1 == all_entries_interesting && ret2 == all_entries_interesting)
+ return all_entries_interesting;
+ else if ((ret1 == entry_matched || ret1 == all_entries_interesting) &&
+ (ret2 == entry_matched || ret2 == all_entries_interesting))
+ return entry_matched;
+ else
+ return entry_interesting;
+}
+
enum exist_status {
index_nonexistent = 0,
index_directory,
@@ -722,11 +813,10 @@ enum directory_treatment {
};
static enum directory_treatment treat_directory(struct dir_struct *dir,
- const char *dirname, int len,
- const struct path_simplify *simplify)
+ struct strbuf *dirname)
{
/* The "len-1" is to strip the final '/' */
- switch (directory_exists_in_index(dirname, len-1)) {
+ switch (directory_exists_in_index(dirname->buf, dirname->len-1)) {
case index_directory:
return recurse_into_directory;
@@ -740,7 +830,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
break;
if (!(dir->flags & DIR_NO_GITLINKS)) {
unsigned char sha1[20];
- if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)
+ if (resolve_gitlink_ref(dirname->buf, "HEAD", sha1) == 0)
return show_directory;
}
return recurse_into_directory;
@@ -749,7 +839,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
/* This is the "show_other_directories" case */
if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
return show_directory;
- if (!read_directory_recursive(dir, dirname, len, 1, simplify))
+ if (!read_directory_recursive(dir, dirname, 1, entry_not_interesting))
return ignore_directory;
return show_directory;
}
@@ -780,31 +870,35 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli
}
/*
- * This function tells us whether an excluded path matches a
- * list of "interesting" pathspecs. That is, whether a path matched
- * by any of the pathspecs could possibly be ignored by excluding
- * the specified path. This can happen if:
+ * This function flags pathspecs that are completely excluded, which
+ * usually means an input mistake. In other words, if all matched
+ * _files_ of a pathspec are excluded, flag the pathspec.
*
- * 1. the path is mentioned explicitly in the pathspec
+ * The negated version would be: if any of matched files (by pathspec
+ * X) are not excluded, pathspec X is clear, which is exactly what
+ * this function does.
*
- * 2. the path is a directory prefix of some element in the
- * pathspec
+ * This function ignores dir->ps1 because that contains exactly one
+ * pathspec item: the path base. No need to worry about that.
*/
-static int exclude_matches_pathspec(const char *path, int len,
- const struct path_simplify *simplify)
+static void mark_useful(struct dir_struct *dir,
+ const char *path, int len,
+ int dtype,
+ struct pathspec *ps, int exclude,
+ enum interesting match)
{
- if (simplify) {
- for (; simplify->path; simplify++) {
- if (len == simplify->len
- && !memcmp(path, simplify->path, len))
- return 1;
- if (len < simplify->len
- && simplify->path[len] == '/'
- && !memcmp(path, simplify->path, len))
- return 1;
- }
- }
- return 0;
+ int i;
+ if (!(dir->flags & DIR_COLLECT_IGNORED))
+ return;
+ /* half-matches (eg. prefix matches) do not count as useful */
+ if (match != all_entries_interesting && match != entry_matched)
+ return;
+ if (exclude && cache_name_is_other(path, len))
+ return;
+
+ for (i = 0; i < ps->nr; i++)
+ if (ps->items[i].useful)
+ dir->useful[i] = 1;
}
static int get_index_dtype(const char *path, int len)
@@ -872,15 +966,24 @@ enum path_treatment {
path_recurse
};
-static enum path_treatment treat_one_path(struct dir_struct *dir,
- char *path, int *len,
- const struct path_simplify *simplify,
- int dtype, struct dirent *de)
+/* base is modified to contain ne */
+static int treat_path(struct dir_struct *dir,
+ struct strbuf *base, const struct name_entry *ne,
+ enum interesting match)
{
- int exclude = excluded(dir, path, &dtype);
- if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
- && exclude_matches_pathspec(path, *len, simplify))
- dir_add_ignored(dir, path, *len);
+ int exclude, dtype;
+
+ strbuf_add(base, ne->path, tree_entry_len(ne));
+
+ /* It does not matter DT_REG or something else, excluded()
+ * only cares if it's DT_DIR or not */
+ dtype = S_ISDIR(ne->mode) ? DT_DIR : DT_REG;
+ exclude = excluded(dir, base->buf, &dtype);
+
+ /* intermediate directory match does not count */
+ if (dtype == DT_REG)
+ mark_useful(dir, base->buf, base->len, dtype,
+ &dir->ps2, exclude, match);
/*
* Excluded? If we don't explicitly want to show
@@ -889,9 +992,6 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
if (exclude && !(dir->flags & DIR_SHOW_IGNORED))
return path_ignored;
- if (dtype == DT_UNKNOWN)
- dtype = get_dtype(de, path, *len);
-
/*
* Do we want to see just the ignored files?
* We still need to recurse into directories,
@@ -899,17 +999,13 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
* directory may contain files that we do..
*/
if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) {
- if (dtype != DT_DIR)
+ if (!S_ISDIR(ne->mode))
return path_ignored;
}
- switch (dtype) {
- default:
- return path_ignored;
- case DT_DIR:
- memcpy(path + *len, "/", 2);
- (*len)++;
- switch (treat_directory(dir, path, *len, simplify)) {
+ if (S_ISDIR(ne->mode)) {
+ strbuf_addch(base, '/');
+ switch (treat_directory(dir, base)) {
case show_directory:
if (exclude != !!(dir->flags
& DIR_SHOW_IGNORED))
@@ -920,38 +1016,14 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
case ignore_directory:
return path_ignored;
}
- break;
- case DT_REG:
- case DT_LNK:
- break;
+
+ /* path_handled for dirs, must be gitlinks */
+ mark_useful(dir, base->buf, base->len, dtype,
+ &dir->ps2, exclude, match);
}
return path_handled;
}
-static enum path_treatment treat_path(struct dir_struct *dir,
- struct dirent *de,
- char *path, int path_max,
- int baselen,
- const struct path_simplify *simplify,
- int *len)
-{
- int dtype;
-
- if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
- return path_ignored;
- *len = strlen(de->d_name);
- /* Ignore overly long pathnames! */
- if (*len + baselen + 8 > path_max)
- return path_ignored;
- memcpy(path + baselen, de->d_name, *len + 1);
- *len += baselen;
- if (simplify_away(path, *len, simplify))
- return path_ignored;
-
- dtype = DTYPE(de);
- return treat_one_path(dir, path, len, simplify, dtype, de);
-}
-
/*
* Read a directory tree. We currently ignore anything but
* directories, regular files and symlinks. That's because git
@@ -962,40 +1034,46 @@ static enum path_treatment treat_path(struct dir_struct *dir,
* That likely will not change.
*/
static int read_directory_recursive(struct dir_struct *dir,
- const char *base, int baselen,
+ struct strbuf *base,
int check_only,
- const struct path_simplify *simplify)
+ enum interesting match)
{
- DIR *fdir = opendir(*base ? base : ".");
- int contents = 0;
- struct dirent *de;
- char path[PATH_MAX + 1];
+ unsigned long size;
+ void *tree_buf = dir_to_tree(base, &size);
+ int contents = 0, baselen = base->len;
+ struct tree_desc desc;
+ struct name_entry ne;
- if (!fdir)
+ if (!tree_buf)
return 0;
- memcpy(path, base, baselen);
+ init_tree_desc(&desc, tree_buf, size);
- while ((de = readdir(fdir)) != NULL) {
- int len;
- switch (treat_path(dir, de, path, sizeof(path),
- baselen, simplify, &len)) {
+ while (tree_entry(&desc, &ne)) {
+ strbuf_setlen(base, baselen);
+ if (match != all_entries_interesting) {
+ match = match_both_pathspecs(dir, base, &ne);
+ if (match == all_entries_not_interesting)
+ break;
+ if (match == entry_not_interesting)
+ continue;
+ }
+ switch (treat_path(dir, base, &ne, match)) {
case path_recurse:
- contents += read_directory_recursive(dir, path, len, 0, simplify);
- continue;
- case path_ignored:
+ contents += read_directory_recursive(dir, base, 0, match);
continue;
case path_handled:
+ contents++;
+ if (check_only)
+ goto exit_early;
+
+ dir_add_name(dir, base->buf, base->len);
break;
}
- contents++;
- if (check_only)
- goto exit_early;
- else
- dir_add_name(dir, path, len);
}
exit_early:
- closedir(fdir);
+ free(tree_buf);
+ strbuf_setlen(base, baselen);
return contents;
}
@@ -1054,6 +1132,7 @@ static void free_simplify(struct path_simplify *simplify)
free(simplify);
}
+#if 0
static int treat_leading_path(struct dir_struct *dir,
const char *path, int len,
const struct path_simplify *simplify)
@@ -1088,20 +1167,52 @@ static int treat_leading_path(struct dir_struct *dir,
return 1; /* finished checking */
}
}
+#endif
-int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec)
+int read_directory(struct dir_struct *dir, const char *path, int len,
+ const char **pathspec)
{
- struct path_simplify *simplify;
+ char *newpath = NULL;
+ struct strbuf base = STRBUF_INIT;
if (has_symlink_leading_path(path, len))
return dir->nr;
- simplify = create_simplify(pathspec);
- if (!len || treat_leading_path(dir, path, len, simplify))
- read_directory_recursive(dir, path, len, 0, simplify);
- free_simplify(simplify);
+ /*
+ * tree_entry_interesting() does not implement AND operator on
+ * pathspecs so we call tree_entry_interesting() twice and
+ * join the results ourselves in match_both_pathspecs()
+ */
+ if (path && *path) {
+ const char *pathspec1[2];
+ newpath = xmalloc(len + 1);
+ memcpy(newpath, path, len);
+ newpath[len] = 0;
+ pathspec1[0] = newpath;
+ pathspec1[1] = NULL;
+ init_pathspec(&dir->ps1, pathspec1);
+ }
+ else
+ init_pathspec(&dir->ps1, NULL);
+ init_pathspec(&dir->ps2, pathspec);
+
+ if (dir->flags & DIR_COLLECT_IGNORED) {
+ int size = sizeof(*dir->useful) * dir->ps2.nr;
+ dir->useful = xmalloc(size);
+ /* guilty until proven useful */
+ memset(dir->useful, 0, size);
+ }
+
+ read_directory_recursive(dir, &base, 0, entry_not_interesting);
+
+ strbuf_release(&base);
+ free_pathspec(&dir->ps1);
+ if (!(dir->flags & DIR_COLLECT_IGNORED))
+ free_pathspec(&dir->ps2);
+ free(newpath);
+
qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
- qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);
+
return dir->nr;
}
diff --git a/dir.h b/dir.h
index dd6947e..362d7b1 100644
--- a/dir.h
+++ b/dir.h
@@ -43,6 +43,11 @@ struct dir_struct {
} flags;
struct dir_entry **entries;
struct dir_entry **ignored;
+ int *useful;
+
+ /* Include info (a joint of ps1 and ps2) */
+ struct pathspec ps1;
+ struct pathspec ps2;
/* Exclude info */
const char *exclude_per_dir;
diff --git a/tree-walk.c b/tree-walk.c
index 6e12f0f..b56fec1 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -600,6 +600,8 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
const char *base_str = base->buf + base_offset;
int matchlen = item->len;
+ /* TODO: 07ccbff (runstatus: do not recurse into subdirectories if not needed - 2006-09-28) */
+
/* assume it will be used (which usually means break
the loop and return), reset it otherwise */
item->useful = 1;
--
1.7.3.1.256.g2539c.dirty
^ permalink raw reply related
* [PATCH/WIP 11/11] dir.c: remove dead code after read_directory() rewrite
From: Nguyễn Thái Ngọc Duy @ 2011-10-24 6:36 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1319438176-7304-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
dir.c | 121 -----------------------------------------------------------------
dir.h | 3 --
2 files changed, 0 insertions(+), 124 deletions(-)
diff --git a/dir.c b/dir.c
index 2946b2d..4094962 100644
--- a/dir.c
+++ b/dir.c
@@ -11,11 +11,6 @@
#include "tree-walk.h"
#include "string-list.h"
-struct path_simplify {
- int len;
- const char *path;
-};
-
static int read_directory_recursive(struct dir_struct *dir,
struct strbuf *base,
int check_only,
@@ -604,15 +599,6 @@ static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathna
return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
}
-struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
-{
- if (!cache_name_is_other(pathname, len))
- return NULL;
-
- ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
- return dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len);
-}
-
/* Read and convert directory to tree object (with invalid SHA-1) */
static void* dir_to_tree(struct strbuf *path, unsigned long *size)
{
@@ -845,31 +831,6 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
}
/*
- * This is an inexact early pruning of any recursive directory
- * reading - if the path cannot possibly be in the pathspec,
- * return true, and we'll skip it early.
- */
-static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify)
-{
- if (simplify) {
- for (;;) {
- const char *match = simplify->path;
- int len = simplify->len;
-
- if (!match)
- break;
- if (len > pathlen)
- len = pathlen;
- if (!memcmp(path, match, len))
- return 0;
- simplify++;
- }
- return 1;
- }
- return 0;
-}
-
-/*
* This function flags pathspecs that are completely excluded, which
* usually means an input mistake. In other words, if all matched
* _files_ of a pathspec are excluded, flag the pathspec.
@@ -1087,88 +1048,6 @@ static int cmp_name(const void *p1, const void *p2)
e2->name, e2->len);
}
-/*
- * Return the length of the "simple" part of a path match limiter.
- */
-static int simple_length(const char *match)
-{
- int len = -1;
-
- for (;;) {
- unsigned char c = *match++;
- len++;
- if (c == '\0' || is_glob_special(c))
- return len;
- }
-}
-
-static struct path_simplify *create_simplify(const char **pathspec)
-{
- int nr, alloc = 0;
- struct path_simplify *simplify = NULL;
-
- if (!pathspec)
- return NULL;
-
- for (nr = 0 ; ; nr++) {
- const char *match;
- if (nr >= alloc) {
- alloc = alloc_nr(alloc);
- simplify = xrealloc(simplify, alloc * sizeof(*simplify));
- }
- match = *pathspec++;
- if (!match)
- break;
- simplify[nr].path = match;
- simplify[nr].len = simple_length(match);
- }
- simplify[nr].path = NULL;
- simplify[nr].len = 0;
- return simplify;
-}
-
-static void free_simplify(struct path_simplify *simplify)
-{
- free(simplify);
-}
-
-#if 0
-static int treat_leading_path(struct dir_struct *dir,
- const char *path, int len,
- const struct path_simplify *simplify)
-{
- char pathbuf[PATH_MAX];
- int baselen, blen;
- const char *cp;
-
- while (len && path[len - 1] == '/')
- len--;
- if (!len)
- return 1;
- baselen = 0;
- while (1) {
- cp = path + baselen + !!baselen;
- cp = memchr(cp, '/', path + len - cp);
- if (!cp)
- baselen = len;
- else
- baselen = cp - path;
- memcpy(pathbuf, path, baselen);
- pathbuf[baselen] = '\0';
- if (!is_directory(pathbuf))
- return 0;
- if (simplify_away(pathbuf, baselen, simplify))
- return 0;
- blen = baselen;
- if (treat_one_path(dir, pathbuf, &blen, simplify,
- DT_DIR, NULL) == path_ignored)
- return 0; /* do not recurse into it */
- if (len <= baselen)
- return 1; /* finished checking */
- }
-}
-#endif
-
int read_directory(struct dir_struct *dir, const char *path, int len,
const char **pathspec)
{
diff --git a/dir.h b/dir.h
index 362d7b1..7a7d818 100644
--- a/dir.h
+++ b/dir.h
@@ -33,7 +33,6 @@ struct exclude_stack {
struct dir_struct {
int nr, alloc;
- int ignored_nr, ignored_alloc;
enum {
DIR_SHOW_IGNORED = 1<<0,
DIR_SHOW_OTHER_DIRECTORIES = 1<<1,
@@ -42,7 +41,6 @@ struct dir_struct {
DIR_COLLECT_IGNORED = 1<<4
} flags;
struct dir_entry **entries;
- struct dir_entry **ignored;
int *useful;
/* Include info (a joint of ps1 and ps2) */
@@ -82,7 +80,6 @@ extern int read_directory(struct dir_struct *, const char *path, int len, const
extern int excluded_from_list(const char *pathname, int pathlen, const char *basename,
int *dtype, struct exclude_list *el);
extern int excluded(struct dir_struct *, const char *, int *);
-struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len);
extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
char **buf_p, struct exclude_list *which, int check_index);
extern void add_excludes_from_file(struct dir_struct *, const char *fname);
--
1.7.3.1.256.g2539c.dirty
^ permalink raw reply related
* Re: [Qemu-devel] [Qemu-discuss] [Qemu-discussion] QEMU via GDB
From: davide.ferraretto @ 2011-10-24 6:42 UTC (permalink / raw)
To: qemu-devel, wdongxu
In-Reply-To: <fc68daf05eb5.4ea523e1@studenti.univr.it>
[-- Attachment #1: Type: text/plain, Size: 1279 bytes --]
It dosen't work. GDB returns the same error.
----- Original Message -----
From: davide.ferraretto@studenti.univr.it
Date: Monday, October 24, 2011 8:37
Subject: Re: [Qemu-discuss] [Qemu-discussion] QEMU via GDB
To: davide.ferraretto@studenti.univr.it
> It dosen't work. GDB return the same error.
>
> ----- Original Message -----
> From: davide.ferraretto@studenti.univr.it
> Date: Friday, October 21, 2011 16:18
> Subject: [Qemu-discuss] [Qemu-discussion] QEMU via GDB
> To: qemu-discuss@nongnu.org
>
> > Dear all,
> > I am trying to debug QEMU via GDB.
> >
> >
> > I configured and compiled QEMU with debugging flags, i.e.,
> > # CFLAGS="-g3 -O0" ./configure --disable-gfx-check
> >
> >
> > and run gdb:
> >
> >
> > # gdb ./i386-linux-user/qemu-i386
> >
> >
> > (gdb) break main
> > (gdb) run
> >
> > Starting program: /home/test/femu/i386-linux-user/qemu-i386
> > Failed to read a valid object file image from memory.
> > Warning:
> > Cannot insert breakpoint 1.
> > Error accessing memory address 0x2f7df: Input/output error.
> >
> >
> > Is there any extra flag to be specified with the GDB for QEMU debugging? I am wondering if the QEMU virtual machine creates any problem to the GDB virtual machine.
> >
> >
> > Thanks.
[-- Attachment #2: Type: text/html, Size: 9195 bytes --]
^ permalink raw reply
* DeviceTree and children devices
From: Felipe Balbi @ 2011-10-24 6:42 UTC (permalink / raw)
To: Felipe Balbi
Cc: Grant Likely, Linux Kernel Mailing List, Linux USB Mailing List
[-- Attachment #1: Type: text/plain, Size: 1731 bytes --]
Hi Grant,
I have a question about how DeviceTree should be written in case a
device has a child device.
The way things are integrated on OMAP is that we will always have a
parent device which is a wrapper around an IP core in order to
integrate with the OMAP context (clocks, power management, etc).
That wrapper has its own address space and its own IRQ number
(generally). On my dwc3 driver I have modeled the OMAP wrapper as a
parent device which allocates a child device for the core IP driver.
This makes it a lot easier to re-use the core IP driver on other SoCs or
PCI (there's a glue layer for PCI too).
So I wonder if we should describe that on DeviceTree and not have the
OMAP glue layer allocate the core IP driver. Just to illustrate, here's
what we have:
static int dwc3_omap_probe(struct platform_device *pdev)
{
struct platform_device *dwc3;
struct resource res[2];
dwc3 = platform_device_alloc("dwc3", -1);
/* check*/
dwc3->dev.parent = &pdev->dev;
/* copy DMA fields from parent too */
res[0].start = start_address;
res[0].end = end_address;
res[0].flags = IORESOURCE_MEM;
res[1].start = irq_number;
res[1].flags = IORESOURCE_IRQ;
ret = platform_add_resources(dwc3, res, ARRAY_SIZE(res));
/* check */
return platform_add_device(dwc3);
}
and I wonder if I should have a DeviceTree like so:
usb@xxxxx {
compatible = "ti,dwc3-omap"; // This is TI OMAP
// wrapper
range = <....>;
...
usb@yyyy {
compatible = "synopsys,dwc3", // This is core IP
// inside wrapper
...
};
};
then I can drop the dwc3 platform_device allocation and all of that
resource copying, etc.
What do you think ?
--
balbi
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [dm-crypt] [RFC] dm-crypt and hardware-optimized crypto modules
From: Arno Wagner @ 2011-10-24 6:42 UTC (permalink / raw)
To: dm-crypt
In-Reply-To: <4EA505E5.5080205@redhat.com>
On Mon, Oct 24, 2011 at 08:29:57AM +0200, Milan Broz wrote:
> On 10/24/2011 01:30 AM, Jonas Meurer wrote:
[...]
> If the modules are present at this time (either compiled-in or as separate
> modules) this seems to be kernel cryptoAPI bug.
So if it is loaded by the autoloader it should try the HW module first
and only if that fails load the SW module? Makes sense.
> If it is not present (in intramfs) then available module is used and later
> it is not replaced by hw accelerated driver.
>
> Anyway, I am using aesni_intel loaded from Debian initramfs and it works
> with no hacks. Wonder what is the difference...
> (kernel 3.0.3 but compiled with own config to own kernel deb package.)
Ah, yes, I fogot: There is an organized and documented process for
rolling your own Debian kernel package. I have not used it though.
> > I'm happy to extend the initramfs scripts to load hardware-optimized
> > modules in case they're available before cryptsetup is invoked. But
> > that an implementation would be ugly and hard to maintain as it needs
> > to be updated for possible kernel crypto driver changes. I would
> > prefer a solution where the kernel crypto api took responsibility for
> > this task.
>
> I think it should load modules automatically according to its priorities
> (hw has always higher priority). Anyway, this is the question
> for linux-crypto (kernel) list.
>
> There is no way how to force dm-crypt load specific driver.
You could do a wrapper and unload the software AES module if loaded.
That would be a pretty dirty hack though.
BTW, nice to see RH folks using Debian ;-)
Arno
--
Arno Wagner, Dr. sc. techn., Dipl. Inform., CISSP -- Email: arno@wagner.name
GnuPG: ID: 1E25338F FP: 0C30 5782 9D93 F785 E79C 0296 797F 6B50 1E25 338F
----
Cuddly UI's are the manifestation of wishful thinking. -- Dylan Evans
If it's in the news, don't worry about it. The very definition of
"news" is "something that hardly ever happens." -- Bruce Schneier
^ permalink raw reply
* nouveau page_flip function implement not wait vblank, which cause screen garbage
From: chris @ 2011-10-24 6:30 UTC (permalink / raw)
To: dri-devel
[-- Attachment #1.1: Type: text/plain, Size: 1909 bytes --]
Dear,
I use NVidia Geforce 7300GT graphics card in my PC, and Linux 3.1rc4 kernel code, git drm 2.4.36.
When I run the vbltest program, it prints "60HZ" which indicated the implementation of drmWaitVBlank() and drm_vblank_wait() is correct.
But when I run modetest with option " -v -s 12:1280x1024" , it prints high fresh rate up to "150 HZ" . I examing the code , and found that no waiting vblank operation is processed in nouveau_crtc_page_flip() function. The screen produced lots of garbage and blink very much.
int
nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event)
{
......
}
I study the i915 intel_crtc_page_flip implementation.
static int intel_crtc_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event)
{
......
ret = drm_vblank_get(dev, intel_crtc->pipe);
if (ret)
goto cleanup_objs;
work->pending_flip_obj = obj;
work->enable_stall_check = true;
/* Block clients from rendering to the new back buffer until
* the flip occurs and the object is no longer visible.
*/
atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
ret = dev_priv->display.queue_flip(dev, crtc, fb, obj);
if (ret)
goto cleanup_pending;
......
}
after vblank irq acquired, the interrupt isr will wakup the runqueue.
6159 static void do_intel_finish_page_flip(struct drm_device *dev,
6160 struct drm_crtc *crtc)
6161 {
......
6211 list_add_tail(&e->base.link,
6212 &e->base.file_priv->event_list);
6213 wake_up_interruptible(&e->base.file_priv->event_wait);
6214 }
6215
6216 drm_vblank_put(dev, intel_crtc->pipe);
6217
Is there anyone use the same driver and found this issues can tell me "is it a bug"?
Thanks!
[-- Attachment #1.2: Type: text/html, Size: 3134 bytes --]
[-- Attachment #2: Type: text/plain, Size: 159 bytes --]
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: Question about how to troubleshoot sandybridge kernel opps and subsequest GPU lockup
From: Daniel Vetter @ 2011-10-24 6:46 UTC (permalink / raw)
To: James R. Leu; +Cc: intel-gfx
In-Reply-To: <20111024041219.GA7575@mindspring.com>
On Sun, Oct 23, 2011 at 11:12:21PM -0500, James R. Leu wrote:
> I'm running wow in wine on 64 bit fedora rawhide on a dell vostro 3550
> (i5 with integrated GPU).
>
> I'm reliably able to produce 2 types of crashes:
> - wow freezes, but I can get to text console, in this case I'm able to
> grab a kernel stack trace (below) prior to seeing the normal
> [drm:i915_wait_request] *ERROR* i915_wait_request returns -11 (awaiting 452684 at 452608, next 452686)
I'm pretty sure that below that line there's a gpu hang report. If that's
the case, the please grab everything in /sys/kernel/debug/dri, put it into
a tar.gz and attach it (you need to do this _after_ the machine is hung,
the kernel will write a gpu crash dump into i915_error_state).
The userspace parts of the i915 driver are very important for gpu hangs,
so please attach the version of mesa, libdrm and xf86-video-intel you've
installed.
Also please attach all your i915.ko module options as listed in
/sys/module/i915/parameters
> - the other is a complete freeze of the system, hard reset required, nothing logged to /var/log/messages
It's rather likely that this is the same issue as above. Depending upon
exact circumstances the gpu can take down the entire system.
> Is there any value in me creating a bug report for this, it seems to be a pretty common issue.
> Is there any use in my trying different kernel command line optios for
> the i915 driver or config options to the xorg intel driver?
Yes, gpu hangs are one of the more common issues, but until you've
submitted the error_state there's no way to diagnose the issue and tell
whether we have got a report already.
> I have the various git trees pulled out (I was looking for recent changes that might be related
> to this issue). I'm capable of building and installing from these git trees if there are specific
> bits that I should test.
>
> [ 939.830806] ------------[ cut here ]------------
> [ 939.830814] WARNING: at drivers/gpu/drm/i915/i915_drv.c:372 gen6_gt_force_wake_put+0x29/0x51 [i915]()
> [ 939.830816] Hardware name: Vostro 3550
> [ 939.830818] Modules linked in: snd_seq_dummy fuse ip6table_filter ip6_tables ebtable_nat ebtables xt_state xt_CHECKSUM iptable_mangle ppdev parport_pc lp parport vboxpci vboxnetadp vboxnetflt vboxdrv bridge stp llc tun rfcomm bnep ipt_MASQUERADE iptable_nat nf_nat nf_conntrack_ipv4 nf_conntrack nf_defrag_ipv4 snd_hda_codec_hdmi snd_hda_codec_idt uvcvideo videodev btusb media bluetooth v4l2_compat_ioctl32 arc4 snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm iwlagn microcode mac80211 dell_laptop iTCO_wdt r8169 i2c_i801 snd_timer cfg80211 snd mii iTCO_vendor_support dcdbas dell_wmi sparse_keymap soundcore rfkill snd_page_alloc virtio_net kvm_intel kvm binfmt_misc wmi i915 drm_kms_helper drm i2c_algo_bit i2c_core video [last unloaded: scsi_wait_scan]
> [ 939.830926] Pid: 0, comm: swapper Tainted: G WC 3.1.0-0.rc10.git0.1.fc17.x86_64 #1
> [ 939.830928] Call Trace:
> [ 939.830930] <IRQ [<ffffffff8105c3a0>] warn_slowpath_common+0x83/0x9b
> [ 939.830941] [<ffffffff8105c3d2>] warn_slowpath_null+0x1a/0x1c
> [ 939.830952] [<ffffffffa006b624>] gen6_gt_force_wake_put+0x29/0x51 [i915]
> [ 939.830963] [<ffffffffa006f45f>] i915_read32+0x44/0x6b [i915]
> [ 939.830975] [<ffffffffa00724a9>] i915_hangcheck_elapsed+0xe8/0x1f8 [i915]
> [ 939.831027] [<ffffffff81062ddd>] irq_exit+0x5d/0xcf
> [ 939.831032] [<ffffffff8150de91>] smp_apic_timer_interrupt+0x7c/0x8a
> [ 939.831036] [<ffffffff8150bd73>] apic_timer_interrupt+0x73/0x80
> [ 939.831038] <EOI [<ffffffff81014ded>] ? paravirt_read_tsc+0x9/0xd
> [ 939.831046] [<ffffffff81297075>] ? intel_idle+0xe5/0x10c
> [ 939.831050] [<ffffffff81297071>] ? intel_idle+0xe1/0x10c
> [ 939.831054] [<ffffffff813e14fe>] cpuidle_idle_call+0x11c/0x1fe
> [ 939.831059] [<ffffffff8100e2ef>] cpu_idle+0xab/0x101
> [ 939.831063] [<ffffffff814df673>] rest_init+0xd7/0xde
> [ 939.831067] [<ffffffff814df59c>] ? csum_partial_copy_generic+0x16c/0x16c
> [ 939.831072] [<ffffffff81d53bb0>] start_kernel+0x3dd/0x3ea
> [ 939.831076] [<ffffffff81d532c4>] x86_64_start_reservations+0xaf/0xb3
> [ 939.831081] [<ffffffff81d53140>] ? early_idt_handlers+0x140/0x140
> [ 939.831085] [<ffffffff81d533ca>] x86_64_start_kernel+0x102/0x111
> [ 939.831088] ---[ end trace f5cba358bac6b7e5 ]---
This WARN here is a possible sideeffect of a dying gpu. Independant, but
rather harmless bug. Unfortunately no easy solution, hence no patch atm.
Yours, Daniel
--
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48
^ permalink raw reply
* [Qemu-devel] Question about intermediate code generation in qemu (tcg)
From: Carter Cheng @ 2011-10-24 6:46 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 342 bytes --]
Hi,
I was wondering if someone could help me understand some aspects of the
current qemu code generation routines. How are floating point and SSE ops
currently handled? I do not see specific tcg routines for these cases(the
README seems to indicate that FP and vector ops are not handled using the
current IL).
Thanks in advanced,
Carter.
[-- Attachment #2: Type: text/html, Size: 417 bytes --]
^ permalink raw reply
* Re: [PATCH net-next] tcp: md5: add more const attributes
From: David Miller @ 2011-10-24 6:51 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev
In-Reply-To: <1319438111.2517.32.camel@edumazet-laptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 24 Oct 2011 08:35:11 +0200
> Now tcp_md5_hash_header() has a const tcphdr argument, we can add more
> const attributes to callers.
>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Applied.
^ permalink raw reply
* [PATCH ] i2c: omap: recover from Bus Busy condition
From: Shubhrajyoti D @ 2011-10-24 6:51 UTC (permalink / raw)
To: linux-i2c-u79uwXL29TY76Z2rM5mHXA
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Vikram Pandita,
Shubhrajyoti D
From: Vikram Pandita <vikram.pandita-l0cyMroinI0@public.gmane.org>
In case a peripheral is holding the DATA bus low, provide a 400Khz
constant clock output using the TEST register.
Also soft reset the I2C controller so that there is no stale state
left in the HW state machine.
A WARN_ON() will be generated when a BB timeout happens.
Signed-off-by: Vikram Pandita <vikram.pandita-l0cyMroinI0@public.gmane.org>
Signed-off-by: Shubhrajyoti D <shubhrajyoti-l0cyMroinI0@public.gmane.org>
---
drivers/i2c/busses/i2c-omap.c | 15 +++++++++++++--
1 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 2dfb631..b6fcd08 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -143,7 +143,6 @@ enum {
#define OMAP_I2C_SCLH_HSSCLH 8
/* I2C System Test Register (OMAP_I2C_SYSTEST): */
-#ifdef DEBUG
#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
@@ -152,7 +151,6 @@ enum {
#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
-#endif
/* OCP_SYSSTATUS bit definitions */
#define SYSS_RESETDONE_MASK (1 << 0)
@@ -641,10 +639,23 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
int i;
int r;
+ u16 val;
omap_i2c_unidle(dev);
r = omap_i2c_wait_for_bb(dev);
+ /* If timeout, try to again check after soft reset of I2C block */
+ if (WARN_ON(r == -ETIMEDOUT)) {
+ /* Provide a permanent clock to recover the peripheral */
+ val = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+ val |= (OMAP_I2C_SYSTEST_ST_EN |
+ OMAP_I2C_SYSTEST_FREE |
+ (2 << OMAP_I2C_SYSTEST_TMODE_SHIFT));
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, val);
+ msleep(1);
+ omap_i2c_init(dev);
+ r = omap_i2c_wait_for_bb(dev);
+ }
if (r < 0)
goto out;
--
1.7.1
^ permalink raw reply related
* [PATCH ] i2c: omap: recover from Bus Busy condition
From: Shubhrajyoti D @ 2011-10-24 6:51 UTC (permalink / raw)
To: linux-i2c; +Cc: linux-kernel, Vikram Pandita, Shubhrajyoti D
From: Vikram Pandita <vikram.pandita@ti.com>
In case a peripheral is holding the DATA bus low, provide a 400Khz
constant clock output using the TEST register.
Also soft reset the I2C controller so that there is no stale state
left in the HW state machine.
A WARN_ON() will be generated when a BB timeout happens.
Signed-off-by: Vikram Pandita <vikram.pandita@ti.com>
Signed-off-by: Shubhrajyoti D <shubhrajyoti@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 15 +++++++++++++--
1 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 2dfb631..b6fcd08 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -143,7 +143,6 @@ enum {
#define OMAP_I2C_SCLH_HSSCLH 8
/* I2C System Test Register (OMAP_I2C_SYSTEST): */
-#ifdef DEBUG
#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
@@ -152,7 +151,6 @@ enum {
#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
-#endif
/* OCP_SYSSTATUS bit definitions */
#define SYSS_RESETDONE_MASK (1 << 0)
@@ -641,10 +639,23 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
int i;
int r;
+ u16 val;
omap_i2c_unidle(dev);
r = omap_i2c_wait_for_bb(dev);
+ /* If timeout, try to again check after soft reset of I2C block */
+ if (WARN_ON(r == -ETIMEDOUT)) {
+ /* Provide a permanent clock to recover the peripheral */
+ val = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+ val |= (OMAP_I2C_SYSTEST_ST_EN |
+ OMAP_I2C_SYSTEST_FREE |
+ (2 << OMAP_I2C_SYSTEST_TMODE_SHIFT));
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, val);
+ msleep(1);
+ omap_i2c_init(dev);
+ r = omap_i2c_wait_for_bb(dev);
+ }
if (r < 0)
goto out;
--
1.7.1
^ permalink raw reply related
* [U-Boot] [PATCH] arch/powerpc/lib/board.c: fix build warning
From: Heiko Schocher @ 2011-10-24 6:53 UTC (permalink / raw)
To: u-boot
In-Reply-To: <CAPnjgZ1eLLDtp95zRW485i8E59VRLcwj7-a_dbQ2a26ZudvweA@mail.gmail.com>
Hello Simon, Wolfgang,
Simon Glass wrote:
> Hi Wolfgang,
>
> On Sun, Oct 23, 2011 at 2:58 PM, Wolfgang Denk <wd@denx.de> wrote:
>> Commit 1272592 "powerpc: Use getenv_ulong() in place of getenv(),
>> strtoul" instroduced a build warning for some PPC systems:
>>
>> board.c: In function 'board_init_r':
>> board.c:626: warning: unused variable 's'
>>
>> Fix it.
>>
>> Signed-off-by: Wolfgang Denk <wd@denx.de>
>
> I sent an alternative to this but they are roughly equivalent so:
>
> Acked-by: Simon Glass <sjg@chromium.org>
Same on arm, posted for this a patch.
Acked-by: Heiko Schocher <hs@denx.de>
bye,
Heiko
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
^ permalink raw reply
* [RFC PATCH 04/15] ARM: uncompress: Only call arch_decomp_setup when needed
From: Uwe Kleine-König @ 2011-10-24 6:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1319404245-12740-4-git-send-email-zoss@devai.org>
On Sun, Oct 23, 2011 at 11:10:34PM +0200, Zoltan Devai wrote:
> As only the minority of the machines uses arch_decomp_setup,
> ifdef it out when not needed, to avoid needless defines in
> all uncompress.h files.
>
> Machines using this feature should add
#define ARCH_HAVE_DECOMP_SETUP
> in their uncompress.h headers.
I guess this was removed by git-commit.
>
> Signed-off-by: Zoltan Devai <zoss@devai.org>
> ---
> arch/arm/boot/compressed/misc.c | 2 ++
> 1 files changed, 2 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
> index 8e2a8fc..a4b8df2 100644
> --- a/arch/arm/boot/compressed/misc.c
> +++ b/arch/arm/boot/compressed/misc.c
> @@ -142,7 +142,9 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
> free_mem_end_ptr = free_mem_ptr_end_p;
> __machine_arch_type = arch_id;
>
> +#ifdef ARCH_HAVE_DECOMP_SETUP
> arch_decomp_setup();
> +#endif /* ARCH_HAVE_DECOMP_SETUP */
This is a place that needs some care for multi-SoC. I don't know if
there are any ideas how to handle it, but using a cpp symbol won't work
I guess. So I think it's not worth to touch arch_decomp_setup without
solving the multi-SoC case.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [patch net-next V2] net: introduce ethernet teaming device
From: Jiri Pirko @ 2011-10-24 6:54 UTC (permalink / raw)
To: Or Gerlitz
Cc: netdev, davem, eric.dumazet, bhutchings, shemminger, fubar, andy,
tgraf, ebiederm, mirqus, kaber, greearb, jesse, fbl,
benjamin.poirier, jzupka
In-Reply-To: <CAJZOPZ+80kZ8-dQLJJ3OYr+fxVw=z=VCQzui2aaif1ga7W-K_g@mail.gmail.com>
Sun, Oct 23, 2011 at 11:46:32PM CEST, or.gerlitz@gmail.com wrote:
>On Fri, Oct 21, 2011 at 2:39 PM, Jiri Pirko <jpirko@redhat.com> wrote:
>> This patch introduces new network device called team. It supposes to be
>> very fast, simple, userspace-driven alternative to existing bonding driver.
>
>Jiri,
>
>Could you elaborate a little further on the motivation for this
>teaming approach/solution vs. the current bonding driver? You say that
>it suppose to be very fast, simple and user space driven, so... do
>you find bonding not to be fast enough? or too complex? or the fact
>that bonding's driving logic being in the kernel is something you
>prefer to see in user-space? anything else?
As I wrote before:
<quote>
Well as I already wrote, the key is to keep kernel code as slim and
clean as possible and do what can be done in userspace in userspace. For
example bonding has active backup slave selection, arp verification and
so on in kernel. That's not conceptional and flexible. Team allows users
to easily write/modify their own control logic based on whatever way
they want to decide to select active port. I can imagine for example
even things like communicating with smart switch and checking port
status there. Bonding is carring a lot of baggage, team does not. It's
light and it suppose to stay that way.
</quote>
Also I would add easy extensibility by writing new mode in case any
existing is not suitable for your needs.
I hope this clears it up for you.
Jirka
>
>thanks,
>
>Or.
>
>
>>
>> Userspace library called libteam with couple of demo apps is available
>> here:
>> https://github.com/jpirko/libteam
>> Note it's still in its dipers atm.
>>
>> team<->libteam use generic netlink for communication. That and rtnl
>> suppose to be the only way to configure team device, no sysfs etc.
>>
>> Python binding basis for libteam was recently introduced (some need
>> still need to be done on it though). Daemon providing arpmon/miimon
>> active-backup functionality will be introduced shortly.
>> All what's necessary is already implemented in kernel team driver.
>>
>> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
>>
>> v1->v2:
>> - modes are made as modules. Makes team more modular and
>> extendable.
>> - several commenters' nitpicks found on v1 were fixed
>> - several other bugs were fixed.
>> - note I ignored Eric's comment about roundrobin port selector
>> as Eric's way may be easily implemented as another mode (mode
>> "random") in future.
>> ---
>> Documentation/networking/team.txt | 2 +
>> MAINTAINERS | 7 +
>> drivers/net/Kconfig | 2 +
>> drivers/net/Makefile | 1 +
>> drivers/net/team/Kconfig | 38 +
>> drivers/net/team/Makefile | 7 +
>> drivers/net/team/team.c | 1593 +++++++++++++++++++++++++++++
>> drivers/net/team/team_mode_activebackup.c | 152 +++
>> drivers/net/team/team_mode_roundrobin.c | 107 ++
>> include/linux/Kbuild | 1 +
>> include/linux/if.h | 1 +
>> include/linux/if_team.h | 233 +++++
>> 12 files changed, 2144 insertions(+), 0 deletions(-)
>> create mode 100644 Documentation/networking/team.txt
>> create mode 100644 drivers/net/team/Kconfig
>> create mode 100644 drivers/net/team/Makefile
>> create mode 100644 drivers/net/team/team.c
>> create mode 100644 drivers/net/team/team_mode_activebackup.c
>> create mode 100644 drivers/net/team/team_mode_roundrobin.c
>> create mode 100644 include/linux/if_team.h
>>
>> diff --git a/Documentation/networking/team.txt b/Documentation/networking/team.txt
>> new file mode 100644
>> index 0000000..5a01368
>> --- /dev/null
>> +++ b/Documentation/networking/team.txt
>> @@ -0,0 +1,2 @@
>> +Team devices are driven from userspace via libteam library which is here:
>> + https://github.com/jpirko/libteam
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 5008b08..c33400d 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -6372,6 +6372,13 @@ W: http://tcp-lp-mod.sourceforge.net/
>> S: Maintained
>> F: net/ipv4/tcp_lp.c
>>
>> +TEAM DRIVER
>> +M: Jiri Pirko <jpirko@redhat.com>
>> +L: netdev@vger.kernel.org
>> +S: Supported
>> +F: drivers/net/team/
>> +F: include/linux/if_team.h
>> +
>> TEGRA SUPPORT
>> M: Colin Cross <ccross@android.com>
>> M: Erik Gilling <konkers@android.com>
>> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
>> index 583f66c..b3020be 100644
>> --- a/drivers/net/Kconfig
>> +++ b/drivers/net/Kconfig
>> @@ -125,6 +125,8 @@ config IFB
>> 'ifb1' etc.
>> Look at the iproute2 documentation directory for usage etc
>>
>> +source "drivers/net/team/Kconfig"
>> +
>> config MACVLAN
>> tristate "MAC-VLAN support (EXPERIMENTAL)"
>> depends on EXPERIMENTAL
>> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
>> index fa877cd..4e4ebfe 100644
>> --- a/drivers/net/Makefile
>> +++ b/drivers/net/Makefile
>> @@ -17,6 +17,7 @@ obj-$(CONFIG_NET) += Space.o loopback.o
>> obj-$(CONFIG_NETCONSOLE) += netconsole.o
>> obj-$(CONFIG_PHYLIB) += phy/
>> obj-$(CONFIG_RIONET) += rionet.o
>> +obj-$(CONFIG_NET_TEAM) += team/
>> obj-$(CONFIG_TUN) += tun.o
>> obj-$(CONFIG_VETH) += veth.o
>> obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
>> diff --git a/drivers/net/team/Kconfig b/drivers/net/team/Kconfig
>> new file mode 100644
>> index 0000000..70a43a6
>> --- /dev/null
>> +++ b/drivers/net/team/Kconfig
>> @@ -0,0 +1,38 @@
>> +menuconfig NET_TEAM
>> + tristate "Ethernet team driver support (EXPERIMENTAL)"
>> + depends on EXPERIMENTAL
>> + ---help---
>> + This allows one to create virtual interfaces that teams together
>> + multiple ethernet devices.
>> +
>> + Team devices can be added using the "ip" command from the
>> + iproute2 package:
>> +
>> + "ip link add link [ address MAC ] [ NAME ] type team"
>> +
>> + To compile this driver as a module, choose M here: the module
>> + will be called team.
>> +
>> +if NET_TEAM
>> +
>> +config NET_TEAM_MODE_ROUNDROBIN
>> + tristate "Round-robin mode support"
>> + depends on NET_TEAM
>> + ---help---
>> + Basic mode where port used for transmitting packets is selected in
>> + round-robin fashion using packet counter.
>> +
>> + To compile this team mode as a module, choose M here: the module
>> + will be called team_mode_roundrobin.
>> +
>> +config NET_TEAM_MODE_ACTIVEBACKUP
>> + tristate "Active-backup mode support"
>> + depends on NET_TEAM
>> + ---help---
>> + Only one port is active at a time and the rest of ports are used
>> + for backup.
>> +
>> + To compile this team mode as a module, choose M here: the module
>> + will be called team_mode_activebackup.
>> +
>> +endif # NET_TEAM
>> diff --git a/drivers/net/team/Makefile b/drivers/net/team/Makefile
>> new file mode 100644
>> index 0000000..85f2028
>> --- /dev/null
>> +++ b/drivers/net/team/Makefile
>> @@ -0,0 +1,7 @@
>> +#
>> +# Makefile for the network team driver
>> +#
>> +
>> +obj-$(CONFIG_NET_TEAM) += team.o
>> +obj-$(CONFIG_NET_TEAM_MODE_ROUNDROBIN) += team_mode_roundrobin.o
>> +obj-$(CONFIG_NET_TEAM_MODE_ACTIVEBACKUP) += team_mode_activebackup.o
>> diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
>> new file mode 100644
>> index 0000000..398be58
>> --- /dev/null
>> +++ b/drivers/net/team/team.c
>> @@ -0,0 +1,1593 @@
>> +/*
>> + * net/drivers/team/team.c - Network team device driver
>> + * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/types.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/slab.h>
>> +#include <linux/rcupdate.h>
>> +#include <linux/errno.h>
>> +#include <linux/ctype.h>
>> +#include <linux/notifier.h>
>> +#include <linux/netdevice.h>
>> +#include <linux/if_arp.h>
>> +#include <linux/socket.h>
>> +#include <linux/etherdevice.h>
>> +#include <linux/rtnetlink.h>
>> +#include <net/rtnetlink.h>
>> +#include <net/genetlink.h>
>> +#include <net/netlink.h>
>> +#include <linux/if_team.h>
>> +
>> +#define DRV_NAME "team"
>> +
>> +
>> +/**********
>> + * Helpers
>> + **********/
>> +
>> +#define team_port_exists(dev) (dev->priv_flags & IFF_TEAM_PORT)
>> +
>> +static struct team_port *team_port_get_rcu(const struct net_device *dev)
>> +{
>> + struct team_port *port = rcu_dereference(dev->rx_handler_data);
>> +
>> + return team_port_exists(dev) ? port : NULL;
>> +}
>> +
>> +static struct team_port *team_port_get_rtnl(const struct net_device *dev)
>> +{
>> + struct team_port *port = rtnl_dereference(dev->rx_handler_data);
>> +
>> + return team_port_exists(dev) ? port : NULL;
>> +}
>> +
>> +/*
>> + * Since the ability to change mac address for open port device is tested in
>> + * team_port_add, this function can be called without control of return value
>> + */
>> +static int __set_port_mac(struct net_device *port_dev,
>> + const unsigned char *dev_addr)
>> +{
>> + struct sockaddr addr;
>> +
>> + memcpy(addr.sa_data, dev_addr, ETH_ALEN);
>> + addr.sa_family = ARPHRD_ETHER;
>> + return dev_set_mac_address(port_dev, &addr);
>> +}
>> +
>> +int team_port_set_orig_mac(struct team_port *port)
>> +{
>> + return __set_port_mac(port->dev, port->orig.dev_addr);
>> +}
>> +EXPORT_SYMBOL(team_port_set_orig_mac);
>> +
>> +int team_port_set_team_mac(struct team_port *port)
>> +{
>> + return __set_port_mac(port->dev, port->team->dev->dev_addr);
>> +}
>> +EXPORT_SYMBOL(team_port_set_team_mac);
>> +
>> +
>> +/*******************
>> + * Options handling
>> + *******************/
>> +
>> +void team_options_register(struct team *team, struct team_option *option,
>> + size_t option_count)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < option_count; i++, option++)
>> + list_add_tail(&option->list, &team->option_list);
>> +}
>> +EXPORT_SYMBOL(team_options_register);
>> +
>> +static void __team_options_change_check(struct team *team,
>> + struct team_option *changed_option);
>> +
>> +static void __team_options_unregister(struct team *team,
>> + struct team_option *option,
>> + size_t option_count)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < option_count; i++, option++)
>> + list_del(&option->list);
>> +}
>> +
>> +void team_options_unregister(struct team *team, struct team_option *option,
>> + size_t option_count)
>> +{
>> + __team_options_unregister(team, option, option_count);
>> + __team_options_change_check(team, NULL);
>> +}
>> +EXPORT_SYMBOL(team_options_unregister);
>> +
>> +static int team_option_get(struct team *team, struct team_option *option,
>> + void *arg)
>> +{
>> + return option->getter(team, arg);
>> +}
>> +
>> +static int team_option_set(struct team *team, struct team_option *option,
>> + void *arg)
>> +{
>> + int err;
>> +
>> + err = option->setter(team, arg);
>> + if (err)
>> + return err;
>> +
>> + __team_options_change_check(team, option);
>> + return err;
>> +}
>> +
>> +/****************
>> + * Mode handling
>> + ****************/
>> +
>> +static LIST_HEAD(mode_list);
>> +static DEFINE_SPINLOCK(mode_list_lock);
>> +
>> +static struct team_mode *__find_mode(const char *kind)
>> +{
>> + struct team_mode *mode;
>> +
>> + list_for_each_entry(mode, &mode_list, list) {
>> + if (strcmp(mode->kind, kind) == 0)
>> + return mode;
>> + }
>> + return NULL;
>> +}
>> +
>> +static bool is_good_mode_name(const char *name)
>> +{
>> + while (*name != '\0') {
>> + if (!isalpha(*name) && !isdigit(*name) && *name != '_')
>> + return false;
>> + name++;
>> + }
>> + return true;
>> +}
>> +
>> +int team_mode_register(struct team_mode *mode)
>> +{
>> + int err = 0;
>> +
>> + if (!is_good_mode_name(mode->kind) ||
>> + mode->priv_size > TEAM_MODE_PRIV_SIZE)
>> + return -EINVAL;
>> + spin_lock(&mode_list_lock);
>> + if (__find_mode(mode->kind)) {
>> + err = -EEXIST;
>> + goto unlock;
>> + }
>> + list_add_tail(&mode->list, &mode_list);
>> +unlock:
>> + spin_unlock(&mode_list_lock);
>> + return err;
>> +}
>> +EXPORT_SYMBOL(team_mode_register);
>> +
>> +int team_mode_unregister(struct team_mode *mode)
>> +{
>> + spin_lock(&mode_list_lock);
>> + list_del_init(&mode->list);
>> + spin_unlock(&mode_list_lock);
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(team_mode_unregister);
>> +
>> +static struct team_mode *team_mode_get(const char *kind)
>> +{
>> + struct team_mode *mode;
>> +
>> + spin_lock(&mode_list_lock);
>> + mode = __find_mode(kind);
>> + if (!mode) {
>> + spin_unlock(&mode_list_lock);
>> + request_module("team-mode-%s", kind);
>> + spin_lock(&mode_list_lock);
>> + mode = __find_mode(kind);
>> + }
>> + if (mode)
>> + if (!try_module_get(mode->owner))
>> + mode = NULL;
>> +
>> + spin_unlock(&mode_list_lock);
>> + return mode;
>> +}
>> +
>> +static void team_mode_put(const char *kind)
>> +{
>> + struct team_mode *mode;
>> +
>> + spin_lock(&mode_list_lock);
>> + mode = __find_mode(kind);
>> + BUG_ON(!mode);
>> + module_put(mode->owner);
>> + spin_unlock(&mode_list_lock);
>> +}
>> +
>> +/*
>> + * We can benefit from the fact that it's ensured no port is present
>> + * at the time of mode change.
>> + */
>> +static int __team_change_mode(struct team *team,
>> + const struct team_mode *new_mode)
>> +{
>> + /* Check if mode was previously set and do cleanup if so */
>> + if (team->mode_kind) {
>> + void (*exit_op)(struct team *team) = team->mode_ops.exit;
>> +
>> + /* Clear ops area so no callback is called any longer */
>> + memset(&team->mode_ops, 0, sizeof(struct team_mode_ops));
>> +
>> + synchronize_rcu();
>> +
>> + if (exit_op)
>> + exit_op(team);
>> + team_mode_put(team->mode_kind);
>> + team->mode_kind = NULL;
>> + /* zero private data area */
>> + memset(&team->mode_priv, 0,
>> + sizeof(struct team) - offsetof(struct team, mode_priv));
>> + }
>> +
>> + if (!new_mode)
>> + return 0;
>> +
>> + if (new_mode->ops->init) {
>> + int err;
>> +
>> + err = new_mode->ops->init(team);
>> + if (err)
>> + return err;
>> + }
>> +
>> + team->mode_kind = new_mode->kind;
>> + memcpy(&team->mode_ops, new_mode->ops, sizeof(struct team_mode_ops));
>> +
>> + return 0;
>> +}
>> +
>> +static int team_change_mode(struct team *team, const char *kind)
>> +{
>> + struct team_mode *new_mode;
>> + struct net_device *dev = team->dev;
>> + int err;
>> +
>> + if (!list_empty(&team->port_list)) {
>> + netdev_err(dev, "No ports can be present during mode change\n");
>> + return -EBUSY;
>> + }
>> +
>> + if (team->mode_kind && strcmp(team->mode_kind, kind) == 0) {
>> + netdev_err(dev, "Unable to change to the same mode the team is in\n");
>> + return -EINVAL;
>> + }
>> +
>> + new_mode = team_mode_get(kind);
>> + if (!new_mode) {
>> + netdev_err(dev, "Mode \"%s\" not found\n", kind);
>> + return -EINVAL;
>> + }
>> +
>> + err = __team_change_mode(team, new_mode);
>> + if (err) {
>> + netdev_err(dev, "Failed to change to mode \"%s\"\n", kind);
>> + team_mode_put(kind);
>> + return err;
>> + }
>> +
>> + netdev_info(dev, "Mode changed to \"%s\"\n", kind);
>> + return 0;
>> +}
>> +
>> +
>> +/************************
>> + * Rx path frame handler
>> + ************************/
>> +
>> +/* note: already called with rcu_read_lock */
>> +static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
>> +{
>> + struct sk_buff *skb = *pskb;
>> + struct team_port *port;
>> + struct team *team;
>> + rx_handler_result_t res = RX_HANDLER_ANOTHER;
>> +
>> + skb = skb_share_check(skb, GFP_ATOMIC);
>> + if (!skb)
>> + return RX_HANDLER_CONSUMED;
>> +
>> + *pskb = skb;
>> +
>> + port = team_port_get_rcu(skb->dev);
>> + team = port->team;
>> +
>> + if (team->mode_ops.receive)
>> + res = team->mode_ops.receive(team, port, skb);
>> +
>> + if (res == RX_HANDLER_ANOTHER) {
>> + struct team_pcpu_stats *pcpu_stats;
>> +
>> + pcpu_stats = this_cpu_ptr(team->pcpu_stats);
>> + u64_stats_update_begin(&pcpu_stats->syncp);
>> + pcpu_stats->rx_packets++;
>> + pcpu_stats->rx_bytes += skb->len;
>> + if (skb->pkt_type == PACKET_MULTICAST)
>> + pcpu_stats->rx_multicast++;
>> + u64_stats_update_end(&pcpu_stats->syncp);
>> +
>> + skb->dev = team->dev;
>> + } else {
>> + this_cpu_inc(team->pcpu_stats->rx_dropped);
>> + }
>> +
>> + return res;
>> +}
>> +
>> +
>> +/****************
>> + * Port handling
>> + ****************/
>> +
>> +static bool team_port_find(const struct team *team,
>> + const struct team_port *port)
>> +{
>> + struct team_port *cur;
>> +
>> + list_for_each_entry(cur, &team->port_list, list)
>> + if (cur == port)
>> + return true;
>> + return false;
>> +}
>> +
>> +static int team_port_list_init(struct team *team)
>> +{
>> + int i;
>> + struct hlist_head *hash;
>> +
>> + hash = kmalloc(sizeof(*hash) * TEAM_PORT_HASHENTRIES, GFP_KERNEL);
>> + if (!hash)
>> + return -ENOMEM;
>> +
>> + for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
>> + INIT_HLIST_HEAD(&hash[i]);
>> + team->port_hlist = hash;
>> + INIT_LIST_HEAD(&team->port_list);
>> + return 0;
>> +}
>> +
>> +static void team_port_list_fini(struct team *team)
>> +{
>> + kfree(team->port_hlist);
>> +}
>> +
>> +/*
>> + * Add/delete port to the team port list. Write guarded by rtnl_lock.
>> + * Takes care of correct port->index setup (might be racy).
>> + */
>> +static void team_port_list_add_port(struct team *team,
>> + struct team_port *port)
>> +{
>> + port->index = team->port_count++;
>> + hlist_add_head_rcu(&port->hlist,
>> + team_port_index_hash(team, port->index));
>> + list_add_tail_rcu(&port->list, &team->port_list);
>> +}
>> +
>> +static void __reconstruct_port_hlist(struct team *team, int rm_index)
>> +{
>> + int i;
>> + struct team_port *port;
>> +
>> + for (i = rm_index + 1; i < team->port_count; i++) {
>> + port = team_get_port_by_index_rcu(team, i);
>> + hlist_del_rcu(&port->hlist);
>> + port->index--;
>> + hlist_add_head_rcu(&port->hlist,
>> + team_port_index_hash(team, port->index));
>> + }
>> +}
>> +
>> +static void team_port_list_del_port(struct team *team,
>> + struct team_port *port)
>> +{
>> + int rm_index = port->index;
>> +
>> + hlist_del_rcu(&port->hlist);
>> + list_del_rcu(&port->list);
>> + __reconstruct_port_hlist(team, rm_index);
>> + team->port_count--;
>> +}
>> +
>> +#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
>> + NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
>> + NETIF_F_HIGHDMA | NETIF_F_LRO)
>> +
>> +static void __team_compute_features(struct team *team)
>> +{
>> + struct team_port *port;
>> + u32 vlan_features = TEAM_VLAN_FEATURES;
>> + unsigned short max_hard_header_len = ETH_HLEN;
>> +
>> + list_for_each_entry(port, &team->port_list, list) {
>> + vlan_features = netdev_increment_features(vlan_features,
>> + port->dev->vlan_features,
>> + TEAM_VLAN_FEATURES);
>> +
>> + if (port->dev->hard_header_len > max_hard_header_len)
>> + max_hard_header_len = port->dev->hard_header_len;
>> + }
>> +
>> + team->dev->vlan_features = vlan_features;
>> + team->dev->hard_header_len = max_hard_header_len;
>> +
>> + netdev_change_features(team->dev);
>> +}
>> +
>> +static void team_compute_features(struct team *team)
>> +{
>> + spin_lock(&team->lock);
>> + __team_compute_features(team);
>> + spin_unlock(&team->lock);
>> +}
>> +
>> +static int team_port_enter(struct team *team, struct team_port *port)
>> +{
>> + int err = 0;
>> +
>> + dev_hold(team->dev);
>> + port->dev->priv_flags |= IFF_TEAM_PORT;
>> + if (team->mode_ops.port_enter) {
>> + err = team->mode_ops.port_enter(team, port);
>> + if (err)
>> + netdev_err(team->dev, "Device %s failed to enter team mode\n",
>> + port->dev->name);
>> + }
>> + return err;
>> +}
>> +
>> +static void team_port_leave(struct team *team, struct team_port *port)
>> +{
>> + if (team->mode_ops.port_leave)
>> + team->mode_ops.port_leave(team, port);
>> + port->dev->priv_flags &= ~IFF_TEAM_PORT;
>> + dev_put(team->dev);
>> +}
>> +
>> +static void __team_port_change_check(struct team_port *port, bool linkup);
>> +
>> +static int team_port_add(struct team *team, struct net_device *port_dev)
>> +{
>> + struct net_device *dev = team->dev;
>> + struct team_port *port;
>> + char *portname = port_dev->name;
>> + char tmp_addr[ETH_ALEN];
>> + int err;
>> +
>> + if (port_dev->flags & IFF_LOOPBACK ||
>> + port_dev->type != ARPHRD_ETHER) {
>> + netdev_err(dev, "Device %s is of an unsupported type\n",
>> + portname);
>> + return -EINVAL;
>> + }
>> +
>> + if (team_port_exists(port_dev)) {
>> + netdev_err(dev, "Device %s is already a port "
>> + "of a team device\n", portname);
>> + return -EBUSY;
>> + }
>> +
>> + if (port_dev->flags & IFF_UP) {
>> + netdev_err(dev, "Device %s is up. Set it down before adding it as a team port\n",
>> + portname);
>> + return -EBUSY;
>> + }
>> +
>> + port = kzalloc(sizeof(struct team_port), GFP_KERNEL);
>> + if (!port)
>> + return -ENOMEM;
>> +
>> + port->dev = port_dev;
>> + port->team = team;
>> +
>> + port->orig.mtu = port_dev->mtu;
>> + err = dev_set_mtu(port_dev, dev->mtu);
>> + if (err) {
>> + netdev_dbg(dev, "Error %d calling dev_set_mtu\n", err);
>> + goto err_set_mtu;
>> + }
>> +
>> + memcpy(port->orig.dev_addr, port_dev->dev_addr, ETH_ALEN);
>> + random_ether_addr(tmp_addr);
>> + err = __set_port_mac(port_dev, tmp_addr);
>> + if (err) {
>> + netdev_dbg(dev, "Device %s mac addr set failed\n",
>> + portname);
>> + goto err_set_mac_rand;
>> + }
>> +
>> + err = dev_open(port_dev);
>> + if (err) {
>> + netdev_dbg(dev, "Device %s opening failed\n",
>> + portname);
>> + goto err_dev_open;
>> + }
>> +
>> + err = team_port_set_orig_mac(port);
>> + if (err) {
>> + netdev_dbg(dev, "Device %s mac addr set failed - Device does not support addr change when it's opened\n",
>> + portname);
>> + goto err_set_mac_opened;
>> + }
>> +
>> + err = team_port_enter(team, port);
>> + if (err) {
>> + netdev_err(dev, "Device %s failed to enter team mode\n",
>> + portname);
>> + goto err_port_enter;
>> + }
>> +
>> + err = netdev_set_master(port_dev, dev);
>> + if (err) {
>> + netdev_err(dev, "Device %s failed to set master\n", portname);
>> + goto err_set_master;
>> + }
>> +
>> + err = netdev_rx_handler_register(port_dev, team_handle_frame,
>> + port);
>> + if (err) {
>> + netdev_err(dev, "Device %s failed to register rx_handler\n",
>> + portname);
>> + goto err_handler_register;
>> + }
>> +
>> + team_port_list_add_port(team, port);
>> + __team_compute_features(team);
>> + __team_port_change_check(port, !!netif_carrier_ok(port_dev));
>> +
>> + netdev_info(dev, "Port device %s added\n", portname);
>> +
>> + return 0;
>> +
>> +err_handler_register:
>> + netdev_set_master(port_dev, NULL);
>> +
>> +err_set_master:
>> + team_port_leave(team, port);
>> +
>> +err_port_enter:
>> +err_set_mac_opened:
>> + dev_close(port_dev);
>> +
>> +err_dev_open:
>> + team_port_set_orig_mac(port);
>> +
>> +err_set_mac_rand:
>> + dev_set_mtu(port_dev, port->orig.mtu);
>> +
>> +err_set_mtu:
>> + kfree(port);
>> +
>> + return err;
>> +}
>> +
>> +static int team_port_del(struct team *team, struct net_device *port_dev)
>> +{
>> + struct net_device *dev = team->dev;
>> + struct team_port *port;
>> + char *portname = port_dev->name;
>> +
>> + port = team_port_get_rtnl(port_dev);
>> + if (!port || !team_port_find(team, port)) {
>> + netdev_err(dev, "Device %s does not act as a port of this team\n",
>> + portname);
>> + return -ENOENT;
>> + }
>> +
>> + __team_port_change_check(port, false);
>> + team_port_list_del_port(team, port);
>> + netdev_rx_handler_unregister(port_dev);
>> + netdev_set_master(port_dev, NULL);
>> + team_port_leave(team, port);
>> + dev_close(port_dev);
>> + team_port_set_orig_mac(port);
>> + dev_set_mtu(port_dev, port->orig.mtu);
>> + synchronize_rcu();
>> + kfree(port);
>> + netdev_info(dev, "Port device %s removed\n", portname);
>> + __team_compute_features(team);
>> +
>> + return 0;
>> +}
>> +
>> +
>> +/*****************
>> + * Net device ops
>> + *****************/
>> +
>> +static const char team_no_mode_kind[] = "*NOMODE*";
>> +
>> +static int team_mode_option_get(struct team *team, void *arg)
>> +{
>> + const char **str = arg;
>> +
>> + *str = team->mode_kind ? team->mode_kind : team_no_mode_kind;
>> + return 0;
>> +}
>> +
>> +static int team_mode_option_set(struct team *team, void *arg)
>> +{
>> + const char **str = arg;
>> +
>> + return team_change_mode(team, *str);
>> +}
>> +
>> +static struct team_option team_options[] = {
>> + {
>> + .name = "mode",
>> + .type = TEAM_OPTION_TYPE_STRING,
>> + .getter = team_mode_option_get,
>> + .setter = team_mode_option_set,
>> + },
>> +};
>> +
>> +static int team_init(struct net_device *dev)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + int err;
>> +
>> + team->dev = dev;
>> + spin_lock_init(&team->lock);
>> +
>> + team->pcpu_stats = alloc_percpu(struct team_pcpu_stats);
>> + if (!team->pcpu_stats)
>> + return -ENOMEM;
>> +
>> + err = team_port_list_init(team);
>> + if (err)
>> + goto err_port_list_init;
>> +
>> + INIT_LIST_HEAD(&team->option_list);
>> + team_options_register(team, team_options, ARRAY_SIZE(team_options));
>> + netif_carrier_off(dev);
>> +
>> + return 0;
>> +
>> +err_port_list_init:
>> +
>> + free_percpu(team->pcpu_stats);
>> +
>> + return err;
>> +}
>> +
>> +static void team_uninit(struct net_device *dev)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + struct team_port *port;
>> + struct team_port *tmp;
>> +
>> + spin_lock(&team->lock);
>> + list_for_each_entry_safe(port, tmp, &team->port_list, list)
>> + team_port_del(team, port->dev);
>> +
>> + __team_change_mode(team, NULL); /* cleanup */
>> + __team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
>> + spin_unlock(&team->lock);
>> +}
>> +
>> +static void team_destructor(struct net_device *dev)
>> +{
>> + struct team *team = netdev_priv(dev);
>> +
>> + team_port_list_fini(team);
>> + free_percpu(team->pcpu_stats);
>> + free_netdev(dev);
>> +}
>> +
>> +static int team_open(struct net_device *dev)
>> +{
>> + netif_carrier_on(dev);
>> + return 0;
>> +}
>> +
>> +static int team_close(struct net_device *dev)
>> +{
>> + netif_carrier_off(dev);
>> + return 0;
>> +}
>> +
>> +/*
>> + * note: already called with rcu_read_lock
>> + */
>> +static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + bool tx_success = false;
>> + unsigned int len = skb->len;
>> +
>> + /*
>> + * Ensure transmit function is called only in case there is at least
>> + * one port present.
>> + */
>> + if (likely(!list_empty(&team->port_list) && team->mode_ops.transmit))
>> + tx_success = team->mode_ops.transmit(team, skb);
>> + if (tx_success) {
>> + struct team_pcpu_stats *pcpu_stats;
>> +
>> + pcpu_stats = this_cpu_ptr(team->pcpu_stats);
>> + u64_stats_update_begin(&pcpu_stats->syncp);
>> + pcpu_stats->tx_packets++;
>> + pcpu_stats->tx_bytes += len;
>> + u64_stats_update_end(&pcpu_stats->syncp);
>> + } else {
>> + this_cpu_inc(team->pcpu_stats->tx_dropped);
>> + }
>> +
>> + return NETDEV_TX_OK;
>> +}
>> +
>> +static void team_change_rx_flags(struct net_device *dev, int change)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + struct team_port *port;
>> + int inc;
>> +
>> + rcu_read_lock();
>> + list_for_each_entry_rcu(port, &team->port_list, list) {
>> + if (change & IFF_PROMISC) {
>> + inc = dev->flags & IFF_PROMISC ? 1 : -1;
>> + dev_set_promiscuity(port->dev, inc);
>> + }
>> + if (change & IFF_ALLMULTI) {
>> + inc = dev->flags & IFF_ALLMULTI ? 1 : -1;
>> + dev_set_allmulti(port->dev, inc);
>> + }
>> + }
>> + rcu_read_unlock();
>> +}
>> +
>> +static void team_set_rx_mode(struct net_device *dev)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + struct team_port *port;
>> +
>> + rcu_read_lock();
>> + list_for_each_entry_rcu(port, &team->port_list, list) {
>> + dev_uc_sync(port->dev, dev);
>> + dev_mc_sync(port->dev, dev);
>> + }
>> + rcu_read_unlock();
>> +}
>> +
>> +static int team_set_mac_address(struct net_device *dev, void *p)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + struct team_port *port;
>> + struct sockaddr *addr = p;
>> +
>> + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
>> + rcu_read_lock();
>> + list_for_each_entry_rcu(port, &team->port_list, list)
>> + if (team->mode_ops.port_change_mac)
>> + team->mode_ops.port_change_mac(team, port);
>> + rcu_read_unlock();
>> + return 0;
>> +}
>> +
>> +static int team_change_mtu(struct net_device *dev, int new_mtu)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + struct team_port *port;
>> + int err;
>> +
>> + rcu_read_lock();
>> + list_for_each_entry_rcu(port, &team->port_list, list) {
>> + err = dev_set_mtu(port->dev, new_mtu);
>> + if (err) {
>> + netdev_err(dev, "Device %s failed to change mtu",
>> + port->dev->name);
>> + goto unwind;
>> + }
>> + }
>> + rcu_read_unlock();
>> +
>> + dev->mtu = new_mtu;
>> +
>> + return 0;
>> +
>> +unwind:
>> + list_for_each_entry_continue_reverse(port, &team->port_list, list)
>> + dev_set_mtu(port->dev, dev->mtu);
>> +
>> + rcu_read_unlock();
>> + return err;
>> +}
>> +
>> +static struct rtnl_link_stats64 *
>> +team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + struct team_pcpu_stats *p;
>> + u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
>> + u32 rx_dropped = 0, tx_dropped = 0;
>> + unsigned int start;
>> + int i;
>> +
>> + for_each_possible_cpu(i) {
>> + p = per_cpu_ptr(team->pcpu_stats, i);
>> + do {
>> + start = u64_stats_fetch_begin_bh(&p->syncp);
>> + rx_packets = p->rx_packets;
>> + rx_bytes = p->rx_bytes;
>> + rx_multicast = p->rx_multicast;
>> + tx_packets = p->tx_packets;
>> + tx_bytes = p->tx_bytes;
>> + } while (u64_stats_fetch_retry_bh(&p->syncp, start));
>> +
>> + stats->rx_packets += rx_packets;
>> + stats->rx_bytes += rx_bytes;
>> + stats->multicast += rx_multicast;
>> + stats->tx_packets += tx_packets;
>> + stats->tx_bytes += tx_bytes;
>> + /*
>> + * rx_dropped & tx_dropped are u32, updated
>> + * without syncp protection.
>> + */
>> + rx_dropped += p->rx_dropped;
>> + tx_dropped += p->tx_dropped;
>> + }
>> + stats->rx_dropped = rx_dropped;
>> + stats->tx_dropped = tx_dropped;
>> + return stats;
>> +}
>> +
>> +static void team_vlan_rx_add_vid(struct net_device *dev, uint16_t vid)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + struct team_port *port;
>> +
>> + rcu_read_lock();
>> + list_for_each_entry_rcu(port, &team->port_list, list) {
>> + const struct net_device_ops *ops = port->dev->netdev_ops;
>> +
>> + ops->ndo_vlan_rx_add_vid(port->dev, vid);
>> + }
>> + rcu_read_unlock();
>> +}
>> +
>> +static void team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + struct team_port *port;
>> +
>> + rcu_read_lock();
>> + list_for_each_entry_rcu(port, &team->port_list, list) {
>> + const struct net_device_ops *ops = port->dev->netdev_ops;
>> +
>> + ops->ndo_vlan_rx_kill_vid(port->dev, vid);
>> + }
>> + rcu_read_unlock();
>> +}
>> +
>> +static int team_add_slave(struct net_device *dev, struct net_device *port_dev)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + int err;
>> +
>> + spin_lock(&team->lock);
>> + err = team_port_add(team, port_dev);
>> + spin_unlock(&team->lock);
>> + return err;
>> +}
>> +
>> +static int team_del_slave(struct net_device *dev, struct net_device *port_dev)
>> +{
>> + struct team *team = netdev_priv(dev);
>> + int err;
>> +
>> + spin_lock(&team->lock);
>> + err = team_port_del(team, port_dev);
>> + spin_unlock(&team->lock);
>> + return err;
>> +}
>> +
>> +static const struct net_device_ops team_netdev_ops = {
>> + .ndo_init = team_init,
>> + .ndo_uninit = team_uninit,
>> + .ndo_open = team_open,
>> + .ndo_stop = team_close,
>> + .ndo_start_xmit = team_xmit,
>> + .ndo_change_rx_flags = team_change_rx_flags,
>> + .ndo_set_rx_mode = team_set_rx_mode,
>> + .ndo_set_mac_address = team_set_mac_address,
>> + .ndo_change_mtu = team_change_mtu,
>> + .ndo_get_stats64 = team_get_stats64,
>> + .ndo_vlan_rx_add_vid = team_vlan_rx_add_vid,
>> + .ndo_vlan_rx_kill_vid = team_vlan_rx_kill_vid,
>> + .ndo_add_slave = team_add_slave,
>> + .ndo_del_slave = team_del_slave,
>> +};
>> +
>> +
>> +/***********************
>> + * rt netlink interface
>> + ***********************/
>> +
>> +static void team_setup(struct net_device *dev)
>> +{
>> + ether_setup(dev);
>> +
>> + dev->netdev_ops = &team_netdev_ops;
>> + dev->destructor = team_destructor;
>> + dev->tx_queue_len = 0;
>> + dev->flags |= IFF_MULTICAST;
>> + dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
>> +
>> + /*
>> + * Indicate we support unicast address filtering. That way core won't
>> + * bring us to promisc mode in case a unicast addr is added.
>> + * Let this up to underlay drivers.
>> + */
>> + dev->priv_flags |= IFF_UNICAST_FLT;
>> +
>> + dev->features |= NETIF_F_LLTX;
>> + dev->features |= NETIF_F_GRO;
>> + dev->hw_features = NETIF_F_HW_VLAN_TX |
>> + NETIF_F_HW_VLAN_RX |
>> + NETIF_F_HW_VLAN_FILTER;
>> +
>> + dev->features |= dev->hw_features;
>> +}
>> +
>> +static int team_newlink(struct net *src_net, struct net_device *dev,
>> + struct nlattr *tb[], struct nlattr *data[])
>> +{
>> + int err;
>> +
>> + if (tb[IFLA_ADDRESS] == NULL)
>> + random_ether_addr(dev->dev_addr);
>> +
>> + err = register_netdevice(dev);
>> + if (err)
>> + return err;
>> +
>> + return 0;
>> +}
>> +
>> +static int team_validate(struct nlattr *tb[], struct nlattr *data[])
>> +{
>> + if (tb[IFLA_ADDRESS]) {
>> + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
>> + return -EINVAL;
>> + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
>> + return -EADDRNOTAVAIL;
>> + }
>> + return 0;
>> +}
>> +
>> +static struct rtnl_link_ops team_link_ops __read_mostly = {
>> + .kind = DRV_NAME,
>> + .priv_size = sizeof(struct team),
>> + .setup = team_setup,
>> + .newlink = team_newlink,
>> + .validate = team_validate,
>> +};
>> +
>> +
>> +/***********************************
>> + * Generic netlink custom interface
>> + ***********************************/
>> +
>> +static struct genl_family team_nl_family = {
>> + .id = GENL_ID_GENERATE,
>> + .name = TEAM_GENL_NAME,
>> + .version = TEAM_GENL_VERSION,
>> + .maxattr = TEAM_ATTR_MAX,
>> + .netnsok = true,
>> +};
>> +
>> +static const struct nla_policy team_nl_policy[TEAM_ATTR_MAX + 1] = {
>> + [TEAM_ATTR_UNSPEC] = { .type = NLA_UNSPEC, },
>> + [TEAM_ATTR_TEAM_IFINDEX] = { .type = NLA_U32 },
>> + [TEAM_ATTR_LIST_OPTION] = { .type = NLA_NESTED },
>> + [TEAM_ATTR_LIST_PORT] = { .type = NLA_NESTED },
>> +};
>> +
>> +static const struct nla_policy
>> +team_nl_option_policy[TEAM_ATTR_OPTION_MAX + 1] = {
>> + [TEAM_ATTR_OPTION_UNSPEC] = { .type = NLA_UNSPEC, },
>> + [TEAM_ATTR_OPTION_NAME] = {
>> + .type = NLA_STRING,
>> + .len = TEAM_STRING_MAX_LEN,
>> + },
>> + [TEAM_ATTR_OPTION_CHANGED] = { .type = NLA_FLAG },
>> + [TEAM_ATTR_OPTION_TYPE] = { .type = NLA_U8 },
>> + [TEAM_ATTR_OPTION_DATA] = {
>> + .type = NLA_BINARY,
>> + .len = TEAM_STRING_MAX_LEN,
>> + },
>> +};
>> +
>> +static int team_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
>> +{
>> + struct sk_buff *msg;
>> + void *hdr;
>> + int err;
>> +
>> + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
>> + if (!msg)
>> + return -ENOMEM;
>> +
>> + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
>> + &team_nl_family, 0, TEAM_CMD_NOOP);
>> + if (IS_ERR(hdr)) {
>> + err = PTR_ERR(hdr);
>> + goto err_msg_put;
>> + }
>> +
>> + genlmsg_end(msg, hdr);
>> +
>> + return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid);
>> +
>> +err_msg_put:
>> + nlmsg_free(msg);
>> +
>> + return err;
>> +}
>> +
>> +/*
>> + * Netlink cmd functions should be locked by following two functions.
>> + * To ensure team_uninit would not be called in between, hold rcu_read_lock
>> + * all the time.
>> + */
>> +static struct team *team_nl_team_get(struct genl_info *info)
>> +{
>> + struct net *net = genl_info_net(info);
>> + int ifindex;
>> + struct net_device *dev;
>> + struct team *team;
>> +
>> + if (!info->attrs[TEAM_ATTR_TEAM_IFINDEX])
>> + return NULL;
>> +
>> + ifindex = nla_get_u32(info->attrs[TEAM_ATTR_TEAM_IFINDEX]);
>> + rcu_read_lock();
>> + dev = dev_get_by_index_rcu(net, ifindex);
>> + if (!dev || dev->netdev_ops != &team_netdev_ops) {
>> + rcu_read_unlock();
>> + return NULL;
>> + }
>> +
>> + team = netdev_priv(dev);
>> + spin_lock(&team->lock);
>> + return team;
>> +}
>> +
>> +static void team_nl_team_put(struct team *team)
>> +{
>> + spin_unlock(&team->lock);
>> + rcu_read_unlock();
>> +}
>> +
>> +static int team_nl_send_generic(struct genl_info *info, struct team *team,
>> + int (*fill_func)(struct sk_buff *skb,
>> + struct genl_info *info,
>> + int flags, struct team *team))
>> +{
>> + struct sk_buff *skb;
>> + int err;
>> +
>> + skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
>> + if (!skb)
>> + return -ENOMEM;
>> +
>> + err = fill_func(skb, info, NLM_F_ACK, team);
>> + if (err < 0)
>> + goto err_fill;
>> +
>> + err = genlmsg_unicast(genl_info_net(info), skb, info->snd_pid);
>> + return err;
>> +
>> +err_fill:
>> + nlmsg_free(skb);
>> + return err;
>> +}
>> +
>> +static int team_nl_fill_options_get_changed(struct sk_buff *skb,
>> + u32 pid, u32 seq, int flags,
>> + struct team *team,
>> + struct team_option *changed_option)
>> +{
>> + struct nlattr *option_list;
>> + void *hdr;
>> + struct team_option *option;
>> +
>> + hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
>> + TEAM_CMD_OPTIONS_GET);
>> + if (IS_ERR(hdr))
>> + return PTR_ERR(hdr);
>> +
>> + NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex);
>> + option_list = nla_nest_start(skb, TEAM_ATTR_LIST_OPTION);
>> + if (!option_list)
>> + return -EMSGSIZE;
>> +
>> + list_for_each_entry(option, &team->option_list, list) {
>> + struct nlattr *option_item;
>> + long arg;
>> +
>> + option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
>> + if (!option_item)
>> + goto nla_put_failure;
>> + NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_NAME, option->name);
>> + if (option == changed_option)
>> + NLA_PUT_FLAG(skb, TEAM_ATTR_OPTION_CHANGED);
>> + switch (option->type) {
>> + case TEAM_OPTION_TYPE_U32:
>> + NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32);
>> + team_option_get(team, option, &arg);
>> + NLA_PUT_U32(skb, TEAM_ATTR_OPTION_DATA, arg);
>> + break;
>> + case TEAM_OPTION_TYPE_STRING:
>> + NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING);
>> + team_option_get(team, option, &arg);
>> + NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_DATA,
>> + (char *) arg);
>> + break;
>> + default:
>> + BUG();
>> + }
>> + nla_nest_end(skb, option_item);
>> + }
>> +
>> + nla_nest_end(skb, option_list);
>> + return genlmsg_end(skb, hdr);
>> +
>> +nla_put_failure:
>> + genlmsg_cancel(skb, hdr);
>> + return -EMSGSIZE;
>> +}
>> +
>> +static int team_nl_fill_options_get(struct sk_buff *skb,
>> + struct genl_info *info, int flags,
>> + struct team *team)
>> +{
>> + return team_nl_fill_options_get_changed(skb, info->snd_pid,
>> + info->snd_seq, NLM_F_ACK,
>> + team, NULL);
>> +}
>> +
>> +static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info)
>> +{
>> + struct team *team;
>> + int err;
>> +
>> + team = team_nl_team_get(info);
>> + if (!team)
>> + return -EINVAL;
>> +
>> + err = team_nl_send_generic(info, team, team_nl_fill_options_get);
>> +
>> + team_nl_team_put(team);
>> +
>> + return err;
>> +}
>> +
>> +static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
>> +{
>> + struct team *team;
>> + int err = 0;
>> + int i;
>> + struct nlattr *nl_option;
>> +
>> + team = team_nl_team_get(info);
>> + if (!team)
>> + return -EINVAL;
>> +
>> + err = -EINVAL;
>> + if (!info->attrs[TEAM_ATTR_LIST_OPTION]) {
>> + err = -EINVAL;
>> + goto team_put;
>> + }
>> +
>> + nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) {
>> + struct nlattr *mode_attrs[TEAM_ATTR_OPTION_MAX + 1];
>> + enum team_option_type opt_type;
>> + struct team_option *option;
>> + char *opt_name;
>> + bool opt_found = false;
>> +
>> + if (nla_type(nl_option) != TEAM_ATTR_ITEM_OPTION) {
>> + err = -EINVAL;
>> + goto team_put;
>> + }
>> + err = nla_parse_nested(mode_attrs, TEAM_ATTR_OPTION_MAX,
>> + nl_option, team_nl_option_policy);
>> + if (err)
>> + goto team_put;
>> + if (!mode_attrs[TEAM_ATTR_OPTION_NAME] ||
>> + !mode_attrs[TEAM_ATTR_OPTION_TYPE] ||
>> + !mode_attrs[TEAM_ATTR_OPTION_DATA]) {
>> + err = -EINVAL;
>> + goto team_put;
>> + }
>> + switch (nla_get_u8(mode_attrs[TEAM_ATTR_OPTION_TYPE])) {
>> + case NLA_U32:
>> + opt_type = TEAM_OPTION_TYPE_U32;
>> + break;
>> + case NLA_STRING:
>> + opt_type = TEAM_OPTION_TYPE_STRING;
>> + break;
>> + default:
>> + goto team_put;
>> + }
>> +
>> + opt_name = nla_data(mode_attrs[TEAM_ATTR_OPTION_NAME]);
>> + list_for_each_entry(option, &team->option_list, list) {
>> + long arg;
>> + struct nlattr *opt_data_attr;
>> +
>> + if (option->type != opt_type ||
>> + strcmp(option->name, opt_name))
>> + continue;
>> + opt_found = true;
>> + opt_data_attr = mode_attrs[TEAM_ATTR_OPTION_DATA];
>> + switch (opt_type) {
>> + case TEAM_OPTION_TYPE_U32:
>> + arg = nla_get_u32(opt_data_attr);
>> + break;
>> + case TEAM_OPTION_TYPE_STRING:
>> + arg = (long) nla_data(opt_data_attr);
>> + break;
>> + default:
>> + BUG();
>> + }
>> + err = team_option_set(team, option, &arg);
>> + if (err)
>> + goto team_put;
>> + }
>> + if (!opt_found) {
>> + err = -ENOENT;
>> + goto team_put;
>> + }
>> + }
>> +
>> +team_put:
>> + team_nl_team_put(team);
>> +
>> + return err;
>> +}
>> +
>> +static int team_nl_fill_port_list_get_changed(struct sk_buff *skb,
>> + u32 pid, u32 seq, int flags,
>> + struct team *team,
>> + struct team_port *changed_port)
>> +{
>> + struct nlattr *port_list;
>> + void *hdr;
>> + struct team_port *port;
>> +
>> + hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
>> + TEAM_CMD_PORT_LIST_GET);
>> + if (IS_ERR(hdr))
>> + return PTR_ERR(hdr);
>> +
>> + NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex);
>> + port_list = nla_nest_start(skb, TEAM_ATTR_LIST_PORT);
>> + if (!port_list)
>> + return -EMSGSIZE;
>> +
>> + list_for_each_entry_rcu(port, &team->port_list, list) {
>> + struct nlattr *port_item;
>> +
>> + port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
>> + if (!port_item)
>> + goto nla_put_failure;
>> + NLA_PUT_U32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex);
>> + if (port == changed_port)
>> + NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_CHANGED);
>> + if (port->linkup)
>> + NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_LINKUP);
>> + NLA_PUT_U32(skb, TEAM_ATTR_PORT_SPEED, port->speed);
>> + NLA_PUT_U8(skb, TEAM_ATTR_PORT_DUPLEX, port->duplex);
>> + nla_nest_end(skb, port_item);
>> + }
>> +
>> + nla_nest_end(skb, port_list);
>> + return genlmsg_end(skb, hdr);
>> +
>> +nla_put_failure:
>> + genlmsg_cancel(skb, hdr);
>> + return -EMSGSIZE;
>> +}
>> +
>> +static int team_nl_fill_port_list_get(struct sk_buff *skb,
>> + struct genl_info *info, int flags,
>> + struct team *team)
>> +{
>> + return team_nl_fill_port_list_get_changed(skb, info->snd_pid,
>> + info->snd_seq, NLM_F_ACK,
>> + team, NULL);
>> +}
>> +
>> +static int team_nl_cmd_port_list_get(struct sk_buff *skb,
>> + struct genl_info *info)
>> +{
>> + struct team *team;
>> + int err;
>> +
>> + team = team_nl_team_get(info);
>> + if (!team)
>> + return -EINVAL;
>> +
>> + err = team_nl_send_generic(info, team, team_nl_fill_port_list_get);
>> +
>> + team_nl_team_put(team);
>> +
>> + return err;
>> +}
>> +
>> +static struct genl_ops team_nl_ops[] = {
>> + {
>> + .cmd = TEAM_CMD_NOOP,
>> + .doit = team_nl_cmd_noop,
>> + .policy = team_nl_policy,
>> + },
>> + {
>> + .cmd = TEAM_CMD_OPTIONS_SET,
>> + .doit = team_nl_cmd_options_set,
>> + .policy = team_nl_policy,
>> + .flags = GENL_ADMIN_PERM,
>> + },
>> + {
>> + .cmd = TEAM_CMD_OPTIONS_GET,
>> + .doit = team_nl_cmd_options_get,
>> + .policy = team_nl_policy,
>> + .flags = GENL_ADMIN_PERM,
>> + },
>> + {
>> + .cmd = TEAM_CMD_PORT_LIST_GET,
>> + .doit = team_nl_cmd_port_list_get,
>> + .policy = team_nl_policy,
>> + .flags = GENL_ADMIN_PERM,
>> + },
>> +};
>> +
>> +static struct genl_multicast_group team_change_event_mcgrp = {
>> + .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
>> +};
>> +
>> +static int team_nl_send_event_options_get(struct team *team,
>> + struct team_option *changed_option)
>> +{
>> + struct sk_buff *skb;
>> + int err;
>> + struct net *net = dev_net(team->dev);
>> +
>> + skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
>> + if (!skb)
>> + return -ENOMEM;
>> +
>> + err = team_nl_fill_options_get_changed(skb, 0, 0, 0, team,
>> + changed_option);
>> + if (err < 0)
>> + goto err_fill;
>> +
>> + err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
>> + GFP_KERNEL);
>> + return err;
>> +
>> +err_fill:
>> + nlmsg_free(skb);
>> + return err;
>> +}
>> +
>> +static int team_nl_send_event_port_list_get(struct team_port *port)
>> +{
>> + struct sk_buff *skb;
>> + int err;
>> + struct net *net = dev_net(port->team->dev);
>> +
>> + skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
>> + if (!skb)
>> + return -ENOMEM;
>> +
>> + err = team_nl_fill_port_list_get_changed(skb, 0, 0, 0,
>> + port->team, port);
>> + if (err < 0)
>> + goto err_fill;
>> +
>> + err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
>> + GFP_KERNEL);
>> + return err;
>> +
>> +err_fill:
>> + nlmsg_free(skb);
>> + return err;
>> +}
>> +
>> +static int team_nl_init(void)
>> +{
>> + int err;
>> +
>> + err = genl_register_family_with_ops(&team_nl_family, team_nl_ops,
>> + ARRAY_SIZE(team_nl_ops));
>> + if (err)
>> + return err;
>> +
>> + err = genl_register_mc_group(&team_nl_family, &team_change_event_mcgrp);
>> + if (err)
>> + goto err_change_event_grp_reg;
>> +
>> + return 0;
>> +
>> +err_change_event_grp_reg:
>> + genl_unregister_family(&team_nl_family);
>> +
>> + return err;
>> +}
>> +
>> +static void team_nl_fini(void)
>> +{
>> + genl_unregister_family(&team_nl_family);
>> +}
>> +
>> +
>> +/******************
>> + * Change checkers
>> + ******************/
>> +
>> +static void __team_options_change_check(struct team *team,
>> + struct team_option *changed_option)
>> +{
>> + int err;
>> +
>> + err = team_nl_send_event_options_get(team, changed_option);
>> + if (err)
>> + netdev_warn(team->dev, "Failed to send options change via netlink\n");
>> +}
>> +
>> +/* rtnl lock is held */
>> +static void __team_port_change_check(struct team_port *port, bool linkup)
>> +{
>> + int err;
>> +
>> + if (port->linkup == linkup)
>> + return;
>> +
>> + port->linkup = linkup;
>> + if (linkup) {
>> + struct ethtool_cmd ecmd;
>> +
>> + err = __ethtool_get_settings(port->dev, &ecmd);
>> + if (!err) {
>> + port->speed = ethtool_cmd_speed(&ecmd);
>> + port->duplex = ecmd.duplex;
>> + goto send_event;
>> + }
>> + }
>> + port->speed = 0;
>> + port->duplex = 0;
>> +
>> +send_event:
>> + err = team_nl_send_event_port_list_get(port);
>> + if (err)
>> + netdev_warn(port->team->dev, "Failed to send port change of device %s via netlink\n",
>> + port->dev->name);
>> +
>> +}
>> +
>> +static void team_port_change_check(struct team_port *port, bool linkup)
>> +{
>> + struct team *team = port->team;
>> +
>> + spin_lock(&team->lock);
>> + __team_port_change_check(port, linkup);
>> + spin_unlock(&team->lock);
>> +}
>> +
>> +/************************************
>> + * Net device notifier event handler
>> + ************************************/
>> +
>> +static int team_device_event(struct notifier_block *unused,
>> + unsigned long event, void *ptr)
>> +{
>> + struct net_device *dev = (struct net_device *) ptr;
>> + struct team_port *port;
>> +
>> + port = team_port_get_rtnl(dev);
>> + if (!port)
>> + return NOTIFY_DONE;
>> +
>> + switch (event) {
>> + case NETDEV_UP:
>> + if (netif_carrier_ok(dev))
>> + team_port_change_check(port, true);
>> + case NETDEV_DOWN:
>> + team_port_change_check(port, false);
>> + case NETDEV_CHANGE:
>> + if (netif_running(port->dev))
>> + team_port_change_check(port,
>> + !!netif_carrier_ok(port->dev));
>> + break;
>> + case NETDEV_UNREGISTER:
>> + team_del_slave(port->team->dev, dev);
>> + break;
>> + case NETDEV_FEAT_CHANGE:
>> + team_compute_features(port->team);
>> + break;
>> + case NETDEV_CHANGEMTU:
>> + /* Forbid to change mtu of underlaying device */
>> + return NOTIFY_BAD;
>> + case NETDEV_CHANGEADDR:
>> + /* Forbid to change addr of underlaying device */
>> + return NOTIFY_BAD;
>> + case NETDEV_PRE_TYPE_CHANGE:
>> + /* Forbid to change type of underlaying device */
>> + return NOTIFY_BAD;
>> + }
>> + return NOTIFY_DONE;
>> +}
>> +
>> +static struct notifier_block team_notifier_block __read_mostly = {
>> + .notifier_call = team_device_event,
>> +};
>> +
>> +
>> +/***********************
>> + * Module init and exit
>> + ***********************/
>> +
>> +static int __init team_module_init(void)
>> +{
>> + int err;
>> +
>> + register_netdevice_notifier(&team_notifier_block);
>> +
>> + err = rtnl_link_register(&team_link_ops);
>> + if (err)
>> + goto err_rtln_reg;
>> +
>> + err = team_nl_init();
>> + if (err)
>> + goto err_nl_init;
>> +
>> + return 0;
>> +
>> +err_nl_init:
>> + rtnl_link_unregister(&team_link_ops);
>> +
>> +err_rtln_reg:
>> + unregister_netdevice_notifier(&team_notifier_block);
>> +
>> + return err;
>> +}
>> +
>> +static void __exit team_module_exit(void)
>> +{
>> + team_nl_fini();
>> + rtnl_link_unregister(&team_link_ops);
>> + unregister_netdevice_notifier(&team_notifier_block);
>> +}
>> +
>> +module_init(team_module_init);
>> +module_exit(team_module_exit);
>> +
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
>> +MODULE_DESCRIPTION("Ethernet team device driver");
>> +MODULE_ALIAS_RTNL_LINK(DRV_NAME);
>> diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
>> new file mode 100644
>> index 0000000..1aa2bfb
>> --- /dev/null
>> +++ b/drivers/net/team/team_mode_activebackup.c
>> @@ -0,0 +1,152 @@
>> +/*
>> + * net/drivers/team/team_mode_activebackup.c - Active-backup mode for team
>> + * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/types.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/errno.h>
>> +#include <linux/netdevice.h>
>> +#include <net/rtnetlink.h>
>> +#include <linux/if_team.h>
>> +
>> +struct ab_priv {
>> + struct team_port __rcu *active_port;
>> +};
>> +
>> +static struct ab_priv *ab_priv(struct team *team)
>> +{
>> + return (struct ab_priv *) &team->mode_priv;
>> +}
>> +
>> +static rx_handler_result_t ab_receive(struct team *team, struct team_port *port,
>> + struct sk_buff *skb) {
>> + struct team_port *active_port;
>> +
>> + active_port = rcu_dereference(ab_priv(team)->active_port);
>> + if (active_port != port)
>> + return RX_HANDLER_EXACT;
>> + return RX_HANDLER_ANOTHER;
>> +}
>> +
>> +static bool ab_transmit(struct team *team, struct sk_buff *skb)
>> +{
>> + struct team_port *active_port;
>> +
>> + active_port = rcu_dereference(ab_priv(team)->active_port);
>> + if (unlikely(!active_port))
>> + goto drop;
>> + skb->dev = active_port->dev;
>> + if (dev_queue_xmit(skb))
>> + return false;
>> + return true;
>> +
>> +drop:
>> + dev_kfree_skb(skb);
>> + return false;
>> +}
>> +
>> +static void ab_port_leave(struct team *team, struct team_port *port)
>> +{
>> + if (ab_priv(team)->active_port == port)
>> + rcu_assign_pointer(ab_priv(team)->active_port, NULL);
>> +}
>> +
>> +static void ab_port_change_mac(struct team *team, struct team_port *port)
>> +{
>> + if (ab_priv(team)->active_port == port)
>> + team_port_set_team_mac(port);
>> +}
>> +
>> +static int ab_active_port_get(struct team *team, void *arg)
>> +{
>> + u32 *ifindex = arg;
>> +
>> + *ifindex = 0;
>> + if (ab_priv(team)->active_port)
>> + *ifindex = ab_priv(team)->active_port->dev->ifindex;
>> + return 0;
>> +}
>> +
>> +static int ab_active_port_set(struct team *team, void *arg)
>> +{
>> + u32 *ifindex = arg;
>> + struct team_port *port;
>> +
>> + list_for_each_entry_rcu(port, &team->port_list, list) {
>> + if (port->dev->ifindex == *ifindex) {
>> + struct team_port *ac_port = ab_priv(team)->active_port;
>> +
>> + /* rtnl_lock needs to be held when setting macs */
>> + rtnl_lock();
>> + if (ac_port)
>> + team_port_set_orig_mac(ac_port);
>> + rcu_assign_pointer(ab_priv(team)->active_port, port);
>> + team_port_set_team_mac(port);
>> + rtnl_unlock();
>> + return 0;
>> + }
>> + }
>> + return -ENOENT;
>> +}
>> +
>> +static struct team_option ab_options[] = {
>> + {
>> + .name = "activeport",
>> + .type = TEAM_OPTION_TYPE_U32,
>> + .getter = ab_active_port_get,
>> + .setter = ab_active_port_set,
>> + },
>> +};
>> +
>> +int ab_init(struct team *team)
>> +{
>> + team_options_register(team, ab_options, ARRAY_SIZE(ab_options));
>> + return 0;
>> +}
>> +
>> +void ab_exit(struct team *team)
>> +{
>> + team_options_unregister(team, ab_options, ARRAY_SIZE(ab_options));
>> +}
>> +
>> +static const struct team_mode_ops ab_mode_ops = {
>> + .init = ab_init,
>> + .exit = ab_exit,
>> + .receive = ab_receive,
>> + .transmit = ab_transmit,
>> + .port_leave = ab_port_leave,
>> + .port_change_mac = ab_port_change_mac,
>> +};
>> +
>> +static struct team_mode ab_mode = {
>> + .kind = "activebackup",
>> + .owner = THIS_MODULE,
>> + .priv_size = sizeof(struct ab_priv),
>> + .ops = &ab_mode_ops,
>> +};
>> +
>> +static int __init ab_init_module(void)
>> +{
>> + return team_mode_register(&ab_mode);
>> +}
>> +
>> +static void __exit ab_cleanup_module(void)
>> +{
>> + team_mode_unregister(&ab_mode);
>> +}
>> +
>> +module_init(ab_init_module);
>> +module_exit(ab_cleanup_module);
>> +
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
>> +MODULE_DESCRIPTION("Active-backup mode for team");
>> +MODULE_ALIAS("team-mode-activebackup");
>> diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
>> new file mode 100644
>> index 0000000..0374052
>> --- /dev/null
>> +++ b/drivers/net/team/team_mode_roundrobin.c
>> @@ -0,0 +1,107 @@
>> +/*
>> + * net/drivers/team/team_mode_roundrobin.c - Round-robin mode for team
>> + * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/types.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/errno.h>
>> +#include <linux/netdevice.h>
>> +#include <linux/if_team.h>
>> +
>> +struct rr_priv {
>> + unsigned int sent_packets;
>> +};
>> +
>> +static struct rr_priv *rr_priv(struct team *team)
>> +{
>> + return (struct rr_priv *) &team->mode_priv;
>> +}
>> +
>> +static struct team_port *__get_first_port_up(struct team *team,
>> + struct team_port *port)
>> +{
>> + struct team_port *cur;
>> +
>> + if (port->linkup)
>> + return port;
>> + cur = port;
>> + list_for_each_entry_continue_rcu(cur, &team->port_list, list)
>> + if (cur->linkup)
>> + return cur;
>> + list_for_each_entry_rcu(cur, &team->port_list, list) {
>> + if (cur == port)
>> + break;
>> + if (cur->linkup)
>> + return cur;
>> + }
>> + return NULL;
>> +}
>> +
>> +static bool rr_transmit(struct team *team, struct sk_buff *skb)
>> +{
>> + struct team_port *port;
>> + int port_index;
>> +
>> + port_index = rr_priv(team)->sent_packets++ % team->port_count;
>> + port = team_get_port_by_index_rcu(team, port_index);
>> + port = __get_first_port_up(team, port);
>> + if (unlikely(!port))
>> + goto drop;
>> + skb->dev = port->dev;
>> + if (dev_queue_xmit(skb))
>> + return false;
>> + return true;
>> +
>> +drop:
>> + dev_kfree_skb(skb);
>> + return false;
>> +}
>> +
>> +static int rr_port_enter(struct team *team, struct team_port *port)
>> +{
>> + return team_port_set_team_mac(port);
>> +}
>> +
>> +static void rr_port_change_mac(struct team *team, struct team_port *port)
>> +{
>> + team_port_set_team_mac(port);
>> +}
>> +
>> +static const struct team_mode_ops rr_mode_ops = {
>> + .transmit = rr_transmit,
>> + .port_enter = rr_port_enter,
>> + .port_change_mac = rr_port_change_mac,
>> +};
>> +
>> +static struct team_mode rr_mode = {
>> + .kind = "roundrobin",
>> + .owner = THIS_MODULE,
>> + .priv_size = sizeof(struct rr_priv),
>> + .ops = &rr_mode_ops,
>> +};
>> +
>> +static int __init rr_init_module(void)
>> +{
>> + return team_mode_register(&rr_mode);
>> +}
>> +
>> +static void __exit rr_cleanup_module(void)
>> +{
>> + team_mode_unregister(&rr_mode);
>> +}
>> +
>> +module_init(rr_init_module);
>> +module_exit(rr_cleanup_module);
>> +
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
>> +MODULE_DESCRIPTION("Round-robin mode for team");
>> +MODULE_ALIAS("team-mode-roundrobin");
>> diff --git a/include/linux/Kbuild b/include/linux/Kbuild
>> index 619b565..0b091b3 100644
>> --- a/include/linux/Kbuild
>> +++ b/include/linux/Kbuild
>> @@ -185,6 +185,7 @@ header-y += if_pppol2tp.h
>> header-y += if_pppox.h
>> header-y += if_slip.h
>> header-y += if_strip.h
>> +header-y += if_team.h
>> header-y += if_tr.h
>> header-y += if_tun.h
>> header-y += if_tunnel.h
>> diff --git a/include/linux/if.h b/include/linux/if.h
>> index db20bd4..06b6ef6 100644
>> --- a/include/linux/if.h
>> +++ b/include/linux/if.h
>> @@ -79,6 +79,7 @@
>> #define IFF_TX_SKB_SHARING 0x10000 /* The interface supports sharing
>> * skbs on transmit */
>> #define IFF_UNICAST_FLT 0x20000 /* Supports unicast filtering */
>> +#define IFF_TEAM_PORT 0x40000 /* device used as team port */
>>
>> #define IF_GET_IFACE 0x0001 /* for querying only */
>> #define IF_GET_PROTO 0x0002
>> diff --git a/include/linux/if_team.h b/include/linux/if_team.h
>> new file mode 100644
>> index 0000000..21581a7
>> --- /dev/null
>> +++ b/include/linux/if_team.h
>> @@ -0,0 +1,233 @@
>> +/*
>> + * include/linux/if_team.h - Network team device driver header
>> + * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#ifndef _LINUX_IF_TEAM_H_
>> +#define _LINUX_IF_TEAM_H_
>> +
>> +#ifdef __KERNEL__
>> +
>> +struct team_pcpu_stats {
>> + u64 rx_packets;
>> + u64 rx_bytes;
>> + u64 rx_multicast;
>> + u64 tx_packets;
>> + u64 tx_bytes;
>> + struct u64_stats_sync syncp;
>> + u32 rx_dropped;
>> + u32 tx_dropped;
>> +};
>> +
>> +struct team;
>> +
>> +struct team_port {
>> + struct net_device *dev;
>> + struct hlist_node hlist; /* node in hash list */
>> + struct list_head list; /* node in ordinary list */
>> + struct team *team;
>> + int index;
>> +
>> + /*
>> + * A place for storing original values of the device before it
>> + * become a port.
>> + */
>> + struct {
>> + unsigned char dev_addr[MAX_ADDR_LEN];
>> + unsigned int mtu;
>> + } orig;
>> +
>> + bool linkup;
>> + u32 speed;
>> + u8 duplex;
>> +
>> + struct rcu_head rcu;
>> +};
>> +
>> +struct team_mode_ops {
>> + int (*init)(struct team *team);
>> + void (*exit)(struct team *team);
>> + rx_handler_result_t (*receive)(struct team *team,
>> + struct team_port *port,
>> + struct sk_buff *skb);
>> + bool (*transmit)(struct team *team, struct sk_buff *skb);
>> + int (*port_enter)(struct team *team, struct team_port *port);
>> + void (*port_leave)(struct team *team, struct team_port *port);
>> + void (*port_change_mac)(struct team *team, struct team_port *port);
>> +};
>> +
>> +enum team_option_type {
>> + TEAM_OPTION_TYPE_U32,
>> + TEAM_OPTION_TYPE_STRING,
>> +};
>> +
>> +struct team_option {
>> + struct list_head list;
>> + const char *name;
>> + enum team_option_type type;
>> + int (*getter)(struct team *team, void *arg);
>> + int (*setter)(struct team *team, void *arg);
>> +};
>> +
>> +struct team_mode {
>> + struct list_head list;
>> + const char *kind;
>> + struct module *owner;
>> + size_t priv_size;
>> + const struct team_mode_ops *ops;
>> +};
>> +
>> +#define TEAM_MODE_PRIV_LONGS 4
>> +#define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS)
>> +
>> +struct team {
>> + struct net_device *dev; /* associated netdevice */
>> + struct team_pcpu_stats __percpu *pcpu_stats;
>> +
>> + spinlock_t lock; /* used for overall locking, e.g. port lists write */
>> +
>> + /*
>> + * port lists with port count
>> + */
>> + int port_count;
>> + struct hlist_head *port_hlist;
>> + struct list_head port_list;
>> +
>> + struct list_head option_list;
>> +
>> + const char *mode_kind;
>> + struct team_mode_ops mode_ops;
>> + long mode_priv[TEAM_MODE_PRIV_LONGS];
>> +};
>> +
>> +#define TEAM_PORT_HASHBITS 4
>> +#define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS)
>> +
>> +static inline struct hlist_head *
>> +team_port_index_hash(const struct team *team,
>> + int port_index)
>> +{
>> + return &team->port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)];
>> +}
>> +
>> +static inline struct team_port *
>> +team_get_port_by_index_rcu(const struct team *team,
>> + int port_index)
>> +{
>> + struct hlist_node *p;
>> + struct team_port *port;
>> + struct hlist_head *head = team_port_index_hash(team, port_index);
>> +
>> + hlist_for_each_entry_rcu(port, p, head, hlist)
>> + if (port->index == port_index)
>> + return port;
>> + return NULL;
>> +}
>> +
>> +extern int team_port_set_orig_mac(struct team_port *port);
>> +extern int team_port_set_team_mac(struct team_port *port);
>> +extern void team_options_register(struct team *team,
>> + struct team_option *option,
>> + size_t option_count);
>> +extern void team_options_unregister(struct team *team,
>> + struct team_option *option,
>> + size_t option_count);
>> +extern int team_mode_register(struct team_mode *mode);
>> +extern int team_mode_unregister(struct team_mode *mode);
>> +
>> +#endif /* __KERNEL__ */
>> +
>> +#define TEAM_STRING_MAX_LEN 32
>> +
>> +/**********************************
>> + * NETLINK_GENERIC netlink family.
>> + **********************************/
>> +
>> +enum {
>> + TEAM_CMD_NOOP,
>> + TEAM_CMD_OPTIONS_SET,
>> + TEAM_CMD_OPTIONS_GET,
>> + TEAM_CMD_PORT_LIST_GET,
>> +
>> + __TEAM_CMD_MAX,
>> + TEAM_CMD_MAX = (__TEAM_CMD_MAX - 1),
>> +};
>> +
>> +enum {
>> + TEAM_ATTR_UNSPEC,
>> + TEAM_ATTR_TEAM_IFINDEX, /* u32 */
>> + TEAM_ATTR_LIST_OPTION, /* nest */
>> + TEAM_ATTR_LIST_PORT, /* nest */
>> +
>> + __TEAM_ATTR_MAX,
>> + TEAM_ATTR_MAX = __TEAM_ATTR_MAX - 1,
>> +};
>> +
>> +/* Nested layout of get/set msg:
>> + *
>> + * [TEAM_ATTR_LIST_OPTION]
>> + * [TEAM_ATTR_ITEM_OPTION]
>> + * [TEAM_ATTR_OPTION_*], ...
>> + * [TEAM_ATTR_ITEM_OPTION]
>> + * [TEAM_ATTR_OPTION_*], ...
>> + * ...
>> + * [TEAM_ATTR_LIST_PORT]
>> + * [TEAM_ATTR_ITEM_PORT]
>> + * [TEAM_ATTR_PORT_*], ...
>> + * [TEAM_ATTR_ITEM_PORT]
>> + * [TEAM_ATTR_PORT_*], ...
>> + * ...
>> + */
>> +
>> +enum {
>> + TEAM_ATTR_ITEM_OPTION_UNSPEC,
>> + TEAM_ATTR_ITEM_OPTION, /* nest */
>> +
>> + __TEAM_ATTR_ITEM_OPTION_MAX,
>> + TEAM_ATTR_ITEM_OPTION_MAX = __TEAM_ATTR_ITEM_OPTION_MAX - 1,
>> +};
>> +
>> +enum {
>> + TEAM_ATTR_OPTION_UNSPEC,
>> + TEAM_ATTR_OPTION_NAME, /* string */
>> + TEAM_ATTR_OPTION_CHANGED, /* flag */
>> + TEAM_ATTR_OPTION_TYPE, /* u8 */
>> + TEAM_ATTR_OPTION_DATA, /* dynamic */
>> +
>> + __TEAM_ATTR_OPTION_MAX,
>> + TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1,
>> +};
>> +
>> +enum {
>> + TEAM_ATTR_ITEM_PORT_UNSPEC,
>> + TEAM_ATTR_ITEM_PORT, /* nest */
>> +
>> + __TEAM_ATTR_ITEM_PORT_MAX,
>> + TEAM_ATTR_ITEM_PORT_MAX = __TEAM_ATTR_ITEM_PORT_MAX - 1,
>> +};
>> +
>> +enum {
>> + TEAM_ATTR_PORT_UNSPEC,
>> + TEAM_ATTR_PORT_IFINDEX, /* u32 */
>> + TEAM_ATTR_PORT_CHANGED, /* flag */
>> + TEAM_ATTR_PORT_LINKUP, /* flag */
>> + TEAM_ATTR_PORT_SPEED, /* u32 */
>> + TEAM_ATTR_PORT_DUPLEX, /* u8 */
>> +
>> + __TEAM_ATTR_PORT_MAX,
>> + TEAM_ATTR_PORT_MAX = __TEAM_ATTR_PORT_MAX - 1,
>> +};
>> +
>> +/*
>> + * NETLINK_GENERIC related info
>> + */
>> +#define TEAM_GENL_NAME "team"
>> +#define TEAM_GENL_VERSION 0x1
>> +#define TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME "change_event"
>> +
>> +#endif /* _LINUX_IF_TEAM_H_ */
>> --
>> 1.7.6
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
^ permalink raw reply
* Re: [PATCH v2 1/3] net: hold sock reference while processing tx timestamps
From: David Miller @ 2011-10-24 6:55 UTC (permalink / raw)
To: eric.dumazet; +Cc: richardcochran, netdev, johannes, stable
In-Reply-To: <1319196710.2338.26.camel@edumazet-HP-Compaq-6005-Pro-SFF-PC>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Fri, 21 Oct 2011 13:31:50 +0200
> Le vendredi 21 octobre 2011 à 12:49 +0200, Richard Cochran a écrit :
>> The pair of functions,
>>
>> * skb_clone_tx_timestamp()
>> * skb_complete_tx_timestamp()
>>
>> were designed to allow timestamping in PHY devices. The first
>> function, called during the MAC driver's hard_xmit method, identifies
>> PTP protocol packets, clones them, and gives them to the PHY device
>> driver. The PHY driver may hold onto the packet and deliver it at a
>> later time using the second function, which adds the packet to the
>> socket's error queue.
>>
>> As pointed out by Johannes, nothing prevents the socket from
>> disappearing while the cloned packet is sitting in the PHY driver
>> awaiting a timestamp. This patch fixes the issue by taking a reference
>> on the socket for each such packet. In addition, the comments
>> regarding the usage of these function are expanded to highlight the
>> rule that PHY drivers must use skb_complete_tx_timestamp() to release
>> the packet, in order to release the socket reference, too.
>>
>> These functions first appeared in v2.6.36.
>>
>> Reported-by: Johannes Berg <johannes@sipsolutions.net>
>> Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
>> Cc: <stable@vger.kernel.org>
>> ---
>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Applied.
^ permalink raw reply
* Re: [PATCH] Reindent closing bracket using tab instead of spaces
From: Junio C Hamano @ 2011-10-24 6:56 UTC (permalink / raw)
To: Nguyễn Thái Ngọc Duy; +Cc: git
In-Reply-To: <1319430291-12612-1-git-send-email-pclouds@gmail.com>
Thanks.
^ permalink raw reply
* Re: [PATCH net-next v3] route: fix ICMP redirect validation
From: David Miller @ 2011-10-24 6:56 UTC (permalink / raw)
To: fbl; +Cc: netdev
In-Reply-To: <1319215448-6777-1-git-send-email-fbl@redhat.com>
From: Flavio Leitner <fbl@redhat.com>
Date: Fri, 21 Oct 2011 14:44:08 -0200
> The commit f39925dbde7788cfb96419c0f092b086aa325c0f
> (ipv4: Cache learned redirect information in inetpeer.)
> removed some ICMP packet validations which are required by
> RFC 1122, section 3.2.2.2:
> ...
> A Redirect message SHOULD be silently discarded if the new
> gateway address it specifies is not on the same connected
> (sub-) net through which the Redirect arrived [INTRO:2,
> Appendix A], or if the source of the Redirect is not the
> current first-hop gateway for the specified destination (see
> Section 3.3.1).
>
> Signed-off-by: Flavio Leitner <fbl@redhat.com>
Applied, thanks.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.