#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline void chkmax(T &x, T y) {
  x = max(x, y);
}
template <typename T>
inline void chkmin(T &x, T y) {
  x = min(x, y);
}
template <typename T>
inline void read(T &x) {
  T f = 1;
  x = 0;
  char c = getchar();
  for (; !isdigit(c); c = getchar())
    if (c == '-') f = -f;
  for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
  x *= f;
}
const int N = 3e5 + 10;
const int M = 6e5 + 10;
struct Edge {
  int to, nxt;
} E[M];
int n, m, tot, timer, ans, C;
int dfn[N], low[N], col[N], head[N], is_bridge[M], f[N];
vector<int> g[N];
inline void AddEdge(int u, int v) {
  E[++tot] = (Edge){v, head[u]};
  head[u] = tot;
}
inline void Tarjan(int u, int pre) {
  dfn[u] = low[u] = ++timer;
  for (int i = head[u]; i; i = E[i].nxt) {
    int v = E[i].to;
    if (!dfn[v]) {
      Tarjan(v, i);
      chkmin(low[u], low[v]);
      if (low[v] > dfn[u]) is_bridge[i] = is_bridge[i ^ 1] = true;
    } else if (i != (pre ^ 1))
      chkmin(low[u], dfn[v]);
  }
}
inline void Color(int u, int c) {
  col[u] = c;
  for (int i = head[u]; i; i = E[i].nxt) {
    int v = E[i].to;
    if (!col[v] && !is_bridge[i]) Color(v, c);
  }
}
inline void solve(int u, int fa) {
  for (int v : g[u]) {
    if (v == fa) continue;
    solve(v, u);
    chkmax(ans, f[u] + 1 + f[v]);
    chkmax(f[u], f[v] + 1);
  }
}
int main() {
  read(n);
  read(m);
  tot = 1;
  for (int i = 1; i <= m; ++i) {
    int u, v;
    read(u), read(v);
    AddEdge(u, v), AddEdge(v, u);
  }
  for (int i = 1; i <= n; ++i)
    if (!dfn[i]) Tarjan(i, 0);
  for (int i = 1; i <= n; ++i)
    if (!col[i]) Color(i, ++C);
  for (int u = 1; u <= n; ++u)
    for (int i = head[u]; i; i = E[i].nxt) {
      int v = E[i].to;
      if (col[u] != col[v]) g[col[u]].emplace_back(col[v]);
    }
  solve(1, 0);
  printf("%d\n", ans);
  return 0;
}
